#pragma once #include "common/string.h" #include "common/types.h" #include #include #include #include #include #include namespace SDLKeyNames { enum : u32 { MODIFIER_SHIFT = 16, KEY_MASK = ((1 << MODIFIER_SHIFT) - 1), MODIFIER_MASK = ~KEY_MASK, }; static const std::map s_sdl_key_names = {{SDLK_RETURN, "Return"}, {SDLK_ESCAPE, "Escape"}, {SDLK_BACKSPACE, "Backspace"}, {SDLK_TAB, "Tab"}, {SDLK_SPACE, "Space"}, {SDLK_EXCLAIM, "Exclam"}, {SDLK_QUOTEDBL, "QuoteDbl"}, {SDLK_HASH, "Hash"}, {SDLK_PERCENT, "Percent"}, {SDLK_DOLLAR, "Dollar"}, {SDLK_AMPERSAND, "Ampersand"}, {SDLK_QUOTE, "Apostrophe"}, {SDLK_LEFTPAREN, "ParenLeft"}, {SDLK_RIGHTPAREN, "ParenRight"}, {SDLK_ASTERISK, "Asterisk"}, {SDLK_PLUS, "PLus"}, {SDLK_COMMA, "Comma"}, {SDLK_MINUS, "Minus"}, {SDLK_PERIOD, "Period"}, {SDLK_SLASH, "Slash"}, {SDLK_0, "0"}, {SDLK_1, "1"}, {SDLK_2, "2"}, {SDLK_3, "3"}, {SDLK_4, "4"}, {SDLK_5, "5"}, {SDLK_6, "6"}, {SDLK_7, "7"}, {SDLK_8, "8"}, {SDLK_9, "9"}, {SDLK_COLON, "Colon"}, {SDLK_SEMICOLON, "Semcolon"}, {SDLK_LESS, "Less"}, {SDLK_EQUALS, "Equal"}, {SDLK_GREATER, "Greater"}, {SDLK_QUESTION, "Question"}, {SDLK_AT, "AT"}, {SDLK_LEFTBRACKET, "BracketLeft"}, {SDLK_BACKSLASH, "Backslash"}, {SDLK_RIGHTBRACKET, "BracketRight"}, {SDLK_CARET, "Caret"}, {SDLK_UNDERSCORE, "Underscore"}, {SDLK_BACKQUOTE, "QuoteLeft"}, {SDLK_a, "A"}, {SDLK_b, "B"}, {SDLK_c, "C"}, {SDLK_d, "D"}, {SDLK_e, "E"}, {SDLK_f, "F"}, {SDLK_g, "G"}, {SDLK_h, "H"}, {SDLK_i, "I"}, {SDLK_j, "J"}, {SDLK_k, "K"}, {SDLK_l, "L"}, {SDLK_m, "M"}, {SDLK_n, "N"}, {SDLK_o, "O"}, {SDLK_p, "P"}, {SDLK_q, "Q"}, {SDLK_r, "R"}, {SDLK_s, "S"}, {SDLK_t, "T"}, {SDLK_u, "U"}, {SDLK_v, "V"}, {SDLK_w, "W"}, {SDLK_x, "X"}, {SDLK_y, "Y"}, {SDLK_z, "Z"}, {SDLK_CAPSLOCK, "CapsLock"}, {SDLK_F1, "F1"}, {SDLK_F2, "F2"}, {SDLK_F3, "F3"}, {SDLK_F4, "F4"}, {SDLK_F5, "F5"}, {SDLK_F6, "F6"}, {SDLK_F7, "F7"}, {SDLK_F8, "F8"}, {SDLK_F9, "F9"}, {SDLK_F10, "F10"}, {SDLK_F11, "F11"}, {SDLK_F12, "F12"}, {SDLK_PRINTSCREEN, "Print"}, {SDLK_SCROLLLOCK, "ScrollLock"}, {SDLK_PAUSE, "Pause"}, {SDLK_INSERT, "Insert"}, {SDLK_HOME, "Home"}, {SDLK_PAGEUP, "PageUp"}, {SDLK_DELETE, "Delete"}, {SDLK_END, "End"}, {SDLK_PAGEDOWN, "PageDown"}, {SDLK_RIGHT, "Right"}, {SDLK_LEFT, "Left"}, {SDLK_DOWN, "Down"}, {SDLK_UP, "Up"}, {SDLK_NUMLOCKCLEAR, "NumLock"}, {SDLK_KP_DIVIDE, "Keypad+Divide"}, {SDLK_KP_MULTIPLY, "Keypad+Multiply"}, {SDLK_KP_MINUS, "Keypad+Minus"}, {SDLK_KP_PLUS, "Keypad+Plus"}, {SDLK_KP_ENTER, "Keypad+Return"}, {SDLK_KP_1, "Keypad+1"}, {SDLK_KP_2, "Keypad+2"}, {SDLK_KP_3, "Keypad+3"}, {SDLK_KP_4, "Keypad+4"}, {SDLK_KP_5, "Keypad+5"}, {SDLK_KP_6, "Keypad+6"}, {SDLK_KP_7, "Keypad+7"}, {SDLK_KP_8, "Keypad+8"}, {SDLK_KP_9, "Keypad+9"}, {SDLK_KP_0, "Keypad+0"}, {SDLK_KP_PERIOD, "Keypad+Period"}, {SDLK_APPLICATION, "Application"}, {SDLK_POWER, "Power"}, {SDLK_KP_EQUALS, "Keypad+Equal"}, {SDLK_F13, "F13"}, {SDLK_F14, "F14"}, {SDLK_F15, "F15"}, {SDLK_F16, "F16"}, {SDLK_F17, "F17"}, {SDLK_F18, "F18"}, {SDLK_F19, "F19"}, {SDLK_F20, "F20"}, {SDLK_F21, "F21"}, {SDLK_F22, "F22"}, {SDLK_F23, "F23"}, {SDLK_F24, "F24"}, {SDLK_EXECUTE, "Execute"}, {SDLK_HELP, "Help"}, {SDLK_MENU, "Menu"}, {SDLK_SELECT, "Select"}, {SDLK_STOP, "Stop"}, {SDLK_AGAIN, "Again"}, {SDLK_UNDO, "Undo"}, {SDLK_CUT, "Cut"}, {SDLK_COPY, "Copy"}, {SDLK_PASTE, "Paste"}, {SDLK_FIND, "Find"}, {SDLK_MUTE, "Mute"}, {SDLK_VOLUMEUP, "VolumeUp"}, {SDLK_VOLUMEDOWN, "VolumeDown"}, {SDLK_KP_COMMA, "Keypad+Comma"}, {SDLK_KP_EQUALSAS400, "Keypad+EqualAS400"}, {SDLK_ALTERASE, "AltErase"}, {SDLK_SYSREQ, "SysReq"}, {SDLK_CANCEL, "Cancel"}, {SDLK_CLEAR, "Clear"}, {SDLK_PRIOR, "Prior"}, {SDLK_RETURN2, "Return2"}, {SDLK_SEPARATOR, "Separator"}, {SDLK_OUT, "Out"}, {SDLK_OPER, "Oper"}, {SDLK_CLEARAGAIN, "ClearAgain"}, {SDLK_CRSEL, "CrSel"}, {SDLK_EXSEL, "ExSel"}, {SDLK_KP_00, "Keypad+00"}, {SDLK_KP_000, "Keypad+000"}, {SDLK_THOUSANDSSEPARATOR, "ThousandsSeparator"}, {SDLK_DECIMALSEPARATOR, "DecimalSeparator"}, {SDLK_CURRENCYUNIT, "CurrencyUnit"}, {SDLK_CURRENCYSUBUNIT, "CurrencySubunit"}, {SDLK_KP_LEFTPAREN, "Keypad+ParenLeft"}, {SDLK_KP_RIGHTPAREN, "Keypad+ParenRight"}, {SDLK_KP_LEFTBRACE, "Keypad+LeftBrace"}, {SDLK_KP_RIGHTBRACE, "Keypad+RightBrace"}, {SDLK_KP_TAB, "Keypad+Tab"}, {SDLK_KP_BACKSPACE, "Keypad+Backspace"}, {SDLK_KP_A, "Keypad+A"}, {SDLK_KP_B, "Keypad+B"}, {SDLK_KP_C, "Keypad+C"}, {SDLK_KP_D, "Keypad+D"}, {SDLK_KP_E, "Keypad+E"}, {SDLK_KP_F, "Keypad+F"}, {SDLK_KP_XOR, "Keypad+XOR"}, {SDLK_KP_POWER, "Keypad+Power"}, {SDLK_KP_PERCENT, "Keypad+Percent"}, {SDLK_KP_LESS, "Keypad+Less"}, {SDLK_KP_GREATER, "Keypad+Greater"}, {SDLK_KP_AMPERSAND, "Keypad+Ampersand"}, {SDLK_KP_DBLAMPERSAND, "Keypad+AmpersandDbl"}, {SDLK_KP_VERTICALBAR, "Keypad+Bar"}, {SDLK_KP_DBLVERTICALBAR, "Keypad+BarDbl"}, {SDLK_KP_COLON, "Keypad+Colon"}, {SDLK_KP_HASH, "Keypad+Hash"}, {SDLK_KP_SPACE, "Keypad+Space"}, {SDLK_KP_AT, "Keypad+At"}, {SDLK_KP_EXCLAM, "Keypad+Exclam"}, {SDLK_KP_MEMSTORE, "Keypad+MemStore"}, {SDLK_KP_MEMRECALL, "Keypad+MemRecall"}, {SDLK_KP_MEMCLEAR, "Keypad+MemClear"}, {SDLK_KP_MEMADD, "Keypad+MemAdd"}, {SDLK_KP_MEMSUBTRACT, "Keypad+MemSubtract"}, {SDLK_KP_MEMMULTIPLY, "Keypad+MemMultiply"}, {SDLK_KP_MEMDIVIDE, "Keypad+MemDivide"}, {SDLK_KP_PLUSMINUS, "Keypad+PlusMinus"}, {SDLK_KP_CLEAR, "Keypad+Clear"}, {SDLK_KP_CLEARENTRY, "Keypad+ClearEntry"}, {SDLK_KP_BINARY, "Keypad+Binary"}, {SDLK_KP_OCTAL, "Keypad+Octal"}, {SDLK_KP_DECIMAL, "Keypad+Decimal"}, {SDLK_KP_HEXADECIMAL, "Keypad+Hexadecimal"}, {SDLK_LCTRL, "LeftControl"}, {SDLK_LSHIFT, "LeftShift"}, {SDLK_LALT, "LeftAlt"}, {SDLK_LGUI, "Super_L"}, {SDLK_RCTRL, "RightCtrl"}, {SDLK_RSHIFT, "RightShift"}, {SDLK_RALT, "RightAlt"}, {SDLK_RGUI, "RightSuper"}, {SDLK_MODE, "Mode"}, {SDLK_AUDIONEXT, "MediaNext"}, {SDLK_AUDIOPREV, "MediaPrevious"}, {SDLK_AUDIOSTOP, "MediaStop"}, {SDLK_AUDIOPLAY, "MediaPlay"}, {SDLK_AUDIOMUTE, "VolumeMute"}, {SDLK_MEDIASELECT, "MediaSelect"}, {SDLK_WWW, "WWW"}, {SDLK_MAIL, "Mail"}, {SDLK_CALCULATOR, "Calculator"}, {SDLK_COMPUTER, "Computer"}, {SDLK_AC_SEARCH, "Search"}, {SDLK_AC_HOME, "Home"}, {SDLK_AC_BACK, "Back"}, {SDLK_AC_FORWARD, "Forward"}, {SDLK_AC_STOP, "Stop"}, {SDLK_AC_REFRESH, "Refresh"}, {SDLK_AC_BOOKMARKS, "Bookmarks"}, {SDLK_BRIGHTNESSDOWN, "BrightnessDown"}, {SDLK_BRIGHTNESSUP, "BrightnessUp"}, {SDLK_DISPLAYSWITCH, "DisplaySwitch"}, {SDLK_KBDILLUMTOGGLE, "IllumToggle"}, {SDLK_KBDILLUMDOWN, "IllumDown"}, {SDLK_KBDILLUMUP, "IllumUp"}, {SDLK_EJECT, "Eject"}, {SDLK_SLEEP, "Sleep"}, {SDLK_APP1, "App1"}, {SDLK_APP2, "App2"}, {SDLK_AUDIOREWIND, "MediaRewind"}, {SDLK_AUDIOFASTFORWARD, "MediaFastForward"}}; struct SDLKeyModifierEntry { SDL_Keymod mod; SDL_Keymod mod_mask; SDL_Keycode key_left; SDL_Keycode key_right; const char* name; }; static const std::array s_sdl_key_modifiers = { {{KMOD_LSHIFT, static_cast(KMOD_LSHIFT | KMOD_RSHIFT), SDLK_LSHIFT, SDLK_RSHIFT, "Shift"}, {KMOD_LCTRL, static_cast(KMOD_LCTRL | KMOD_LCTRL), SDLK_LCTRL, SDLK_RCTRL, "Control"}, {KMOD_LALT, static_cast(KMOD_LALT | KMOD_RALT), SDLK_LALT, SDLK_RALT, "Alt"}, {KMOD_LGUI, static_cast(KMOD_LGUI | KMOD_RGUI), SDLK_LGUI, SDLK_RGUI, "Meta"}}}; static const char* GetKeyName(SDL_Keycode key) { const auto it = s_sdl_key_names.find(key); return it == s_sdl_key_names.end() ? nullptr : it->second; } static std::optional GetKeyCodeForName(const std::string_view key_name) { for (const auto& it : s_sdl_key_names) { if (key_name == it.second) return it.first; } return std::nullopt; } static u32 KeyEventToInt(const SDL_Event* event) { u32 code = static_cast(event->key.keysym.sym); const SDL_Keymod mods = static_cast(event->key.keysym.mod); if (mods & (KMOD_LSHIFT | KMOD_RSHIFT)) code |= static_cast(KMOD_LSHIFT) << MODIFIER_SHIFT; if (mods & (KMOD_LCTRL | KMOD_RCTRL)) code |= static_cast(KMOD_LCTRL) << MODIFIER_SHIFT; if (mods & (KMOD_LALT | KMOD_RALT)) code |= static_cast(KMOD_LALT) << MODIFIER_SHIFT; if (mods & (KMOD_LGUI | KMOD_RGUI)) code |= static_cast(KMOD_LGUI) << MODIFIER_SHIFT; return code; } static bool KeyEventToString(const SDL_Event* event, String& out_string) { const SDL_Keycode key = event->key.keysym.sym; const SDL_Keymod mods = static_cast(event->key.keysym.mod); const char* key_name = GetKeyName(event->key.keysym.sym); if (!key_name) return false; out_string.Clear(); for (const SDLKeyModifierEntry& mod : s_sdl_key_modifiers) { if (mods & mod.mod_mask && key != mod.key_left && key != mod.key_right) { out_string.AppendString(mod.name); out_string.AppendCharacter('+'); } } out_string.AppendString(key_name); return true; } static std::optional ParseKeyString(const std::string_view key_str) { u32 modifiers = 0; std::string_view::size_type pos = 0; for (;;) { std::string_view::size_type plus_pos = key_str.find('+', pos); if (plus_pos == std::string_view::npos) break; const std::string_view mod_part = key_str.substr(pos, plus_pos - pos); // Keypad in SDL is not a mod and should always be the last + in the string bool known_mod = false; for (const SDLKeyModifierEntry& mod : s_sdl_key_modifiers) { if (mod_part == mod.name) { modifiers |= static_cast(mod.mod); known_mod = true; break; } } if (!known_mod) break; pos = plus_pos + 1; } std::optional key_code = GetKeyCodeForName(key_str.substr(pos)); if (!key_code) return std::nullopt; return static_cast(key_code.value()) | (modifiers << MODIFIER_SHIFT); } } // namespace SDLKeyNames