src/platform/qt/input/InputController.cpp (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "InputController.h"
7
8#include "ConfigController.h"
9#include "GameController.h"
10#include "GamepadAxisEvent.h"
11#include "GamepadButtonEvent.h"
12#include "InputItem.h"
13#include "InputModel.h"
14#include "InputProfile.h"
15
16#include <QApplication>
17#include <QKeyEvent>
18#include <QMenu>
19#include <QTimer>
20#include <QWidget>
21
22#include <mgba/core/interface.h>
23#include <mgba-util/configuration.h>
24
25#include <initializer_list>
26
27using namespace QGBA;
28
29#ifdef BUILD_SDL
30int InputController::s_sdlInited = 0;
31mSDLEvents InputController::s_sdlEvents;
32#endif
33
34InputController::InputController(int playerId, QWidget* topLevel, QObject* parent)
35 : QObject(parent)
36 , m_playerId(playerId)
37 , m_topLevel(topLevel)
38 , m_focusParent(topLevel)
39 , m_bindings(new QMenu(tr("Controls")))
40 , m_autofire(new QMenu(tr("Autofire")))
41{
42#ifdef BUILD_SDL
43 if (s_sdlInited == 0) {
44 mSDLInitEvents(&s_sdlEvents);
45 }
46 ++s_sdlInited;
47 updateJoysticks();
48#endif
49
50#ifdef BUILD_SDL
51 connect(&m_gamepadTimer, &QTimer::timeout, [this]() {
52 testGamepad(SDL_BINDING_BUTTON);
53 if (m_playerId == 0) {
54 updateJoysticks();
55 }
56 });
57#endif
58 m_gamepadTimer.setInterval(50);
59 m_gamepadTimer.start();
60
61 static QList<QPair<QString, int>> defaultBindings({
62 qMakePair(QLatin1String("A"), Qt::Key_Z),
63 qMakePair(QLatin1String("B"), Qt::Key_X),
64 qMakePair(QLatin1String("L"), Qt::Key_A),
65 qMakePair(QLatin1String("R"), Qt::Key_S),
66 qMakePair(QLatin1String("Start"), Qt::Key_Return),
67 qMakePair(QLatin1String("Select"), Qt::Key_Backspace),
68 qMakePair(QLatin1String("Up"), Qt::Key_Up),
69 qMakePair(QLatin1String("Down"), Qt::Key_Down),
70 qMakePair(QLatin1String("Left"), Qt::Key_Left),
71 qMakePair(QLatin1String("Right"), Qt::Key_Right)
72 });
73
74 for (auto k : defaultBindings) {
75 addKey(k.first);
76 }
77 m_keyIndex.rebuild();
78 for (auto k : defaultBindings) {
79 bindKey(KEYBOARD, k.second, k.first);
80 }
81}
82
83void InputController::addKey(const QString& name) {
84 if (itemForKey(name)) {
85 return;
86 }
87 m_keyIndex.addItem(qMakePair([this, name]() {
88 emit keyPressed(keyId(name));
89 }, [this, name]() {
90 emit keyReleased(keyId(name));
91 }), name, QString("key%0").arg(name), m_bindings.get());
92
93 m_keyIndex.addItem(qMakePair([this, name]() {
94 emit keyAutofire(keyId(name), true);
95 }, [this, name]() {
96 emit keyAutofire(keyId(name), false);
97 }), name, QString("autofire%1").arg(name), m_autofire.get());
98}
99
100void InputController::addPlatform(mPlatform platform, const mInputPlatformInfo* info) {
101 m_keyInfo[platform] = info;
102 for (size_t i = 0; i < info->nKeys; ++i) {
103 addKey(info->keyId[i]);
104 }
105}
106
107void InputController::setPlatform(mPlatform platform) {
108 if (m_activeKeyInfo) {
109 mInputMapDeinit(&m_inputMap);
110 }
111
112 m_sdlPlayer.bindings = &m_inputMap;
113 m_activeKeyInfo = m_keyInfo[platform];
114 mInputMapInit(&m_inputMap, m_activeKeyInfo);
115
116 loadConfiguration(KEYBOARD);
117#ifdef BUILD_SDL
118 mSDLInitBindingsGBA(&m_inputMap);
119 loadConfiguration(SDL_BINDING_BUTTON);
120#endif
121
122 rebuildKeyIndex();
123 restoreModel();
124}
125
126InputController::~InputController() {
127 if (m_activeKeyInfo) {
128 mInputMapDeinit(&m_inputMap);
129 }
130
131#ifdef BUILD_SDL
132 if (m_playerAttached) {
133 mSDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer);
134 }
135
136 --s_sdlInited;
137 if (s_sdlInited == 0) {
138 mSDLDeinitEvents(&s_sdlEvents);
139 }
140#endif
141}
142
143void InputController::rebuildIndex(const InputIndex* index) {
144 m_inputIndex.rebuild(index);
145}
146
147void InputController::rebuildKeyIndex(const InputIndex* index) {
148 m_keyIndex.rebuild(index);
149
150 for (const InputItem* item : m_keyIndex.items()) {
151 if (!item->name().startsWith(QLatin1String("key"))) {
152 rebindKey(item->visibleName());
153 }
154 }
155}
156
157void InputController::setConfiguration(ConfigController* config) {
158 m_config = config;
159 m_inputIndex.setConfigController(config);
160 m_keyIndex.setConfigController(config);
161 setAllowOpposing(config->getOption("allowOpposingDirections").toInt());
162 loadConfiguration(KEYBOARD);
163 loadProfile(KEYBOARD, profileForType(KEYBOARD));
164#ifdef BUILD_SDL
165 mSDLEventsLoadConfig(&s_sdlEvents, config->input());
166 if (!m_playerAttached) {
167 m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer);
168 }
169 loadConfiguration(SDL_BINDING_BUTTON);
170 loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
171#endif
172 restoreModel();
173}
174
175void InputController::loadConfiguration(uint32_t type) {
176 if (!m_activeKeyInfo) {
177 return;
178 }
179 mInputMapLoad(&m_inputMap, type, m_config->input());
180#ifdef BUILD_SDL
181 if (m_playerAttached) {
182 mSDLPlayerLoadConfig(&m_sdlPlayer, m_config->input());
183 }
184#endif
185}
186
187void InputController::loadProfile(uint32_t type, const QString& profile) {
188 const InputProfile* ip = InputProfile::findProfile(profile);
189 if (ip) {
190 ip->apply(this);
191 }
192 recalibrateAxes();
193 emit profileLoaded(profile);
194}
195
196void InputController::saveConfiguration() {
197 saveConfiguration(KEYBOARD);
198#ifdef BUILD_SDL
199 saveConfiguration(SDL_BINDING_BUTTON);
200 saveProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
201 if (m_playerAttached) {
202 mSDLPlayerSaveConfig(&m_sdlPlayer, m_config->input());
203 }
204#endif
205 m_inputIndex.saveConfig();
206 m_keyIndex.saveConfig();
207 m_config->write();
208}
209
210void InputController::saveConfiguration(uint32_t type) {
211 if (m_activeKeyInfo) {
212 mInputMapSave(&m_inputMap, type, m_config->input());
213 }
214 m_config->write();
215}
216
217void InputController::saveProfile(uint32_t type, const QString& profile) {
218 if (m_activeKeyInfo) {
219 mInputProfileSave(&m_inputMap, type, m_config->input(), profile.toUtf8().constData());
220 }
221 m_config->write();
222}
223
224const char* InputController::profileForType(uint32_t type) {
225 UNUSED(type);
226#ifdef BUILD_SDL
227 if (type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) {
228#if SDL_VERSION_ATLEAST(2, 0, 0)
229 return SDL_JoystickName(m_sdlPlayer.joystick->joystick);
230#else
231 return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick->joystick));
232#endif
233 }
234#endif
235 return 0;
236}
237
238QStringList InputController::connectedGamepads(uint32_t type) const {
239 UNUSED(type);
240
241#ifdef BUILD_SDL
242 if (type == SDL_BINDING_BUTTON) {
243 QStringList pads;
244 for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) {
245 const char* name;
246#if SDL_VERSION_ATLEAST(2, 0, 0)
247 name = SDL_JoystickName(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick);
248#else
249 name = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick));
250#endif
251 if (name) {
252 pads.append(QString(name));
253 } else {
254 pads.append(QString());
255 }
256 }
257 return pads;
258 }
259#endif
260
261 return QStringList();
262}
263
264int InputController::gamepad(uint32_t type) const {
265#ifdef BUILD_SDL
266 if (type == SDL_BINDING_BUTTON) {
267 return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0;
268 }
269#endif
270 return 0;
271}
272
273void InputController::setGamepad(uint32_t type, int index) {
274#ifdef BUILD_SDL
275 if (type == SDL_BINDING_BUTTON) {
276 mSDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index);
277 }
278#endif
279}
280
281void InputController::setPreferredGamepad(uint32_t type, const QString& device) {
282 if (!m_config) {
283 return;
284 }
285 mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, device.toUtf8().constData());
286}
287
288mRumble* InputController::rumble() {
289#ifdef BUILD_SDL
290#if SDL_VERSION_ATLEAST(2, 0, 0)
291 if (m_playerAttached) {
292 return &m_sdlPlayer.rumble.d;
293 }
294#endif
295#endif
296 return nullptr;
297}
298
299mRotationSource* InputController::rotationSource() {
300#ifdef BUILD_SDL
301 if (m_playerAttached) {
302 return &m_sdlPlayer.rotation.d;
303 }
304#endif
305 return nullptr;
306}
307
308void InputController::registerTiltAxisX(int axis) {
309#ifdef BUILD_SDL
310 if (m_playerAttached) {
311 m_sdlPlayer.rotation.axisX = axis;
312 }
313#endif
314}
315
316void InputController::registerTiltAxisY(int axis) {
317#ifdef BUILD_SDL
318 if (m_playerAttached) {
319 m_sdlPlayer.rotation.axisY = axis;
320 }
321#endif
322}
323
324void InputController::registerGyroAxisX(int axis) {
325#ifdef BUILD_SDL
326 if (m_playerAttached) {
327 m_sdlPlayer.rotation.gyroX = axis;
328 }
329#endif
330}
331
332void InputController::registerGyroAxisY(int axis) {
333#ifdef BUILD_SDL
334 if (m_playerAttached) {
335 m_sdlPlayer.rotation.gyroY = axis;
336 }
337#endif
338}
339
340float InputController::gyroSensitivity() const {
341#ifdef BUILD_SDL
342 if (m_playerAttached) {
343 return m_sdlPlayer.rotation.gyroSensitivity;
344 }
345#endif
346 return 0;
347}
348
349void InputController::setGyroSensitivity(float sensitivity) {
350#ifdef BUILD_SDL
351 if (m_playerAttached) {
352 m_sdlPlayer.rotation.gyroSensitivity = sensitivity;
353 }
354#endif
355}
356
357void InputController::updateJoysticks() {
358#ifdef BUILD_SDL
359 QString profile = profileForType(SDL_BINDING_BUTTON);
360 mSDLUpdateJoysticks(&s_sdlEvents, m_config->input());
361 QString newProfile = profileForType(SDL_BINDING_BUTTON);
362 if (profile != newProfile) {
363 loadProfile(SDL_BINDING_BUTTON, newProfile);
364 }
365#endif
366}
367
368const mInputMap* InputController::map() {
369 return &m_inputMap;
370}
371
372int InputController::pollEvents() {
373 int activeButtons = 0;
374#ifdef BUILD_SDL
375 if (m_playerAttached && m_sdlPlayer.joystick) {
376 SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick;
377 SDL_JoystickUpdate();
378 int numButtons = SDL_JoystickNumButtons(joystick);
379 int i;
380 for (i = 0; i < numButtons; ++i) {
381 GBAKey key = static_cast<GBAKey>(mInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i));
382 if (key == GBA_KEY_NONE) {
383 continue;
384 }
385 if (hasPendingEvent(key)) {
386 continue;
387 }
388 if (SDL_JoystickGetButton(joystick, i)) {
389 activeButtons |= 1 << key;
390 }
391 }
392 int numHats = SDL_JoystickNumHats(joystick);
393 for (i = 0; i < numHats; ++i) {
394 int hat = SDL_JoystickGetHat(joystick, i);
395 activeButtons |= mInputMapHat(&m_inputMap, SDL_BINDING_BUTTON, i, hat);
396 }
397
398 int numAxes = SDL_JoystickNumAxes(joystick);
399 for (i = 0; i < numAxes; ++i) {
400 int value = SDL_JoystickGetAxis(joystick, i);
401
402 enum GBAKey key = static_cast<GBAKey>(mInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value));
403 if (key != GBA_KEY_NONE) {
404 activeButtons |= 1 << key;
405 }
406 }
407 }
408#endif
409 return activeButtons;
410}
411
412QSet<int> InputController::activeGamepadButtons(int type) {
413 QSet<int> activeButtons;
414#ifdef BUILD_SDL
415 if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) {
416 SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick;
417 SDL_JoystickUpdate();
418 int numButtons = SDL_JoystickNumButtons(joystick);
419 int i;
420 for (i = 0; i < numButtons; ++i) {
421 if (SDL_JoystickGetButton(joystick, i)) {
422 activeButtons.insert(i);
423 }
424 }
425 }
426#endif
427 return activeButtons;
428}
429
430void InputController::recalibrateAxes() {
431#ifdef BUILD_SDL
432 if (m_playerAttached && m_sdlPlayer.joystick) {
433 SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick;
434 SDL_JoystickUpdate();
435 int numAxes = SDL_JoystickNumAxes(joystick);
436 if (numAxes < 1) {
437 return;
438 }
439 m_deadzones.resize(numAxes);
440 int i;
441 for (i = 0; i < numAxes; ++i) {
442 m_deadzones[i] = SDL_JoystickGetAxis(joystick, i);
443 }
444 }
445#endif
446}
447
448QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes(int type) {
449 QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;
450#ifdef BUILD_SDL
451 if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) {
452 SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick;
453 SDL_JoystickUpdate();
454 int numAxes = SDL_JoystickNumAxes(joystick);
455 if (numAxes < 1) {
456 return activeAxes;
457 }
458 m_deadzones.resize(numAxes);
459 int i;
460 for (i = 0; i < numAxes; ++i) {
461 int32_t axis = SDL_JoystickGetAxis(joystick, i);
462 axis -= m_deadzones[i];
463 if (axis >= AXIS_THRESHOLD || axis <= -AXIS_THRESHOLD) {
464 activeAxes.insert(qMakePair(i, axis > 0 ? GamepadAxisEvent::POSITIVE : GamepadAxisEvent::NEGATIVE));
465 }
466 }
467 }
468#endif
469 return activeAxes;
470}
471
472void InputController::bindKey(uint32_t type, int key, const QString& keyName) {
473 InputItem* item = itemForKey(keyName);
474 if (type != KEYBOARD) {
475 item->setButton(key);
476 } else {
477 item->setShortcut(key);
478 }
479 if (m_activeKeyInfo) {
480 int coreKey = keyId(keyName);
481 mInputBindKey(&m_inputMap, type, key, coreKey);
482 }
483}
484
485void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, const QString& key) {
486 InputItem* item = itemForKey(key);
487 item->setAxis(axis, direction);
488
489 if (!m_activeKeyInfo) {
490 return;
491 }
492
493 const mInputAxis* old = mInputQueryAxis(&m_inputMap, type, axis);
494 mInputAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD };
495 if (old) {
496 description = *old;
497 }
498 int deadzone = 0;
499 if (axis > 0 && m_deadzones.size() > axis) {
500 deadzone = m_deadzones[axis];
501 }
502 switch (direction) {
503 case GamepadAxisEvent::NEGATIVE:
504 description.lowDirection = keyId(key);
505
506 description.deadLow = deadzone - AXIS_THRESHOLD;
507 break;
508 case GamepadAxisEvent::POSITIVE:
509 description.highDirection = keyId(key);
510 description.deadHigh = deadzone + AXIS_THRESHOLD;
511 break;
512 default:
513 return;
514 }
515 mInputBindAxis(&m_inputMap, type, axis, &description);
516}
517
518QSet<QPair<int, GamepadHatEvent::Direction>> InputController::activeGamepadHats(int type) {
519 QSet<QPair<int, GamepadHatEvent::Direction>> activeHats;
520#ifdef BUILD_SDL
521 if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) {
522 SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick;
523 SDL_JoystickUpdate();
524 int numHats = SDL_JoystickNumHats(joystick);
525 if (numHats < 1) {
526 return activeHats;
527 }
528
529 int i;
530 for (i = 0; i < numHats; ++i) {
531 int hat = SDL_JoystickGetHat(joystick, i);
532 if (hat & GamepadHatEvent::UP) {
533 activeHats.insert(qMakePair(i, GamepadHatEvent::UP));
534 }
535 if (hat & GamepadHatEvent::RIGHT) {
536 activeHats.insert(qMakePair(i, GamepadHatEvent::RIGHT));
537 }
538 if (hat & GamepadHatEvent::DOWN) {
539 activeHats.insert(qMakePair(i, GamepadHatEvent::DOWN));
540 }
541 if (hat & GamepadHatEvent::LEFT) {
542 activeHats.insert(qMakePair(i, GamepadHatEvent::LEFT));
543 }
544 }
545 }
546#endif
547 return activeHats;
548}
549
550void InputController::bindHat(uint32_t type, int hat, GamepadHatEvent::Direction direction, const QString& key) {
551 if (!m_activeKeyInfo) {
552 return;
553 }
554
555 mInputHatBindings bindings{ -1, -1, -1, -1 };
556 mInputQueryHat(&m_inputMap, type, hat, &bindings);
557 switch (direction) {
558 case GamepadHatEvent::UP:
559 bindings.up = keyId(key);
560 break;
561 case GamepadHatEvent::RIGHT:
562 bindings.right = keyId(key);
563 break;
564 case GamepadHatEvent::DOWN:
565 bindings.down = keyId(key);
566 break;
567 case GamepadHatEvent::LEFT:
568 bindings.left = keyId(key);
569 break;
570 default:
571 return;
572 }
573 mInputBindHat(&m_inputMap, type, hat, &bindings);
574}
575
576void InputController::testGamepad(int type) {
577 auto activeAxes = activeGamepadAxes(type);
578 auto oldAxes = m_activeAxes;
579 m_activeAxes = activeAxes;
580
581 auto activeButtons = activeGamepadButtons(type);
582 auto oldButtons = m_activeButtons;
583 m_activeButtons = activeButtons;
584
585 auto activeHats = activeGamepadHats(type);
586 auto oldHats = m_activeHats;
587 m_activeHats = activeHats;
588
589 if (!QApplication::focusWidget()) {
590 return;
591 }
592
593 activeAxes.subtract(oldAxes);
594 oldAxes.subtract(m_activeAxes);
595
596 for (auto& axis : m_activeAxes) {
597 bool newlyAboveThreshold = activeAxes.contains(axis);
598 if (newlyAboveThreshold) {
599 GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, newlyAboveThreshold, type, this);
600 postPendingEvent(event->gbaKey());
601 sendGamepadEvent(event);
602 if (!event->isAccepted()) {
603 clearPendingEvent(event->gbaKey());
604 }
605 }
606 }
607 for (auto axis : oldAxes) {
608 GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, false, type, this);
609 clearPendingEvent(event->gbaKey());
610 sendGamepadEvent(event);
611 }
612
613 if (!QApplication::focusWidget()) {
614 return;
615 }
616
617 activeButtons.subtract(oldButtons);
618 oldButtons.subtract(m_activeButtons);
619
620 for (int button : activeButtons) {
621 GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Down(), button, type, this);
622 postPendingEvent(event->gbaKey());
623 sendGamepadEvent(event);
624 if (!event->isAccepted()) {
625 clearPendingEvent(event->gbaKey());
626 }
627 }
628 for (int button : oldButtons) {
629 GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Up(), button, type, this);
630 clearPendingEvent(event->gbaKey());
631 sendGamepadEvent(event);
632 }
633
634 activeHats.subtract(oldHats);
635 oldHats.subtract(m_activeHats);
636
637 for (auto& hat : activeHats) {
638 GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Down(), hat.first, hat.second, type, this);
639 postPendingEvent(event->gbaKey());
640 sendGamepadEvent(event);
641 if (!event->isAccepted()) {
642 clearPendingEvent(event->gbaKey());
643 }
644 }
645 for (auto& hat : oldHats) {
646 GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Up(), hat.first, hat.second, type, this);
647 clearPendingEvent(event->gbaKey());
648 sendGamepadEvent(event);
649 }
650}
651
652void InputController::sendGamepadEvent(QEvent* event) {
653 QWidget* focusWidget = nullptr;
654 if (m_focusParent) {
655 focusWidget = m_focusParent->focusWidget();
656 if (!focusWidget) {
657 focusWidget = m_focusParent;
658 }
659 } else {
660 focusWidget = QApplication::focusWidget();
661 }
662 QApplication::sendEvent(focusWidget, event);
663}
664
665void InputController::postPendingEvent(int key) {
666 m_pendingEvents.insert(key);
667}
668
669void InputController::clearPendingEvent(int key) {
670 m_pendingEvents.remove(key);
671}
672
673bool InputController::hasPendingEvent(int key) const {
674 return m_pendingEvents.contains(key);
675}
676
677void InputController::suspendScreensaver() {
678#ifdef BUILD_SDL
679#if SDL_VERSION_ATLEAST(2, 0, 0)
680 mSDLSuspendScreensaver(&s_sdlEvents);
681#endif
682#endif
683}
684
685void InputController::resumeScreensaver() {
686#ifdef BUILD_SDL
687#if SDL_VERSION_ATLEAST(2, 0, 0)
688 mSDLResumeScreensaver(&s_sdlEvents);
689#endif
690#endif
691}
692
693void InputController::setScreensaverSuspendable(bool suspendable) {
694#ifdef BUILD_SDL
695#if SDL_VERSION_ATLEAST(2, 0, 0)
696 mSDLSetScreensaverSuspendable(&s_sdlEvents, suspendable);
697#endif
698#endif
699}
700
701void InputController::stealFocus(QWidget* focus) {
702 m_focusParent = focus;
703}
704
705void InputController::releaseFocus(QWidget* focus) {
706 if (focus == m_focusParent) {
707 m_focusParent = m_topLevel;
708 }
709}
710
711bool InputController::eventFilter(QObject*, QEvent* event) {
712 event->ignore();
713 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
714 QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
715 int key = keyEvent->key();
716 if (!InputIndex::isModifierKey(key)) {
717 key |= (keyEvent->modifiers() & ~Qt::KeypadModifier);
718 } else {
719 key = InputIndex::toModifierKey(key | (keyEvent->modifiers() & ~Qt::KeypadModifier));
720 }
721
722 if (keyEvent->isAutoRepeat()) {
723 event->accept();
724 return true;
725 }
726
727 event->ignore();
728 InputItem* item = m_inputIndex.itemForShortcut(key);
729 if (item) {
730 item->trigger(event->type() == QEvent::KeyPress);
731 event->accept();
732 }
733 item = m_keyIndex.itemForShortcut(key);
734 if (item) {
735 item->trigger(event->type() == QEvent::KeyPress);
736 event->accept();
737 }
738 }
739
740
741 if (event->type() == GamepadButtonEvent::Down() || event->type() == GamepadButtonEvent::Up()) {
742 GamepadButtonEvent* gbe = static_cast<GamepadButtonEvent*>(event);
743 InputItem* item = m_inputIndex.itemForButton(gbe->value());
744 if (item) {
745 item->trigger(event->type() == GamepadButtonEvent::Down());
746 event->accept();
747 }
748 item = m_keyIndex.itemForButton(gbe->value());
749 if (item) {
750 item->trigger(event->type() == GamepadButtonEvent::Down());
751 event->accept();
752 }
753 }
754 if (event->type() == GamepadAxisEvent::Type()) {
755 GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event);
756 InputItem* item = m_inputIndex.itemForAxis(gae->axis(), gae->direction());
757 if (item) {
758 item->trigger(event->type() == gae->isNew());
759 event->accept();
760 }
761 item = m_keyIndex.itemForAxis(gae->axis(), gae->direction());
762 if (item) {
763 item->trigger(event->type() == gae->isNew());
764 event->accept();
765 }
766 }
767 return event->isAccepted();
768}
769
770InputItem* InputController::itemForKey(const QString& key) {
771 return m_keyIndex.itemAt(QString("key%0").arg(key));
772}
773
774int InputController::keyId(const QString& key) {
775 for (int i = 0; i < m_activeKeyInfo->nKeys; ++i) {
776 if (m_activeKeyInfo->keyId[i] == key) {
777 return i;
778 }
779 }
780 return -1;
781}
782
783void InputController::restoreModel() {
784 if (!m_activeKeyInfo) {
785 return;
786 }
787 int nKeys = m_inputMap.info->nKeys;
788 for (int i = 0; i < nKeys; ++i) {
789 const QString& keyName = m_inputMap.info->keyId[i];
790 InputItem* item = itemForKey(keyName);
791 if (item) {
792 int key = mInputQueryBinding(&m_inputMap, KEYBOARD, i);
793 if (key >= 0) {
794 item->setShortcut(key);
795 } else {
796 item->clearShortcut();
797 }
798#ifdef BUILD_SDL
799 key = mInputQueryBinding(&m_inputMap, SDL_BINDING_BUTTON, i);
800 if (key >= 0) {
801 item->setButton(key);
802 } else {
803 item->clearButton();
804 }
805#endif
806 }
807 }
808#ifdef BUILD_SDL
809 mInputEnumerateAxes(&m_inputMap, SDL_BINDING_BUTTON, [](int axis, const struct mInputAxis* description, void* user) {
810 InputController* controller = static_cast<InputController*>(user);
811 InputItem* item;
812 const mInputPlatformInfo* inputMap = controller->m_inputMap.info;
813 if (description->highDirection >= 0 && description->highDirection < controller->m_inputMap.info->nKeys) {
814 int id = description->lowDirection;
815 if (id >= 0 && id < inputMap->nKeys) {
816 item = controller->itemForKey(inputMap->keyId[id]);
817 if (item) {
818 item->setAxis(axis, GamepadAxisEvent::POSITIVE);
819 }
820 }
821 }
822 if (description->lowDirection >= 0 && description->lowDirection < controller->m_inputMap.info->nKeys) {
823 int id = description->highDirection;
824 if (id >= 0 && id < inputMap->nKeys) {
825 item = controller->itemForKey(inputMap->keyId[id]);
826 if (item) {
827 item->setAxis(axis, GamepadAxisEvent::NEGATIVE);
828 }
829 }
830 }
831 }, this);
832#endif
833 rebuildKeyIndex();
834}
835
836void InputController::rebindKey(const QString& key) {
837 InputItem* item = itemForKey(key);
838 bindKey(KEYBOARD, item->shortcut(), key);
839#ifdef BUILD_SDL
840 bindKey(SDL_BINDING_BUTTON, item->button(), key);
841 bindAxis(SDL_BINDING_BUTTON, item->axis(), item->direction(), key);
842#endif
843}