Line data Source code
1 : /* Copyright (C) 2021 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : // Ooh, a file of keynames. Fun.
19 :
20 : #include "precompiled.h"
21 :
22 : #include "KeyName.h"
23 :
24 : #include "lib/external_libraries/libsdl.h"
25 : #include "ps/CStr.h"
26 :
27 : #include <algorithm>
28 : #include <unordered_map>
29 : #include <vector>
30 :
31 : // Some scancodes <-> names that SDL doesn't recognise.
32 : // Those are tested first so they override SDL defaults (useful for UNIFIED keys).
33 105 : static const std::unordered_map<int, std::vector<CStr>> scancodemap {{
34 : { SDL_SCANCODE_DOWN, { "DownArrow" } },
35 : { SDL_SCANCODE_UP, { "UpArrow" } },
36 : { SDL_SCANCODE_LEFT, { "LeftArrow" } },
37 : { SDL_SCANCODE_RIGHT, { "RightArrow" } },
38 :
39 : { SDL_SCANCODE_EQUALS, { "Plus" } },
40 : { SDL_SCANCODE_MINUS, { "Minus" } },
41 :
42 : { SDL_SCANCODE_KP_ENTER, { "NumEnter" } },
43 : { SDL_SCANCODE_KP_DIVIDE, { "NumDivide" } },
44 : { SDL_SCANCODE_KP_MULTIPLY, { "NumMultiply" } },
45 : { SDL_SCANCODE_KP_EQUALS, { "NumEquals" } },
46 : { SDL_SCANCODE_KP_PERIOD, { "NumDecimal" } },
47 : { SDL_SCANCODE_KP_PLUS, { "NumPlus" } },
48 : { SDL_SCANCODE_KP_MINUS, { "NumMinus" } },
49 : { SDL_SCANCODE_KP_0, { "Num0" } },
50 : { SDL_SCANCODE_KP_1, { "Num1" } },
51 : { SDL_SCANCODE_KP_2, { "Num2" } },
52 : { SDL_SCANCODE_KP_3, { "Num3" } },
53 : { SDL_SCANCODE_KP_4, { "Num4" } },
54 : { SDL_SCANCODE_KP_5, { "Num5" } },
55 : { SDL_SCANCODE_KP_6, { "Num6" } },
56 : { SDL_SCANCODE_KP_7, { "Num7" } },
57 : { SDL_SCANCODE_KP_8, { "Num8" } },
58 : { SDL_SCANCODE_KP_9, { "Num9" } },
59 :
60 : { SDL_SCANCODE_COMMA, { "Comma" } },
61 : { SDL_SCANCODE_PERIOD, { "Period" } },
62 : { SDL_SCANCODE_APOSTROPHE, { "Quote" } },
63 : { SDL_SCANCODE_SEMICOLON, { "Semicolon" } },
64 : { SDL_SCANCODE_GRAVE, { "Backquote" } },
65 : { SDL_SCANCODE_LEFTBRACKET, { "LeftBracket" } },
66 : { SDL_SCANCODE_RIGHTBRACKET, { "RightBracket" } },
67 : { SDL_SCANCODE_BACKSLASH, { "Backslash" } },
68 : { SDL_SCANCODE_SLASH, { "Slash" } },
69 :
70 : { SDL_SCANCODE_RETURN, { "Enter" } },
71 : { SDL_SCANCODE_ESCAPE, { "Esc" } },
72 : { SDL_SCANCODE_PAUSE, { "Break" } },
73 : { SDL_SCANCODE_DELETE, { "Del" } },
74 :
75 : { MOUSE_LEFT, { "MouseLeft" } },
76 : { MOUSE_RIGHT, { "MouseRight" } },
77 : { MOUSE_MIDDLE, { "MouseMiddle" } },
78 : { MOUSE_WHEELUP, { "WheelUp" } },
79 : { MOUSE_WHEELDOWN, { "WheelDown" } },
80 : { MOUSE_X1, { "WheelLeft", "MouseX1" } },
81 : { MOUSE_X2, { "WheelRight", "MouseX2" } },
82 :
83 : { UNIFIED_SHIFT, { "Shift", "Left Shift", "Right Shift" } },
84 : { UNIFIED_CTRL, { "Ctrl", "Left Ctrl", "Right Ctrl" } },
85 : { UNIFIED_ALT, { "Alt", "Left Alt", "Right Alt" } },
86 : { UNIFIED_SUPER, { "Super", "Left Gui", "Right Gui" } },
87 104 : }};
88 :
89 25 : SDL_Scancode FindScancode(const CStr8& keyname)
90 : {
91 : // Find (ignoring case) a corresponding scancode, if one exists.
92 : std::unordered_map<int, std::vector<CStr>>::const_iterator it =
93 2350 : std::find_if(scancodemap.begin(), scancodemap.end(), [&keyname](const std::pair<int, std::vector<CStr>>& names) {
94 3775 : return std::find_if(names.second.begin(), names.second.end(), [&keyname](const CStr& t) {
95 2850 : return t.LowerCase() == keyname.LowerCase();
96 6375 : })!= names.second.end();
97 2375 : });
98 :
99 25 : if (it != scancodemap.end())
100 0 : return static_cast<SDL_Scancode>(it->first);
101 :
102 25 : SDL_Scancode code = SDL_GetScancodeFromName(keyname.c_str());
103 25 : if (code != SDL_SCANCODE_UNKNOWN)
104 25 : return code;
105 :
106 : // Parse SYM_XX codes, see below.
107 0 : if (keyname.size() > 4 && keyname.Left(4) == "SYM_")
108 0 : return static_cast<SDL_Scancode>(CStr(keyname.substr(4)).ToInt());
109 :
110 0 : return SDL_SCANCODE_UNKNOWN;
111 : }
112 :
113 0 : CStr FindScancodeName(SDL_Scancode scancode)
114 : {
115 0 : if (scancodemap.find(scancode) != scancodemap.end())
116 0 : return scancodemap.at(scancode).front();
117 :
118 0 : const char* name = SDL_GetScancodeName(scancode);
119 : // Some scancodes have no name, but we must have something to save/load/recognize it, so parse it as SYM_XX
120 0 : if (strlen(name) == 0)
121 0 : return CStr("SYM_") + CStr::FromInt(scancode);
122 0 : return name;
123 : }
124 :
125 : // Rename some SDL key names (!scancodes) for easier readability.
126 : // NB: this does not intend to be exhaustive, merely cover the usual suspects.
127 37 : static const std::unordered_map<SDL_Keycode, CStr> keyNames {{
128 : { SDLK_COMMA, "Comma" },
129 : { SDLK_SEMICOLON, "Semicolon" },
130 : { SDLK_COLON, "Colon" },
131 : { SDLK_PERIOD, "Period" },
132 : { SDLK_EQUALS, "Equals" },
133 : { SDLK_PLUS, "Plus" },
134 : { SDLK_MINUS, "Minus" },
135 :
136 : { SDLK_QUOTE, "SingleQuote" },
137 : { SDLK_QUOTEDBL, "DoubleQuote" },
138 : { SDLK_BACKQUOTE, "BackQuote" },
139 :
140 : { SDLK_LEFTPAREN, { "LeftParen" } },
141 :
142 : { SDLK_LEFTBRACKET, { "LeftBracket" } },
143 : { SDLK_RIGHTBRACKET, { "RightBracket" } },
144 : { SDLK_BACKSLASH, { "Backslash" } },
145 : { SDLK_SLASH, { "Slash" } },
146 :
147 : { SDLK_KP_ENTER, "NumEnter" },
148 : { SDLK_KP_DIVIDE, "NumDivide" },
149 : { SDLK_KP_MULTIPLY, "NumMultiply" },
150 : { SDLK_KP_EQUALS, "NumEquals" },
151 : { SDLK_KP_PERIOD, "NumDecimal" },
152 : { SDLK_KP_PLUS, "NumPlus" },
153 : { SDLK_KP_MINUS, "NumMinus" },
154 : { SDLK_KP_0, "Num0" },
155 : { SDLK_KP_1, "Num1" },
156 : { SDLK_KP_2, "Num2" },
157 : { SDLK_KP_3, "Num3" },
158 : { SDLK_KP_4, "Num4" },
159 : { SDLK_KP_5, "Num5" },
160 : { SDLK_KP_6, "Num6" },
161 : { SDLK_KP_7, "Num7" },
162 : { SDLK_KP_8, "Num8" },
163 : { SDLK_KP_9, "Num9" },
164 :
165 : { SDLK_UP, "\xe2\x86\x91" },
166 : { SDLK_DOWN, "\xe2\x86\x93" },
167 : { SDLK_LEFT, "\xe2\x86\x90" },
168 : { SDLK_RIGHT, "\xe2\x86\x92" },
169 36 : }};
170 :
171 0 : CStr FindKeyName(SDL_Scancode scancode)
172 : {
173 : // Mouse and unified modifiers are harcoded.
174 0 : if (static_cast<int>(scancode) == UNIFIED_SHIFT)
175 0 : return "Shift";
176 0 : else if (static_cast<int>(scancode) == UNIFIED_ALT)
177 0 : return "Alt";
178 0 : else if (static_cast<int>(scancode) == UNIFIED_CTRL)
179 0 : return "Ctrl";
180 0 : else if (static_cast<int>(scancode) == UNIFIED_SUPER)
181 0 : return "Super";
182 0 : else if (static_cast<int>(scancode) == MOUSE_LEFT)
183 0 : return "MouseLeft";
184 0 : else if (static_cast<int>(scancode) == MOUSE_RIGHT)
185 0 : return "MouseRight";
186 0 : else if (static_cast<int>(scancode) == MOUSE_MIDDLE)
187 0 : return "MouseMiddle";
188 0 : else if (static_cast<int>(scancode) == MOUSE_WHEELUP)
189 0 : return "WheelUp";
190 0 : else if (static_cast<int>(scancode) == MOUSE_WHEELDOWN)
191 0 : return "WheelDown";
192 0 : else if (static_cast<int>(scancode) == MOUSE_X1)
193 0 : return "WheelLeft";
194 0 : else if (static_cast<int>(scancode) == MOUSE_X2)
195 0 : return "WheelRight";
196 :
197 0 : SDL_Keycode code = SDL_GetKeyFromScancode(scancode);
198 :
199 0 : if (keyNames.find(code) != keyNames.end())
200 0 : return keyNames.at(code);
201 :
202 0 : if (code != SDLK_UNKNOWN)
203 : {
204 0 : const char* keyName = SDL_GetKeyName(code);
205 0 : if (strlen(keyName) != 0)
206 0 : return keyName;
207 : }
208 :
209 : // Try the scancode name.
210 0 : const char* name = SDL_GetScancodeName(scancode);
211 :
212 : // xxtreme hack: some SDLKeycodes map to chars, and we need to escape [ and \ .
213 0 : if (keyNames.find(static_cast<SDL_Keycode>(*name)) != keyNames.end())
214 0 : return keyNames.at(static_cast<SDL_Keycode>(*name));
215 :
216 0 : if (strlen(name) != 0)
217 0 : return name;
218 :
219 : // Else, show something regardless, so the player knows it's at least recognized.
220 0 : return CStr("SYM_") + CStr::FromInt(scancode);
221 3 : }
222 :
223 :
|