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 |