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