GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 106, 0 excluded
0.0%
Functions:
0 of 6, 0 excluded
0.0%
Branches:
0 of 1062, 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 doc = kdl::parse(eu::io::string_from_file(path));
76
77 bool ok = true;
78
79 for (const auto& node : doc)
80 {
81 if (node.name() == "action")
82 {
83 const auto name = node.args()[0].as_string();
84
85 const auto existing = index_from_action.find(name);
86 if (existing != index_from_action.end())
87 {
88 LOG_WARN("Duplicate action found: '{}'", name);
89 ok = false;
90 continue;
91 }
92 const auto new_index = actions.size();
93 actions.emplace_back(Action{
94 .name = name,
95 .is_down = false,
96 .last_down = false
97 });
98 index_from_action[name] = new_index;
99 }
100 else if (node.name() == "key")
101 {
102 const auto action_name = node.args()[0].as_string();
103 const auto found_action = index_from_action.find(action_name);
104 if (found_action == index_from_action.end())
105 {
106 LOG_WARN("Invalid action name: {}", action_name);
107 ok = false;
108 continue;
109 }
110
111 const auto key_name = node.args()[1].as_string();
112 const auto key = key_from_name(key_name);
113 if (!key)
114 {
115 LOG_WARN("Invalid key name: {}", key_name);
116 ok = false;
117 continue;
118 }
119
120 const auto bind = KeyBind{
121 .sdl_keyboard_key = *key,
122 .bind_action = found_action->second
123 };
124 bind_from_key[*key] = bind;
125 }
126 else
127 {
128 LOG_WARN("Unknown node in input file: '{}'", node.name());
129 ok = false;
130 }
131 }
132
133 return ok && !bind_from_key.empty();
134 }
135
136
137 void Input::update()
138 {
139 for (auto& action : actions)
140 {
141 action.last_down = action.is_down;
142 }
143 }
144
145
146 void Input::on_key(int key, bool state)
147 {
148 const auto found = bind_from_key.find(key);
149 if (found == bind_from_key.end())
150 {
151 return;
152 }
153
154 const KeyBind& bind = found->second;
155 auto& action = actions[bind.bind_action];
156 action.is_down = state;
157 }
158
159
160 InputFrame Input::get_current_frame() const
161 {
162 InputFrame ret;
163 for (const auto& a: actions)
164 {
165 ret.binds.emplace_back(ScriptBind{
166 .name = a.name,
167 .current = a.is_down ? 1.0f : 0.0f,
168 .last = a.last_down ? 1.0f : 0.0f
169 });
170 }
171 return ret;
172 }
173
174
175
176 }
177