1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "backends/keymapper/hardware-input.h"
24
25 #include "backends/keymapper/keymapper.h"
26
27 #include "common/tokenizer.h"
28 #include "common/translation.h"
29
30 namespace Common {
31
32 // TODO: Maybe make 'Command' a separate mac-specific modifier so we can define
33 // defaults key bindings from the original mac game versions without binding
34 // them to the meta key on other platforms?
35 #if defined(WIN32)
36 #define META_KEY_NAME "Win"
37 #elif defined(MACOSX) || defined(IPHONE)
38 #define META_KEY_NAME "Cmd"
39 #else
40 #define META_KEY_NAME "Meta"
41 #endif
42
43 const KeyTableEntry defaultKeys[] = {
44 {"BACKSPACE", KEYCODE_BACKSPACE, "Backspace"},
45 {"TAB", KEYCODE_TAB, "Tab"},
46 {"CLEAR", KEYCODE_CLEAR, "Clear"},
47 {"RETURN", KEYCODE_RETURN, "Return"},
48 {"PAUSE", KEYCODE_PAUSE, "Pause"},
49 {"ESCAPE", KEYCODE_ESCAPE, "Esc"},
50 {"SPACE", KEYCODE_SPACE, "Space"},
51 {"EXCLAIM", KEYCODE_EXCLAIM, "!"},
52 {"QUOTEDBL", KEYCODE_QUOTEDBL, "\""},
53 {"HASH", KEYCODE_HASH, "#"},
54 {"DOLLAR", KEYCODE_DOLLAR, "$"},
55 {"PERCENT", KEYCODE_PERCENT, "%"},
56 {"AMPERSAND", KEYCODE_AMPERSAND, "&"},
57 {"QUOTE", KEYCODE_QUOTE, "'"},
58 {"LEFTPAREN", KEYCODE_LEFTPAREN, "("},
59 {"RIGHTPAREN", KEYCODE_RIGHTPAREN, ")"},
60 {"ASTERISK", KEYCODE_ASTERISK, "*"},
61 {"PLUS", KEYCODE_PLUS, "+"},
62 {"COMMA", KEYCODE_COMMA, ","},
63 {"MINUS", KEYCODE_MINUS, "-"},
64 {"PERIOD", KEYCODE_PERIOD, "."},
65 {"SLASH", KEYCODE_SLASH, "/"},
66 {"0", KEYCODE_0, "0"},
67 {"1", KEYCODE_1, "1"},
68 {"2", KEYCODE_2, "2"},
69 {"3", KEYCODE_3, "3"},
70 {"4", KEYCODE_4, "4"},
71 {"5", KEYCODE_5, "5"},
72 {"6", KEYCODE_6, "6"},
73 {"7", KEYCODE_7, "7"},
74 {"8", KEYCODE_8, "8"},
75 {"9", KEYCODE_9, "9"},
76 {"COLON", KEYCODE_COLON, ":"},
77 {"SEMICOLON", KEYCODE_SEMICOLON, ";"},
78 {"LESS", KEYCODE_LESS, "<"},
79 {"EQUALS", KEYCODE_EQUALS, "="},
80 {"GREATER", KEYCODE_GREATER, ">"},
81 {"QUESTION", KEYCODE_QUESTION, "?"},
82 {"AT", KEYCODE_AT, "@"},
83
84 {"LEFTBRACKET", KEYCODE_LEFTBRACKET, "["},
85 {"BACKSLASH", KEYCODE_BACKSLASH, "\\"},
86 {"RIGHTBRACKET", KEYCODE_RIGHTBRACKET, "]"},
87 {"CARET", KEYCODE_CARET, "^"},
88 {"UNDERSCORE", KEYCODE_UNDERSCORE, "_"},
89 {"BACKQUOTE", KEYCODE_BACKQUOTE, "`"},
90 {"a", KEYCODE_a, "a"},
91 {"b", KEYCODE_b, "b"},
92 {"c", KEYCODE_c, "c"},
93 {"d", KEYCODE_d, "d"},
94 {"e", KEYCODE_e, "e"},
95 {"f", KEYCODE_f, "f"},
96 {"g", KEYCODE_g, "g"},
97 {"h", KEYCODE_h, "h"},
98 {"i", KEYCODE_i, "i"},
99 {"j", KEYCODE_j, "j"},
100 {"k", KEYCODE_k, "k"},
101 {"l", KEYCODE_l, "l"},
102 {"m", KEYCODE_m, "m"},
103 {"n", KEYCODE_n, "n"},
104 {"o", KEYCODE_o, "o"},
105 {"p", KEYCODE_p, "p"},
106 {"q", KEYCODE_q, "q"},
107 {"r", KEYCODE_r, "r"},
108 {"s", KEYCODE_s, "s"},
109 {"t", KEYCODE_t, "t"},
110 {"u", KEYCODE_u, "u"},
111 {"v", KEYCODE_v, "v"},
112 {"w", KEYCODE_w, "w"},
113 {"x", KEYCODE_x, "x"},
114 {"y", KEYCODE_y, "y"},
115 {"z", KEYCODE_z, "z"},
116 {"DELETE", KEYCODE_DELETE, "Del"},
117
118 // Numeric keypad
119 {"KP0", KEYCODE_KP0, "KP0"},
120 {"KP1", KEYCODE_KP1, "KP1"},
121 {"KP2", KEYCODE_KP2, "KP2"},
122 {"KP3", KEYCODE_KP3, "KP3"},
123 {"KP4", KEYCODE_KP4, "KP4"},
124 {"KP5", KEYCODE_KP5, "KP5"},
125 {"KP6", KEYCODE_KP6, "KP6"},
126 {"KP7", KEYCODE_KP7, "KP7"},
127 {"KP8", KEYCODE_KP8, "KP8"},
128 {"KP9", KEYCODE_KP9, "KP9"},
129 {"KP_PERIOD", KEYCODE_KP_PERIOD, "KP."},
130 {"KP_DIVIDE", KEYCODE_KP_DIVIDE, "KP/"},
131 {"KP_MULTIPLY", KEYCODE_KP_MULTIPLY, "KP*"},
132 {"KP_MINUS", KEYCODE_KP_MINUS, "KP-"},
133 {"KP_PLUS", KEYCODE_KP_PLUS, "KP+"},
134 {"KP_ENTER", KEYCODE_KP_ENTER, "KP Enter"},
135 {"KP_EQUALS", KEYCODE_KP_EQUALS, "KP="},
136
137 // Arrows + Home/End pad
138 {"UP", KEYCODE_UP, "Up"},
139 {"DOWN", KEYCODE_DOWN, "Down"},
140 {"RIGHT", KEYCODE_RIGHT, "Right"},
141 {"LEFT", KEYCODE_LEFT, "Left"},
142 {"INSERT", KEYCODE_INSERT, "Insert"},
143 {"HOME", KEYCODE_HOME, "Home"},
144 {"END", KEYCODE_END, "End"},
145 {"PAGEUP", KEYCODE_PAGEUP, "PgUp"},
146 {"PAGEDOWN", KEYCODE_PAGEDOWN, "PgDn"},
147
148 // Function keys
149 {"F1", KEYCODE_F1, "F1"},
150 {"F2", KEYCODE_F2, "F2"},
151 {"F3", KEYCODE_F3, "F3"},
152 {"F4", KEYCODE_F4, "F4"},
153 {"F5", KEYCODE_F5, "F5"},
154 {"F6", KEYCODE_F6, "F6"},
155 {"F7", KEYCODE_F7, "F7"},
156 {"F8", KEYCODE_F8, "F8"},
157 {"F9", KEYCODE_F9, "F9"},
158 {"F10", KEYCODE_F10, "F10"},
159 {"F11", KEYCODE_F11, "F11"},
160 {"F12", KEYCODE_F12, "F12"},
161 {"F13", KEYCODE_F13, "F13"},
162 {"F14", KEYCODE_F14, "F14"},
163 {"F15", KEYCODE_F15, "F15"},
164 {"F16", KEYCODE_F16, "F16"},
165 {"F17", KEYCODE_F17, "F17"},
166 {"F18", KEYCODE_F18, "F18"},
167
168 // Miscellaneous function keys
169 {"HELP", KEYCODE_HELP, "Help"},
170 {"PRINT", KEYCODE_PRINT, "Print"},
171 {"SYSREQ", KEYCODE_SYSREQ, "SysRq"},
172 {"BREAK", KEYCODE_BREAK, "Break"},
173 {"MENU", KEYCODE_MENU, "Menu"},
174 // Power Macintosh power key
175 {"POWER", KEYCODE_POWER, "Power"},
176 // Some european keyboards
177 {"EURO", KEYCODE_EURO, "Euro"},
178 // Atari keyboard has Undo
179 {"UNDO", KEYCODE_UNDO, "Undo"},
180 {"SLEEP", KEYCODE_SLEEP, "Sleep"},
181 {"MUTE", KEYCODE_MUTE, "Mute"},
182 {"EJECT", KEYCODE_EJECT, "Eject"},
183 {"VOLUMEUP", KEYCODE_VOLUMEUP, "Volume Up"},
184 {"VOLUMEDOWN", KEYCODE_VOLUMEDOWN, "Volume Down"},
185 {"LEFTSOFT", KEYCODE_LEFTSOFT, "Left Soft"},
186 {"RIGHTSOFT", KEYCODE_RIGHTSOFT, "Right Soft"},
187 {"CALL", KEYCODE_CALL, "Call"},
188 {"HANGUP", KEYCODE_HANGUP, "Hang up"},
189 {"CAMERA", KEYCODE_CAMERA, "Camera"},
190 {"WWW", KEYCODE_WWW, "WWW"},
191 {"MAIL", KEYCODE_MAIL, "Mail"},
192 {"CALCULATOR", KEYCODE_CALCULATOR, "Calculator"},
193 {"CUT", KEYCODE_CUT, "Cut"},
194 {"COPY", KEYCODE_COPY, "Copy"},
195 {"PASTE", KEYCODE_PASTE, "Paste"},
196 {"SELECT", KEYCODE_SELECT, "Select"},
197 {"CANCEL", KEYCODE_CANCEL, "Cancel"},
198
199 // Action keys
200 {"AC_SEARCH", KEYCODE_AC_SEARCH, "AC Search"},
201 {"AC_HOME", KEYCODE_AC_HOME, "AC Home"},
202 {"AC_BACK", KEYCODE_AC_BACK, "AC Back"},
203 {"AC_FORWARD", KEYCODE_AC_FORWARD, "AC Forward"},
204 {"AC_STOP", KEYCODE_AC_STOP, "AC Stop"},
205 {"AC_REFRESH", KEYCODE_AC_REFRESH, "AC Refresh"},
206 {"AC_BOOKMARKS", KEYCODE_AC_BOOKMARKS, "AC Bookmarks"},
207
208 // Audio keys
209 {"AUDIONEXT", KEYCODE_AUDIONEXT, "Audio Next"},
210 {"AUDIOPREV", KEYCODE_AUDIOPREV, "Audio Previous"},
211 {"AUDIOSTOP", KEYCODE_AUDIOSTOP, "Audio Stop"},
212 {"AUDIOPLAY", KEYCODE_AUDIOPLAY, "Audio Play"},
213 {"AUDIOPAUSE", KEYCODE_AUDIOPAUSE, "Audio Pause"},
214 {"AUDIOPLAYPAUSE", KEYCODE_AUDIOPLAYPAUSE, "Audio Play/Pause"},
215 {"AUDIOMUTE", KEYCODE_AUDIOMUTE, "Audio Mute"},
216 {"AUDIOREWIND", KEYCODE_AUDIOREWIND, "Audio Rewind"},
217 {"AUDIOFASTFORWARD", KEYCODE_AUDIOFASTFORWARD, "Audio Fast-Forward"},
218
219 // Modifier keys
220 {"SCROLLOCK", KEYCODE_SCROLLOCK, "Scroll Lock" },
221 {"CAPSLOCK", KEYCODE_CAPSLOCK, "Caps Lock" },
222 {"NUMLOCK", KEYCODE_NUMLOCK, "Num Lock" },
223 {"LSHIFT", KEYCODE_LSHIFT, "Left Shift" },
224 {"RSHIFT", KEYCODE_RSHIFT, "Right Shift" },
225 {"LALT", KEYCODE_LALT, "Left Alt" },
226 {"RALT", KEYCODE_RALT, "Right Alt" },
227 {"LCTRL", KEYCODE_LCTRL, "Left Control" },
228 {"RCTRL", KEYCODE_RCTRL, "Right Control" },
229 {"LMETA", KEYCODE_LMETA, "Left " META_KEY_NAME },
230 {"RMETA", KEYCODE_RMETA, "Right " META_KEY_NAME },
231
232 {0, KEYCODE_INVALID, 0}
233 };
234
235 // TODO: Add NUM_LOCK
236 const ModifierTableEntry defaultModifiers[] = {
237 { KBD_CTRL, "C", "Ctrl+" },
238 { KBD_SHIFT, "S", "Shift+" },
239 { KBD_ALT, "A", "Alt+" },
240 { KBD_META, "M", META_KEY_NAME "+" },
241 { 0, nullptr, nullptr }
242 };
243
244 const HardwareInputTableEntry defaultMouseButtons[] = {
245 { "MOUSE_LEFT", MOUSE_BUTTON_LEFT, _s("Left Mouse Button") },
246 { "MOUSE_RIGHT", MOUSE_BUTTON_RIGHT, _s("Right Mouse Button") },
247 { "MOUSE_MIDDLE", MOUSE_BUTTON_MIDDLE, _s("Middle Mouse Button") },
248 { "MOUSE_WHEEL_UP", MOUSE_WHEEL_UP, _s("Mouse Wheel Up") },
249 { "MOUSE_WHEEL_DOWN", MOUSE_WHEEL_DOWN, _s("Mouse Wheel Down") },
250 { "MOUSE_X1", MOUSE_BUTTON_X1, _s("X1 Mouse Button") },
251 { "MOUSE_X2", MOUSE_BUTTON_X2, _s("X2 Mouse Button") },
252 { nullptr, 0, nullptr }
253 };
254
255 const HardwareInputTableEntry defaultJoystickButtons[] = {
256 { "JOY_A", JOYSTICK_BUTTON_A, _s("Joy A") },
257 { "JOY_B", JOYSTICK_BUTTON_B, _s("Joy B") },
258 { "JOY_X", JOYSTICK_BUTTON_X, _s("Joy X") },
259 { "JOY_Y", JOYSTICK_BUTTON_Y, _s("Joy Y") },
260 { "JOY_BACK", JOYSTICK_BUTTON_BACK, _s("Joy Back") },
261 { "JOY_GUIDE", JOYSTICK_BUTTON_GUIDE, _s("Joy Guide") },
262 { "JOY_START", JOYSTICK_BUTTON_START, _s("Joy Start") },
263 { "JOY_LEFT_STICK", JOYSTICK_BUTTON_LEFT_STICK, _s("Left Stick") },
264 { "JOY_RIGHT_STICK", JOYSTICK_BUTTON_RIGHT_STICK, _s("Right Stick") },
265 { "JOY_LEFT_SHOULDER", JOYSTICK_BUTTON_LEFT_SHOULDER, _s("Left Shoulder") },
266 { "JOY_RIGHT_SHOULDER", JOYSTICK_BUTTON_RIGHT_SHOULDER, _s("Right Shoulder") },
267 { "JOY_UP", JOYSTICK_BUTTON_DPAD_UP, _s("D-pad Up") },
268 { "JOY_DOWN", JOYSTICK_BUTTON_DPAD_DOWN, _s("D-pad Down") },
269 { "JOY_LEFT", JOYSTICK_BUTTON_DPAD_LEFT, _s("D-pad Left") },
270 { "JOY_RIGHT", JOYSTICK_BUTTON_DPAD_RIGHT, _s("D-pad Right") },
271 { nullptr, 0, nullptr }
272 };
273
274 const AxisTableEntry defaultJoystickAxes[] = {
275 { "JOY_LEFT_TRIGGER", JOYSTICK_AXIS_LEFT_TRIGGER, kAxisTypeHalf, _s("Left Trigger") },
276 { "JOY_RIGHT_TRIGGER", JOYSTICK_AXIS_RIGHT_TRIGGER, kAxisTypeHalf, _s("Right Trigger") },
277 { "JOY_LEFT_STICK_X", JOYSTICK_AXIS_LEFT_STICK_X, kAxisTypeFull, _s("Left Stick X") },
278 { "JOY_LEFT_STICK_Y", JOYSTICK_AXIS_LEFT_STICK_Y, kAxisTypeFull, _s("Left Stick Y") },
279 { "JOY_RIGHT_STICK_X", JOYSTICK_AXIS_RIGHT_STICK_X, kAxisTypeFull, _s("Right Stick X") },
280 { "JOY_RIGHT_STICK_Y", JOYSTICK_AXIS_RIGHT_STICK_Y, kAxisTypeFull, _s("Right Stick Y") },
281 { nullptr, 0, kAxisTypeFull, nullptr }
282 };
283
~HardwareInputSet()284 HardwareInputSet::~HardwareInputSet() {
285 }
286
KeyboardHardwareInputSet(const KeyTableEntry * keys,const ModifierTableEntry * modifiers)287 KeyboardHardwareInputSet::KeyboardHardwareInputSet(const KeyTableEntry *keys, const ModifierTableEntry *modifiers) :
288 _keys(keys),
289 _modifiers(modifiers) {
290 assert(_keys);
291 assert(_modifiers);
292 }
293
findHardwareInput(const String & id) const294 HardwareInput KeyboardHardwareInputSet::findHardwareInput(const String &id) const {
295 StringTokenizer tokenizer(id, "+");
296
297 byte modifierFlags = 0;
298
299 // TODO: Normalize modifier order
300 U32String fullKeyDesc;
301
302 String token;
303 while (!tokenizer.empty()) {
304 token = tokenizer.nextToken();
305
306 const ModifierTableEntry *modifier = nullptr;
307 for (modifier = _modifiers; modifier->id; modifier++) {
308 if (token == modifier->id) {
309 break;
310 }
311 }
312
313 if (modifier && modifier->id) {
314 modifierFlags |= modifier->flag;
315 fullKeyDesc += _(modifier->desc);
316 } else {
317 // We reached the end of the modifiers, the token is a keycode
318 break;
319 }
320 }
321
322 if (!tokenizer.empty()) {
323 return HardwareInput();
324 }
325
326 const KeyTableEntry *key = nullptr;
327 for (key = _keys; key->hwId; key++) {
328 if (token.equals(key->hwId)) {
329 break;
330 }
331 }
332
333 if (!key || !key->hwId) {
334 return HardwareInput();
335 }
336
337 const KeyState keystate = KeyState(key->keycode, 0, modifierFlags);
338 return HardwareInput::createKeyboard(id, keystate, fullKeyDesc + _(key->desc));
339 }
340
findHardwareInput(const Event & event) const341 HardwareInput KeyboardHardwareInputSet::findHardwareInput(const Event &event) const {
342 switch (event.type) {
343 case EVENT_KEYDOWN:
344 case EVENT_KEYUP: {
345 KeyState normalizedKeystate = normalizeKeyState(event.kbd);
346
347 const KeyTableEntry *key = nullptr;
348 for (key = _keys; key->hwId; key++) {
349 if (normalizedKeystate.keycode == key->keycode) {
350 break;
351 }
352 }
353
354 if (!key || !key->hwId) {
355 return HardwareInput();
356 }
357
358 String id;
359 U32String fullKeyDesc;
360 byte modifierFlags = 0;
361
362 for (const ModifierTableEntry *modifier = _modifiers; modifier->id; modifier++) {
363 if (normalizedKeystate.flags & modifier->flag) {
364 id += modifier->id;
365 id += "+";
366 fullKeyDesc += _(modifier->desc);
367 modifierFlags |= modifier->flag;
368 }
369 }
370
371 const KeyState keystate = KeyState(key->keycode, 0, modifierFlags);
372 return HardwareInput::createKeyboard(id + key->hwId, keystate, fullKeyDesc + _(key->desc));
373 }
374 default:
375 return HardwareInput();
376 }
377 }
378
normalizeKeyState(const KeyState & keystate)379 KeyState KeyboardHardwareInputSet::normalizeKeyState(const KeyState &keystate) {
380 KeyState normalizedKeystate = keystate;
381
382 // We ignore the sticky modifiers as they traditionally
383 // have no impact on the outcome of key presses.
384 // TODO: Maybe Num Lock should act as a modifier for the keypad.
385 normalizedKeystate.flags &= ~KBD_STICKY;
386
387 // Modifier keypresses ignore the corresponding modifier flag.
388 // That way, for example, `Left Shift` is not identified
389 // as `Shift+Left Shift` by the keymapper.
390 switch (normalizedKeystate.keycode) {
391 case KEYCODE_LSHIFT:
392 case KEYCODE_RSHIFT:
393 normalizedKeystate.flags &= ~KBD_SHIFT;
394 break;
395 case KEYCODE_LCTRL:
396 case KEYCODE_RCTRL:
397 normalizedKeystate.flags &= ~KBD_CTRL;
398 break;
399 case KEYCODE_LALT:
400 case KEYCODE_RALT:
401 normalizedKeystate.flags &= ~KBD_ALT;
402 break;
403 case KEYCODE_LMETA:
404 case KEYCODE_RMETA:
405 normalizedKeystate.flags &= ~KBD_META;
406 break;
407 case KEYCODE_SCROLLOCK:
408 normalizedKeystate.flags &= ~KBD_SCRL;
409 break;
410 case KEYCODE_CAPSLOCK:
411 normalizedKeystate.flags &= ~KBD_CAPS;
412 break;
413 case KEYCODE_NUMLOCK:
414 normalizedKeystate.flags &= ~KBD_NUM;
415 break;
416 default:
417 break;
418 }
419
420 return normalizedKeystate;
421 }
422
MouseHardwareInputSet(const HardwareInputTableEntry * buttonEntries)423 MouseHardwareInputSet::MouseHardwareInputSet(const HardwareInputTableEntry *buttonEntries) :
424 _buttonEntries(buttonEntries) {
425 assert(_buttonEntries);
426 }
427
findHardwareInput(const String & id) const428 HardwareInput MouseHardwareInputSet::findHardwareInput(const String &id) const {
429 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithId(_buttonEntries, id);
430 if (!hw || !hw->hwId) {
431 return HardwareInput();
432 }
433
434 return HardwareInput::createMouse(hw->hwId, hw->code, _(hw->desc));
435 }
436
findHardwareInput(const Event & event) const437 HardwareInput MouseHardwareInputSet::findHardwareInput(const Event &event) const {
438 int button;
439 switch (event.type) {
440 case EVENT_LBUTTONDOWN:
441 case EVENT_LBUTTONUP:
442 button = MOUSE_BUTTON_LEFT;
443 break;
444 case EVENT_RBUTTONDOWN:
445 case EVENT_RBUTTONUP:
446 button = MOUSE_BUTTON_RIGHT;
447 break;
448 case EVENT_MBUTTONDOWN:
449 case EVENT_MBUTTONUP:
450 button = MOUSE_BUTTON_MIDDLE;
451 break;
452 case Common::EVENT_WHEELUP:
453 button = MOUSE_WHEEL_UP;
454 break;
455 case Common::EVENT_WHEELDOWN:
456 button = MOUSE_WHEEL_DOWN;
457 break;
458 case EVENT_X1BUTTONDOWN:
459 case EVENT_X1BUTTONUP:
460 button = MOUSE_BUTTON_X1;
461 break;
462 case EVENT_X2BUTTONDOWN:
463 case EVENT_X2BUTTONUP:
464 button = MOUSE_BUTTON_X2;
465 break;
466 default:
467 button = -1;
468 break;
469 }
470
471 if (button == -1) {
472 return HardwareInput();
473 }
474
475 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithCode(_buttonEntries, button);
476 if (!hw || !hw->hwId) {
477 return HardwareInput();
478 }
479
480 return HardwareInput::createMouse(hw->hwId, hw->code, _(hw->desc));
481 }
482
JoystickHardwareInputSet(const HardwareInputTableEntry * buttonEntries,const AxisTableEntry * axisEntries)483 JoystickHardwareInputSet::JoystickHardwareInputSet(const HardwareInputTableEntry *buttonEntries, const AxisTableEntry *axisEntries) :
484 _buttonEntries(buttonEntries),
485 _axisEntries(axisEntries) {
486 assert(_buttonEntries);
487 assert(_axisEntries);
488 }
489
findHardwareInput(const String & id) const490 HardwareInput JoystickHardwareInputSet::findHardwareInput(const String &id) const {
491 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithId(_buttonEntries, id);
492 if (hw && hw->hwId) {
493 return HardwareInput::createJoystickButton(hw->hwId, hw->code, _(hw->desc));
494 }
495
496 bool hasHalfSuffix = id.lastChar() == '-' || id.lastChar() == '+';
497 Common::String tableId = hasHalfSuffix ? Common::String(id.c_str(), id.size() - 1) : id;
498 const AxisTableEntry *axis = AxisTableEntry::findWithId(_axisEntries, tableId);
499 if (axis && axis->hwId) {
500 if (hasHalfSuffix && axis->type == kAxisTypeHalf) {
501 return HardwareInput(); // Half axes can't be split in halves
502 } else if (!hasHalfSuffix && axis->type == kAxisTypeFull) {
503 return HardwareInput(); // For now it's only possible to bind half axes
504 }
505
506 if (axis->type == kAxisTypeHalf) {
507 return HardwareInput::createJoystickHalfAxis(axis->hwId, axis->code, true, _(axis->desc));
508 } else {
509 bool positiveHalf = id.lastChar() == '+';
510 Common::U32String desc = U32String::format("%S%c", _(axis->desc).c_str(), id.lastChar());
511 return HardwareInput::createJoystickHalfAxis(id, axis->code, positiveHalf, desc);
512 }
513 }
514
515 return HardwareInput();
516 }
517
findHardwareInput(const Event & event) const518 HardwareInput JoystickHardwareInputSet::findHardwareInput(const Event &event) const {
519 switch (event.type) {
520 case EVENT_JOYBUTTON_DOWN:
521 case EVENT_JOYBUTTON_UP: {
522 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithCode(_buttonEntries, event.joystick.button);
523 if (!hw || !hw->hwId) {
524 return HardwareInput();
525 }
526
527 return HardwareInput::createJoystickButton(hw->hwId, hw->code, _(hw->desc));
528 }
529 case EVENT_JOYAXIS_MOTION: {
530 if (ABS(event.joystick.position) < (JOYAXIS_MAX / 2)) {
531 return HardwareInput(); // Ignore incomplete presses for remapping purposes
532 }
533
534 const AxisTableEntry *hw = AxisTableEntry::findWithCode(_axisEntries, event.joystick.axis);
535 if (!hw || !hw->hwId) {
536 return HardwareInput();
537 }
538
539 if (hw->type == kAxisTypeHalf) {
540 return HardwareInput::createJoystickHalfAxis(hw->hwId, hw->code, true, _(hw->desc));
541 } else {
542 bool positiveHalf = event.joystick.position >= 0;
543 char halfSuffix = positiveHalf ? '+' : '-';
544 Common::String hwId = String::format("%s%c", hw->hwId, halfSuffix);
545 Common::U32String desc = U32String::format("%S%c", _(hw->desc).c_str(), halfSuffix);
546 return HardwareInput::createJoystickHalfAxis(hwId, hw->code, positiveHalf, desc);
547 }
548 }
549
550 default:
551 return HardwareInput();
552 }
553 }
554
CustomHardwareInputSet(const HardwareInputTableEntry * hardwareEntries)555 CustomHardwareInputSet::CustomHardwareInputSet(const HardwareInputTableEntry *hardwareEntries) :
556 _hardwareEntries(hardwareEntries) {
557 assert(_hardwareEntries);
558 }
559
findHardwareInput(const String & id) const560 HardwareInput CustomHardwareInputSet::findHardwareInput(const String &id) const {
561 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithId(_hardwareEntries, id);
562 if (!hw || !hw->hwId) {
563 return HardwareInput();
564 }
565
566 return HardwareInput::createCustom(hw->hwId, hw->code, _(hw->desc));
567 }
568
findHardwareInput(const Event & event) const569 HardwareInput CustomHardwareInputSet::findHardwareInput(const Event &event) const {
570 switch (event.type) {
571 case EVENT_CUSTOM_BACKEND_HARDWARE: {
572 const HardwareInputTableEntry *hw = HardwareInputTableEntry::findWithCode(_hardwareEntries, event.customType);
573 if (!hw || !hw->hwId) {
574 return HardwareInput();
575 }
576
577 return HardwareInput::createCustom(hw->hwId, hw->code, _(hw->desc));
578 }
579 default:
580 return HardwareInput();
581 }
582 }
583
~CompositeHardwareInputSet()584 CompositeHardwareInputSet::~CompositeHardwareInputSet() {
585 for (uint i = 0; i < _inputSets.size(); i++) {
586 delete _inputSets[i];
587 }
588 }
589
findHardwareInput(const String & id) const590 HardwareInput CompositeHardwareInputSet::findHardwareInput(const String &id) const {
591 for (uint i = 0; i < _inputSets.size(); i++) {
592 HardwareInput hardwareInput = _inputSets[i]->findHardwareInput(id);
593 if (hardwareInput.type != kHardwareInputTypeInvalid) {
594 return hardwareInput;
595 }
596 }
597
598 return HardwareInput();
599 }
600
findHardwareInput(const Event & event) const601 HardwareInput CompositeHardwareInputSet::findHardwareInput(const Event &event) const {
602 for (uint i = 0; i < _inputSets.size(); i++) {
603 HardwareInput hardwareInput = _inputSets[i]->findHardwareInput(event);
604 if (hardwareInput.type != kHardwareInputTypeInvalid) {
605 return hardwareInput;
606 }
607 }
608
609 return HardwareInput();
610 }
611
addHardwareInputSet(HardwareInputSet * hardwareInputSet)612 void CompositeHardwareInputSet::addHardwareInputSet(HardwareInputSet *hardwareInputSet) {
613 _inputSets.push_back(hardwareInputSet);
614 }
615
616 } //namespace Common
617