| 1 |
#include "SDLKey.hh" |
| 2 |
|
| 3 |
#include "StringOp.hh" |
| 4 |
#include "one_of.hh" |
| 5 |
#include "ranges.hh" |
| 6 |
|
| 7 |
#include <algorithm> |
| 8 |
#include <array> |
| 9 |
|
| 10 |
namespace openmsx { |
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
static SDL_Keycode getKeyFromOldOpenmsxName(std::string_view name) |
| 18 |
{ |
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
struct M { |
| 39 |
std::string_view name; |
| 40 |
SDL_Keycode code; |
| 41 |
}; |
| 42 |
static constexpr std::array unsortedMap = { |
| 43 |
|
| 44 |
M{"EXCLAIM", SDLK_EXCLAIM}, |
| 45 |
M{"QUOTEDBL", SDLK_QUOTEDBL}, |
| 46 |
M{"HASH", SDLK_HASH}, |
| 47 |
M{"DOLLAR", SDLK_DOLLAR}, |
| 48 |
M{"AMPERSAND", SDLK_AMPERSAND}, |
| 49 |
M{"QUOTE", SDLK_QUOTE}, |
| 50 |
M{"LEFTPAREN", SDLK_LEFTPAREN}, |
| 51 |
M{"RIGHTPAREN", SDLK_RIGHTPAREN}, |
| 52 |
M{"ASTERISK", SDLK_ASTERISK}, |
| 53 |
M{"PLUS", SDLK_PLUS}, |
| 54 |
M{"COMMA", SDLK_COMMA}, |
| 55 |
M{"MINUS", SDLK_MINUS}, |
| 56 |
M{"PERIOD", SDLK_PERIOD}, |
| 57 |
M{"SLASH", SDLK_SLASH}, |
| 58 |
M{"COLON", SDLK_COLON}, |
| 59 |
M{"SEMICOLON", SDLK_SEMICOLON}, |
| 60 |
M{"LESS", SDLK_LESS}, |
| 61 |
M{"EQUALS", SDLK_EQUALS}, |
| 62 |
M{"GREATER", SDLK_GREATER}, |
| 63 |
M{"QUESTION", SDLK_QUESTION}, |
| 64 |
M{"AT", SDLK_AT}, |
| 65 |
M{"LEFTBRACKET", SDLK_LEFTBRACKET}, |
| 66 |
M{"BACKSLASH", SDLK_BACKSLASH}, |
| 67 |
M{"RIGHTBRACKET",SDLK_RIGHTBRACKET}, |
| 68 |
M{"CARET", SDLK_CARET}, |
| 69 |
M{"UNDERSCORE", SDLK_UNDERSCORE}, |
| 70 |
M{"BACKQUOTE", SDLK_BACKQUOTE}, |
| 71 |
M{"PRINT", SDLK_PRINTSCREEN}, |
| 72 |
M{"SCROLLOCK", SDLK_SCROLLLOCK}, |
| 73 |
M{"KP_DIVIDE", SDLK_KP_DIVIDE}, |
| 74 |
M{"KP_MULTIPLY", SDLK_KP_MULTIPLY}, |
| 75 |
M{"KP_MINUS", SDLK_KP_MINUS}, |
| 76 |
M{"KP_PLUS", SDLK_KP_PLUS}, |
| 77 |
M{"KP_ENTER", SDLK_KP_ENTER}, |
| 78 |
M{"KP0", SDLK_KP_0}, |
| 79 |
M{"KP1", SDLK_KP_1}, |
| 80 |
M{"KP2", SDLK_KP_2}, |
| 81 |
M{"KP3", SDLK_KP_3}, |
| 82 |
M{"KP4", SDLK_KP_4}, |
| 83 |
M{"KP5", SDLK_KP_5}, |
| 84 |
M{"KP6", SDLK_KP_6}, |
| 85 |
M{"KP7", SDLK_KP_7}, |
| 86 |
M{"KP8", SDLK_KP_8}, |
| 87 |
M{"KP9", SDLK_KP_9}, |
| 88 |
M{"KP_PERIOD", SDLK_KP_PERIOD}, |
| 89 |
M{"KP_EQUALS", SDLK_KP_EQUALS}, |
| 90 |
M{"LCTRL", SDLK_LCTRL}, |
| 91 |
M{"LSHIFT", SDLK_LSHIFT}, |
| 92 |
M{"LALT", SDLK_LALT}, |
| 93 |
M{"LSUPER", SDLK_LGUI}, |
| 94 |
M{"RCTRL", SDLK_RCTRL}, |
| 95 |
M{"RSHIFT", SDLK_RSHIFT}, |
| 96 |
M{"RALT", SDLK_RALT}, |
| 97 |
M{"RSUPER", SDLK_RGUI}, |
| 98 |
M{"RMODE", SDLK_MODE}, |
| 99 |
}; |
| 100 |
static constexpr auto map = []{ |
| 101 |
auto result = unsortedMap; |
| 102 |
std::ranges::sort(result, {}, &M::name); |
| 103 |
return result; |
| 104 |
}(); |
| 105 |
|
| 106 |
if (const auto* p = binary_find(map, name, StringOp::caseless{}, &M::name)) { |
| 107 |
return p->code; |
| 108 |
} |
| 109 |
return SDLK_UNKNOWN; |
| 110 |
} |
| 111 |
|
| 112 |
SDL_Keycode SDLKey::keycodeFromString(zstring_view name) |
| 113 |
{ |
| 114 |
auto result = SDL_GetKeyFromName(name.c_str()); |
| 115 |
if (result == SDLK_UNKNOWN) { |
| 116 |
|
| 117 |
result = getKeyFromOldOpenmsxName(name); |
| 118 |
} |
| 119 |
return result; |
| 120 |
} |
| 121 |
|
| 122 |
std::optional<SDLKey> SDLKey::fromString(std::string_view name) |
| 123 |
{ |
| 124 |
|
| 125 |
|
| 126 |
|
| 127 |
|
| 128 |
|
| 129 |
|
| 130 |
|
| 131 |
|
| 132 |
|
| 133 |
|
| 134 |
|
| 135 |
|
| 136 |
|
| 137 |
|
| 138 |
|
| 139 |
|
| 140 |
|
| 141 |
|
| 142 |
|
| 143 |
|
| 144 |
|
| 145 |
|
| 146 |
|
| 147 |
|
| 148 |
|
| 149 |
|
| 150 |
|
| 151 |
|
| 152 |
|
| 153 |
|
| 154 |
|
| 155 |
|
| 156 |
|
| 157 |
|
| 158 |
|
| 159 |
|
| 160 |
|
| 161 |
|
| 162 |
|
| 163 |
SDLKey result = {}; |
| 164 |
result.sym.scancode = SDL_SCANCODE_UNKNOWN; |
| 165 |
result.sym.sym = SDLK_UNKNOWN; |
| 166 |
result.sym.mod = KMOD_NONE; |
| 167 |
result.sym.unused = 0; |
| 168 |
result.down = true; |
| 169 |
|
| 170 |
while (!name.empty()) { |
| 171 |
std::string_view part = [&] { |
| 172 |
auto pos = name.find_first_of(",+/"); |
| 173 |
if (pos == std::string_view::npos) { |
| 174 |
|
| 175 |
return std::exchange(name, std::string_view{}); |
| 176 |
} else if ((pos + 1) == name.size()) { |
| 177 |
|
| 178 |
return std::exchange(name, std::string_view{}); |
| 179 |
} else { |
| 180 |
if (name[pos + 1] == one_of(',', '+', '/')) { |
| 181 |
|
| 182 |
|
| 183 |
++pos; |
| 184 |
} |
| 185 |
auto r = name.substr(0, pos); |
| 186 |
name.remove_prefix(pos + 1); |
| 187 |
return r; |
| 188 |
} |
| 189 |
}(); |
| 190 |
|
| 191 |
StringOp::casecmp cmp; |
| 192 |
if (cmp(part, "SHIFT")) { |
| 193 |
result.sym.mod |= KMOD_SHIFT; |
| 194 |
} else if (cmp(part, "CTRL")) { |
| 195 |
result.sym.mod |= KMOD_CTRL; |
| 196 |
} else if (cmp(part, "ALT")) { |
| 197 |
result.sym.mod |= KMOD_ALT; |
| 198 |
} else if (cmp(part, "GUI") || |
| 199 |
cmp(part, "META")) { |
| 200 |
result.sym.mod |= KMOD_GUI; |
| 201 |
} else if (cmp(part, "MODE")) { |
| 202 |
result.sym.mod |= KMOD_MODE; |
| 203 |
|
| 204 |
} else if (cmp(part, "PRESS")) { |
| 205 |
result.down = true; |
| 206 |
} else if (cmp(part, "RELEASE")) { |
| 207 |
result.down = false; |
| 208 |
|
| 209 |
} else { |
| 210 |
if (result.sym.sym != SDLK_UNKNOWN) { |
| 211 |
|
| 212 |
return {}; |
| 213 |
} |
| 214 |
result.sym.sym = keycodeFromString(std::string(part)); |
| 215 |
if (result.sym.sym == SDLK_UNKNOWN) { |
| 216 |
return {}; |
| 217 |
} |
| 218 |
} |
| 219 |
} |
| 220 |
if (result.sym.sym == SDLK_UNKNOWN) { |
| 221 |
return {}; |
| 222 |
} |
| 223 |
return result; |
| 224 |
} |
| 225 |
|
| 226 |
std::string SDLKey::toString(SDL_Keycode code) |
| 227 |
{ |
| 228 |
std::string result = SDL_GetKeyName(code); |
| 229 |
if (result.empty()) result = "unknown"; |
| 230 |
return result; |
| 231 |
} |
| 232 |
|
| 233 |
std::string SDLKey::toString() const |
| 234 |
{ |
| 235 |
std::string result = toString(sym.sym); |
| 236 |
if (sym.mod & KMOD_CTRL) { |
| 237 |
result += "+CTRL"; |
| 238 |
} |
| 239 |
if (sym.mod & KMOD_SHIFT) { |
| 240 |
result += "+SHIFT"; |
| 241 |
} |
| 242 |
if (sym.mod & KMOD_ALT) { |
| 243 |
result += "+ALT"; |
| 244 |
} |
| 245 |
if (sym.mod & KMOD_GUI) { |
| 246 |
result += "+GUI"; |
| 247 |
} |
| 248 |
if (sym.mod & KMOD_MODE) { |
| 249 |
result += "+MODE"; |
| 250 |
} |
| 251 |
if (!down) { |
| 252 |
result += ",RELEASE"; |
| 253 |
} |
| 254 |
return result; |
| 255 |
} |
| 256 |
|
| 257 |
} |