1/**************************************************************************/
2/* keyboard.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "keyboard.h"
32
33#include "core/os/os.h"
34
35struct _KeyCodeText {
36 Key code;
37 const char *text;
38};
39
40static const _KeyCodeText _keycodes[] = {
41 /* clang-format off */
42 {Key::ESCAPE ,"Escape"},
43 {Key::TAB ,"Tab"},
44 {Key::BACKTAB ,"Backtab"},
45 {Key::BACKSPACE ,"Backspace"},
46 {Key::ENTER ,"Enter"},
47 {Key::KP_ENTER ,"Kp Enter"},
48 {Key::INSERT ,"Insert"},
49 {Key::KEY_DELETE ,"Delete"},
50 {Key::PAUSE ,"Pause"},
51 {Key::PRINT ,"Print"},
52 {Key::SYSREQ ,"SysReq"},
53 {Key::CLEAR ,"Clear"},
54 {Key::HOME ,"Home"},
55 {Key::END ,"End"},
56 {Key::LEFT ,"Left"},
57 {Key::UP ,"Up"},
58 {Key::RIGHT ,"Right"},
59 {Key::DOWN ,"Down"},
60 {Key::PAGEUP ,"PageUp"},
61 {Key::PAGEDOWN ,"PageDown"},
62 {Key::SHIFT ,"Shift"},
63 {Key::CTRL ,"Ctrl"},
64#if defined(MACOS_ENABLED)
65 {Key::META ,"Command"},
66 {Key::CMD_OR_CTRL ,"Command"},
67 {Key::ALT ,"Option"},
68#elif defined(WINDOWS_ENABLED)
69 {Key::META ,"Windows"},
70 {Key::CMD_OR_CTRL ,"Ctrl"},
71 {Key::ALT ,"Alt"},
72#else
73 {Key::META ,"Meta"},
74 {Key::CMD_OR_CTRL ,"Ctrl"},
75 {Key::ALT ,"Alt"},
76#endif
77 {Key::CAPSLOCK ,"CapsLock"},
78 {Key::NUMLOCK ,"NumLock"},
79 {Key::SCROLLLOCK ,"ScrollLock"},
80 {Key::F1 ,"F1"},
81 {Key::F2 ,"F2"},
82 {Key::F3 ,"F3"},
83 {Key::F4 ,"F4"},
84 {Key::F5 ,"F5"},
85 {Key::F6 ,"F6"},
86 {Key::F7 ,"F7"},
87 {Key::F8 ,"F8"},
88 {Key::F9 ,"F9"},
89 {Key::F10 ,"F10"},
90 {Key::F11 ,"F11"},
91 {Key::F12 ,"F12"},
92 {Key::F13 ,"F13"},
93 {Key::F14 ,"F14"},
94 {Key::F15 ,"F15"},
95 {Key::F16 ,"F16"},
96 {Key::F17 ,"F17"},
97 {Key::F18 ,"F18"},
98 {Key::F19 ,"F19"},
99 {Key::F20 ,"F20"},
100 {Key::F21 ,"F21"},
101 {Key::F22 ,"F22"},
102 {Key::F23 ,"F23"},
103 {Key::F24 ,"F24"},
104 {Key::F25 ,"F25"},
105 {Key::F26 ,"F26"},
106 {Key::F27 ,"F27"},
107 {Key::F28 ,"F28"},
108 {Key::F29 ,"F29"},
109 {Key::F30 ,"F30"},
110 {Key::F31 ,"F31"},
111 {Key::F32 ,"F32"},
112 {Key::F33 ,"F33"},
113 {Key::F34 ,"F34"},
114 {Key::F35 ,"F35"},
115 {Key::KP_MULTIPLY ,"Kp Multiply"},
116 {Key::KP_DIVIDE ,"Kp Divide"},
117 {Key::KP_SUBTRACT ,"Kp Subtract"},
118 {Key::KP_PERIOD ,"Kp Period"},
119 {Key::KP_ADD ,"Kp Add"},
120 {Key::KP_0 ,"Kp 0"},
121 {Key::KP_1 ,"Kp 1"},
122 {Key::KP_2 ,"Kp 2"},
123 {Key::KP_3 ,"Kp 3"},
124 {Key::KP_4 ,"Kp 4"},
125 {Key::KP_5 ,"Kp 5"},
126 {Key::KP_6 ,"Kp 6"},
127 {Key::KP_7 ,"Kp 7"},
128 {Key::KP_8 ,"Kp 8"},
129 {Key::KP_9 ,"Kp 9"},
130 {Key::MENU ,"Menu"},
131 {Key::HYPER ,"Hyper"},
132 {Key::HELP ,"Help"},
133 {Key::BACK ,"Back"},
134 {Key::FORWARD ,"Forward"},
135 {Key::STOP ,"Stop"},
136 {Key::REFRESH ,"Refresh"},
137 {Key::VOLUMEDOWN ,"VolumeDown"},
138 {Key::VOLUMEMUTE ,"VolumeMute"},
139 {Key::VOLUMEUP ,"VolumeUp"},
140 {Key::MEDIAPLAY ,"MediaPlay"},
141 {Key::MEDIASTOP ,"MediaStop"},
142 {Key::MEDIAPREVIOUS ,"MediaPrevious"},
143 {Key::MEDIANEXT ,"MediaNext"},
144 {Key::MEDIARECORD ,"MediaRecord"},
145 {Key::HOMEPAGE ,"HomePage"},
146 {Key::FAVORITES ,"Favorites"},
147 {Key::SEARCH ,"Search"},
148 {Key::STANDBY ,"StandBy"},
149 {Key::OPENURL ,"OpenURL"},
150 {Key::LAUNCHMAIL ,"LaunchMail"},
151 {Key::LAUNCHMEDIA ,"LaunchMedia"},
152 {Key::LAUNCH0 ,"Launch0"},
153 {Key::LAUNCH1 ,"Launch1"},
154 {Key::LAUNCH2 ,"Launch2"},
155 {Key::LAUNCH3 ,"Launch3"},
156 {Key::LAUNCH4 ,"Launch4"},
157 {Key::LAUNCH5 ,"Launch5"},
158 {Key::LAUNCH6 ,"Launch6"},
159 {Key::LAUNCH7 ,"Launch7"},
160 {Key::LAUNCH8 ,"Launch8"},
161 {Key::LAUNCH9 ,"Launch9"},
162 {Key::LAUNCHA ,"LaunchA"},
163 {Key::LAUNCHB ,"LaunchB"},
164 {Key::LAUNCHC ,"LaunchC"},
165 {Key::LAUNCHD ,"LaunchD"},
166 {Key::LAUNCHE ,"LaunchE"},
167 {Key::LAUNCHF ,"LaunchF"},
168 {Key::GLOBE ,"Globe"},
169 {Key::KEYBOARD ,"On-screen keyboard"},
170 {Key::JIS_EISU ,"JIS Eisu"},
171 {Key::JIS_KANA ,"JIS Kana"},
172 {Key::UNKNOWN ,"Unknown"},
173 {Key::SPACE ,"Space"},
174 {Key::EXCLAM ,"Exclam"},
175 {Key::QUOTEDBL ,"QuoteDbl"},
176 {Key::NUMBERSIGN ,"NumberSign"},
177 {Key::DOLLAR ,"Dollar"},
178 {Key::PERCENT ,"Percent"},
179 {Key::AMPERSAND ,"Ampersand"},
180 {Key::APOSTROPHE ,"Apostrophe"},
181 {Key::PARENLEFT ,"ParenLeft"},
182 {Key::PARENRIGHT ,"ParenRight"},
183 {Key::ASTERISK ,"Asterisk"},
184 {Key::PLUS ,"Plus"},
185 {Key::COMMA ,"Comma"},
186 {Key::MINUS ,"Minus"},
187 {Key::PERIOD ,"Period"},
188 {Key::SLASH ,"Slash"},
189 {Key::KEY_0 ,"0"},
190 {Key::KEY_1 ,"1"},
191 {Key::KEY_2 ,"2"},
192 {Key::KEY_3 ,"3"},
193 {Key::KEY_4 ,"4"},
194 {Key::KEY_5 ,"5"},
195 {Key::KEY_6 ,"6"},
196 {Key::KEY_7 ,"7"},
197 {Key::KEY_8 ,"8"},
198 {Key::KEY_9 ,"9"},
199 {Key::COLON ,"Colon"},
200 {Key::SEMICOLON ,"Semicolon"},
201 {Key::LESS ,"Less"},
202 {Key::EQUAL ,"Equal"},
203 {Key::GREATER ,"Greater"},
204 {Key::QUESTION ,"Question"},
205 {Key::AT ,"At"},
206 {Key::A ,"A"},
207 {Key::B ,"B"},
208 {Key::C ,"C"},
209 {Key::D ,"D"},
210 {Key::E ,"E"},
211 {Key::F ,"F"},
212 {Key::G ,"G"},
213 {Key::H ,"H"},
214 {Key::I ,"I"},
215 {Key::J ,"J"},
216 {Key::K ,"K"},
217 {Key::L ,"L"},
218 {Key::M ,"M"},
219 {Key::N ,"N"},
220 {Key::O ,"O"},
221 {Key::P ,"P"},
222 {Key::Q ,"Q"},
223 {Key::R ,"R"},
224 {Key::S ,"S"},
225 {Key::T ,"T"},
226 {Key::U ,"U"},
227 {Key::V ,"V"},
228 {Key::W ,"W"},
229 {Key::X ,"X"},
230 {Key::Y ,"Y"},
231 {Key::Z ,"Z"},
232 {Key::BRACKETLEFT ,"BracketLeft"},
233 {Key::BACKSLASH ,"BackSlash"},
234 {Key::BRACKETRIGHT ,"BracketRight"},
235 {Key::ASCIICIRCUM ,"AsciiCircum"},
236 {Key::UNDERSCORE ,"UnderScore"},
237 {Key::QUOTELEFT ,"QuoteLeft"},
238 {Key::BRACELEFT ,"BraceLeft"},
239 {Key::BAR ,"Bar"},
240 {Key::BRACERIGHT ,"BraceRight"},
241 {Key::ASCIITILDE ,"AsciiTilde"},
242 {Key::YEN ,"Yen"},
243 {Key::SECTION ,"Section"},
244 {Key::NONE ,nullptr}
245 /* clang-format on */
246};
247
248bool keycode_has_unicode(Key p_keycode) {
249 switch (p_keycode) {
250 case Key::ESCAPE:
251 case Key::TAB:
252 case Key::BACKTAB:
253 case Key::BACKSPACE:
254 case Key::ENTER:
255 case Key::KP_ENTER:
256 case Key::INSERT:
257 case Key::KEY_DELETE:
258 case Key::PAUSE:
259 case Key::PRINT:
260 case Key::SYSREQ:
261 case Key::CLEAR:
262 case Key::HOME:
263 case Key::END:
264 case Key::LEFT:
265 case Key::UP:
266 case Key::RIGHT:
267 case Key::DOWN:
268 case Key::PAGEUP:
269 case Key::PAGEDOWN:
270 case Key::SHIFT:
271 case Key::CTRL:
272 case Key::META:
273 case Key::ALT:
274 case Key::CAPSLOCK:
275 case Key::NUMLOCK:
276 case Key::SCROLLLOCK:
277 case Key::F1:
278 case Key::F2:
279 case Key::F3:
280 case Key::F4:
281 case Key::F5:
282 case Key::F6:
283 case Key::F7:
284 case Key::F8:
285 case Key::F9:
286 case Key::F10:
287 case Key::F11:
288 case Key::F12:
289 case Key::F13:
290 case Key::F14:
291 case Key::F15:
292 case Key::F16:
293 case Key::F17:
294 case Key::F18:
295 case Key::F19:
296 case Key::F20:
297 case Key::F21:
298 case Key::F22:
299 case Key::F23:
300 case Key::F24:
301 case Key::F25:
302 case Key::F26:
303 case Key::F27:
304 case Key::F28:
305 case Key::F29:
306 case Key::F30:
307 case Key::F31:
308 case Key::F32:
309 case Key::F33:
310 case Key::F34:
311 case Key::F35:
312 case Key::MENU:
313 case Key::HYPER:
314 case Key::HELP:
315 case Key::BACK:
316 case Key::FORWARD:
317 case Key::STOP:
318 case Key::REFRESH:
319 case Key::VOLUMEDOWN:
320 case Key::VOLUMEMUTE:
321 case Key::VOLUMEUP:
322 case Key::MEDIAPLAY:
323 case Key::MEDIASTOP:
324 case Key::MEDIAPREVIOUS:
325 case Key::MEDIANEXT:
326 case Key::MEDIARECORD:
327 case Key::HOMEPAGE:
328 case Key::FAVORITES:
329 case Key::SEARCH:
330 case Key::STANDBY:
331 case Key::OPENURL:
332 case Key::LAUNCHMAIL:
333 case Key::LAUNCHMEDIA:
334 case Key::LAUNCH0:
335 case Key::LAUNCH1:
336 case Key::LAUNCH2:
337 case Key::LAUNCH3:
338 case Key::LAUNCH4:
339 case Key::LAUNCH5:
340 case Key::LAUNCH6:
341 case Key::LAUNCH7:
342 case Key::LAUNCH8:
343 case Key::LAUNCH9:
344 case Key::LAUNCHA:
345 case Key::LAUNCHB:
346 case Key::LAUNCHC:
347 case Key::LAUNCHD:
348 case Key::LAUNCHE:
349 case Key::LAUNCHF:
350 case Key::GLOBE:
351 case Key::KEYBOARD:
352 case Key::JIS_EISU:
353 case Key::JIS_KANA:
354 return false;
355 default: {
356 }
357 }
358
359 return true;
360}
361
362String keycode_get_string(Key p_code) {
363 String codestr;
364 if ((p_code & KeyModifierMask::SHIFT) != Key::NONE) {
365 codestr += find_keycode_name(Key::SHIFT);
366 codestr += "+";
367 }
368 if ((p_code & KeyModifierMask::ALT) != Key::NONE) {
369 codestr += find_keycode_name(Key::ALT);
370 codestr += "+";
371 }
372 if ((p_code & KeyModifierMask::CMD_OR_CTRL) != Key::NONE) {
373 if (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) {
374 codestr += find_keycode_name(Key::META);
375 } else {
376 codestr += find_keycode_name(Key::CTRL);
377 }
378 codestr += "+";
379 }
380 if ((p_code & KeyModifierMask::CTRL) != Key::NONE) {
381 codestr += find_keycode_name(Key::CTRL);
382 codestr += "+";
383 }
384 if ((p_code & KeyModifierMask::META) != Key::NONE) {
385 codestr += find_keycode_name(Key::META);
386 codestr += "+";
387 }
388
389 p_code &= KeyModifierMask::CODE_MASK;
390
391 const _KeyCodeText *kct = &_keycodes[0];
392
393 while (kct->text) {
394 if (kct->code == p_code) {
395 codestr += kct->text;
396 return codestr;
397 }
398 kct++;
399 }
400
401 codestr += String::chr((char32_t)p_code);
402
403 return codestr;
404}
405
406Key find_keycode(const String &p_codestr) {
407 Key keycode = Key::NONE;
408 Vector<String> code_parts = p_codestr.split("+");
409 if (code_parts.size() < 1) {
410 return keycode;
411 }
412
413 String last_part = code_parts[code_parts.size() - 1];
414 const _KeyCodeText *kct = &_keycodes[0];
415
416 while (kct->text) {
417 if (last_part.nocasecmp_to(kct->text) == 0) {
418 keycode = kct->code;
419 break;
420 }
421 kct++;
422 }
423
424 for (int part = 0; part < code_parts.size() - 1; part++) {
425 String code_part = code_parts[part];
426 if (code_part.nocasecmp_to(find_keycode_name(Key::SHIFT)) == 0) {
427 keycode |= KeyModifierMask::SHIFT;
428 } else if (code_part.nocasecmp_to(find_keycode_name(Key::CTRL)) == 0) {
429 keycode |= KeyModifierMask::CTRL;
430 } else if (code_part.nocasecmp_to(find_keycode_name(Key::META)) == 0) {
431 keycode |= KeyModifierMask::META;
432 } else if (code_part.nocasecmp_to(find_keycode_name(Key::ALT)) == 0) {
433 keycode |= KeyModifierMask::ALT;
434 }
435 }
436
437 return keycode;
438}
439
440const char *find_keycode_name(Key p_keycode) {
441 const _KeyCodeText *kct = &_keycodes[0];
442
443 while (kct->text) {
444 if (kct->code == p_keycode) {
445 return kct->text;
446 }
447 kct++;
448 }
449
450 return "";
451}
452
453int keycode_get_count() {
454 const _KeyCodeText *kct = &_keycodes[0];
455
456 int count = 0;
457 while (kct->text) {
458 count++;
459 kct++;
460 }
461 return count;
462}
463
464int keycode_get_value_by_index(int p_index) {
465 return (int)_keycodes[p_index].code;
466}
467
468const char *keycode_get_name_by_index(int p_index) {
469 return _keycodes[p_index].text;
470}
471
472char32_t fix_unicode(char32_t p_char) {
473 if (p_char >= 0x20 && p_char != 0x7F) {
474 return p_char;
475 }
476 return 0;
477}
478
479Key fix_keycode(char32_t p_char, Key p_key) {
480 if (p_char >= 0x20 && p_char <= 0x7E) {
481 return (Key)String::char_uppercase(p_char);
482 }
483 return p_key;
484}
485
486Key fix_key_label(char32_t p_char, Key p_key) {
487 if (p_char >= 0x20 && p_char != 0x7F) {
488 return (Key)String::char_uppercase(p_char);
489 }
490 return p_key;
491}
492