Fix scaling-related crashes
[lsnes.git] / src / platform / wxwidgets / keyboard.cpp
blob7a10108460f88f3bb66132aca9266f1c408c4dac
1 #include <wx/wx.h>
2 #include <wx/event.h>
3 #include <wx/control.h>
4 #include <wx/combobox.h>
6 #include "library/keyboard.hpp"
7 #include "library/keyboard-mapper.hpp"
8 #include "core/instance.hpp"
9 #include "core/instance-map.hpp"
10 #include "core/queue.hpp"
11 #include "core/window.hpp"
12 #include "core/ui-services.hpp"
13 #include "platform/wxwidgets/platform.hpp"
15 #include <cstdint>
16 #include <map>
18 int wx_escape_count = 0;
20 namespace
22 //Modifier table.
23 struct modifier_entry
25 int mod;
26 const char* name;
27 const char* lname;
28 } modifiers[] = {
29 { wxMOD_ALT, "alt", NULL },
30 { wxMOD_CONTROL, "ctrl", NULL },
31 { wxMOD_SHIFT, "shift", NULL },
32 { wxMOD_META, "meta", NULL },
33 #ifdef __WXMAC__
34 { wxMOD_CMD, "cmd", NULL },
35 #endif
36 { 0, NULL, NULL }
39 struct key_entry
41 int keynum;
42 const char* name;
43 const char* clazz;
44 } keys[] = {
45 { WXK_BACK, "back", "editing" },
46 { WXK_TAB, "tab", "editing" },
47 { WXK_RETURN, "return", "editing" },
48 { WXK_ESCAPE, "escape", "editing" },
49 { WXK_SPACE, "space", "characters" },
50 { 33, "exclaim", "characters" },
51 { 34, "quotedbl", "characters" },
52 { 35, "hash", "characters" },
53 { 36, "dollar", "characters" },
54 { 37, "percent", "characters" },
55 { 38, "ampersand", "characters" },
56 { 39, "quote", "characters" },
57 { 40, "leftparen", "characters" },
58 { 41, "rightparen", "characters" },
59 { 42, "asterisk", "characters" },
60 { 43, "plus", "characters" },
61 { 44, "comma", "characters" },
62 { 45, "minus", "characters" },
63 { 46, "period", "characters" },
64 { 47, "slash", "characters" },
65 { 48, "0", "numeric" },
66 { 49, "1", "numeric" },
67 { 50, "2", "numeric" },
68 { 51, "3", "numeric" },
69 { 52, "4", "numeric" },
70 { 53, "5", "numeric" },
71 { 54, "6", "numeric" },
72 { 55, "7", "numeric" },
73 { 56, "8", "numeric" },
74 { 57, "9", "numeric" },
75 { 58, "colon", "characters" },
76 { 59, "semicolon", "characters" },
77 { 60, "less", "characters" },
78 { 61, "equals", "characters" },
79 { 62, "greater", "characters" },
80 { 63, "question", "characters" },
81 { 64, "at", "characters" },
82 { 65, "a", "alphabetic" },
83 { 66, "b", "alphabetic" },
84 { 67, "c", "alphabetic" },
85 { 68, "d", "alphabetic" },
86 { 69, "e", "alphabetic" },
87 { 70, "f", "alphabetic" },
88 { 71, "g", "alphabetic" },
89 { 72, "h", "alphabetic" },
90 { 73, "i", "alphabetic" },
91 { 74, "j", "alphabetic" },
92 { 75, "k", "alphabetic" },
93 { 76, "l", "alphabetic" },
94 { 77, "m", "alphabetic" },
95 { 78, "n", "alphabetic" },
96 { 79, "o", "alphabetic" },
97 { 80, "p", "alphabetic" },
98 { 81, "q", "alphabetic" },
99 { 82, "r", "alphabetic" },
100 { 83, "s", "alphabetic" },
101 { 84, "t", "alphabetic" },
102 { 85, "u", "alphabetic" },
103 { 86, "v", "alphabetic" },
104 { 87, "w", "alphabetic" },
105 { 88, "x", "alphabetic" },
106 { 89, "y", "alphabetic" },
107 { 90, "z", "alphabetic" },
108 { 91, "leftbracket", "characters" },
109 { 92, "backslash", "characters" },
110 { 93, "rightbracket", "characters" },
111 { 94, "caret", "characters" },
112 { 95, "underscore", "characters" },
113 { 96, "backquote", "characters" },
114 { 97, "a", "alphabetic" },
115 { 98, "b", "alphabetic" },
116 { 99, "c", "alphabetic" },
117 { 100, "d", "alphabetic" },
118 { 101, "e", "alphabetic" },
119 { 102, "f", "alphabetic" },
120 { 103, "g", "alphabetic" },
121 { 104, "h", "alphabetic" },
122 { 105, "i", "alphabetic" },
123 { 106, "j", "alphabetic" },
124 { 107, "k", "alphabetic" },
125 { 108, "l", "alphabetic" },
126 { 109, "m", "alphabetic" },
127 { 110, "n", "alphabetic" },
128 { 111, "o", "alphabetic" },
129 { 112, "p", "alphabetic" },
130 { 113, "q", "alphabetic" },
131 { 114, "r", "alphabetic" },
132 { 115, "s", "alphabetic" },
133 { 116, "t", "alphabetic" },
134 { 117, "u", "alphabetic" },
135 { 118, "v", "alphabetic" },
136 { 119, "w", "alphabetic" },
137 { 120, "x", "alphabetic" },
138 { 121, "y", "alphabetic" },
139 { 122, "z", "alphabetic" },
140 { 123, "leftcurly", "characters" },
141 { 124, "pipe", "characters" },
142 { 125, "rightcurly", "characters" },
143 { 126, "tilde", "characters" },
144 { WXK_DELETE, "delete", "editing" },
145 { WXK_START, "start", "special" },
146 { WXK_LBUTTON, "lbutton", "special" },
147 { WXK_RBUTTON, "rbutton", "special" },
148 { WXK_CANCEL, "cancel", "special" },
149 { WXK_MBUTTON, "mbutton", "special" },
150 { WXK_CLEAR, "clear", "editing" },
151 { WXK_SHIFT, "shift", "modifiers" },
152 { WXK_ALT, "alt", "modifiers" },
153 { WXK_CONTROL, "control", "modifiers" },
154 { WXK_MENU, "menu", "special" },
155 { WXK_PAUSE, "pause", "special" },
156 { WXK_CAPITAL, "capital", "locks" },
157 { WXK_END, "end", "editing" },
158 { WXK_HOME, "home", "editing" },
159 { WXK_LEFT, "lefT", "editing" },
160 { WXK_UP, "up", "editing" },
161 { WXK_RIGHT, "right", "editing" },
162 { WXK_DOWN, "down", "editing" },
163 { WXK_SELECT, "select", "special" },
164 { WXK_PRINT, "print", "special" },
165 { WXK_EXECUTE, "execute", "special" },
166 { WXK_SNAPSHOT, "snapshot", "special" },
167 { WXK_INSERT, "insert", "editing" },
168 { WXK_HELP, "help", "special" },
169 { WXK_NUMPAD0, "numpad0", "numeric" },
170 { WXK_NUMPAD1, "numpad1", "numeric" },
171 { WXK_NUMPAD2, "numpad2", "numeric" },
172 { WXK_NUMPAD3, "numpad3", "numeric" },
173 { WXK_NUMPAD4, "numpad4", "numeric" },
174 { WXK_NUMPAD5, "numpad5", "numeric" },
175 { WXK_NUMPAD6, "numpad6", "numeric" },
176 { WXK_NUMPAD7, "numpad7", "numeric" },
177 { WXK_NUMPAD8, "numpad8", "numeric" },
178 { WXK_NUMPAD9, "numpad9", "numeric" },
179 { WXK_MULTIPLY, "multiply", "characters" },
180 { WXK_ADD, "add", "characters" },
181 { WXK_SEPARATOR, "separator", "characters" },
182 { WXK_SUBTRACT, "subtract", "characters" },
183 { WXK_DECIMAL, "decimal", "characters" },
184 { WXK_DIVIDE, "divide", "characters" },
185 { WXK_F1, "f1", "F-keys" },
186 { WXK_F2, "f2", "F-keys" },
187 { WXK_F3, "f3", "F-keys" },
188 { WXK_F4, "f4", "F-keys" },
189 { WXK_F5, "f5", "F-keys" },
190 { WXK_F6, "f6", "F-keys" },
191 { WXK_F7, "f7", "F-keys" },
192 { WXK_F8, "f8", "F-keys" },
193 { WXK_F9, "f9", "F-keys" },
194 { WXK_F10, "f10", "F-keys" },
195 { WXK_F11, "f11", "F-keys" },
196 { WXK_F12, "f12", "F-keys" },
197 { WXK_F13, "f13", "F-keys" },
198 { WXK_F14, "f14", "F-keys" },
199 { WXK_F15, "f15", "F-keys" },
200 { WXK_F16, "f16", "F-keys" },
201 { WXK_F17, "f17", "F-keys" },
202 { WXK_F18, "f18", "F-keys" },
203 { WXK_F19, "f19", "F-keys" },
204 { WXK_F20, "f20", "F-keys" },
205 { WXK_F21, "f21", "F-keys" },
206 { WXK_F22, "f22", "F-keys" },
207 { WXK_F23, "f23", "F-keys" },
208 { WXK_F24, "f24", "F-keys" },
209 { WXK_NUMLOCK, "numlock", "locks" },
210 { WXK_SCROLL, "scroll", "locks" },
211 { WXK_PAGEUP, "pageup", "editing" },
212 { WXK_PAGEDOWN, "pagedown", "editing" },
213 { WXK_NUMPAD_SPACE, "numpad_space", "editing" },
214 { WXK_NUMPAD_TAB, "numpad_tab", "editing" },
215 { WXK_NUMPAD_ENTER, "numpad_enter", "editing" },
216 { WXK_NUMPAD_F1, "numpad_f1", "F-keys" },
217 { WXK_NUMPAD_F2, "numpad_f2", "F-keys" },
218 { WXK_NUMPAD_F3, "numpad_f3", "F-keys" },
219 { WXK_NUMPAD_F4, "numpad_f4", "F-keys" },
220 { WXK_NUMPAD_HOME, "numpad_home", "editing" },
221 { WXK_NUMPAD_LEFT, "numpad_left", "editing" },
222 { WXK_NUMPAD_UP, "numpad_up", "editing" },
223 { WXK_NUMPAD_RIGHT, "numpad_right", "editing" },
224 { WXK_NUMPAD_DOWN, "numpad_down", "editing" },
225 { WXK_NUMPAD_PAGEUP, "numpad_pageup", "editing" },
226 { WXK_NUMPAD_PAGEDOWN, "numpad_pagedown", "editing" },
227 { WXK_NUMPAD_END, "numpad_end", "editing" },
228 { WXK_NUMPAD_BEGIN, "numpad_begin", "editing" },
229 { WXK_NUMPAD_INSERT, "numpad_insert", "editing" },
230 { WXK_NUMPAD_DELETE, "numpad_delete", "editing" },
231 { WXK_NUMPAD_EQUAL, "numpad_equal", "characters" },
232 { WXK_NUMPAD_MULTIPLY, "numpad_multiply", "characters" },
233 { WXK_NUMPAD_ADD, "numpad_add", "characters" },
234 { WXK_NUMPAD_SEPARATOR, "numpad_separator", "characters" },
235 { WXK_NUMPAD_SUBTRACT, "numpad_subtract", "characters" },
236 { WXK_NUMPAD_DECIMAL, "numpad_decimal", "characters" },
237 { WXK_NUMPAD_DIVIDE, "numpad_divide", "characters" },
238 { WXK_WINDOWS_LEFT, "windows_left", "modifiers" },
239 { WXK_WINDOWS_RIGHT, "windows_right", "modifiers" },
240 { WXK_WINDOWS_MENU, "windows_menu", "modifiers" },
241 { WXK_COMMAND, "command", "special" },
242 { WXK_SPECIAL1, "special1", "special" },
243 { WXK_SPECIAL2, "special2", "special" },
244 { WXK_SPECIAL3, "special3", "special" },
245 { WXK_SPECIAL4, "special4", "special" },
246 { WXK_SPECIAL5, "special5", "special" },
247 { WXK_SPECIAL6, "special6", "special" },
248 { WXK_SPECIAL7, "special7", "special" },
249 { WXK_SPECIAL8, "special8", "special" },
250 { WXK_SPECIAL9, "special9", "special" },
251 { WXK_SPECIAL10, "special10", "special" },
252 { WXK_SPECIAL11, "special11", "special" },
253 { WXK_SPECIAL12, "special12", "special" },
254 { WXK_SPECIAL13, "special13", "special" },
255 { WXK_SPECIAL14, "special14", "special" },
256 { WXK_SPECIAL15, "special15", "special" },
257 { WXK_SPECIAL16, "special16", "special" },
258 { WXK_SPECIAL17, "special17", "special" },
259 { WXK_SPECIAL18, "special18", "special" },
260 { WXK_SPECIAL19, "special19", "special" },
261 { WXK_SPECIAL20, "special20", "special" },
262 { 0, NULL, NULL }
265 struct keyboard_state
267 keyboard_state(emulator_instance& inst)
270 ~keyboard_state()
272 modifier_map.clear();
273 key_map.clear();
274 keys_allocated.clear();
275 keys_held.clear();
276 for(auto& m : mallocated)
277 delete m.second;
278 for(auto& k : kallocated)
279 delete k.second;
280 mallocated.clear();
281 kallocated.clear();
283 std::map<int, keyboard::modifier*> modifier_map;
284 std::map<int, keyboard::key_key*> key_map;
285 std::map<std::string, int> keys_allocated;
286 std::set<int> keys_held;
287 std::map<modifier_entry*, keyboard::modifier*> mallocated;
288 std::map<key_entry*, keyboard::key_key*> kallocated;
290 instance_map<keyboard_state> keyboard_states;
293 std::string map_keycode_to_key(int kcode)
295 key_entry* k = keys;
296 while(k->name) {
297 if(k->keynum == kcode)
298 return k->name;
299 k++;
301 return "";
304 void handle_wx_keyboard(emulator_instance& inst, wxKeyEvent& e, bool polarity)
306 CHECK_UI_THREAD;
307 auto s = keyboard_states.lookup(inst);
308 if(!s) return;
309 int mods = e.GetModifiers();
310 int keyc = e.GetKeyCode();
311 if(polarity) {
312 if(keyc == WXK_ESCAPE)
313 wx_escape_count++;
314 else
315 wx_escape_count = 0;
317 keyboard::modifier_set mset;
318 for(auto m : s->mallocated) {
319 if((mods & m.first->mod) == m.first->mod) {
320 mset.add(*m.second);
323 if(polarity) {
324 if(s->keys_held.count(keyc)) {
325 e.Skip();
326 return;
328 s->keys_held.insert(keyc);
329 } else
330 s->keys_held.erase(keyc);
331 keyboard::key_key* grp = NULL;
332 for(auto k : s->kallocated) {
333 if(k.first->keynum == keyc) {
334 grp = k.second;
335 break;
338 if(grp)
339 UI_do_keypress(inst, mset, *grp, polarity);
340 e.Skip();
343 void initialize_wx_keyboard(emulator_instance& inst)
345 if(keyboard_states.exists(inst))
346 return;
347 auto s = keyboard_states.create(inst);
348 modifier_entry* m = modifiers;
349 while(m->name) {
350 if(m->lname)
351 s->mallocated[m] = new keyboard::modifier(*inst.keyboard, m->name, m->lname);
352 else
353 s->mallocated[m] = new keyboard::modifier(*inst.keyboard, m->name);
354 s->modifier_map[m->mod] = s->mallocated[m];
355 m++;
357 key_entry* k = keys;
358 while(k->name) {
359 if(!s->keys_allocated.count(k->name)) {
360 s->kallocated[k] = new keyboard::key_key(*inst.keyboard, k->name, k->clazz);
361 s->key_map[k->keynum] = s->kallocated[k];
362 s->keys_allocated[k->name] = k->keynum;
363 } else
364 s->key_map[k->keynum] = s->key_map[s->keys_allocated[k->name]];
365 k++;
369 void deinitialize_wx_keyboard(emulator_instance& inst)
371 keyboard_states.destroy(inst);