GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 107, 0 excluded
0.0%
Functions:
0 of 6, 0 excluded
0.0%
Branches:
0 of 1096, 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(QUOTEDBL),
27 K(HASH), K(PERCENT), K(DOLLAR), K(AMPERSAND), K(QUOTE), 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(BACKQUOTE),
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(AUDIONEXT), K(AUDIOPREV), K(AUDIOSTOP), K(AUDIOPLAY), K(AUDIOMUTE),
56 K(MEDIASELECT), K(WWW), K(MAIL), K(CALCULATOR), K(COMPUTER), K(AC_SEARCH), K(AC_HOME), K(AC_BACK),
57 K(AC_FORWARD), K(AC_STOP), K(AC_REFRESH), K(AC_BOOKMARKS), K(BRIGHTNESSDOWN),
58 K(BRIGHTNESSUP), K(DISPLAYSWITCH), K(KBDILLUMTOGGLE), K(KBDILLUMDOWN), K(KBDILLUMUP),
59 K(EJECT), K(SLEEP), K(APP1), K(APP2), K(AUDIOREWIND), K(AUDIOFASTFORWARD),
60 K(SOFTLEFT), K(SOFTRIGHT), K(CALL), K(ENDCALL),
61 #undef K
62 };
63
64 const auto it = key_map.find(lower(name));
65 if (it != key_map.end())
66 {
67 return it->second;
68 }
69
70 LOG_WARN("Unknown key name: '{}'", name);
71 return std::nullopt;
72 }
73
74 bool Input::load_from_file(const std::string& path)
75 {
76 const auto doc = kdl::parse(eu::io::string_from_file(path));
77
78 bool ok = true;
79
80 for (const auto& node : doc)
81 {
82 if (node.name() == "action")
83 {
84 const auto name = node.args()[0].as_string();
85
86 const auto existing = index_from_action.find(name);
87 if (existing != index_from_action.end())
88 {
89 LOG_WARN("Duplicate action found: '{}'", name);
90 ok = false;
91 continue;
92 }
93 const auto new_index = actions.size();
94 actions.emplace_back(Action{
95 .name = name,
96 .is_down = false,
97 .last_down = false
98 });
99 index_from_action[name] = new_index;
100 }
101 else if (node.name() == "key")
102 {
103 const auto action_name = node.args()[0].as_string();
104 const auto found_action = index_from_action.find(action_name);
105 if (found_action == index_from_action.end())
106 {
107 LOG_WARN("Invalid action name: {}", action_name);
108 ok = false;
109 continue;
110 }
111
112 const auto key_name = node.args()[1].as_string();
113 const auto key = key_from_name(key_name);
114 if (!key)
115 {
116 LOG_WARN("Invalid key name: {}", key_name);
117 ok = false;
118 continue;
119 }
120
121 const auto bind = KeyBind{
122 .sdl_keyboard_key = *key,
123 .bind_action = found_action->second
124 };
125 bind_from_key[*key] = bind;
126 }
127 else
128 {
129 LOG_WARN("Unknown node in input file: '{}'", node.name());
130 ok = false;
131 }
132 }
133
134 return ok && !bind_from_key.empty();
135 }
136
137
138 void Input::update()
139 {
140 for (auto& action : actions)
141 {
142 action.last_down = action.is_down;
143 }
144 }
145
146
147 void Input::on_key(int key, bool state)
148 {
149 const auto found = bind_from_key.find(key);
150 if (found == bind_from_key.end())
151 {
152 return;
153 }
154
155 const KeyBind& bind = found->second;
156 auto& action = actions[bind.bind_action];
157 action.is_down = state;
158 }
159
160
161 InputFrame Input::get_current_frame() const
162 {
163 InputFrame ret;
164 for (const auto& a: actions)
165 {
166 ret.binds.emplace_back(ScriptBind{
167 .name = a.name,
168 .current = a.is_down ? 1.0f : 0.0f,
169 .last = a.last_down ? 1.0f : 0.0f
170 });
171 }
172 return ret;
173 }
174
175
176
177 }
178