GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 110, 0 excluded
0.0%
Functions:
0 of 6, 0 excluded
0.0%
Branches:
0 of 1070, 0 excluded
0.0%

apps/runner/src/eu/runner/input.cc
Line Branch Exec Source
1 #include "eu/runner/input.h"
2
3 #include <SDL_keycode.h>
4
5 #include "eu/io/file.h"
6 #include "eu/kdl/kdl.h"
7
8 namespace eu::runner
9 {
10
11 ✗ std::string lower(const std::string& str)
12 {
13 ✗ std::string result;
14 ✗ result.reserve(str.size());
15 ✗ for (const char c : str)
16 {
17 ✗ result.push_back(static_cast<char>(std::tolower(c)));
18 }
19 ✗ return result;
20 ✗ }
21
22 ✗ std::optional<KeyboardKey> key_from_name(const std::string& name)
23 {
24 static const std::unordered_map<std::string, KeyboardKey> key_map = {
25 #define K(name){lower(#name), SDLK_##name}
26 ✗ K(RETURN), K(ESCAPE), K(BACKSPACE), K(TAB), K(SPACE), K(EXCLAIM), K(DBLAPOSTROPHE),
27 ✗ K(HASH), K(PERCENT), K(DOLLAR), K(AMPERSAND), K(APOSTROPHE), K(LEFTPAREN),
28 ✗ K(RIGHTPAREN), K(ASTERISK), K(PLUS), K(COMMA), K(MINUS), K(PERIOD), K(SLASH),
29 ✗ K(0), K(1), K(2), K(3), K(4), K(5), K(6), K(7), K(8), K(9),
30 ✗ K(COLON), K(SEMICOLON), K(LESS), K(EQUALS), K(GREATER), K(QUESTION), K(AT),
31 ✗ K(LEFTBRACKET), K(BACKSLASH), K(RIGHTBRACKET), K(CARET), K(UNDERSCORE), K(GRAVE),
32 ✗ K(A), K(B), K(C), K(D), K(E), K(F), K(G), K(H), K(I), K(J),
33 ✗ K(K), K(L), K(M), K(N), K(O), K(P), K(Q), K(R), K(S), K(T),
34 ✗ K(U), K(V), K(W), K(X), K(Y), K(Z),
35 ✗ K(CAPSLOCK), K(F1), K(F2), K(F3), K(F4), K(F5), K(F6), K(F7), K(F8), K(F9), K(F10), K(F11), K(F12),
36 ✗ K(PRINTSCREEN), K(SCROLLLOCK), K(PAUSE), K(INSERT), K(HOME), K(PAGEUP), K(DELETE),
37 ✗ K(END), K(PAGEDOWN), K(RIGHT), K(LEFT), K(DOWN), K(UP), K(NUMLOCKCLEAR),
38 ✗ K(KP_DIVIDE), K(KP_MULTIPLY), K(KP_MINUS), K(KP_PLUS), K(KP_ENTER),
39 ✗ K(KP_1), K(KP_2), K(KP_3), K(KP_4), K(KP_5), K(KP_6), K(KP_7), K(KP_8), K(KP_9), K(KP_0),
40 ✗ K(KP_PERIOD), K(APPLICATION), K(POWER), K(KP_EQUALS),
41 ✗ K(F13), K(F14), K(F15), K(F16), K(F17), K(F18), K(F19), K(F20), K(F21), K(F22), K(F23), K(F24),
42 ✗ K(EXECUTE), K(HELP), K(MENU), K(SELECT), K(STOP), K(AGAIN), K(UNDO),
43 ✗ K(CUT), K(COPY), K(PASTE), K(FIND), K(MUTE), K(VOLUMEUP), K(VOLUMEDOWN),
44 ✗ K(KP_COMMA), K(KP_EQUALSAS400), K(ALTERASE), K(SYSREQ), K(CANCEL), K(CLEAR),
45 ✗ K(PRIOR), K(RETURN2), K(SEPARATOR), K(OUT), K(OPER), K(CLEARAGAIN), K(CRSEL),
46 ✗ K(EXSEL), K(KP_00), K(KP_000), K(THOUSANDSSEPARATOR), K(DECIMALSEPARATOR),
47 ✗ K(CURRENCYUNIT), K(CURRENCYSUBUNIT), K(KP_LEFTPAREN), K(KP_RIGHTPAREN), K(KP_LEFTBRACE),
48 ✗ K(KP_RIGHTBRACE), K(KP_TAB), K(KP_BACKSPACE), K(KP_A), K(KP_B), K(KP_C), K(KP_D),
49 ✗ K(KP_E), K(KP_F), K(KP_XOR), K(KP_POWER), K(KP_PERCENT), K(KP_LESS), K(KP_GREATER),
50 ✗ K(KP_AMPERSAND), K(KP_DBLAMPERSAND), K(KP_VERTICALBAR), K(KP_DBLVERTICALBAR), K(KP_COLON),
51 ✗ K(KP_HASH), K(KP_SPACE), K(KP_AT), K(KP_EXCLAM), K(KP_MEMSTORE), K(KP_MEMRECALL),
52 ✗ K(KP_MEMCLEAR), K(KP_MEMADD), K(KP_MEMSUBTRACT), K(KP_MEMMULTIPLY), K(KP_MEMDIVIDE),
53 ✗ K(KP_PLUSMINUS), K(KP_CLEAR), K(KP_CLEARENTRY), K(KP_BINARY), K(KP_OCTAL), K(KP_DECIMAL),
54 ✗ K(KP_HEXADECIMAL), K(LCTRL), K(LSHIFT), K(LALT), K(LGUI), K(RCTRL), K(RSHIFT), K(RALT),
55 ✗ K(RGUI), K(MODE), K(MEDIA_NEXT_TRACK), K(MEDIA_PREVIOUS_TRACK), K(MEDIA_STOP), K(MEDIA_PLAY), K(MUTE),
56 ✗ K(MEDIA_SELECT), K(AC_SEARCH), K(AC_HOME), K(AC_BACK),
57 ✗ K(AC_FORWARD), K(AC_STOP), K(AC_REFRESH), K(AC_BOOKMARKS),
58 ✗ K(MEDIA_EJECT), K(SLEEP), K(MEDIA_REWIND), K(MEDIA_FAST_FORWARD),
59 ✗ K(SOFTLEFT), K(SOFTRIGHT), K(CALL), K(ENDCALL),
60 #undef K
61 ✗ };
62
63 ✗ const auto it = key_map.find(lower(name));
64 ✗ if (it != key_map.end())
65 {
66 ✗ return it->second;
67 }
68
69 ✗ LOG_WARN("Unknown key name: '{}'", name);
70 ✗ return std::nullopt;
71 ✗ }
72
73 ✗ bool Input::load_from_file(const std::string& path)
74 {
75 ✗ const auto parsed = kdl::parse(eu::io::string_from_file(path));
76 ✗ if (parsed.document.has_value() == false)
77 {
78 ✗ LOG_WARN("Failed to parse {}: '{}'", path, parsed.error);
79 ✗ return false;
80 }
81
82 ✗ const auto& doc = *parsed.document;
83
84 ✗ bool ok = true;
85
86 ✗ for (const auto& node : doc)
87 {
88 ✗ if (node.name == "action")
89 {
90 ✗ const auto name = node.args[0].as_string();
91
92 ✗ const auto existing = index_from_action.find(name);
93 ✗ if (existing != index_from_action.end())
94 {
95 ✗ LOG_WARN("Duplicate action found: '{}'", name);
96 ✗ ok = false;
97 ✗ continue;
98 }
99 ✗ const auto new_index = actions.size();
100 ✗ actions.emplace_back(Action{
101 .name = name,
102 .is_down = false,
103 .last_down = false
104 });
105 ✗ index_from_action[name] = new_index;
106 ✗ }
107 ✗ else if (node.name == "key")
108 {
109 ✗ const auto action_name = node.args[0].as_string();
110 ✗ const auto found_action = index_from_action.find(action_name);
111 ✗ if (found_action == index_from_action.end())
112 {
113 ✗ LOG_WARN("Invalid action name: {}", action_name);
114 ✗ ok = false;
115 ✗ continue;
116 }
117
118 ✗ const auto key_name = node.args[1].as_string();
119 ✗ const auto key = key_from_name(key_name);
120 ✗ if (!key)
121 {
122 ✗ LOG_WARN("Invalid key name: {}", key_name);
123 ✗ ok = false;
124 ✗ continue;
125 }
126
127 const auto bind = KeyBind{
128 ✗ .sdl_keyboard_key = *key,
129 ✗ .bind_action = found_action->second
130 ✗ };
131 ✗ bind_from_key[*key] = bind;
132 ✗ }
133 else
134 {
135 ✗ LOG_WARN("Unknown node in input file: '{}'", node.name);
136 ✗ ok = false;
137 }
138 }
139
140 ✗ return ok && !bind_from_key.empty();
141 ✗ }
142
143
144 ✗ void Input::update()
145 {
146 ✗ for (auto& action : actions)
147 {
148 ✗ action.last_down = action.is_down;
149 }
150 ✗ }
151
152
153 ✗ void Input::on_key(int key, bool state)
154 {
155 ✗ const auto found = bind_from_key.find(key);
156 ✗ if (found == bind_from_key.end())
157 {
158 ✗ return;
159 }
160
161 ✗ const KeyBind& bind = found->second;
162 ✗ auto& action = actions[bind.bind_action];
163 ✗ action.is_down = state;
164 }
165
166
167 ✗ InputFrame Input::get_current_frame() const
168 {
169 ✗ InputFrame ret;
170 ✗ for (const auto& a: actions)
171 {
172 ✗ ret.binds.emplace_back(ScriptBind{
173 ✗ .name = a.name,
174 ✗ .current = a.is_down ? 1.0f : 0.0f,
175 ✗ .last = a.last_down ? 1.0f : 0.0f
176 });
177 }
178 ✗ return ret;
179 ✗ }
180
181
182
183 }
184