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