From 39bbb8049f5d56eaf611e6dfa9db64cd70616137 Mon Sep 17 00:00:00 2001 From: Johan Solbakken Date: Tue, 15 Aug 2023 12:25:56 +0200 Subject: [PATCH] Expand scope of QtGamepad to QtUniversalInput This patch transforms the QtGamepad module from Qt 5 into a new module that expands the scope to include all forms of exotic input. The majority of the previous QtGamepad functionality and APIs are preserved, but now there is also a more general API for getting the state of input devices like joysticks, flight yokes, and any other devices that define themselves in terms of buttons and axes. In addition to being able to receive input, it is also now possible to output feedback in devices that support it. Experimental input mapping functionality has been added to facilitate mapping an arbitrary input to a predefined action. Change-Id: Ic35b73282944cfd4eea9defbcf82c4abc55d7237 Reviewed-by: Andy Nichols --- .cmake.conf | 5 + .gitmodules | 0 .qmake.conf | 6 - CMakeLists.txt | 22 + LICENSE.LGPLv3 | 173 -- LICENSES/BSD-3-Clause.txt | 9 + LICENSES/GFDL-1.3-no-invariants-only.txt | 451 ++++ LICENSES/GPL-2.0-only.txt | 339 +++ LICENSE.GPL => LICENSES/GPL-3.0-only.txt | 0 LICENSES/LGPL-3.0-only.txt | 165 ++ LICENSES/LicenseRef-Qt-Commercial.txt | 8 + LICENSES/Qt-GPL-exception-1.0.txt | 22 + README.md | 18 +- config.tests/sdl/main.cpp | 45 - config.tests/sdl/sdl.pro | 3 - configure.cmake | 24 + configure.json | 5 - dependencies.yaml | 7 - dist/changes-5.10.0 | 22 - dist/changes-5.10.1 | 26 - dist/changes-5.11.0 | 22 - dist/changes-5.11.1 | 24 - dist/changes-5.11.2 | 24 - dist/changes-5.11.3 | 20 - dist/changes-5.12.0 | 18 - dist/changes-5.12.1 | 20 - dist/changes-5.12.2 | 20 - dist/changes-5.12.3 | 20 - dist/changes-5.12.4 | 20 - dist/changes-5.12.5 | 20 - dist/changes-5.13.0 | 18 - dist/changes-5.13.1 | 20 - dist/changes-5.13.2 | 20 - dist/changes-5.14.0 | 18 - dist/changes-5.14.1 | 20 - dist/changes-5.14.2 | 20 - dist/changes-5.15.0 | 18 - dist/changes-5.15.1 | 20 - dist/changes-5.9.0 | 16 - dist/changes-5.9.1 | 24 - dist/changes-5.9.2 | 22 - dist/changes-5.9.3 | 24 - dist/changes-5.9.4 | 25 - dist/changes-5.9.5 | 24 - dist/changes-5.9.6 | 24 - examples/CMakeLists.txt | 9 + examples/examples.pro | 3 - .../configureButtons/configureButtons.pro | 19 - .../configuregamepadbuttons-example.png | Bin 20239 -> 0 bytes .../doc/src/configbuttonsexample.qdoc | 35 - examples/gamepad/configureButtons/main.cpp | 49 - examples/gamepad/configureButtons/main.qml | 645 ------ examples/gamepad/configureButtons/qml.qrc | 5 - examples/gamepad/gamepad.pro | 15 - .../images/keynavigationgamepad-example.png | Bin 3812 -> 0 bytes .../keyNavigation/doc/src/keynaviexample.qdoc | 35 - .../gamepad/keyNavigation/keyNavigation.pro | 13 - .../gamepad/keyNavigation/keyNavigation64.png | Bin 3400 -> 0 bytes .../gamepad/keyNavigation/keyNavigation80.png | Bin 4945 -> 0 bytes examples/gamepad/keyNavigation/main.cpp | 62 - examples/gamepad/keyNavigation/qml.qrc | 5 - examples/gamepad/keyNavigation/qml/main.qml | 122 - .../mouseItem/doc/src/mouseitemexample.qdoc | 34 - examples/gamepad/mouseItem/main.cpp | 63 - examples/gamepad/mouseItem/mouseItem.pro | 13 - examples/gamepad/mouseItem/mouseItem64.png | Bin 3400 -> 0 bytes examples/gamepad/mouseItem/mouseItem80.png | Bin 4945 -> 0 bytes examples/gamepad/mouseItem/qml.qrc | 5 - examples/gamepad/mouseItem/qml/main.qml | 133 -- .../doc/images/qtquickgamepad-example.png | Bin 50662 -> 0 bytes .../doc/src/quickgamepadexample.qdoc | 35 - examples/gamepad/quickGamepad/main.cpp | 62 - examples/gamepad/quickGamepad/qml.qrc | 24 - .../gamepad/quickGamepad/qml/ButtonImage.qml | 82 - examples/gamepad/quickGamepad/qml/DPad.qml | 110 - .../quickGamepad/qml/JoystickViewer.qml | 84 - .../quickGamepad/qml/LeftThumbstick.qml | 72 - .../quickGamepad/qml/RightThumbstick.qml | 73 - examples/gamepad/quickGamepad/qml/main.qml | 231 -- .../quickGamepad/qml/xboxControllerBack.png | Bin 11012 -> 0 bytes .../qml/xboxControllerButtonA.png | Bin 13764 -> 0 bytes .../qml/xboxControllerButtonB.png | Bin 13480 -> 0 bytes .../qml/xboxControllerButtonGuide.png | Bin 37297 -> 0 bytes .../qml/xboxControllerButtonX.png | Bin 14017 -> 0 bytes .../qml/xboxControllerButtonY.png | Bin 13911 -> 0 bytes .../quickGamepad/qml/xboxControllerDPad.png | Bin 33024 -> 0 bytes .../qml/xboxControllerLeftShoulder.png | Bin 22224 -> 0 bytes .../qml/xboxControllerLeftThumbstick.png | Bin 28966 -> 0 bytes .../qml/xboxControllerLeftTrigger.png | Bin 13918 -> 0 bytes .../qml/xboxControllerRightShoulder.png | Bin 21209 -> 0 bytes .../qml/xboxControllerRightThumbstick.png | Bin 29386 -> 0 bytes .../qml/xboxControllerRightTrigger.png | Bin 14152 -> 0 bytes .../quickGamepad/qml/xboxControllerStart.png | Bin 11271 -> 0 bytes .../gamepad/quickGamepad/quickGamepad.pro | 13 - .../gamepad/quickGamepad/quickGamepad64.png | Bin 3400 -> 0 bytes .../gamepad/quickGamepad/quickGamepad80.png | Bin 4945 -> 0 bytes .../simple/android/AndroidManifest.xml | 54 - .../gamepad/simple/doc/src/simpleexample.qdoc | 34 - examples/gamepad/simple/gamepadmonitor.cpp | 120 - examples/gamepad/simple/gamepadmonitor.h | 72 - examples/gamepad/simple/main.cpp | 61 - examples/gamepad/simple/simple.pro | 17 - examples/universalinput/CMakeLists.txt | 9 + .../universalinput/actionpong/ActionMap.qml | 70 + examples/universalinput/actionpong/Ball.qml | 38 + .../universalinput/actionpong/CMakeLists.txt | 50 + examples/universalinput/actionpong/Paddle.qml | 28 + .../actionpong/PaddleController.qml | 44 + examples/universalinput/actionpong/main.cpp | 27 + examples/universalinput/actionpong/main.qml | 180 ++ .../consolejoystickmonitor/CMakeLists.txt | 36 + .../consolejoystickmonitor/main.cpp | 31 + .../universalinput/mousegrab/CMakeLists.txt | 46 + examples/universalinput/mousegrab/main.cpp | 33 + examples/universalinput/mousegrab/main.qml | 109 + .../universalinput/quickaction/CMakeLists.txt | 51 + .../universalinput/quickaction/Controller.qml | 93 + .../universalinput/quickaction/GameObject.qml | 31 + .../quickaction/GameObjectList.qml | 10 + .../universalinput/quickaction/Platform.qml | 9 + .../universalinput/quickaction/Player.qml | 62 + examples/universalinput/quickaction/main.cpp | 34 + examples/universalinput/quickaction/main.qml | 114 + examples/universalinput/simple/CMakeLists.txt | 44 + .../simple}/android/AndroidManifest.xml | 8 +- .../universalinput/simple/gamepadmonitor.cpp | 113 + .../universalinput/simple/gamepadmonitor.h | 35 + examples/universalinput/simple/main.cpp | 14 + .../virtualgamepad/ButtonIsland.qml | 85 + .../virtualgamepad/CMakeLists.txt | 50 + .../virtualgamepad/JoyButton.qml | 41 + .../virtualgamepad/Joystick.qml | 108 + .../virtualgamepad/VirtualGamepad.qml | 123 + .../universalinput/virtualgamepad/main.cpp | 27 + .../universalinput/virtualgamepad/main.qml | 74 + qtgamepad.pro | 3 - src/3rdparty/sdlgamecontrollerdb/LICENSE | 17 + src/3rdparty/sdlgamecontrollerdb/README.md | 57 + .../sdlgamecontrollerdb/gamecontrollerdb.txt | 2052 +++++++++++++++++ ...import_from_sdlgamecontrollerdb_tarball.sh | 50 + .../sdlgamecontrollerdb/qt_attribution.json | 15 + src/CMakeLists.txt | 11 + src/gamepad/CMakeLists.txt | 20 + src/gamepad/configure.json | 41 - src/gamepad/doc/qtgamepad.qdocconf | 55 - src/gamepad/doc/src/qtgamepad-cpp.qdoc | 50 - src/gamepad/doc/src/qtgamepad-examples.qdoc | 36 - src/gamepad/doc/src/qtgamepad-index.qdoc | 178 -- src/gamepad/doc/src/qtgamepad-qmltypes.qdoc | 52 - src/gamepad/gamepad.pro | 36 - src/gamepad/qgamepad.cpp | 430 +--- src/gamepad/qgamepad.h | 129 +- src/gamepad/qgamepadbackend.cpp | 114 - src/gamepad/qgamepadbackend_p.h | 118 - src/gamepad/qgamepadbackendfactory.cpp | 60 - src/gamepad/qgamepadbackendfactory_p.h | 68 - src/gamepad/qgamepadbackendplugin.cpp | 52 - src/gamepad/qgamepadbackendplugin_p.h | 79 - src/gamepad/qgamepadkeynavigation.cpp | 584 ----- src/gamepad/qgamepadkeynavigation.h | 150 -- src/gamepad/qgamepadmanager.cpp | 308 --- src/gamepad/qgamepadmanager.h | 135 -- src/gamepad/qtgamepadglobal.h | 58 - src/imports/gamepad/gamepad.pro | 17 - src/imports/gamepad/plugins.qmltypes | 539 ----- src/imports/gamepad/qgamepadmouseitem.cpp | 225 -- src/imports/gamepad/qgamepadmouseitem.h | 117 - src/imports/gamepad/qmldir | 4 - src/imports/gamepad/qtgamepad.cpp | 85 - src/imports/imports.pro | 2 - src/plugins/CMakeLists.txt | 5 + src/plugins/gamepads/android/android.pro | 2 - src/plugins/gamepads/android/jar/jar.pro | 18 - .../qt/android/gamepad/QtGamepad.java | 110 - src/plugins/gamepads/android/src/main.cpp | 61 - .../android/src/qandroidgamepadbackend.cpp | 635 ----- .../android/src/qandroidgamepadbackend_p.h | 135 -- src/plugins/gamepads/android/src/src.pro | 17 - src/plugins/gamepads/darwin/darwin.json | 3 - src/plugins/gamepads/darwin/darwin.pro | 19 - src/plugins/gamepads/darwin/main.cpp | 61 - .../gamepads/darwin/qdarwingamepadbackend.mm | 570 ----- .../gamepads/darwin/qdarwingamepadbackend_p.h | 77 - src/plugins/gamepads/evdev/evdev.json | 3 - src/plugins/gamepads/evdev/evdev.pro | 14 - src/plugins/gamepads/evdev/main.cpp | 62 - .../gamepads/evdev/qevdevgamepadbackend.cpp | 553 ----- .../gamepads/evdev/qevdevgamepadbackend_p.h | 138 -- src/plugins/gamepads/gamepads.pro | 7 - src/plugins/gamepads/sdl2/main.cpp | 61 - .../gamepads/sdl2/qsdlgamepadbackend.cpp | 210 -- .../gamepads/sdl2/qsdlgamepadbackend_p.h | 74 - src/plugins/gamepads/sdl2/sdl2.json | 3 - src/plugins/gamepads/sdl2/sdl2.pro | 17 - src/plugins/gamepads/xinput/main.cpp | 62 - .../gamepads/xinput/qxinputgamepadbackend.cpp | 291 --- .../gamepads/xinput/qxinputgamepadbackend_p.h | 63 - src/plugins/gamepads/xinput/xinput.json | 3 - src/plugins/gamepads/xinput/xinput.pro | 14 - src/plugins/joystickinputs/CMakeLists.txt | 23 + .../joystickinputs/android/CMakeLists.txt | 43 + .../android}/android.json | 0 .../android/androidjoystickinput.cpp | 142 ++ .../android/androidjoystickinput.h | 39 + .../android/androidjoystickinputplugin.cpp | 17 + .../android/androidjoystickinputplugin.h | 23 + .../android/jar/AndroidManifest.xml | 6 + .../qt/android/universalinput/QtJoystick.java | 28 + .../QtJoystickInputHandler.java | 308 +++ src/plugins/joystickinputs/ios/CMakeLists.txt | 17 + src/plugins/joystickinputs/ios/ios.json | 3 + .../joystickinputs/ios/iosjoystickinput.h | 27 + .../joystickinputs/ios/iosjoystickinput.mm | 318 +++ .../ios/iosjoystickinputplugin.cpp | 17 + .../ios/iosjoystickinputplugin.h | 23 + .../joystickinputs/linux/CMakeLists.txt | 17 + src/plugins/joystickinputs/linux/linux.json | 3 + .../linux/linuxjoystickinput.cpp | 453 ++++ .../joystickinputs/linux/linuxjoystickinput.h | 101 + .../linux/linuxjoystickinputplugin.cpp | 17 + .../linux/linuxjoystickinputplugin.h | 23 + .../joystickinputs/macos/CMakeLists.txt | 19 + src/plugins/joystickinputs/macos/macos.json | 3 + .../joystickinputs/macos/macosjoystickinput.h | 104 + .../macos/macosjoystickinput.mm | 623 +++++ .../macos/macosjoystickinputplugin.cpp | 17 + .../macos/macosjoystickinputplugin.h | 23 + .../joystickinputs/windows/CMakeLists.txt | 16 + .../joystickinputs/windows/windows.json | 3 + .../windows/windowsjoystickinput.cpp | 571 +++++ .../windows/windowsjoystickinput.h | 123 + .../windows/windowsjoystickinputplugin.cpp | 17 + .../windows/windowsjoystickinputplugin.h | 23 + src/plugins/mouseinputs/CMakeLists.txt | 23 + src/plugins/mouseinputs/linux/CMakeLists.txt | 15 + src/plugins/mouseinputs/linux/linux.json | 3 + .../mouseinputs/linux/linuxmouseinput.cpp | 84 + .../mouseinputs/linux/linuxmouseinput.h | 41 + .../linux/linuxmouseinputplugin.cpp | 17 + .../mouseinputs/linux/linuxmouseinputplugin.h | 23 + src/plugins/mouseinputs/macos/CMakeLists.txt | 18 + src/plugins/mouseinputs/macos/macos.json | 3 + .../mouseinputs/macos/macosmouseinput.h | 41 + .../mouseinputs/macos/macosmouseinput.mm | 82 + .../macos/macosmouseinputplugin.cpp | 17 + .../mouseinputs/macos/macosmouseinputplugin.h | 23 + .../mouseinputs/windows/CMakeLists.txt | 15 + src/plugins/mouseinputs/windows/windows.json | 3 + .../mouseinputs/windows/windowsmouseinput.cpp | 84 + .../mouseinputs/windows/windowsmouseinput.h | 41 + .../windows/windowsmouseinputplugin.cpp | 17 + .../windows/windowsmouseinputplugin.h | 23 + src/plugins/plugins.pro | 2 - src/quickactionstore/CMakeLists.txt | 20 + src/quickactionstore/qquickactionhandler.cpp | 177 ++ src/quickactionstore/qquickactionhandler_p.h | 104 + src/quickactionstore/qquickactionstore.cpp | 316 +++ src/quickactionstore/qquickactionstore_p.h | 315 +++ src/quickactionstore/qquickeventlistener.cpp | 95 + src/quickactionstore/qquickeventlistener_p.h | 58 + src/quickgamepad/CMakeLists.txt | 18 + src/quickgamepad/qquickgamepad.cpp | 19 + src/quickgamepad/qquickgamepad_p.h | 36 + src/quickuniversalinput/CMakeLists.txt | 18 + .../qquickuniversalinput.cpp | 70 + .../qquickuniversalinput_p.h | 64 + src/src.pro | 11 - src/universalinput/CMakeLists.txt | 45 + src/universalinput/GODOT_LICENSE.txt | 20 + .../doc/images/gamecontrollers.jpg | Bin 0 -> 45722 bytes src/universalinput/qactionstore.cpp | 196 ++ src/universalinput/qactionstore.h | 141 ++ .../qjoydevicemappingparser.cpp | 248 ++ .../qjoydevicemappingparser_p.h | 54 + src/universalinput/qjoystickinput_p.h | 30 + src/universalinput/qjoystickinputfactory.cpp | 24 + src/universalinput/qjoystickinputfactory_p.h | 34 + src/universalinput/qjoystickinputplugin_p.h | 40 + src/universalinput/qmouseinput_p.h | 30 + src/universalinput/qmouseinputfactory.cpp | 24 + src/universalinput/qmouseinputfactory_p.h | 34 + src/universalinput/qmouseinputplugin_p.h | 40 + src/universalinput/qt_attribution.json | 16 + src/universalinput/qtuniversalinputglobal.h | 10 + src/universalinput/qtuniversalinputglobal_p.h | 21 + src/universalinput/quniversalinput.cpp | 742 ++++++ src/universalinput/quniversalinput.h | 263 +++ src/universalinput/quniversalinput_p.h | 85 + sync.profile | 16 - tests/CMakeLists.txt | 5 + tests/auto/CMakeLists.txt | 7 + tests/auto/auto.pro | 2 - tests/auto/cmake/CMakeLists.txt | 12 - tests/auto/cmake/cmake.pro | 5 - tests/tests.pro | 3 - 295 files changed, 12452 insertions(+), 10123 deletions(-) create mode 100644 .cmake.conf create mode 100644 .gitmodules delete mode 100644 .qmake.conf create mode 100644 CMakeLists.txt delete mode 100644 LICENSE.LGPLv3 create mode 100644 LICENSES/BSD-3-Clause.txt create mode 100644 LICENSES/GFDL-1.3-no-invariants-only.txt create mode 100644 LICENSES/GPL-2.0-only.txt rename LICENSE.GPL => LICENSES/GPL-3.0-only.txt (100%) create mode 100644 LICENSES/LGPL-3.0-only.txt create mode 100644 LICENSES/LicenseRef-Qt-Commercial.txt create mode 100644 LICENSES/Qt-GPL-exception-1.0.txt delete mode 100644 config.tests/sdl/main.cpp delete mode 100644 config.tests/sdl/sdl.pro create mode 100644 configure.cmake delete mode 100644 configure.json delete mode 100644 dependencies.yaml delete mode 100644 dist/changes-5.10.0 delete mode 100644 dist/changes-5.10.1 delete mode 100644 dist/changes-5.11.0 delete mode 100644 dist/changes-5.11.1 delete mode 100644 dist/changes-5.11.2 delete mode 100644 dist/changes-5.11.3 delete mode 100644 dist/changes-5.12.0 delete mode 100644 dist/changes-5.12.1 delete mode 100644 dist/changes-5.12.2 delete mode 100644 dist/changes-5.12.3 delete mode 100644 dist/changes-5.12.4 delete mode 100644 dist/changes-5.12.5 delete mode 100644 dist/changes-5.13.0 delete mode 100644 dist/changes-5.13.1 delete mode 100644 dist/changes-5.13.2 delete mode 100644 dist/changes-5.14.0 delete mode 100644 dist/changes-5.14.1 delete mode 100644 dist/changes-5.14.2 delete mode 100644 dist/changes-5.15.0 delete mode 100644 dist/changes-5.15.1 delete mode 100644 dist/changes-5.9.0 delete mode 100644 dist/changes-5.9.1 delete mode 100644 dist/changes-5.9.2 delete mode 100644 dist/changes-5.9.3 delete mode 100644 dist/changes-5.9.4 delete mode 100644 dist/changes-5.9.5 delete mode 100644 dist/changes-5.9.6 create mode 100644 examples/CMakeLists.txt delete mode 100644 examples/examples.pro delete mode 100644 examples/gamepad/configureButtons/configureButtons.pro delete mode 100644 examples/gamepad/configureButtons/doc/images/configuregamepadbuttons-example.png delete mode 100644 examples/gamepad/configureButtons/doc/src/configbuttonsexample.qdoc delete mode 100644 examples/gamepad/configureButtons/main.cpp delete mode 100644 examples/gamepad/configureButtons/main.qml delete mode 100644 examples/gamepad/configureButtons/qml.qrc delete mode 100644 examples/gamepad/gamepad.pro delete mode 100644 examples/gamepad/keyNavigation/doc/images/keynavigationgamepad-example.png delete mode 100644 examples/gamepad/keyNavigation/doc/src/keynaviexample.qdoc delete mode 100644 examples/gamepad/keyNavigation/keyNavigation.pro delete mode 100644 examples/gamepad/keyNavigation/keyNavigation64.png delete mode 100644 examples/gamepad/keyNavigation/keyNavigation80.png delete mode 100644 examples/gamepad/keyNavigation/main.cpp delete mode 100644 examples/gamepad/keyNavigation/qml.qrc delete mode 100644 examples/gamepad/keyNavigation/qml/main.qml delete mode 100644 examples/gamepad/mouseItem/doc/src/mouseitemexample.qdoc delete mode 100644 examples/gamepad/mouseItem/main.cpp delete mode 100644 examples/gamepad/mouseItem/mouseItem.pro delete mode 100644 examples/gamepad/mouseItem/mouseItem64.png delete mode 100644 examples/gamepad/mouseItem/mouseItem80.png delete mode 100644 examples/gamepad/mouseItem/qml.qrc delete mode 100644 examples/gamepad/mouseItem/qml/main.qml delete mode 100644 examples/gamepad/quickGamepad/doc/images/qtquickgamepad-example.png delete mode 100644 examples/gamepad/quickGamepad/doc/src/quickgamepadexample.qdoc delete mode 100644 examples/gamepad/quickGamepad/main.cpp delete mode 100644 examples/gamepad/quickGamepad/qml.qrc delete mode 100644 examples/gamepad/quickGamepad/qml/ButtonImage.qml delete mode 100644 examples/gamepad/quickGamepad/qml/DPad.qml delete mode 100644 examples/gamepad/quickGamepad/qml/JoystickViewer.qml delete mode 100644 examples/gamepad/quickGamepad/qml/LeftThumbstick.qml delete mode 100644 examples/gamepad/quickGamepad/qml/RightThumbstick.qml delete mode 100644 examples/gamepad/quickGamepad/qml/main.qml delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerBack.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerButtonA.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerButtonB.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerButtonGuide.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerButtonX.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerButtonY.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerDPad.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerLeftShoulder.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerLeftThumbstick.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerLeftTrigger.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerRightShoulder.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerRightThumbstick.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerRightTrigger.png delete mode 100644 examples/gamepad/quickGamepad/qml/xboxControllerStart.png delete mode 100644 examples/gamepad/quickGamepad/quickGamepad.pro delete mode 100644 examples/gamepad/quickGamepad/quickGamepad64.png delete mode 100644 examples/gamepad/quickGamepad/quickGamepad80.png delete mode 100644 examples/gamepad/simple/android/AndroidManifest.xml delete mode 100644 examples/gamepad/simple/doc/src/simpleexample.qdoc delete mode 100644 examples/gamepad/simple/gamepadmonitor.cpp delete mode 100644 examples/gamepad/simple/gamepadmonitor.h delete mode 100644 examples/gamepad/simple/main.cpp delete mode 100644 examples/gamepad/simple/simple.pro create mode 100644 examples/universalinput/CMakeLists.txt create mode 100644 examples/universalinput/actionpong/ActionMap.qml create mode 100644 examples/universalinput/actionpong/Ball.qml create mode 100644 examples/universalinput/actionpong/CMakeLists.txt create mode 100644 examples/universalinput/actionpong/Paddle.qml create mode 100644 examples/universalinput/actionpong/PaddleController.qml create mode 100644 examples/universalinput/actionpong/main.cpp create mode 100644 examples/universalinput/actionpong/main.qml create mode 100644 examples/universalinput/consolejoystickmonitor/CMakeLists.txt create mode 100644 examples/universalinput/consolejoystickmonitor/main.cpp create mode 100644 examples/universalinput/mousegrab/CMakeLists.txt create mode 100644 examples/universalinput/mousegrab/main.cpp create mode 100644 examples/universalinput/mousegrab/main.qml create mode 100644 examples/universalinput/quickaction/CMakeLists.txt create mode 100644 examples/universalinput/quickaction/Controller.qml create mode 100644 examples/universalinput/quickaction/GameObject.qml create mode 100644 examples/universalinput/quickaction/GameObjectList.qml create mode 100644 examples/universalinput/quickaction/Platform.qml create mode 100644 examples/universalinput/quickaction/Player.qml create mode 100644 examples/universalinput/quickaction/main.cpp create mode 100644 examples/universalinput/quickaction/main.qml create mode 100644 examples/universalinput/simple/CMakeLists.txt rename examples/{gamepad/configureButtons => universalinput/simple}/android/AndroidManifest.xml (87%) create mode 100644 examples/universalinput/simple/gamepadmonitor.cpp create mode 100644 examples/universalinput/simple/gamepadmonitor.h create mode 100644 examples/universalinput/simple/main.cpp create mode 100644 examples/universalinput/virtualgamepad/ButtonIsland.qml create mode 100644 examples/universalinput/virtualgamepad/CMakeLists.txt create mode 100644 examples/universalinput/virtualgamepad/JoyButton.qml create mode 100644 examples/universalinput/virtualgamepad/Joystick.qml create mode 100644 examples/universalinput/virtualgamepad/VirtualGamepad.qml create mode 100644 examples/universalinput/virtualgamepad/main.cpp create mode 100644 examples/universalinput/virtualgamepad/main.qml delete mode 100644 qtgamepad.pro create mode 100644 src/3rdparty/sdlgamecontrollerdb/LICENSE create mode 100644 src/3rdparty/sdlgamecontrollerdb/README.md create mode 100644 src/3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt create mode 100755 src/3rdparty/sdlgamecontrollerdb/import_from_sdlgamecontrollerdb_tarball.sh create mode 100644 src/3rdparty/sdlgamecontrollerdb/qt_attribution.json create mode 100644 src/CMakeLists.txt create mode 100644 src/gamepad/CMakeLists.txt delete mode 100644 src/gamepad/configure.json delete mode 100644 src/gamepad/doc/qtgamepad.qdocconf delete mode 100644 src/gamepad/doc/src/qtgamepad-cpp.qdoc delete mode 100644 src/gamepad/doc/src/qtgamepad-examples.qdoc delete mode 100644 src/gamepad/doc/src/qtgamepad-index.qdoc delete mode 100644 src/gamepad/doc/src/qtgamepad-qmltypes.qdoc delete mode 100644 src/gamepad/gamepad.pro delete mode 100644 src/gamepad/qgamepadbackend.cpp delete mode 100644 src/gamepad/qgamepadbackend_p.h delete mode 100644 src/gamepad/qgamepadbackendfactory.cpp delete mode 100644 src/gamepad/qgamepadbackendfactory_p.h delete mode 100644 src/gamepad/qgamepadbackendplugin.cpp delete mode 100644 src/gamepad/qgamepadbackendplugin_p.h delete mode 100644 src/gamepad/qgamepadkeynavigation.cpp delete mode 100644 src/gamepad/qgamepadkeynavigation.h delete mode 100644 src/gamepad/qgamepadmanager.cpp delete mode 100644 src/gamepad/qgamepadmanager.h delete mode 100644 src/gamepad/qtgamepadglobal.h delete mode 100644 src/imports/gamepad/gamepad.pro delete mode 100644 src/imports/gamepad/plugins.qmltypes delete mode 100644 src/imports/gamepad/qgamepadmouseitem.cpp delete mode 100644 src/imports/gamepad/qgamepadmouseitem.h delete mode 100644 src/imports/gamepad/qmldir delete mode 100644 src/imports/gamepad/qtgamepad.cpp delete mode 100644 src/imports/imports.pro create mode 100644 src/plugins/CMakeLists.txt delete mode 100644 src/plugins/gamepads/android/android.pro delete mode 100644 src/plugins/gamepads/android/jar/jar.pro delete mode 100644 src/plugins/gamepads/android/jar/src/org/qtproject/qt/android/gamepad/QtGamepad.java delete mode 100644 src/plugins/gamepads/android/src/main.cpp delete mode 100644 src/plugins/gamepads/android/src/qandroidgamepadbackend.cpp delete mode 100644 src/plugins/gamepads/android/src/qandroidgamepadbackend_p.h delete mode 100644 src/plugins/gamepads/android/src/src.pro delete mode 100644 src/plugins/gamepads/darwin/darwin.json delete mode 100644 src/plugins/gamepads/darwin/darwin.pro delete mode 100644 src/plugins/gamepads/darwin/main.cpp delete mode 100644 src/plugins/gamepads/darwin/qdarwingamepadbackend.mm delete mode 100644 src/plugins/gamepads/darwin/qdarwingamepadbackend_p.h delete mode 100644 src/plugins/gamepads/evdev/evdev.json delete mode 100644 src/plugins/gamepads/evdev/evdev.pro delete mode 100644 src/plugins/gamepads/evdev/main.cpp delete mode 100644 src/plugins/gamepads/evdev/qevdevgamepadbackend.cpp delete mode 100644 src/plugins/gamepads/evdev/qevdevgamepadbackend_p.h delete mode 100644 src/plugins/gamepads/gamepads.pro delete mode 100644 src/plugins/gamepads/sdl2/main.cpp delete mode 100644 src/plugins/gamepads/sdl2/qsdlgamepadbackend.cpp delete mode 100644 src/plugins/gamepads/sdl2/qsdlgamepadbackend_p.h delete mode 100644 src/plugins/gamepads/sdl2/sdl2.json delete mode 100644 src/plugins/gamepads/sdl2/sdl2.pro delete mode 100644 src/plugins/gamepads/xinput/main.cpp delete mode 100644 src/plugins/gamepads/xinput/qxinputgamepadbackend.cpp delete mode 100644 src/plugins/gamepads/xinput/qxinputgamepadbackend_p.h delete mode 100644 src/plugins/gamepads/xinput/xinput.json delete mode 100644 src/plugins/gamepads/xinput/xinput.pro create mode 100644 src/plugins/joystickinputs/CMakeLists.txt create mode 100644 src/plugins/joystickinputs/android/CMakeLists.txt rename src/plugins/{gamepads/android/src => joystickinputs/android}/android.json (100%) create mode 100644 src/plugins/joystickinputs/android/androidjoystickinput.cpp create mode 100644 src/plugins/joystickinputs/android/androidjoystickinput.h create mode 100644 src/plugins/joystickinputs/android/androidjoystickinputplugin.cpp create mode 100644 src/plugins/joystickinputs/android/androidjoystickinputplugin.h create mode 100644 src/plugins/joystickinputs/android/jar/AndroidManifest.xml create mode 100644 src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java create mode 100644 src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java create mode 100644 src/plugins/joystickinputs/ios/CMakeLists.txt create mode 100644 src/plugins/joystickinputs/ios/ios.json create mode 100644 src/plugins/joystickinputs/ios/iosjoystickinput.h create mode 100644 src/plugins/joystickinputs/ios/iosjoystickinput.mm create mode 100644 src/plugins/joystickinputs/ios/iosjoystickinputplugin.cpp create mode 100644 src/plugins/joystickinputs/ios/iosjoystickinputplugin.h create mode 100644 src/plugins/joystickinputs/linux/CMakeLists.txt create mode 100644 src/plugins/joystickinputs/linux/linux.json create mode 100644 src/plugins/joystickinputs/linux/linuxjoystickinput.cpp create mode 100644 src/plugins/joystickinputs/linux/linuxjoystickinput.h create mode 100644 src/plugins/joystickinputs/linux/linuxjoystickinputplugin.cpp create mode 100644 src/plugins/joystickinputs/linux/linuxjoystickinputplugin.h create mode 100644 src/plugins/joystickinputs/macos/CMakeLists.txt create mode 100644 src/plugins/joystickinputs/macos/macos.json create mode 100644 src/plugins/joystickinputs/macos/macosjoystickinput.h create mode 100644 src/plugins/joystickinputs/macos/macosjoystickinput.mm create mode 100644 src/plugins/joystickinputs/macos/macosjoystickinputplugin.cpp create mode 100644 src/plugins/joystickinputs/macos/macosjoystickinputplugin.h create mode 100644 src/plugins/joystickinputs/windows/CMakeLists.txt create mode 100644 src/plugins/joystickinputs/windows/windows.json create mode 100644 src/plugins/joystickinputs/windows/windowsjoystickinput.cpp create mode 100644 src/plugins/joystickinputs/windows/windowsjoystickinput.h create mode 100644 src/plugins/joystickinputs/windows/windowsjoystickinputplugin.cpp create mode 100644 src/plugins/joystickinputs/windows/windowsjoystickinputplugin.h create mode 100644 src/plugins/mouseinputs/CMakeLists.txt create mode 100644 src/plugins/mouseinputs/linux/CMakeLists.txt create mode 100644 src/plugins/mouseinputs/linux/linux.json create mode 100644 src/plugins/mouseinputs/linux/linuxmouseinput.cpp create mode 100644 src/plugins/mouseinputs/linux/linuxmouseinput.h create mode 100644 src/plugins/mouseinputs/linux/linuxmouseinputplugin.cpp create mode 100644 src/plugins/mouseinputs/linux/linuxmouseinputplugin.h create mode 100644 src/plugins/mouseinputs/macos/CMakeLists.txt create mode 100644 src/plugins/mouseinputs/macos/macos.json create mode 100644 src/plugins/mouseinputs/macos/macosmouseinput.h create mode 100644 src/plugins/mouseinputs/macos/macosmouseinput.mm create mode 100644 src/plugins/mouseinputs/macos/macosmouseinputplugin.cpp create mode 100644 src/plugins/mouseinputs/macos/macosmouseinputplugin.h create mode 100644 src/plugins/mouseinputs/windows/CMakeLists.txt create mode 100644 src/plugins/mouseinputs/windows/windows.json create mode 100644 src/plugins/mouseinputs/windows/windowsmouseinput.cpp create mode 100644 src/plugins/mouseinputs/windows/windowsmouseinput.h create mode 100644 src/plugins/mouseinputs/windows/windowsmouseinputplugin.cpp create mode 100644 src/plugins/mouseinputs/windows/windowsmouseinputplugin.h delete mode 100644 src/plugins/plugins.pro create mode 100644 src/quickactionstore/CMakeLists.txt create mode 100644 src/quickactionstore/qquickactionhandler.cpp create mode 100644 src/quickactionstore/qquickactionhandler_p.h create mode 100644 src/quickactionstore/qquickactionstore.cpp create mode 100644 src/quickactionstore/qquickactionstore_p.h create mode 100644 src/quickactionstore/qquickeventlistener.cpp create mode 100644 src/quickactionstore/qquickeventlistener_p.h create mode 100644 src/quickgamepad/CMakeLists.txt create mode 100644 src/quickgamepad/qquickgamepad.cpp create mode 100644 src/quickgamepad/qquickgamepad_p.h create mode 100644 src/quickuniversalinput/CMakeLists.txt create mode 100644 src/quickuniversalinput/qquickuniversalinput.cpp create mode 100644 src/quickuniversalinput/qquickuniversalinput_p.h delete mode 100644 src/src.pro create mode 100644 src/universalinput/CMakeLists.txt create mode 100644 src/universalinput/GODOT_LICENSE.txt create mode 100644 src/universalinput/doc/images/gamecontrollers.jpg create mode 100644 src/universalinput/qactionstore.cpp create mode 100644 src/universalinput/qactionstore.h create mode 100644 src/universalinput/qjoydevicemappingparser.cpp create mode 100644 src/universalinput/qjoydevicemappingparser_p.h create mode 100644 src/universalinput/qjoystickinput_p.h create mode 100644 src/universalinput/qjoystickinputfactory.cpp create mode 100644 src/universalinput/qjoystickinputfactory_p.h create mode 100644 src/universalinput/qjoystickinputplugin_p.h create mode 100644 src/universalinput/qmouseinput_p.h create mode 100644 src/universalinput/qmouseinputfactory.cpp create mode 100644 src/universalinput/qmouseinputfactory_p.h create mode 100644 src/universalinput/qmouseinputplugin_p.h create mode 100644 src/universalinput/qt_attribution.json create mode 100644 src/universalinput/qtuniversalinputglobal.h create mode 100644 src/universalinput/qtuniversalinputglobal_p.h create mode 100644 src/universalinput/quniversalinput.cpp create mode 100644 src/universalinput/quniversalinput.h create mode 100644 src/universalinput/quniversalinput_p.h delete mode 100644 sync.profile create mode 100644 tests/CMakeLists.txt create mode 100644 tests/auto/CMakeLists.txt delete mode 100644 tests/auto/auto.pro delete mode 100644 tests/auto/cmake/CMakeLists.txt delete mode 100644 tests/auto/cmake/cmake.pro delete mode 100644 tests/tests.pro diff --git a/.cmake.conf b/.cmake.conf new file mode 100644 index 0000000..d240926 --- /dev/null +++ b/.cmake.conf @@ -0,0 +1,5 @@ +set(QT_REPO_MODULE_VERSION "6.8.0") +set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") +list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") +list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1") +list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_CONTEXTLESS_CONNECT=1") diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/.qmake.conf b/.qmake.conf deleted file mode 100644 index 7f73e1f..0000000 --- a/.qmake.conf +++ /dev/null @@ -1,6 +0,0 @@ -load(qt_build_config) - -CONFIG += warning_clean -DEFINES += QT_NO_FOREACH - -MODULE_VERSION = 6.4.0 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cbd749a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +include(.cmake.conf) +project(QtUniversalInput + VERSION "${QT_REPO_MODULE_VERSION}" + DESCRIPTION "Qt Universal Input Libraries" + HOMEPAGE_URL "https://qt.io/" + LANGUAGES CXX C +) + +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core) +find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Concurrent Network Quick Widgets PacketProtocolPrivate) + +if(VXWORKS OR WATCHOS) + message(NOTICE "Skipping the build as the condition \"NOT VXWORKS AND NOT WATCHOS\" is not met.") + return() +endif() + +qt_build_repo() diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3 deleted file mode 100644 index 8fbb743..0000000 --- a/LICENSE.LGPLv3 +++ /dev/null @@ -1,173 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - - The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. - Contact: http://www.qt.io/licensing/ - - You may use, distribute and copy the Qt GUI Toolkit under the terms of - GNU Lesser General Public License version 3, which is displayed below. - -------------------------------------------------------------------------- - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright © 2007 Free Software Foundation, Inc. -Everyone is permitted to copy and distribute verbatim copies of this -licensedocument, but changing it is not allowed. - -This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - -0. Additional Definitions. - - As used herein, “this License” refers to version 3 of the GNU Lesser -General Public License, and the “GNU GPL” refers to version 3 of the -GNU General Public License. - - “The Library” refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An “Application” is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A “Combined Work” is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the “Linked -Version”. - - The “Minimal Corresponding Source” for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The “Corresponding Application Code” for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - -1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - -2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort - to ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - -3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this - license document. - -4. Combined Works. - - You may convey a Combined Work under terms of your choice that, taken -together, effectively do not restrict modification of the portions of -the Library contained in the Combined Work and reverse engineering for -debugging such modifications, if you also do each of the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this - license document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of - this License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with - the Library. A suitable mechanism is one that (a) uses at run - time a copy of the Library already present on the user's - computer system, and (b) will operate properly with a modified - version of the Library that is interface-compatible with the - Linked Version. - - e) Provide Installation Information, but only if you would - otherwise be required to provide such information under section 6 - of the GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the Application - with a modified version of the Linked Version. (If you use option - 4d0, the Installation Information must accompany the Minimal - Corresponding Source and Corresponding Application Code. If you - use option 4d1, you must provide the Installation Information in - the manner specified by section 6 of the GNU GPL for conveying - Corresponding Source.) - -5. Combined Libraries. - - You may place library facilities that are a work based on the Library -side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities, conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of - it is a work based on the Library, and explaining where to find - the accompanying uncombined form of the same work. - -6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -as you received it specifies that a certain numbered version of the -GNU Lesser General Public License “or any later version” applies to -it, you have the option of following the terms and conditions either -of that published version or of any later version published by the -Free Software Foundation. If the Library as you received it does not -specify a version number of the GNU Lesser General Public License, -you may choose any version of the GNU Lesser General Public License -ever published by the Free Software Foundation. - -If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the Library. - diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000..b91bbd8 --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) . + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/GFDL-1.3-no-invariants-only.txt b/LICENSES/GFDL-1.3-no-invariants-only.txt new file mode 100644 index 0000000..857214d --- /dev/null +++ b/LICENSES/GFDL-1.3-no-invariants-only.txt @@ -0,0 +1,451 @@ + + GNU Free Documentation License + Version 1.3, 3 November 2008 + + + Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The "publisher" means any person or entity that distributes copies of +the Document to the public. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no +other conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to +give them a chance to provide you with an updated version of the +Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other +documents released under this License, and replace the individual +copies of this License in the various documents with a single copy +that is included in the collection, provided that you follow the rules +of this License for verbatim copying of each of the documents in all +other respects. + +You may extract a single document from such a collection, and +distribute it individually under this License, provided you insert a +copy of this License into the extracted document, and follow this +License in all other respects regarding verbatim copying of that +document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions of the +GNU Free Documentation License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. See +https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +11. RELICENSING + +"Massive Multiauthor Collaboration Site" (or "MMC Site") means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +"Massive Multiauthor Collaboration" (or "MMC") contained in the site +means any set of copyrightable works thus published on the MMC site. + +"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +"Incorporate" means to publish or republish a Document, in whole or in +part, as part of another Document. + +An MMC is "eligible for relicensing" if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole or +in part into the MMC, (1) had no cover texts or invariant sections, and +(2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/LICENSES/GPL-2.0-only.txt b/LICENSES/GPL-2.0-only.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSES/GPL-2.0-only.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSE.GPL b/LICENSES/GPL-3.0-only.txt similarity index 100% rename from LICENSE.GPL rename to LICENSES/GPL-3.0-only.txt diff --git a/LICENSES/LGPL-3.0-only.txt b/LICENSES/LGPL-3.0-only.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSES/LGPL-3.0-only.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/LICENSES/LicenseRef-Qt-Commercial.txt b/LICENSES/LicenseRef-Qt-Commercial.txt new file mode 100644 index 0000000..825b1f3 --- /dev/null +++ b/LICENSES/LicenseRef-Qt-Commercial.txt @@ -0,0 +1,8 @@ +Licensees holding valid commercial Qt licenses may use this software in +accordance with the the terms contained in a written agreement between +you and The Qt Company. Alternatively, the terms and conditions that were +accepted by the licensee when buying and/or downloading the +software do apply. + +For the latest licensing terms and conditions, see https://www.qt.io/terms-conditions. +For further information use the contact form at https://www.qt.io/contact-us. diff --git a/LICENSES/Qt-GPL-exception-1.0.txt b/LICENSES/Qt-GPL-exception-1.0.txt new file mode 100644 index 0000000..d0322bf --- /dev/null +++ b/LICENSES/Qt-GPL-exception-1.0.txt @@ -0,0 +1,22 @@ +The Qt Company GPL Exception 1.0 + +Exception 1: + +As a special exception you may create a larger work which contains the +output of this application and distribute that work under terms of your +choice, so long as the work is not otherwise derived from or based on +this application and so long as the work does not in itself generate +output that contains the output from this application in its original +or modified form. + +Exception 2: + +As a special exception, you have permission to combine this application +with Plugins licensed under the terms of your choice, to produce an +executable, and to copy and distribute the resulting executable under +the terms of your choice. However, the executable must be accompanied +by a prominent notice offering all users of the executable the entire +source code to this application, excluding the source code of the +independent modules, but including any changes you have made to this +application, under the terms of this license. + diff --git a/README.md b/README.md index fcb02d8..a3b0427 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,5 @@ -Qt Gamepad +# Qt Universal Input +An experimental module to demonstrate novel solutions for handling exotic input devices. -A Qt 5 module that adds support for getting events from gamepad devices on multiple platforms. +![Stylistic Gamepads](src/universalinput/doc/images/gamecontrollers.jpg) -Supported Platforms: -Native Backends - - Linux (evdev) - - Window (xinput) - - Android - - OS X/iOS/tvOS - -For other platforms there is a backend that uses SDL2 for gamepad support. - -This module provides classes that can: - - Read input events from game controllers (Button and Axis events), both from C++ and Qt Quick (QML) - - Provide a queryable input state (by processing events) - - Provide key bindings diff --git a/config.tests/sdl/main.cpp b/config.tests/sdl/main.cpp deleted file mode 100644 index 193d16a..0000000 --- a/config.tests/sdl/main.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -int main(int argc, char** argv) -{ - SDL_Init(SDL_INIT_GAMECONTROLLER); - SDL_Quit(); - return 0; -} diff --git a/config.tests/sdl/sdl.pro b/config.tests/sdl/sdl.pro deleted file mode 100644 index 7b447d1..0000000 --- a/config.tests/sdl/sdl.pro +++ /dev/null @@ -1,3 +0,0 @@ -SOURCES += main.cpp -QT = -CONFIG -= qt diff --git a/configure.cmake b/configure.cmake new file mode 100644 index 0000000..0c17be3 --- /dev/null +++ b/configure.cmake @@ -0,0 +1,24 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + + + +#### Inputs + + + +#### Libraries + + + +#### Tests + + + +#### Features + + +qt_extra_definition("QT_VERSION_STR" "\"${PROJECT_VERSION}\"" PUBLIC) +qt_extra_definition("QT_VERSION_MAJOR" ${PROJECT_VERSION_MAJOR} PUBLIC) +qt_extra_definition("QT_VERSION_MINOR" ${PROJECT_VERSION_MINOR} PUBLIC) +qt_extra_definition("QT_VERSION_PATCH" ${PROJECT_VERSION_PATCH} PUBLIC) diff --git a/configure.json b/configure.json deleted file mode 100644 index c5953c1..0000000 --- a/configure.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "subconfigs": [ - "src/gamepad" - ] -} diff --git a/dependencies.yaml b/dependencies.yaml deleted file mode 100644 index 53d5f77..0000000 --- a/dependencies.yaml +++ /dev/null @@ -1,7 +0,0 @@ -dependencies: - ../qtbase: - ref: befa3729db0d1010694bd1bb4cbadd36ff5c49fb - required: true - ../qtdeclarative: - ref: 7e3f5f2224ba0e57a9dffa6251bb002cde564f56 - required: false diff --git a/dist/changes-5.10.0 b/dist/changes-5.10.0 deleted file mode 100644 index a41f02a..0000000 --- a/dist/changes-5.10.0 +++ /dev/null @@ -1,22 +0,0 @@ -Qt 5.10 introduces many new features and improvements as well as bugfixes -over the 5.9.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.10 series is binary compatible with the 5.10.x series. -Applications compiled for 5.9 will continue to run with 5.10. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.10.0 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.10.1 b/dist/changes-5.10.1 deleted file mode 100644 index 695c4e3..0000000 --- a/dist/changes-5.10.1 +++ /dev/null @@ -1,26 +0,0 @@ -Qt 5.10.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.10.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.10 series is binary compatible with the 5.9.x series. -Applications compiled for 5.9 will continue to run with 5.10. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -This release contains all fixes included in the Qt 5.9.4 release. - -**************************************************************************** -* Qt 5.10.1 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.11.0 b/dist/changes-5.11.0 deleted file mode 100644 index 162ab57..0000000 --- a/dist/changes-5.11.0 +++ /dev/null @@ -1,22 +0,0 @@ -Qt 5.11 introduces many new features and improvements as well as bugfixes -over the 5.10.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.11 series is binary compatible with the 5.10.x series. -Applications compiled for 5.10 will continue to run with 5.11. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.11.0 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.11.1 b/dist/changes-5.11.1 deleted file mode 100644 index 030ea3f..0000000 --- a/dist/changes-5.11.1 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.11.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.11.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.11 series is binary compatible with the 5.10.x series. -Applications compiled for 5.10 will continue to run with 5.11. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.11.1 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.11.2 b/dist/changes-5.11.2 deleted file mode 100644 index 8efdf5e..0000000 --- a/dist/changes-5.11.2 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.11.2 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.11.0 through 5.11.1. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.11 series is binary compatible with the 5.10.x series. -Applications compiled for 5.10 will continue to run with 5.11. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.11.2 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.11.3 b/dist/changes-5.11.3 deleted file mode 100644 index f71fa34..0000000 --- a/dist/changes-5.11.3 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.11.3 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.11.0 through 5.11.2. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.11 series is binary compatible with the 5.10.x series. -Applications compiled for 5.10 will continue to run with 5.11. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.0 b/dist/changes-5.12.0 deleted file mode 100644 index 4f6c63e..0000000 --- a/dist/changes-5.12.0 +++ /dev/null @@ -1,18 +0,0 @@ -Qt 5.12 introduces many new features and improvements as well as bugfixes -over the 5.11.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.1 b/dist/changes-5.12.1 deleted file mode 100644 index 1cb4dd7..0000000 --- a/dist/changes-5.12.1 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.12.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.12.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.2 b/dist/changes-5.12.2 deleted file mode 100644 index 0c8bd85..0000000 --- a/dist/changes-5.12.2 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.12.2 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.12.0 through 5.12.1. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.3 b/dist/changes-5.12.3 deleted file mode 100644 index 8803320..0000000 --- a/dist/changes-5.12.3 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.12.3 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.12.0 through 5.12.2. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4 deleted file mode 100644 index a285cd8..0000000 --- a/dist/changes-5.12.4 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.12.4 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.12.0 through 5.12.3. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.12.5 b/dist/changes-5.12.5 deleted file mode 100644 index e8be931..0000000 --- a/dist/changes-5.12.5 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.12.5 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.12.0 through 5.12.4. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.12 series is binary compatible with the 5.11.x series. -Applications compiled for 5.11 will continue to run with 5.12. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 deleted file mode 100644 index ebb4be1..0000000 --- a/dist/changes-5.13.0 +++ /dev/null @@ -1,18 +0,0 @@ -Qt 5.13 introduces many new features and improvements as well as bugfixes -over the 5.12.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.13 series is binary compatible with the 5.12.x series. -Applications compiled for 5.12 will continue to run with 5.13. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.13.1 b/dist/changes-5.13.1 deleted file mode 100644 index 57ebdbe..0000000 --- a/dist/changes-5.13.1 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.13.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.13.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.13 series is binary compatible with the 5.12.x series. -Applications compiled for 5.12 will continue to run with 5.13. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 deleted file mode 100644 index e3bb833..0000000 --- a/dist/changes-5.13.2 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.13.2 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.13.0 through 5.13.1. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.13 series is binary compatible with the 5.12.x series. -Applications compiled for 5.12 will continue to run with 5.13. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 deleted file mode 100644 index 29a2c83..0000000 --- a/dist/changes-5.14.0 +++ /dev/null @@ -1,18 +0,0 @@ -Qt 5.14 introduces many new features and improvements as well as bugfixes -over the 5.13.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.14 series is binary compatible with the 5.13.x series. -Applications compiled for 5.13 will continue to run with 5.14. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.14.1 b/dist/changes-5.14.1 deleted file mode 100644 index d008638..0000000 --- a/dist/changes-5.14.1 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.14.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.14.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.14 series is binary compatible with the 5.13.x series. -Applications compiled for 5.13 will continue to run with 5.14. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.14.2 b/dist/changes-5.14.2 deleted file mode 100644 index 68a0051..0000000 --- a/dist/changes-5.14.2 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.14.2 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.14.0 through 5.14.1. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.14 series is binary compatible with the 5.13.x series. -Applications compiled for 5.13 will continue to run with 5.14. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0 deleted file mode 100644 index 40076ce..0000000 --- a/dist/changes-5.15.0 +++ /dev/null @@ -1,18 +0,0 @@ -Qt 5.15 introduces many new features and improvements as well as bugfixes -over the 5.14.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.15 series is binary compatible with the 5.14.x series. -Applications compiled for 5.14 will continue to run with 5.15. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.15.1 b/dist/changes-5.15.1 deleted file mode 100644 index 332ee9d..0000000 --- a/dist/changes-5.15.1 +++ /dev/null @@ -1,20 +0,0 @@ -Qt 5.15.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.15.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -https://doc.qt.io/qt-5/index.html - -The Qt version 5.15 series is binary compatible with the 5.14.x series. -Applications compiled for 5.14 will continue to run with 5.15. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - - - This release contains only minor code improvements. diff --git a/dist/changes-5.9.0 b/dist/changes-5.9.0 deleted file mode 100644 index e33a407..0000000 --- a/dist/changes-5.9.0 +++ /dev/null @@ -1,16 +0,0 @@ -Qt 5.9 introduces many new features and improvements as well as bugfixes -over the 5.8.x series. For more details, refer to the online documentation -included in this distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. diff --git a/dist/changes-5.9.1 b/dist/changes-5.9.1 deleted file mode 100644 index e0a6a4b..0000000 --- a/dist/changes-5.9.1 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.9.1 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Library * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.9.2 b/dist/changes-5.9.2 deleted file mode 100644 index a4cffb5..0000000 --- a/dist/changes-5.9.2 +++ /dev/null @@ -1,22 +0,0 @@ -Qt 5.9.2 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.9.2 Changes * -**************************************************************************** diff --git a/dist/changes-5.9.3 b/dist/changes-5.9.3 deleted file mode 100644 index bb5db63..0000000 --- a/dist/changes-5.9.3 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.9.3 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.9.3 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4 deleted file mode 100644 index 1014937..0000000 --- a/dist/changes-5.9.4 +++ /dev/null @@ -1,25 +0,0 @@ -Qt 5.9.4 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.9.4 Changes * -**************************************************************************** - - - This release does not contain any changes to this module. - diff --git a/dist/changes-5.9.5 b/dist/changes-5.9.5 deleted file mode 100644 index 8df339e..0000000 --- a/dist/changes-5.9.5 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.9.5 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.9 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.9.5 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/dist/changes-5.9.6 b/dist/changes-5.9.6 deleted file mode 100644 index f0179a5..0000000 --- a/dist/changes-5.9.6 +++ /dev/null @@ -1,24 +0,0 @@ -Qt 5.9.6 is a bug-fix release. It maintains both forward and backward -compatibility (source and binary) with Qt 5.9.0 through 5.9.5. - -For more details, refer to the online documentation included in this -distribution. The documentation is also available online: - -http://doc.qt.io/qt-5/index.html - -The Qt version 5.9 series is binary compatible with the 5.8.x series. -Applications compiled for 5.8 will continue to run with 5.9. - -Some of the changes listed in this file include issue tracking numbers -corresponding to tasks in the Qt Bug Tracker: - -https://bugreports.qt.io/ - -Each of these identifiers can be entered in the bug tracker to obtain more -information about a particular change. - -**************************************************************************** -* Qt 5.9.6 Changes * -**************************************************************************** - - - This release contains only minor code improvements. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..a00b4ba --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_examples_build_begin(EXTERNAL_BUILD) + +add_subdirectory(universalinput) + +qt_examples_build_end() + diff --git a/examples/examples.pro b/examples/examples.pro deleted file mode 100644 index 5daa1a6..0000000 --- a/examples/examples.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += gamepad - diff --git a/examples/gamepad/configureButtons/configureButtons.pro b/examples/gamepad/configureButtons/configureButtons.pro deleted file mode 100644 index 89d6da0..0000000 --- a/examples/gamepad/configureButtons/configureButtons.pro +++ /dev/null @@ -1,19 +0,0 @@ -TEMPLATE = app - -QT += qml quick gamepad - -SOURCES += main.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/configureButtons -INSTALLS += target - -DISTFILES += \ - android/AndroidManifest.xml - -ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android - diff --git a/examples/gamepad/configureButtons/doc/images/configuregamepadbuttons-example.png b/examples/gamepad/configureButtons/doc/images/configuregamepadbuttons-example.png deleted file mode 100644 index 408f7a6139ebd1aa4ab1b97663870c6dbbaab98c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20239 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 -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); - - return app.exec(); -} - diff --git a/examples/gamepad/configureButtons/main.qml b/examples/gamepad/configureButtons/main.qml deleted file mode 100644 index 6522631..0000000 --- a/examples/gamepad/configureButtons/main.qml +++ /dev/null @@ -1,645 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.5 -import QtQuick.Controls 2.1 -import QtQuick.Layouts 1.2 -import QtQuick.Window 2.0 -import QtGamepad 1.0 - - -ApplicationWindow { - visible: true - title: qsTr("Configure gamepad") - width: 400 - height: 600 - - Component.onCompleted: { - if (Qt.platform.os === "android") - visibility = Window.Maximized - } - - property Button checkedButton: null - function pressButton(button) - { - if (checkedButton !== null && button !== checkedButton) - checkedButton.checked = false; - checkedButton = button - } - - Gamepad { - id: gamepad - deviceId: GamepadManager.connectedGamepads.length > 0 ? GamepadManager.connectedGamepads[0] : -1 - onDeviceIdChanged: GamepadManager.setCancelConfigureButton(deviceId, GamepadManager.ButtonStart); - } - - Connections { - target: GamepadManager - onButtonConfigured: pressButton(null) - onAxisConfigured: pressButton(null) - onConfigurationCanceled: pressButton(null) - } - - Rectangle { - id: headerRectangle - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left - height: headerLayout.implicitHeight + 16 - color: "white" - z: 1 - - ColumnLayout { - id: headerLayout - anchors.top: parent.top - anchors.right: parent.right - anchors.left: parent.left - anchors.margins: 8 - - Label { - text: qsTr("Gamepad configuration Utility") - font.pointSize: 16 - } - - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Connected gamepads") - } - ComboBox { - Layout.fillWidth: true - model: GamepadManager.connectedGamepads - onCurrentIndexChanged: gamepad.deviceId[GamepadManager.connectedGamepads[currentIndex]] - } - } - - Label { - text: qsTr("Start button cancel's current configuration") - Layout.fillWidth: true - } - } - } - - Flickable { - id: scrollArea - anchors.top: headerRectangle.bottom - anchors.right: parent.right - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.margins: 8 - contentHeight: contentLayout.implicitHeight - ScrollIndicator.vertical: ScrollIndicator { } - ColumnLayout { - id: contentLayout - width: parent.width - ColumnLayout { - GroupBox { - title: qsTr("Configure Gamepad Buttons") - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonA") - horizontalAlignment: Text.AlignRight - } - - Label { - text: gamepad.buttonA ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonA); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonB") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonB ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonB); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonX") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonX ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonX); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonY") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonY ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonY); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonStart") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonStart ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonStart); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("ButtonSelect") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonSelect ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonSelect); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button L1") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonL1 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonL1); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button R1") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonR1 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonR1); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button L2") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonL2 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonL2); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button R2") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonR2 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonR2); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button L3") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonL3 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonL3); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button R3") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonR3 ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonR3); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Up") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonUp ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonUp); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Down") - horizontalAlignment: Text.AlignRight - } - Label { - text: gamepad.buttonDown ? qsTr("DOWN") : qsTr("UP") - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonDown ); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Left") - horizontalAlignment: Text.AlignRight - } - Label { - Layout.fillWidth: true - text: gamepad.buttonLeft ? qsTr("DOWN") : qsTr("UP") - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonLeft); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Right") - horizontalAlignment: Text.AlignRight - } - Label { - Layout.fillWidth: true - text: gamepad.buttonRight ? qsTr("DOWN") : qsTr("UP") - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonRight); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Center") - horizontalAlignment: Text.AlignRight - } - Label { - Layout.fillWidth: true - text: gamepad.buttonCenter ? qsTr("DOWN") : qsTr("UP") - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonCenter); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("Button Guide") - horizontalAlignment: Text.AlignRight - } - Label { - Layout.fillWidth: true - text: gamepad.buttonGuide ? qsTr("DOWN") : qsTr("UP") - horizontalAlignment: Text.AlignRight - } - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureButton(gamepad.deviceId, GamepadManager.ButtonGuide); - } - } - } - } - } - GroupBox { - title: qsTr("Gamepad Axies") - Layout.fillWidth: true - - ColumnLayout { - anchors.fill: parent - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("AxisLeftX") - horizontalAlignment: Text.AlignRight - } - - Label { - text: gamepad.axisLeftX - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureAxis(gamepad.deviceId, GamepadManager.AxisLeftX); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("AxisLeftY") - horizontalAlignment: Text.AlignRight - } - - Label { - text: gamepad.axisLeftY - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureAxis(gamepad.deviceId, GamepadManager.AxisLeftY); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("AxisRightX") - horizontalAlignment: Text.AlignRight - } - - Label { - text: gamepad.axisRightX - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureAxis(gamepad.deviceId, GamepadManager.AxisRightX); - } - } - } - RowLayout { - Layout.fillWidth: true - Label { - text: qsTr("AxisRightY") - horizontalAlignment: Text.AlignRight - } - - Label { - text: gamepad.axisRightY - Layout.fillWidth: true - horizontalAlignment: Text.AlignRight - } - - Button { - text: qsTr("Configure") - checkable: true - enabled: !checked - onCheckedChanged: { - pressButton(this); - if (checked) - GamepadManager.configureAxis(gamepad.deviceId, GamepadManager.AxisRightY); - } - } - } - - Item { - Layout.fillHeight: true - } - } - } - } - } - } -} diff --git a/examples/gamepad/configureButtons/qml.qrc b/examples/gamepad/configureButtons/qml.qrc deleted file mode 100644 index 5f6483a..0000000 --- a/examples/gamepad/configureButtons/qml.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - main.qml - - diff --git a/examples/gamepad/gamepad.pro b/examples/gamepad/gamepad.pro deleted file mode 100644 index 5622954..0000000 --- a/examples/gamepad/gamepad.pro +++ /dev/null @@ -1,15 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS += simple - -qtHaveModule(quick) { - SUBDIRS += \ - mouseItem \ - keyNavigation - - qtHaveModule(quickcontrols2) { - SUBDIRS += \ - configureButtons \ - quickGamepad - } -} diff --git a/examples/gamepad/keyNavigation/doc/images/keynavigationgamepad-example.png b/examples/gamepad/keyNavigation/doc/images/keynavigationgamepad-example.png deleted file mode 100644 index fa2fa1ca781cce71699405074e372e61b4b36a34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3812 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 YGBv8IItN4N-~M}GVqmFXtLG8>A2PU+RsaA1 diff --git a/examples/gamepad/keyNavigation/doc/src/keynaviexample.qdoc b/examples/gamepad/keyNavigation/doc/src/keynaviexample.qdoc deleted file mode 100644 index 39a06d6..0000000 --- a/examples/gamepad/keyNavigation/doc/src/keynaviexample.qdoc +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! -\example keyNavigation -\ingroup qtgamepad-examples -\title Qt Gamepad Key Navigation Example -\brief Demonstrates how to use navigation keys on the gamepad. -\image keynavigationgamepad-example.png -\include examples-run.qdocinc -*/ diff --git a/examples/gamepad/keyNavigation/keyNavigation.pro b/examples/gamepad/keyNavigation/keyNavigation.pro deleted file mode 100644 index 65f9ce3..0000000 --- a/examples/gamepad/keyNavigation/keyNavigation.pro +++ /dev/null @@ -1,13 +0,0 @@ -TEMPLATE = app - -QT += qml quick - -SOURCES += main.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/keyNavigation -INSTALLS += target diff --git a/examples/gamepad/keyNavigation/keyNavigation64.png b/examples/gamepad/keyNavigation/keyNavigation64.png deleted file mode 100644 index 707d5c4e85d82959740b243a8a36d5071c277299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3400 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 Jjgn>L{{TKddny0` diff --git a/examples/gamepad/keyNavigation/main.cpp b/examples/gamepad/keyNavigation/main.cpp deleted file mode 100644 index a10c579..0000000 --- a/examples/gamepad/keyNavigation/main.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml"))); - - return app.exec(); -} diff --git a/examples/gamepad/keyNavigation/qml.qrc b/examples/gamepad/keyNavigation/qml.qrc deleted file mode 100644 index 69145a8..0000000 --- a/examples/gamepad/keyNavigation/qml.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - qml/main.qml - - diff --git a/examples/gamepad/keyNavigation/qml/main.qml b/examples/gamepad/keyNavigation/qml/main.qml deleted file mode 100644 index c014593..0000000 --- a/examples/gamepad/keyNavigation/qml/main.qml +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -import QtQuick 2.2 -import QtQuick.Window 2.0 -import QtGamepad 1.0 - -Window { - visible: true - width: 640 - height: 480 - title: qsTr("Gamepad Key Navigation") - - Gamepad { - id: gamepad1 - deviceId: GamepadManager.connectedGamepads.length > 0 ? GamepadManager.connectedGamepads[0] : -1 - } - - Connections { - target: GamepadManager - onGamepadConnected: gamepad1.deviceId = deviceId - } - - GamepadKeyNavigation { - id: gamepadKeyNavigation - gamepad: gamepad1 - active: true - buttonYKey: Qt.Key_Y - } - - Text { - text: qsTr("Test key events from Gamepad") - anchors.centerIn: parent - focus: true - Keys.onPressed: { - if (event.key === Qt.Key_Up) { - text = "Key Up Pressed"; - } else if (event.key === Qt.Key_Down) { - text = "Key Down Pressed"; - } else if (event.key === Qt.Key_Right) { - text = "Key Right Pressed"; - } else if (event.key === Qt.Key_Left) { - text = "Key Left Pressed"; - } else if (event.key === Qt.Key_Return) { - text = "Key Return Pressed"; - } else if (event.key === Qt.Key_Back) { - text = "Key Back Pressed"; - } else if (event.key === Qt.Key_Forward) { - text = "Key Forward Pressed"; - } else if (event.key === Qt.Key_Y) { - text = "Key Y Pressed"; - } - } - Keys.onReleased: { - if (event.key === Qt.Key_Up) { - text = "Key Up Released"; - } else if (event.key === Qt.Key_Down) { - text = "Key Down Released"; - } else if (event.key === Qt.Key_Right) { - text = "Key Right Released"; - } else if (event.key === Qt.Key_Left) { - text = "Key Left Released"; - } else if (event.key === Qt.Key_Return) { - text = "Key Return Released"; - } else if (event.key === Qt.Key_Back) { - text = "Key Back Released"; - } else if (event.key === Qt.Key_Forward) { - text = "Key Forward Released"; - } else if (event.key === Qt.Key_Y) { - text = "Key Y Released"; - } - } - } -} diff --git a/examples/gamepad/mouseItem/doc/src/mouseitemexample.qdoc b/examples/gamepad/mouseItem/doc/src/mouseitemexample.qdoc deleted file mode 100644 index 1e0c78d..0000000 --- a/examples/gamepad/mouseItem/doc/src/mouseitemexample.qdoc +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! -\example mouseItem -\ingroup qtgamepad-examples -\title Qt Gamepad Mouse Item Example -\brief Depicts joystick movement using a pointer. -\include examples-run.qdocinc -*/ diff --git a/examples/gamepad/mouseItem/main.cpp b/examples/gamepad/mouseItem/main.cpp deleted file mode 100644 index 0559efc..0000000 --- a/examples/gamepad/mouseItem/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include -#include - -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml"))); - - return app.exec(); -} diff --git a/examples/gamepad/mouseItem/mouseItem.pro b/examples/gamepad/mouseItem/mouseItem.pro deleted file mode 100644 index 95d667d..0000000 --- a/examples/gamepad/mouseItem/mouseItem.pro +++ /dev/null @@ -1,13 +0,0 @@ -TEMPLATE = app - -QT += qml quick - -SOURCES += main.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/mouseItem -INSTALLS += target diff --git a/examples/gamepad/mouseItem/mouseItem64.png b/examples/gamepad/mouseItem/mouseItem64.png deleted file mode 100644 index 707d5c4e85d82959740b243a8a36d5071c277299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3400 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 Jjgn>L{{TKddny0` diff --git a/examples/gamepad/mouseItem/qml.qrc b/examples/gamepad/mouseItem/qml.qrc deleted file mode 100644 index 69145a8..0000000 --- a/examples/gamepad/mouseItem/qml.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - qml/main.qml - - diff --git a/examples/gamepad/mouseItem/qml/main.qml b/examples/gamepad/mouseItem/qml/main.qml deleted file mode 100644 index 66d56e0..0000000 --- a/examples/gamepad/mouseItem/qml/main.qml +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Window 2.0 -import QtGamepad 1.0 - -Window { - visible: true - width: 640 - height: 480 - title: qsTr("Gamepad Mouse Item") - - Text { - id: instructionLabel - anchors.centerIn: parent - text: qsTr("Simulate mouse input using a Gamepad") - } - Text { - id: outputLabel - anchors.horizontalCenter: instructionLabel.horizontalCenter - anchors.top: instructionLabel.bottom - text: "" - } - - Connections { - target: GamepadManager - onGamepadConnected: gamepad1.deviceId = deviceId - } - - Gamepad { - id: gamepad1 - deviceId: GamepadManager.connectedGamepads.length > 0 ? GamepadManager.connectedGamepads[0] : -1 - - onButtonAChanged: { - if (value == true) { - gamepadMouse.mouseButtonPressed(Qt.LeftButton); - outputLabel.text = "Mouse click at: " + gamepadMouse.mousePosition.x + "," + gamepadMouse.mousePosition.y; - } else { - gamepadMouse.mouseButtonReleased(Qt.LeftButton); - outputLabel.text = ""; - } - } - } - - GamepadMouseItem { - id: gamepadMouse - anchors.fill: parent - gamepad: gamepad1 - active: true - - Rectangle { - id: cursor - width: 9 - height: 9 - radius: 4.5 - x: gamepadMouse.mousePosition.x - y: gamepadMouse.mousePosition.y - color: "transparent" - border.color: "red" - Rectangle { - x: cursor.width * 0.5 - 0.5 - y: 1 - width: 1 - height: cursor.height - 2 - color: "black" - } - Rectangle { - x: 1 - y: cursor.height * 0.5 - 0.5 - height: 1 - width: cursor.width - 2 - color: "black" - } - } - } - - - - MouseArea { - anchors.fill: parent - onClicked: { - console.log("clicked at: " + mouse.x + "," + mouse.y); - } - } -} diff --git a/examples/gamepad/quickGamepad/doc/images/qtquickgamepad-example.png b/examples/gamepad/quickGamepad/doc/images/qtquickgamepad-example.png deleted file mode 100644 index 9f46e4d492cbbb96c1cbcfdc434573a400246e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50662 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

beaDIaB*aQ`&qgxn^_S4Y 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 diff --git a/examples/gamepad/quickGamepad/doc/src/quickgamepadexample.qdoc b/examples/gamepad/quickGamepad/doc/src/quickgamepadexample.qdoc deleted file mode 100644 index b0f87a7..0000000 --- a/examples/gamepad/quickGamepad/doc/src/quickgamepadexample.qdoc +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! -\example quickGamepad -\ingroup qtgamepad-examples -\title Qt Gamepad Qt Quick Example -\brief Demonstrates how to interact with the gamepad using QML. -\image qtquickgamepad-example.png -\include examples-run.qdocinc -*/ diff --git a/examples/gamepad/quickGamepad/main.cpp b/examples/gamepad/quickGamepad/main.cpp deleted file mode 100644 index a10c579..0000000 --- a/examples/gamepad/quickGamepad/main.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml"))); - - return app.exec(); -} diff --git a/examples/gamepad/quickGamepad/qml.qrc b/examples/gamepad/quickGamepad/qml.qrc deleted file mode 100644 index d82637e..0000000 --- a/examples/gamepad/quickGamepad/qml.qrc +++ /dev/null @@ -1,24 +0,0 @@ - - - qml/main.qml - qml/JoystickViewer.qml - qml/xboxControllerButtonA.png - qml/xboxControllerButtonB.png - qml/xboxControllerButtonX.png - qml/xboxControllerButtonY.png - qml/ButtonImage.qml - qml/xboxControllerBack.png - qml/xboxControllerButtonGuide.png - qml/xboxControllerDPad.png - qml/xboxControllerLeftShoulder.png - qml/xboxControllerLeftThumbstick.png - qml/xboxControllerLeftTrigger.png - qml/xboxControllerRightShoulder.png - qml/xboxControllerRightThumbstick.png - qml/xboxControllerRightTrigger.png - qml/xboxControllerStart.png - qml/LeftThumbstick.qml - qml/RightThumbstick.qml - qml/DPad.qml - - diff --git a/examples/gamepad/quickGamepad/qml/ButtonImage.qml b/examples/gamepad/quickGamepad/qml/ButtonImage.qml deleted file mode 100644 index 755fa6f..0000000 --- a/examples/gamepad/quickGamepad/qml/ButtonImage.qml +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -//import QtGraphicalEffects 1.0 - -Item { - width: buttonImage.sourceSize.width - height: buttonImage.sourceSize.height - - property alias source: buttonImage.source - property bool active: false - - Image { - id: buttonImage - smooth: true -// visible: !active - } - - Rectangle { - anchors.fill: buttonImage - color: "#14abff" - opacity: 0.6 - radius: 8 - visible: active - } - - // BrightnessContrast { - // anchors.fill: buttonImage - // source: buttonImage - // brightness: 0.5 - // contrast: 0.5 - // visible: active - // } -} diff --git a/examples/gamepad/quickGamepad/qml/DPad.qml b/examples/gamepad/quickGamepad/qml/DPad.qml deleted file mode 100644 index 98e7975..0000000 --- a/examples/gamepad/quickGamepad/qml/DPad.qml +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtGamepad 1.0 - -Item { - property Gamepad gamepad - - width: dpadImage.sourceSize.width - height: dpadImage.sourceSize.height - Image { - id: dpadImage - anchors.fill: parent - source: "xboxControllerDPad.png" - } - - Rectangle { - id: upArea - visible: gamepad.buttonUp - color: "#3814abff" - radius: 5 - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width * 0.3 - height: parent.height * 0.3 - anchors.topMargin: parent.height * 0.05 - } - Rectangle { - id: downArea - visible: gamepad.buttonDown - color: "#3814abff" - radius: 5 - width: parent.width * 0.3 - height: parent.height * 0.3 - anchors.bottom: parent.bottom - anchors.bottomMargin: parent.height * 0.05 - anchors.horizontalCenter: parent.horizontalCenter - } - Rectangle { - id: leftArea - visible: gamepad.buttonLeft - color: "#3814abff" - radius: 5 - width: parent.width * 0.3 - height: parent.height * 0.3 - anchors.left: parent.left - anchors.leftMargin: parent.width * 0.05 - anchors.verticalCenter: parent.verticalCenter - } - - Rectangle { - id: rightArea - visible: gamepad.buttonRight - color: "#3814abff" - radius: 5 - width: parent.width * 0.3 - height: parent.height * 0.3 - anchors.right: parent.right - anchors.rightMargin: parent.width * 0.05 - anchors.verticalCenter: parent.verticalCenter - } -} diff --git a/examples/gamepad/quickGamepad/qml/JoystickViewer.qml b/examples/gamepad/quickGamepad/qml/JoystickViewer.qml deleted file mode 100644 index a524bfa..0000000 --- a/examples/gamepad/quickGamepad/qml/JoystickViewer.qml +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 - -Item { - width: 100 - height: 100 - - property real xAxisValue: 0 - property real yAxisValue: 0 - - onXAxisValueChanged: { - joystickCanvas.requestPaint(); - } - onYAxisValueChanged: { - joystickCanvas.requestPaint() - } - - Canvas { - id: joystickCanvas - anchors.fill: parent - - onPaint: { - var context = joystickCanvas.getContext("2d") - context.clearRect(0, 0, width, height); - var targetX = (xAxisValue + 1) / 2 * width; - var targetY = (yAxisValue + 1) / 2 * height; - context.fillStyle = "red"; - context.beginPath(); - context.arc(targetX, targetY, 5, 0, 2 * Math.PI, false); - context.closePath(); - context.fill(); - } - } - -} diff --git a/examples/gamepad/quickGamepad/qml/LeftThumbstick.qml b/examples/gamepad/quickGamepad/qml/LeftThumbstick.qml deleted file mode 100644 index 1bd6232..0000000 --- a/examples/gamepad/quickGamepad/qml/LeftThumbstick.qml +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtGamepad 1.0 - -ButtonImage { - - property Gamepad gamepad - - id: leftStickButton - source: "xboxControllerLeftThumbstick.png" - active: gamepad.buttonL3 - - JoystickViewer { - id: leftJoystick - anchors.top: parent.top - anchors.left: parent.left - anchors.margins: parent.width * (3 / 153) - width: parent.width * (140 / 153) - xAxisValue: gamepad.axisLeftX - yAxisValue: gamepad.axisLeftY - height: width - } -} diff --git a/examples/gamepad/quickGamepad/qml/RightThumbstick.qml b/examples/gamepad/quickGamepad/qml/RightThumbstick.qml deleted file mode 100644 index fd61a7a..0000000 --- a/examples/gamepad/quickGamepad/qml/RightThumbstick.qml +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtGamepad 1.0 - -ButtonImage { - - property Gamepad gamepad - - id: rightStickButton - source: "xboxControllerRightThumbstick.png" - active: gamepad.buttonR3 - - JoystickViewer { - id: rightJoystick - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: parent.width * (3 / 153) - width: parent.width * (140 / 153) - xAxisValue: gamepad.axisRightX - yAxisValue: gamepad.axisRightY - height: width - } -} - diff --git a/examples/gamepad/quickGamepad/qml/main.qml b/examples/gamepad/quickGamepad/qml/main.qml deleted file mode 100644 index 1f37cda..0000000 --- a/examples/gamepad/quickGamepad/qml/main.qml +++ /dev/null @@ -1,231 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.1 -import QtQuick.Window 2.0 -import QtGamepad 1.0 - -Window { - id: applicationWindow1 - visible: true - width: 800 - height: 600 - title: qsTr("QtGamepad Example") - color: "#363330" - - Item { - id: background - anchors.fill: parent - - ColumnLayout { - anchors.fill: parent - anchors.margins: 8 - RowLayout { - id: topRow - width: parent.width - ColumnLayout { - id: buttonL2Item - Layout.alignment: Qt.AlignLeft - ButtonImage { - id: leftTrigger - Layout.alignment: Qt.AlignCenter - source: "xboxControllerLeftTrigger.png" - active: gamepad.buttonL2 != 0 - } - ProgressBar { - id: buttonL2Value - width: leftTrigger.width - value: gamepad.buttonL2 - } - } - - Item { - id: centerButtons - Layout.alignment: Qt.AlignCenter - Layout.fillWidth: true - height: guideButton.height - width: guideButton.width + 16 + backButton.width + startButton.width - ButtonImage { - id: backButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: guideButton.left - anchors.rightMargin: 8 - source: "xboxControllerBack.png" - active: gamepad.buttonSelect - } - ButtonImage { - id: guideButton - anchors.centerIn: parent - source: "xboxControllerButtonGuide.png" - active: gamepad.buttonGuide - } - ButtonImage { - anchors.verticalCenter: parent.verticalCenter - anchors.left: guideButton.right - anchors.leftMargin: 8 - id: startButton - source: "xboxControllerStart.png" - active: gamepad.buttonStart - } - } - - - ColumnLayout { - id: buttonR2Item - Layout.alignment: Qt.AlignRight - ButtonImage { - id: rightTrigger - Layout.alignment: Qt.AlignCenter - source: "xboxControllerRightTrigger.png" - active: gamepad.buttonR2 != 0 - } - - ProgressBar { - id: buttonR2Value - width: rightTrigger.width - value: gamepad.buttonR2 - } - } - } - - RowLayout { - id: middleRow - ButtonImage { - id: buttonL1 - source: "xboxControllerLeftShoulder.png" - active: gamepad.buttonL1 - } - Item { - id: spacer1 - Layout.fillWidth: true - } - - ButtonImage { - id: buttonR1 - source: "xboxControllerRightShoulder.png" - active: gamepad.buttonR1 - } - } - - RowLayout { - id: bottomRow - width: parent.width - DPad { - id: dPad - Layout.alignment: Qt.AlignLeft - gamepad: gamepad - } - - LeftThumbstick { - id: leftThumbstick - Layout.alignment: Qt.AlignLeft - gamepad: gamepad - } - - Item { - id: spacer2 - Layout.fillWidth: true - } - - RightThumbstick { - id: rightThumbstick - Layout.alignment: Qt.AlignRight - gamepad: gamepad - } - - Item { - width: 200 - height: 200 - Layout.alignment: Qt.AlignRight - ButtonImage { - id: buttonA - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - source: "xboxControllerButtonA.png"; - active: gamepad.buttonA - } - ButtonImage { - id: buttonB - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - source: "xboxControllerButtonB.png"; - active: gamepad.buttonB - } - ButtonImage { - id: buttonX - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - source: "xboxControllerButtonX.png"; - active: gamepad.buttonX - } - ButtonImage { - id: buttonY - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - source: "xboxControllerButtonY.png"; - active: gamepad.buttonY - } - } - } - } - } - - Connections { - target: GamepadManager - onGamepadConnected: gamepad.deviceId = deviceId - } - - Gamepad { - id: gamepad - deviceId: GamepadManager.connectedGamepads.length > 0 ? GamepadManager.connectedGamepads[0] : -1 - } -} diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerBack.png b/examples/gamepad/quickGamepad/qml/xboxControllerBack.png deleted file mode 100644 index d97972c06406ae2432444023990a1b2633fb19bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11012 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 diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerButtonA.png b/examples/gamepad/quickGamepad/qml/xboxControllerButtonA.png deleted file mode 100644 index 271e8c85657afb2b2bdfeedb17e5051d777db236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13764 zcmZ{~1yEeuwl&<{bmQ*s7Tn#P1P$))?gVYz2@u>RK!Otp?ry;)xVyWB@aLR+zxU36 z>%LvJZO%E?9AmCEt9I31Q7THZD2RlJ0000*UQX)$pS#LmCp_$*YdpqPB>;dZZX+qF zA}=XPuHx!sX=85z0LY=_qozPy2?Pes+9EZYOEc?c_sJtTIS23&idkh63xW`=^2<0l!#y&gl*2lye?YjrzqXSX3fnA%HmSEWjDbVb%cHxYSFLDEQ zcV{e6^VVgiP8C|W`PaZiN?u87SOB8*9FI@{E#59DS*@<0fa4WBa+C6gBb=QBw*aBA zf^xgB+WxL|kFj+)J&ks!fKX?gpp7dxwpC>(`I7T8B|NMjS6MO}da@X3ArZLX*>kNnoT0Phm3ooH~BylDx>Lb}cF z!I0(CWu4liDLZ3wui|E;x5C6tJ#su79<`6doqzL9-FJPZhun2+Kvmjqt?wLsq0A50Mt9citTPzD4&x9t{{N=wd`xs zaC^g~zAa=rq?nTvdpBU79Sh?D?{i+T(@1AH|9!^j*|Vl#37%*Wl{^loh4gMoX~{dO zu`y)Sv+I z$4v!sO0~T^giYj0wt5Km&BKMvxd@wr6xh${Qye4zFu@^KBEZ2x?;w-X_rnfGNzV z=M%ix5IoG3j5a*crIbX1HZ>4~!Y+~WGw7>yW&-MGqUJccM3)^H*oXp?bbQ6!|7dpwrtoI#Jl#inz$CE9cqqMism7+G=5eVWD}jrD5MYGHnw zoCp%54t5c25jzJo;p=laa#w*H(H3G`p~t-_o3xkSZ47JJ=fP;*ZWpG06dj0x#DS#i zAISzf=@Jlh!FIuD6shFY_SEX=gz)?DFQFJcT&h7|l-()A(LeO*o4%=y|0&)kPfV-y z30pp#8t*;zn~eG(b$MG#16pC)c8X8K0_L)=_&Q>S%2m{P_I zywZ$V^5~2x0^j~F`PBqc?H21+3o5G7ERfl(?-34@m(DCqF^x3MG>tM1+2Zb3rD;nF zN@~PZ{wj7@Gfh)WK`1d({9(GOUa?+a$zq9(M3(pS^USBi{u{D`_8SBX8VkK$`d#8( z!ri)&_pm)|#t)qD35sJs#kR(Nyyn_#p4gsP=Bc(Zd~JJ^^2p%G;Fm&~VwnO=`BD zDUr{s<-(O_U+T22ij?Zcu?&(}^mxS^^&8c^B$VH=YO@+utDYB#sODAXeeRU))C(Nx znj~K`juFr5{!$QK&}ouuQnYDCRhC#j#ZaVMBsjol*5DF-DYC6cTN9NdpClhQtf=;L zc1_*5Wukrp*>2C8maCk*b+E8zMMtMXWp^|FJrgi=zQsFXXH!Qb9BbvjH8SfAtB>k z;LS4QyH2@mHW9lfvY4~P8hJYx%xWyBZ0jCBjVUg~?R)k)^sW9BUVLeKW<-03mM9xD zm|Xg4pKt=nFfy%LD^aVuG3nm)-1fXwL_j1;Bu)gY!?UB@pY_4y1@z+iw0ga8vH!I2 ztPJJ@S0Ef9eg?~cHQ_{%I1n%)9^l??V0UXU8SAtWwf-zFNaB~IXP6KIH?jfFlN&w@ z6ITW8$%iHl?*MNvFte$&lw@D4+{dBmA=#KX+;_NMGQ+a{(sQzk(!SDZ((lr=nRM!Q zWMXw=$xDQB$%t@#sXbl4-cPT-i`YKdLfk%M;nYv9J6Ur5zWa4_qAJ0tTgQcgl!%OE z9sM;5tLN*kLe-5?v)3+o;ZtkGbJG3*<9^(w!Gp!GL~vT@x6mo6v_69*41BZcA=2 z533H(-{HTyxzFrSE5qii^p~5JybQWqHg7wQKRS>*$Sq!s%8bTY5Uo2#ug$9FtJZWF zTi2cM4M;RgsBX41kL#h@_uJ#xpRQWgRoX76Q5sI&nvQNoZz!h5Z(9=2R-XPD|3E>2c$7*y_#T@_w6wrZVpXqxD`7^B&IH2+x7@#S0l z+iF|cxzeN0M?r)iGxyq$d>c=5mIjv>I@cWnXMk}q{cs|r*u-stL-#6nmEsQlCM%m2 zy%WcUM=hOJfkuH+r*fBx6S85l#e+Q`J>~>w7kIz$CiC>fB@NVWy9_$LY}`uvVwE4N za27Q`fcYr+FSiCC$j)<-g%&?V`TxrvGG;#T|b1*Ana-)IsahKiN~<=! zY!;Z2gPuPKk!%Ds?@uM>(!u{Uf9J4oey}s+WpiFq8ogHDA$k|| zQt)hcGnjaIqWqwok{2iH<%jU=%A3}~a&P@U^!k}YKquhOHzk6zoQ@j+fQ0qe2?S(j z;{yO-N*i@;cWp%l0W&8D787$PQwtVv2j@T00DzFUz@JA43wIN8ZwGrvHvw;9%D*E7 z{yhI>W~C(mJH*{im{MC&gk3iPHJgn?2Y^?tcX5nq~f586o z{GTv$v;R@$?BQzvw<6m zYhS{|iuE66A=dvIE%aw42q-$4+gN^(GI6&M;b3FuVrJuJX5&<6;}Bru7U1C%V*QVp ze=zvVBk5{k;_l?C?&M@I^0x|yzh22XS^lX0PyfH6Lacvv(LcKCUoHE$^-s@=ApSxA zzy23NtXo9g0sv^A<)y^cy@99Mk240cANHTu-0q)QmfD9?+mgFs&0<};R6@a)@4r%O ze6ypjw^&tOB&c&o_H#=RkiNj@NT|D`%A9;BuP&IN_R|E6D1xrh zZvZ#o8)SEcrSP4u=;yW$EI1aqJTV+N!gqs{<&&b4)nZO5)Lo$0ui?sAV*ScWKIoWD z6Ot3+A0_bKUVWe`(O*+j@!K6crZJ!iKzPErfu+uO-7BTs%Y%i23L{4hCM1kPazl57 z`ZeR1p_)#g)gwfa9;z0ri(&n=-QSlb_F9GGEIFaPGGmPM3pL_bZ2Le0D|bfqO!|w7 zA5m|3Za8kt4y+RNThROq#R8H5h|$Cz1Wz0{rUbr$gou;2x5%2$?#v#O(6C@V2zQ!P zxow}JBZ!yBlLYPhI{~is!0?)YA{qb(XoO^f3ZgNtmH<6S9?%>xxWoHXiY=8WQw}k@ zE-VzBOBjW*ND^%z*6ThCMW6lFWzcoMp%$nw)NG(Gyvn?PH`x^VONfo-%?O|Bxa&8i zZ7({IvCGD%i3u@nga&hYPEs8@U$ z!`TK015Y?rhywl0LdmXPfK%A*h&m`A;w@%ItgmI5wP75~PSM-AU{jDWEN-$;^9%cl zH9_n*5qN#gmtN0Z8A6|Q)G{Hy9`qai2~-a=H)p1o20T+>7O*J|2GBvH)5j4tQ!Gi( zsj5XU2a!U#d1YMn5p)5A`4v0tz#SilHhs8HPn`XS1Z|K60@`&=+25E?f(L=g3(-%f zOUa?F2+bN^pRVtOQijU*!DmF1G+)ZE&V{w#y~s8dNy5&6Y36JKA-FD6eb(3>vC@@( zj+Vm#h{1#t$3E1)8X_acIwI6iP^mZqAg*988dL6mcQb49_DaNU)lO)t3x4M{xPG2Y z=dUBCZx3!_az%&JG$EzgR0iA zQ}zH-SSTs0^{XqtGSb*F@yzipCU}05L#2>dHIz~WVFUC9q6i9~BfgN=V;)ji!eyR! zCNV^)l@XcVP7oke!xcF|i-g=#1wE(&xn3nFz4ApP0^q&@rSC<|?-2yVOF0@78JuGS z%GEx*l}?mCj|(R#oo562mL}@>GXuhtGMNT#!hcFn?BZ*eG`yDt03cN+b&<`6!IOmJ zx&AduQA2Jx=u@rZ+@q#zA8$qgkpVKbNtyj5Gb$P;v zQW9aqC#tmF4?vf-X~^tx;9S!~#B&nF%y3Jw4QtYjXuS;&hKT`qdVj?^K+-(6X`_pHmBIDSx{TUX6m;@P(BNTDlbCSxn?RR*=fT zfbKUM_QLnM2s62oTky2O${;qu=@)fQlJx) zoL}Ap34Jo+B}vHk)pBsaS{ix(o!}%tp}|Q2>bNAtsY}w{%d2rFX2M^v{UXfibKODP zqfaJkIPdh2&F}7f{=6u7vNoz&#ww}WmQ7(wI4L+R8;mMtd>?(j&{E;KbRcz=S!o!? zsgN)oC##mqW;BHh^DIQZ(sn}l@U5d{h?HPA4%u-k%rLf*mAN?h#DE*j%1NR3;p?#Z z#83D)bdzM_Xp;SRW(PtiRSsV=U@pe<1oJv>=gv!5g&$L9k8h{Zg&RfNa#3k{*)d_R zx^wV98aCoh_-b$93e>_v`O!z^v0G9V-*S6Tt5lFMTM&$2x6m%a21xi%77B>T+j0Rb zHS&E}BUN*pFy5jc=VXf%WqclC)3wsOU~q45qxA`VU<3Hy0dDdNI-$A2y1L81shWX= z$myavqJbeB%EEUFwvCyG_%IaSRD3M0EX>Gn={#Cb$USP-p|AtW{5` zAn|E2%*|>x!Fx#vO9W-rfG3L^gmsk0(=3cCj^Y4&`K#FT!rn?zQ?y4`GkN`)ls^6- zH}u+%r~iU)8=mDeF}j*Qqa$_`N;=T~gHbR(8#}yfQ%FJ9qBw;TD#>T>BaVo(xR}PK z&DuLTci$RcFGP?p!4nI$w;-tGlYN*WV}k+m0MdjXr~la$YnKg5Y@cFRYhvmHrl-ul zw}IXih9QICX4mp!kBl!05yC7)Xw||iLq;%!D;s%(4}kbsENOAl8qR&+`Qb&&q&w@N zW&>qZOF!xnX^>b&)a6nsrE9D z1?z8f@K*5VhCMn)JIkJuIGM*?NuOF6%Bs<-N)!~&IsQA=J z*LxDr=GDrzK1%D~8s&)KYMT|?9Rr!_vK7}0WD5|HYMYr?5X5putSA<>gz?K6JZT9* z-VT=d%4Tft8ZzlsM1u=##J=kBoO))_5Q_`%2*MpGyv#R{xJqjNd#jOo^U$4^FOrTM z1P0`(f`AfgZLS3UEw1~Pmsx9LKQ=D*d+DasG5^~o;$#4;?Z}V2=`xa1U8o#NI-*uL zq$Y}{3MR9Bo5yR^MiQ0oa+0j$51THy;Y;oV4s0awXF-eO)O0KEJG^XM4CHx8F@s$S3BS(6^L1Voj(C z-4_U(?EqVku^Vdam4)7Gq&e&ji!70=4yXtfb<;<7M)ho6t()`K;t;k9*BuM; z5G)|i(YAkdoui~PWz7LWC>08{JI<9nKRl6I4b7+#*)=yEI$&AOP1=qp7B{$G0GHom z@qoHw6&3`(Y_8j%Y395ye#4mT3qxX|kGogb{GNZJjp)EN>jNuakUPJ9?bycRrA#}C zaZ8J7ix>;}Hce!P(YPMbXhB;YSnQ?Su~nH$uhzX76&aBnsJ7w9DyD_g^`p?5FtIzp zK`aytQY)UfD^XnO+mahyfwU_@b8T}#T#rBp#HQsGh6{srM(c%z&lOOlIZjfqTU3y( zfD5Y|D})|?Ra$*4 znC55LZODaUO!TF5wxynRFm!q>U8b!)UjX041dCK7!bdhpJicy7=h>6DYh~xWN7RSH z!Ii<~2oedDx{lGPMRv&`tZpQw%{YhP*babXujE>ZrZ8-Ol%?&L9 zPK;gC2{peFBgb_)pg55ONAg)Egprmb_^?mKH($_@Jo4G)4!~eMh9Cl(m!8o{Y50I2 zo1dvF$9+L90Guj@g)nt$CIGQ#Lqly>4wosnG^)FXg@#cL<{}hn6CZm56E9e!O5gYK zDU;Nk<-I$nv76Y6rC4?cWH?CNg0$}g&D8P63O+tI@DxEq21h_4nmrDF($dsJxw5`O)16+Lu9 z2>DD;(sBTu?ILTLHYv1d;SFv3iog&{R(k|)n4CQHecKzZ}t=R z1r08s{Ro!=O?62&=XUyxowWCOUF5EmxU2%F_cx^73nCIa9zHa!ochdDuB>ec7f>94 zAu32#huWnB%`PT%-qmVdsorjP?*t4GcmWH~VNJqR{@xgB8#! z&9@lG8UirEYA0GgyrZqHywivpkpTzvGjmE7!AT~drU&meR6dIxb&EsDzu}dZ#@3w` z8IRt{9yS8PtVcGJ4>28kookYl#J7|hE!jvui!giA{m{TA%6j3EPDfaa4fE~u64!Ua zrSNp)V>|9Z*4H*c0p}xpc5o(#Oq55)Hlq{Y>LR_<-=G}&{(buEe8NzWlAz?^Fgz|T zLDLk7s$eYqp;ic!ixg?){^mW08VBxu%kY70h$2}^`^sfDQ|p+ zSGgJqcU2!k!(r%HhK*h2iqfr22e@cFr%{huLLsnC!`_*hjM-MCj$MrXJYAoz0l|bb z(Eec9av_JG3+%E^$cR^YmUtpvJoA zJ#xVvYgIN63K4%S?9hf9BXgqqw#h`D)CP&HoTMp*TSE(?hb~XS<=CJn3s0BLg?E@Yj092Rnj%?-JOF3;5j_10 zll(^0t>8D6(?g*7nA^sfN%S_pqXU9S5$;5x>eQ`XegbX!(-+sykgsyEk)S=vEfhZe zIhdw{_W?3Ic|_QY0xi{NSKJ%JaMoWw0k&Kt+To3AK$Aq3)o5lKlzsDA^eaE#;Ge;v zy#G2#pBVKUhWh?)H2m7>FrLT};g|_nIC{ef$X1fmdk-PWEPT$k>2pU(0FlG>fWErN z_s>h{LRmGsIe$Iy>svRt3iC>IxP&I@RTBaw(hc#`k+KKWbq*^B!OpfzZGfl?A5%`9*_m*3M$ax2YHU@>G=qy}sOX<<} z%p{WQcY%JB;l{z%N(*x5kLmWU4zTg4yU!l9kJ};vJ4LA!ODx5#F2z$#WC2^%5x*U2 zl!3g7(;z-Z0aaL9s%WQ!o{_2m4Sxd=o~ni3+a9$-FzMajU5mCeO7H`qwLPCKK8C&B zRRx+n38w44(zD!?UPdqKO3|Du_GY{im$HN}NfZP~(%59mC8)Bv1sn;@@!J(09)fR3 zH$n~7gdmtB)vBmDM0H#C7`ju#*u68JU7TJ?1@>6-M+`&~BD|IH;hx<|3isksFk7b_ zDF&R}VxJc*hoP>Dm#UH#HcwElM2b(GpE$IGnjX!~q}n=ghKN{YG&H_#g$3e{<4lb1 zL=HP$0)x(dEHYP$^@2#pQ1kg{j!;yJgb?_J-sH==T z?|o{(rXPDR{m!@9Fv2QAQ^FK&f(iSca4?vT<<2U+;zlaw?S+`qS)C9{oSR1w8sH`B z$<2WAs%&QTvp$g0!EF>EXssEn!%Ix>Z8p@j33xKUR=P=wkN64sv>)-=?i3^x;IzBH zWK{y7^bV^!u0eLPoFO??ERqT`Mljs_x*B|p3_Xh67Oa|X|1iivB7MaOAaTC+Jhq>0mfFJ$T zTkYn{;U=Yjoql_{F20zF><-UDR_|PYS4lP349i@KU|;attY4ZO=}K2dWtLPj`oV;0 zhv!xLQA0SHmV-b4hgs38H%xw{4{qNB_TcTeQc3I$bto|0r{<0QywV^Dj`h*1njwB? zpwF8Hz-&pUSfaNH$~b!tjcmJL0<(DjtT=bL-$=?H#9+K25r#E=OFjBwMV(x0fsm-* zTZkllXy8U+68#l+rwbdPmtsZ?UBrO(I0;W%pLNZVztUL61*|rt~pX z1R|RtITbSoB>$iUc(VaPA{7)|wsAGXhA|GfHS7;V+1rQ%u!UILr9@vy>S%b8e+w9Y zi43A}5Lt<=!FQ+;K-g#%ij?jNa}y!Ng-%`plE|7F@y6Y%PT%cBAq9MiBTk%vOANWs zp7+pg%CN9AO~upbi%Cri+09Ch895&mEViL8dA`;uefdt`r_#1Q2avGpyN;N z-5qowwl`Nr&#h2L+KM51bU0m8u;i#nH>!}Fm%)&!!>(tn0i-XBcBb~>WA`zI(DXC4 zwWYctl9(%s=m^v7O1tL@@vsbxMsU@How>eBIBRT_qy%<2ln}S=s3M0h(0G5q$(Fpt!y%G^mff`#CL!+Ea!6| zLYqbmd%~U$>M*A2=j0nb$i6MmbpFNdLoj!s8d>ej40fouG6!GqkQ~75K5-8rm+r%5 zhq?6h_|}$DB+$GW`0ZwXtsZSfj*&B7-Pe-6G3@k$`h;f4D%WIT&eVNxir*HU5Y!4W zHa_?W*b}*mueLz)<+u~zLuL{D?#4iZdiO!m#p3>BJ?^sOGRZjIH&?33@hm#-3G3dl zGlpq#|4G|G{yfng&Tm=4=s!Mn8%F%$!aGp9P!Jf@fsm8CV&1z)L8A4Wx(msXE8cen z+{`8b;~kwwl2Qy{Xytft)Ha%svwPGB@<@r~|3FU#$nfK01}45q^V$*--Sb~V5W`Wv z)yG{$PW7pgTW;diBfimRBXgP@N0mi?k_!%541=+u-lgw2+l4}A)bA}2#qWim$C2knw6rXah zRNF|o5D{1B!!^T1ghd0-poI2#@naMBjt9E4v1yPOe}6huiw*h570ke6Z6RI)Vm^M9M(9YS zcM+){Rtutk;)j#7WL94Rv}tcVbf)^xD)!h)8dC`TVtprFy5tq<64*qtZN`lXS`;ee z{#Zz8)t0eujW@>R%D=f_L0z4MEhk{;v_;gU>dw@dJd$x1VMq0>ye4Yn*dT45&iPpv zZ$tC@qgznInA`?tU3gMqHs9iNWWIY1cQRE+cj-a*!SR7X^!n(%E$7QT<~Y|5ZU>wy zRdEKk4^bA^q3wUq|8{ju7PKP*%7$}wkH>cvR8y_IRDww}DMx}9Ab`WYs3oO93DtAF zRSHEyho26M*}t784)*K7BA9Jx(((_%7!v_@sl`*uwHu6uUr+9I8X%~^I30BTpXMxQ z;poj%G>-a!P5)riUVOc~0a)L=Hn@Q#NGbEY#J3mK9NW$}Pv>PFJTc3KS zz2}qPd8X>%iBI{uZ%k2|vwwg;ju^vWM_^G&sH*R&;98(vo^0#y{{YCTRb$Ho`Ah}l`gk8h3k zCo_A2XLhZf!p0l4gV$U{-Tr)|KyqR>A2?YjqceD13_f;MKhDqk_-A19h?gy_$2<%p z+ULb>#&Y+w$BJiLhDFyfeoH2HQz&C8r(jgTG(gMHr-}7QN|0c60zaX4HbVa}zNt^t zQn`6?0Ksy14b2F#8aT5Ua;@D6t6!4!dNkC=n77N=}+T+XKBn4^<(9kTSO}SZRf-Oq^JbZ@u)|r zAdvn&?L3e2=(nZm}bbE$Dx#S7X>cm~C|Afj1r5pmc z8gJ@c5R>mX&zK6tFD=rw->83*_S;>w2BHJzxlQNe0L+`DDB?&(=$vTXA;&vn&B_3r zMF5UnTknUXqA3xLm0xk_rHbF2e}2Qgon|*$$a6ipRz8`8 zR)HM#+8>Gsl8L|H+yoZHOonw6jp{xV7tR8u0Ew$FP*&8PWUHfxJB;}PtAi1i(z7he z7>zL1A^HUj7@B4fU{JU8ezo0fI-QiEr)_!<;N6Pm0c6)y{(^_0@0RN`95hH%F74`> z2Z?5C0l+tMr=Niny5rhl_RFchFS!x7K=!S0k>}0((+Yc435k_3jP9&{I-*=cavxQh zPhW{laVpS{VMI4|eaP-J4nqJHO&4%G&0v45<9h!aSLU1`It#an{64LOXrkg!3?R8O z@9@*Yosld*+5s1@u0gRNU*a@)+K##m7H& zyLAiP2Qt1Z<()trplQH_>;KqrAMZroqpMXIVu>WqLMFM%QVnt=;4_z;KD4!<%vCz_DCD zlNc^}HaeDnu=bFqL3kRLtXcRhtouSG$8?4-f-LsV2Pp}ORjjmNFn(PdJC22<%_#2; z3CvkOBObxV^g{gez&NH@~X5tEEoVP!CE6GcR8v@GQB)?1Zb$y8vZD5iSJHV{2iSq0o zmRsy5omSUwAW=)zL3WxS>y`lRI$05S!)`CvA02tB#zEY)ZO1*O*T-#g2_#49w<;ZQ z#B)}Kk#h9=RA$O&4S>){kD?U0_3}j;8?V5 z_+AN&~OZLWt;Q>VSR{> z64Bpfb`@Y<4D7xcEgx*Ik+;;+F{j_9S=vw|rxZl#z!H~?Zt>c=tbiQd5a%VV%CJJ7 zXVWejAizu`e}-JmPLNP4fZSBf&1NJ}?N@KNcRDH>A2`r0Is91-p#OOoa54JoIA z4Vfn*VuYG_Z~H{dR%7&3a6XPl&Y>kfmNd_^V;3CstTiF%q_#kMsy1Zcxr}lDryKSn zyq)uy`zc@p)v@OTFCBD{vRl;<8UDh(D=hTB>V=cBkQK(SVt0@yJiGMgZ><9c>Q5^g z5A*=teDX57S(GybdvV?U@f~ZOEV7Mo=R$)bpdFiAe!KU5L4{45re3*~?5`dUP2u|d zU6&1H%tM7`E~O-!$4Gc4;Dg)Ee6q#;l>30XeKIP>OnVl<%RfEdu`7tz%ErBGk?@z` zexrhO&(cxr6@|ag_F%dD18!WtPQBj#1D#6$2d(DcDn;Gb%Mz*8%SmTPu$8#$v;J8R z$_3Su`xKU{xAne>9$m7NCe&KoS#=Kcw-oO6&qQ7T&|zDx^QZy?nz^SP^L_ zMIRIhLby1~tUcVO_`z3UsH=|BOPn+ln=|tkH9IfNf7<>;m88ca=LRRL{Ky)}uV~J&zVCD=TgM0!C)p{SGTTBX; z>qPAl5M-|Sodx}QjV>yH=BKT|vYGMFi3Ol(UQ1r+@4(K4>AjU8Xn)M1q zdw~aSeJnX2dhI|z^))(br}^mt^u>Ncyg@m5H%W7Vy>soXx1 zox(Yb2~Tl>Q2NOrpchtJCKJ)g^7ZmYyZfPdLCVV`)5NO;poSqkEo2fPZ^)Cj{@`=g zg*-?br_6Dd!zesAtOHgUVYuK(!GpRz!s<(Vfs#4TjO9ypYi}k}T_WuLazJjg2#%iOVy%KfA8F z%HAJ$4GdskP}Y8)`atM|zZ8@{3t?xBcbc62>go!q%1LvxM9(!i8MRfUxm`X^fVP7Q zATV6reg3G;bWiR*R=|znRK}LE;1Et6tLDk(?=Bwgqu)_mj1ddPF9s5}z8cPCB2LP; zjJIc7iqvmgVTsrQlEmB2E78!v60RR9X%YBei`?FX1YlDON^B;$PT?qgnh}%d?s>n%7 zlBu{lS=!ix0Duq3-&4Fa)PLcGPj>KjOkq%vQQs2y!jsJie!zxOjg$kcK!k4%S!i?vWy2}VrLho$gUlA;uhCQndsL;Q_ts+U;4dn>j1%AxjI?4uOK+)IaWdV0x+!TS4i z7O+Lz3R9N~joZTe=R^u#Nh%lsg7iF(&?g$)J&3RB^#k}E?@%MR$@Cmy>>N0`@Oc#! zJN?!6_r?2+Z9mgeX?Al7bSLoJxw2x~RMs=7xAJ44at+d`H?8vhVL=@lav6ZV2fEqW z$4mtP8&}@?A>BIhtdi*LOm|`5`l;*J2FWM& zSK(pbXU!{`)5$FHm@M55`_l^64jjNemEJev`p#rcK!XE}*xpu!@&y^-8XC~Bo_RwO zW^eSRe;bJwG5Yk>-VK;-$HI8X`sq;*@UP@ql%iv>c+=lQMAcs#VQ z_@BPpVOe_^0|G+%Ra)d=hn<80l9Z5Cj-tL00Vn!s>V{}sq>id^EX25dmu0pVBK>NxB^+&Aec;$iNKuBkn3cC5by^y$P`GH z4-htDP<7%WOMjLi`x4MI*wz^^7w9_$r4+>D3}XPL-Hq&why<1uLkR2n$Oc>ww1Eq{ zM8nP#FH68FKuwoeKqJ(H^N|!+;lqL)kc><~`y%!8vv1ZV>Psu3iDlkFYdl=8;TgvIS%*^+O;5kYD0#oZ#j1Tcjf z_a?!K4Z}fB%jm!nUP(zL=uiRC$?Xy;3Lr|QGZIh=2!F(WNOakSgbB|zO~b<(#NP?m zjoC8OGF>o}XPZwmPt#Js-RH4H;|zQXDm0s~Ez+T_5cP!TLH`!Z+^=O4Z=zq5S_`>k zdMZeSGSrQ~P2~Kk1m+>&^^91)FD z5|&&T6|Nc;eR@NnhMX;hA&oFi2YJ#@0Sj4IJY6v(1eQ&<%y&v zekt+G{}A&L^N}o6LoRWg(nR=7D^RqIkJkc)sB-M{v`Rih; zSE?~fHmx!FXZg3Hmlg=s95RN&vk0>cvq-bxZSDb8>h>>z zUz#zLOT~_AW~d9v2_$94b zUj2v~OfQ?sBc~dEVN6m?TTJ{7*Zz;moyirRY8#{XcKYNe21f?}WQt_VWMFc9nS!R% zJl6d8GKVtdIW}7wTT|O#w$Jk{<*}2+lU`Yq-;KH6cVEJfYg!|HTYlT#^&JZzClO>2 zbQ0hbXcDAy4RYgWIA;9J*vmNJ8fviCLu`c7+tWK}G-69mKOfVuq^^(V&#kOFD`uV+ zDOf8Pt~4*H*Rjf1s-M6#{KBHoE8c9-tnMYD{E=0M)wo*qB3DE;yE40=OSVh@^GNp; z*|JHr__v;t+^F0x(=5~cEpy7U#PVr|e7$_ZK|b>)m#8a|9etXb$nSDrQ=}snuPp!?0!zr%kDC@*d@$ z;+f`|9acEpJG=wsVaeT-t}P^B9{uESt7YOUW(StmkG6JJu6X0S?gae=@?{vpeKdWAc=i0fcC&bS@O$xD z8Hx|80{#%807?c*3swY?10Dm~1FEkF*wYq7$~t3AWiW>WA@L&V87c(Njbw=Z+YOI} ziK~L<)Tc$$`;)g96tkJMlw^O~hxp-{VcF41QF*$SKFq9r4Bt83M%X!L;WS98KV5ch+$$ZOtV%HM(RE=UAtWW< zKzonG>@D3>sJb=&;k5^~nA8^j{N-Sf@gVlf@DcQq2$dRA7cwoC+HV+XE>|UoEw=-q zEZ(^3QD=M|xLf));cGrUXX$k5xJ^jIW5cWjwP{ohqamj-Z3k-~S3a9$>xj+#xh7_w z*mR--otv&@TUy+k!rg}$s&CZ6x`_3*b?a8LpzIOVG4%c0-HctwQR1IBKc7EwTXK7O zSao{7g}wA}pWC5ShAvbYto%^&GVE#Hy6ZfNcOY~4@au9^W;7N=xZxPJKBt%8mcHto|+EmM6L6I7dci}(hPlDZE0 zYFpX);^TtjK!W&;{f=Y5=Ckk1Lo1728xEgmfw7PSup%T_MD3r4A5`or#T^DrSGOwq zCQtH?Tf3}28-JEM`*4*wDH|$VIMf^OF)ui`$Xmkum8UoM%V6z}%aGIS=AEP;X8Dl{ zXa0{zC_ZxjtL>pj(u*u4pW6FTO2_kyW@@=r6~Cci!1sWTv#{6L1(LR`6ywuRHb;#Y4jo6%^{**Am2sWW0SCVg zpIO)MTLbpu-oFz>=tdFpY4{MQReNTR>R_=qIES+SOX^=UVt(2XNd5T%{t-T$%9F0kx z-3jfYe`|V3o-WV+ao15)5HNRgU@^6DG6S)AJ2?MA0{}wa0)Gx2K<=hw-VXMTZUWxI6n`TG z{v7{hW~Cte8{%#!OrfKwLMG|t3L@iX;bLK<5J4a#BNKA9uoO^}lKD6N&zUfVwY$5s z04uAPmlul{CySG-6)QVGKR+uQ2P+2$^B)AWn~$TrsW-Eu8|A+S`G4a`f!xepZJgb0 zoE*vi8rRg!$-`Zkg5s}0|MUA-p6)i5{~O8C?ccKg2xR@s!^+OW#`@oAAa9%hgZ7u_ z|D;)%|BotX4_EuYHCdRmg6u&KAV+t%KRovT8tzYR|A+YhOVZoa`Cq~QF56y5@%*o0XB ztK&b3l1}zcuIkRF=Age4`4x{^jh53i$A4Cgt0XGjbTadZ?KW6LCoc+D_ zB}}bY|6vwl{jX@DKPy2%(aFNb(nreF9VEiR#?Hme#?8#eslmn}z{V}W{zvYAVE&Q8 zUmi(Ukg2-4y~y7x9R4~b<7D}x`ak{urV6qC)kXj4s(-cY-_}1pD}wNc`TzP~ z1VJt2uo?iM-jI_L*YF0OWj-Yt4tNYbpViySQ)hK8VDcgfx;}M-zTO>g-rMzj)1>Eq-2? zmG46J3K2Vt)7$XbfiY}IJW{iaNJg2FVB$qe1kOk{C042_JfM%h8~3In=R9E6NbizZ zkk)~j$e%y5J7kIJEs}i*Y6>%uW}(y`xs~?`2wZ9)i%(>w_SXfB&;;^F5y_m(l1M61 z+(aN%ELr*T!r<(BB}N4fjtID-_(1x=K9yhraURccj>CiE%V zw({3aLC1`otSPQ3kKDVT6Hw8B$?0Cw;}t<6j)VEYei6pbYNJ(bmefC(77(aM1`O2*q29RpPlUVA!=kA+nroKLL}ldbwte!TMmLBD zaqKr;c@{`a%%`XlID9Kqp=To3dHCdcXUEqx2&#ZeiqzaSf~9QUD5QO4)oH z9W#y#iD1@KfhkEG)fylp1ET^#@9k5_bFLa_r1PU*L#%pslJJ!RAJe~6U{6%`4aEl^ zeNG=jmCcb_=bi3P`EZ9969cy0gRt+8_PG~8nlw$dN-+s>#H?>VasF=-$`1ftm>kl zs{SAWqbxYQRiUrxbttZ=?_urRJ&C~AWk5RKi?cZ;ww;|#OB|+z9zeY-)mB<`9#9?! zmqPYY;2m#K!(8Wdz&pkvR8A61jDc%0!j-<5f5yYpt?BcPXSs{TT60Wj*0G4c+rQX& z?njcRL3LoMluF?wB`@^$I0PNd0~sp?_DxFW$RdG*zd$sncbR##>Y1o7*LVM01p)Wp z?ipEG^5#oCfQGmEJub1Z6FZ>Mv8OtuM`dmkH;uiY)feDsE$)6Sh&Euc0XYpZ^&DNs zECiX^`kQ7ePMILHH+VI-izjb~c~43qEUW*m>FAL+Slodxj(AqP1A5ynA(Hf~O&($R zH|VKis`*Br9-$t;DqtU8yExoQ$^6)yyFkFcg23x-Qps7MMlkW~{QO*-KmKM_!PbZ^ zU~$Qk5V6E#HCDhw!Yy6ph1NttZ}Slsv`)zq!;aWUF!C|qgu0dt2HY@PeH?RQ6LpKV z)}ZP^YO9Xc0r@1H(^dQvLd&j@*B6}D5ngO_EHEeeDWWBRT5Fxn;&`=&4}oZMC&Km_ zqmFc#V6wYCm~9fCCtVB^4F?xzHeJ-4T=?w3_Fzhs z^Q%r;uyEb^L?-5vbw`S6`dS)>orO}=B(AmWN5B&vVa-gkfz~0xFRvsez1`4qjeFK{ zC}UphjBEO3L;N^{$L}W?9HA}Ua5=CzyhvS$VneR1*H**XWJAQG=1c9Er*t2N`VCDV zh=tNfJ|C?d-Kr}WrKhKBm~6DBvJ{H|;&^$@)rjrQ!s`}J6>R(Fd=cBm$G#&$kxw{= z#~Wx%8@eXejA1Vg^xF8I?Z!$^yFALWod76w&I^55fF?pF*ZyJ<4sc!(OCpvdJfq;@ zLbBH2x}^G8+jhNmNH`JPgorGN+g1`c=U&qoN(fh& zjhqdeqr3&ZTb*E);Pcw<#IrJ;G&i@;%)->&o;m~HZP!=wb}hfurdLg>yy2h=gEVCr z>OwgP;G+??B?s^ik}A~HSvSuB^m%GXM-VNh&I`!NaQls9V=fM(mItulsuZyMUB^-8 zQT1sdA^S1J(u#f-*)GANC!WnjhfUeL^=S};VF#QgnoC5kP(>Wn|x$gjRl;znkVh5@|ch>8+B%AX=|%RM=GC` zsC#6T5jz$nx)3Rz6W%A+5wxCk4h@V?hv<@Rlsn)QhYOD1MxTp`9SncM@PYS%)s^(u zS_~y*SCRb9yxTS$@L`9sNa3z1-Gn2UX2f;xeiLu?7nemEDd%R2^h}?G&Yu%h}{c{jCnna!98AG`Vcx2 z;;7()OW8&9I!(8>Fe$-pi4>jieS$5W=6KM9g{)8xq~Jt);mD{p4~E# z^~MajIpOmHc1^pyp7%J`~WGPxqyFx5B{?SCk1{o%I)ITT;p$M>_zF0B>UMblaP zxWnka4bLBZu$HI-^#zmfY}jASjSBN{Ke=2hXNRVi(w))I~r-%R@{P3CucBN)My>1!^s?{mC!si zgBs(0{vZ=rnnlvWnfO8uR{v0gHZO{TI7)WYzspA1&(Z6Tv5f zsekBx>ZgJNs&pq;}t`if?BWgh(%F^S>o)hJk;B&YuZ?U#}#M}EWOLa>p4E2`^3;P}laEkG(S_1$?E@CP} z&alo%8j{5M(a)_E8P3Bm9vD5XcAMA$?G_U{fbQ3B7{OprdM-X!cV2ar&wi-0@%Ibh z9c;rz&PZ}S@sM6asghYqYjET*QTG#a6%G|P!G1@e$1o~{89oYnbS!~DkHZ%-bz6i@ z8;f-aV*vhPG)@U?nD3{Hb*@3VdyPUJT_x^`n_~qb6sWWi6KG3JEa(Jg9dPk6!W{RM zg`q(bFCNMafK<(^Kz23Ww}xp6Qm02gUAK(YIt|y>J_gQ$IDEAaTHGCdD}f0>#MTa6 ztW)9ntrM{MI9b9%29bqyN>(dtbr{Z`GLfBQ?2W)5*1{pXbo9aQ=3EwqBGv~7bt4NO zs{ZHNzO$^rIg+#cGhYqmwg6!6@(u&VCAL^}!KCgGF2iY@$g+h7$u`0`O_OH`g15jh zcS<=P*6n`HYxaJ@Qp;upbjBr^3`sQHw3K_uI+EM2m103VnkX<)+mvjlT;VbRWC}iL zv+60w;gdbw;c3yIA!)*|=3#?ObNKOWvDR|uVt=J!%#Klh3GW3#Crv61#kRiU3+c3r zxw+LZ4n8t-_#O&5e|EnOzW_8DV-VU-TX$XIm)2gkU(pcC5+L(o)JtfS0Q3WkF8`LC@2u8pH z#m==F!h;q~>qr89$jJ2{8VPJV4qS1nSsH@PZqYfa09dr~&B_$Ng|B8-bi^7yD{dV0 zLd`EGrLgO>5L?FQ4JtSeH`xmD65i9>6VFD@C*MmSt-^r8sp+)Vb@6Ggvyh(b3+Q~$ zCM-ZrVvp6;Re8fEU*rqf^hebgILmcmD9E4D(xLvs5U4s~Sl*AD@+Jo)VN@){N& z+c-zmFyL><&>#*y|;!Do*3dE8@UBbX9e`q_F{6gVEB&Qm;y~n(&O5 z#5pwQ`6Q{(Z56)*ZBG19546eY!KSG6_Rja&597aZYzbjK6S^p7aeVbSfm6{8oXnS4 zy*@OvJ{D+lZ0xV1#(-SH-H$FXX9YgTkoG%xUDNptn$+26K$x-v1t>>~ph&o~V?sc$ zMEX7(ae3KMhp@lLN{QTXbi^2!hKopo=Gx$C53h<>pn7I_qeZd(+!uJ#=3E0cHqqlb z9j*>e_3*-Zde1DufvxQdt58fvd~2c*_9{T;UGEv;>mZo}(`e?{(kzO)!txH&Xa%3= z9moQj_Di4U$iV?%Dpjx*yM*o75jBVxO-h4Z%K`}XQWM!9)+dV+{w;5XGR!fzko9}288UiX=0oTyIRos$>0SSbC?@i<7^lx2x|g?&sqkUDC_k85{oTa zDPlDs9&;t&u%;RM>RW~&LR=kWgXfc71{kCwYKs3J$zMb8Yk3%*iB1R#S}dTph>;5t zp%MDjIl~J;`+R$*G0$^WmthHDB!gDIZ9z6C+n*t0B9HmyusOd63fC$lHMhD9%J-h* zRy*xC8EbJ@@yE_t7E~tH(>g#Zc>OWY82qXEMEWrZ8*J3_TQ6<37kbtjbG(Iz7DZIf z>ON62m+9)qqsZdO4n$6xJ#O+jJ6&pg7J~xZLm@;0A2{FeQ7L@A*s- zx`eO)e#VkI?Mu2X|5AegGdF(fYMnU+EW3IvWE+B5H1s4$z>z3FnpSLbeJs-Cw9k!+ z7TeY?xNOxQzkl3=uNSr7(N{y%5~IvoM3Y?$R2_(OA6vz6d8%bn71|=FFeX$*Fc@2HHfk z#g2$6pQ_2C1>;HUZG0QEVg^NmqRz;Q4O-(4CdS`hS`<(kp$t=@V5jT_&+dLk0^HWu!=WYEXgOG{&>A6_1#x5YynJiSJ_I?bl;&6UXtU_3GE5Ujo1i zw#{CfGk^Fn^aeF)l3GU-x6v`-)q*2S+%ug8mv3W6)!i%l4UDsCc`vQVxI(f0Vy(zA zKkV9U(%N2_eADPgtqyiI`1riUc~XtSM<1_;Wl1>PD@N_b{X)qKNgr!ZYB@|hLhRw| z2{XDUhR^j>m6xavr1S1<;&eQ&Xd!fItZzF^G3wobB=2y&F;jimFMys~z9+!wPLvEF z-Z;!3$)BLo5pzz^`a*2!ga7%1#i6@3CGVROjZz~5lKz6~G<9cG%Lp#oR`CekZzMvz z&D>=snjho4I8(PY7I|xB*bO)pJr{qs@Zr;kF+?~b zu96-QL%-8U+mROGL)2bzEIT(#zQb|$83RB_G5BFV$N3uI!6x+o;KG#avf zlrAW;Y63_45-5nndYR`FXW)nWp7hk7GP=TNx2e{z{WgdRi)9UeA*ZcVqCT$Q?#0oiBHzicp+#C69f@!wgmc)cADe@q7=Y;Y-BKlqVdUs0u4fC z0OyWX`b26O%nAk=giY#xK7a=EsaPXCZIV0qXNZUUE5-;$5AzT(;wdFaH#9917nIeR zf7G6G@M5j0r1ngZ!)F@h=0`iK)R&ZF#5?Y6!77=j0H~DZ|A~~xFrw^Cz|i4#GK@a)l{z$X zz_MTarJn%YuS_uUMS*y}=X>ExZ>J-c0t0ny0(Tj8=#aN9;Tj74JqPHjfoK(Mo?ng; z*xxDO`aP063PvJ)uQ8r0lNyznNC$h#Pp&QS^#LT1d0FExkP5Ym26_gY zb78XGvqm4L@GSAs<<5**(8??*a@k$;}l7SENE9?KIu7?xWYhCd9byWNxuLq;E& z!11|A9pEI}p?=&p;J`~GcY7hdO4h}PI#=AKz`$l8wEn^Hg0gMqD#~DxnolxY((1XD zgx`DQ((X|Y7Qu7Iwjh3p{(U7e2y`VzYA|YF%JZC;0_3?k!ZOcHW72Z4#Z9_O-9<;O zvQ~(%7TZ&re1%Obt7bqvtStuZ-F}l66*(Rozg+qHWA6S$CoSTQgS>M(EK(%oScR{P zVBGD}^cmELfJF5u3mEuNL2(MDBKSz|isOS-gCo+vur>sys!?iSs+hyyy{4q=8TO1o z0Co5Fm#b_{mT7TN5NK@b#y6nJ;D|{X1Tr{-jC%wS*4`;pPR5jA)6S*%ILwSZqgv&WR*Qpfl)Ap$F=s`yywCWx$1-}6f6Dbhc>=(D z#d~kVX5g3_&v%3g1v9nB6MPPxT!!EiV8-)aXR|9j%yQuiNrPIP5yr!mF5z?(XPb%) zZ|x&HR)F}~66LwSf1g;#geyaVhvTzQ%TSwh12(Hhq|2QUVZ&S4$seUDTe0k!a{TSk zWbDkXtJ5%D_Yuc8qv|;9{ii>zaXSZTtGrbk=3R#vVr`;@xZL&$;C4B5mp4Ley_uhg zM`Vkh#H=RhaH|9s8M-9I0gISc!U)fPhC>Q>=-u5-YFJq!DDYNX6{eeDthY5RA}I8S z;;r3IS!cjGmXihxp3k0UfU4}pz!+>h|LG+QbsFt6fW33}-n4ERhtjAGGVLN8(KzC& zwdrGP^vG`l3I9p2aGPYIpwA*Q4WG-ds7^IZIW^6-)0-294lOnWiSpKiMX3uL0|N%f zQ5z1YgEgI`fS7I~QA{y%Nz9)te+%3afGuT`uayn&W5_pMh)-kvs~Pvx zS)He#FEiRPmfBSQ-RX3RDcts=-9tV%c z9q2JlL%ZIiGiCd&F+`AapzAI~6RRnrN2RA*BFIICAGeW3OZvkFz^S6I!z`hk*n$U% zvq;GTEMC7|m1_DaM|Ofb?J=>Mbiq=vK~lqHYC|KpnC#uqn6c%b6ziSmt_Z?7B00sy zM>n7H2kAv3Y(bcmHpX}9Fwyd;+?ZmrPs>H3aM3wCF9O#eE$V*Dz<>6HRLPv6cn=f`WZI16 z-3VGYHpOV?M1Z;W{a(E#3ofZ-B>$>P9SA`f7(`rq;a-O!D=d2A-+V@}+bvQp$CbvTq-$!=IdgW_qtA+Ot z@Fb9~QFc94=o)-`vbD@+9QGSlPOOhuGQjnOoI;>@McnO5Fdyz|_Iq76h2ff16oPZ> zYX3<&BD%k$4(BhVZHcX?6cv7h>J=vUdn?}^u|`4F@;e;J>@=_20+LOPvkGumAYFqb z!uIA2025Tze%oBK?Pe7@A@cayj&olXJLqm=MBCj5?>0I}ZU^)h78yOcMi)!vv3tod zfpm387Y)>d$>ZhODN%;-?SHVP&o(7}YU7xCi3(*+5{dLrGDaEi3d;>hq_ur`laNbV z4byU#AJ{+@(+>Uv%wshcY{O6Sg>aVGZtbJ4sQL?%O*8 zw#tcM8$g;EkM5}uDDsTZkmt#OLd4#zQPaVXiN(;U{m*;yLTsb^>P^$lvH|hHgxBXm zGDC1;h`h&VvENn^I;R98sA9T@Q7;^>Xjl2YexFy)xc8r8SLkWZe9vVzl*tLehl3l+ zy#!5E>ZvjmKQ(^g@gf3LcQKmnhv=p|*`EkxA51rNG}o3DXR7KxASWCL4OqOFRBH4uf!Nyc8PC~$Eq0Cx(l8V zT$=YMFXEs5l@#G4->2voH2zQ~*ZP2Jr-x%=o?Tgh4WY!m&rZ>2YPu&Xm^lMQrs#Gg z3(#Y)OonneH#mM?l^5E?HZ6j{9wV~_hbx3xs{h>Z?g7eZgCnF9Y9c@_IC+lQz@Z>} z2qn1Lts}XyVZ3}oan3V6+r`i_P-oF0w`!%q>oMUswmrR@dH>aW+BE1% zE4uSd$f0EM17VIHTOCIA%2H&C8EMW1ZXxq|bxD;Xp7sHlOy}S{C{?~ksC#AUw1{!- zQ!B&`)a1q&>xYT0xi{;^p=vQmq4;tGzIT`>_U)=ZpAEKEBrwlCy)`V9TXqohiN6|> z-3^;L3}CkdLlDOdvIS@fPn86NI!tL&08QHs5rWZxQv%fuL0uh;^ z@Q}@aM?c`GrU0W`h4NlFIo93ah*oO7)3>rx8jOeU7qxXkiSw}yJ!UQ*ZQ&y*J0EO` zFIOE79XsO2pMNs2s90vXJ!4aNzei+BQjK09@gn9B!{=Q{LaWNKkbV4f>jb1hsgZ+C zuL0~s!X_?QS#%d-^owXnA%p2NfMtxVF>~Z`nAmvuHrLniA20dT1-KACW5yEN^j%*3 zZk6}f+4bA3Ouhp+`h48vI9YJk^k+VbcO)9^azvUfx8s}pwO`uAq1^ZiyURo&=g6>% z0QRJdSXWuu^f@7_OJ!Fy#K&qxTbU5tAQsO^%wDb}dBcwXV^ddv(qRsUe$7$F(@@qPfG@@Og9T2YtI!odF(n>APm zN@YdFbDY;wpzn%O60D{e0KeO(?hhxrK~!YCP1UwTR+81qP}TG~{sr+`#C3Ko-!Wtb zdTOv$OyF10gY59lu#E*yDf9MfR{FN=@{){l`OX0(;OK&lBj<%h(ZsYu)ba>WK`L_$ z^(+E)*lV;8wDd!u0c;n$^g}@Nk${im2QRiDxag!hixl-A^vQfcvGcs|6Ov4KbnBA0 zH}0CNO#VTuU&r&;J+_np4U{%T%pdn#8godWrY0;&o%ch7DY>Ih)q`C7$(4{EcUopJ_VI7Q@lQC zQ|{>aeRmL4!PyiGmB?3;z%ku0LdT~o_nH@^uB?=}vCJ}qFj40L7gQhC9&UZ{DWpYs zR`Cb5pX}>o2;PR3s}pO!*^W(yXskb^4-tPP6GcimXGes&*H_{pQ`ZzRmUoH|Dg*Mg z2HtK7jWEA5A!&NlIG`>Ol&+pjj&#M^qJ(d)j6i5D*tUlrPpn1ZlS~y| z&xObn?8i27%2AZvX=6j@RZ*Va_=IgiTpcpx;>kw|b>wjjptN zl(r5?SZM`DERP`~OXNE%SVZOx*ClsKkw2P=vKe$@-E8L^;l()27bp~!DMlibC80!7 zwd9C+kZ3}4bq15J^+T&w`ygR4ffxN(aT&s@!wUcMI@_uup!}O}JjyoCr4BudKs?z{ zqVTW+{cL~d=weZr92F0rPkR3N%=@a0fg<+V%5wy`BiJ7dmtoQ>c0op`ZS4HW0a)d? z(9{N76df}mLNBz)vnDKv<0^=A!DZ!?W-W7Ts{@zmaet)PET|`UeZ2%hwz#RS>w}?g xWss2c<$i!yBLX>Q>e@!Qe!mB_5W>BX`Xd^z?{}h({q^~$oV1cum4r#q{|9$U%|8GD diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerButtonGuide.png b/examples/gamepad/quickGamepad/qml/xboxControllerButtonGuide.png deleted file mode 100644 index 287d32b8bfb06cf3692324eb4d18e1760b3e58b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37297 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 a;Qs+{Z*Xa~eXzCw0000x+54RD-u<6C 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 YImVQEt`%ACU%PeXq?9G=#ZANiKRZFp9{>OV diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerDPad.png b/examples/gamepad/quickGamepad/qml/xboxControllerDPad.png deleted file mode 100644 index efaeb16e95a7b3c753437ba221d9b608a3d9bcf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33024 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 diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerLeftShoulder.png b/examples/gamepad/quickGamepad/qml/xboxControllerLeftShoulder.png deleted file mode 100644 index 9b084df91c344cd4549f8a81c7006c5d4bf90156..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22224 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 Y0ed=zkO3WlrvLx|07*qoM6N<$g4Cx`!~g&Q diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerLeftThumbstick.png b/examples/gamepad/quickGamepad/qml/xboxControllerLeftThumbstick.png deleted file mode 100644 index 08fbaa2f909913e82e5b3b6670e10a7055492baf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28966 zcmZ^J1ymf{((VlI65QS0gS&fhx53>VhT!h*!QF$qy9Kx45G+Ut&dWLXzW+b(uKQ-K zp6;&tzFpG0dTRG{q>7R>G6FsV002Oim67=LXP^0J%Y%dY^G&8x4gmllh+2z_tH_Fr zld8BlT3Fke0{}9}xoMv2YHQfxv)w%1b05e_sqXN7;7J$wWw4-BBW1xV5Md$I9um+} znCNtxAoV_=bU3-0Bqn0;XVVq<8#I-XepLy{!>t%w_^TSO+wH8^QJtN&TNDFTsGmXg-Ll9J*1TI?HVbh0n|5*W zAx8ngikWFNbxd7o7s)P(iFX-!0|9_b8RG47L5Y6kwaNo{m0BJ|K}E`%mZGm@SRbB@ zSv*}gsXdyqF{BJC?nZbi%-%I4#j)am>m1W0fmAy7nO2DxHG~%zI?G2^kG*RUD$vptN+;cm6^6)E5b8qmC*b4wg% zXP7j!heU%IeSU7|3e2}vQ=7K_7N^02h5R9<3g z3JE2B7WDcX?R~$G*Lr$S-aO#_P; zkZX%+7lV9jP-O`)g;!r#PI>3 zDu|M+9o-|vgIuV-Fya;MgxK{%d`N(GD?s23VrGS4G)5)_b2ve6lLA7(GH8%#kjyd= z)*?`iqC%^GrXbrY&?DH!3Ggk*XAVl~Gq)3rK9p7;vJ)Z_SXu-jtY4lLxE*8-_xUFp z))&#r1ngqeOtED&0$n(7aZ#0zn2^KbkqKx?B9C*_<+$|0m4)Ief_D^d_#JQt!A}LS zbEKRwuR#A0^bCka6XaFESMXXrKOvm-z~pxcFRUC`oW6}+xi)Mel-2>9U4owg#!#by zWH^yAILLV^Z8(B!39$riN+3F!Z6bLwM1^El0!lGKd#p^N^8qAGc%exKF7^oCez;D| zuBoQUvZ);FQifTErUK3pw*?wU(BtP4)1`(|ZJKIf4|s0$>{zBDP2+fDz54V9$W@bb zenOPdKD<3br+_wGeRc<~TBugkm6%TO*&y;R^|efy6uU zBqO~v3Glj5wx3bS(nu-oDAm#M;f~>6L(m5}RfEcv-N?hxyodBn=^ElzMZ07Psg;s3 zWy2_OK2g$THV3K8+K?Mi3sQHJC6Dugq+M`zL=2T{Df3BAA`6szD}8B$Q0*7#R|_ht*DRFUZ5|K|m6go;l4=@Znq?Yk8ob9ftV-3D6qMBZ zLAgTYw0?oAgbZJ7vBZ0!ty!^|Z{2*Il}MVW_<1q;boh?sr27uuoXTA9koJ)95dW}g z;uFjOtMLQJC%lrF4S_SyZ}4emN?!}l(_)JJ*;dcRciREtz#YJ8=FhT{_E zQf{SvrSdmc8)_R9n>Cx~CFZKw*|J&ByxCkM&i8|t@E`RZkv?rtHopdc2>wXM&%*D) z$HUjaPv;!r!pm~V8qYe+I_4a0w$epxfzmzHJ#H~%P0hTVQn#RLismh>sl6y;nineG zsuHX*D{s=aEK+Kk!7xZ-*5eUv)o)ev6jPRG(PlBKQ@tt_Qq8Z)FYcA@)eD^Hn@~?VDcUuos7$Pyr!Uei;ve~F_SHG+T4-O7x;`>jHc2*iTv2WH+qSxK z$87T~lI@WdHD?u9=jfOEO&y(TspSIRL4h&9BJb=+21LPV?dV+WEo>vk3r01jGe!~} zIvr?j`{p0@PlM}2S+)jd{-a?w`({lurCUcWH5E)d9=#X-{80tW{_u!5Rq_x;(TMm zb(weGZ6kC^WCk(E7Jq|!;(wVijuyP>5}s4+Kf6)2U0P* zF{Gt}*dzp4zLXv=6~7m@9H{+C2}UR+2lzpOcP97>;AF4Ia#25~0#V8bjtK(uWKp&17q3v1Iollto*< zyEhu$1RYeQB%~D4aa7D#Ok0OEKQu3jQJF;5GZ=6P(sZ*7au%_QcT89>U20%_5t&a^ zpmo);=*)W?H-k#K6X6@&s)MTtV!Hz@J_BYi6)%qS|tEQ`? z5wUhL)!lBU89fxcVLL3li!F<$8k>!Da>MywrjvV7d&*RsNoPAc{#uV)Q}-bk-6i)W z&z|2s;5;|CPCIV3Gfj02*XC-!8`K<5-F&%e?bJH&(KOL>Hb%9M2gNtDmp69H)!9fd zmHjCG5riL~b=3XCxAh`-eRN}`cgH?(5f}?O3@b#8N!S%Q_FKiaM$~@TWOKKAaQ5uW zkB(l;K%+p33z_T0S?N&elF@;9_a**sD?H^qDcl3GNh1yW&ZCa6-+zhwVpN@~a1^ya zKz$_Rz1|yrAi2sz5?J$&@~=FldCkB7I;R_@Te!Tr9Qn1F+uB#bcjpwmm`gN6#3Y>k z?spe+pPAJ(VJSbGID?gw&71ETa3eMndL12!6V9jQCe+b&R69Jcs_SqnvM_sw4Fc86qegA@8Nw~zPCRHog6HBT3?lxMQvC02;T?27CxKZ zjV7L+D?ccw=En+q`oX{4cv0J19PRuLxqW8m(+T*~Q^GsR=(qv^h!}ruKtNUwE&u>U zX|1m9rmd*JXXa?nYyxsLHD~s+clv_{00g}F{v6tyyP1%B+1oj|@_7l8|Bc}LbNrW> zg`D(nh?}h-xwfJTskozyIVl%2Co?O#5CSPFselW}g71@r)W7L}&IHM=+}xb_SXewg zJ()c@m>pd#S=e}ad0AN5S=iZ`{veoKy&c?4yqFwZDgHIc{~brd+||s*+R4q@(Sh`@ zaZOAe-Q5Jq$^SC+Kc9d3>1J*5zm^|PX99YcM|^H}O=f4^Fr|=(yzf#YqV(n#ar!8UqC!v2w!N$cQ!17-; z|H%}0v~zS(b22eA|I4$#DgO}tC;D$YI{&ou@t=17q4@_BWX9*}Zfaw0=Jt>4_2;Vn zJ^RH>ELr{`7GU|WXn{X-fltv9WNqOsVd7>k#Lmjb$;8UV#LA)0#>>ab#mCJn!15oM ze|YehM%=~R#Ldw~-O|2ie*VEz;Kf9n5D6=3$QrGKhc2;mR& z|K0(F5U9ClasdDlfUJb5x)<=GJF?Y4+GE=jC=i1R37p{=yVO*+b8jtrHKu)Y`7#zqDb1wUNbb%AC${ezp$c3nMs&526&ZG2A?#7RMM!ZY4b-NbhOjq1CQDK}B@b zc#gLw-w2NUNz-_2KAVb&Twk*QpzV9f8%lg@1$S;mM{LLD`d z3;V6oYdG=1qI$buscmtXJXP=g*ILbYk_D-JHL*qVnBQkHPkIFE}K0E~V+~UkYRI zs&MbUw%-W;an@*6Z3zMrh@05bc+)hwuG9{%udkc#Z2LzO@q04g*VVBsd$18ru6jH~ z7DXHIbGdA{H?_H+9qn!MIwg;7v^p{|8+BBd^GDli)iFA3ceS_q`>Ivny~L7XsQ~LS z8UrbwwHh5KzC7Ya&4(EA-AY2~poY#?@EE2*tM8<~W-$(ut|Qe9cTHH70h%qZwuj$d zVX@D`QJCTg1#O%zK8$(LIfUzb)$?;6_ZIaM@gKNmP);()uJH6JN$AjKG251i1o4=sG%baka+ON%NgvadW#k{eG_#VoEck_FdoLf`%rqE7T6K^Hw z`D1VVI^a>(NzHMb1;0E|m^R#}In7@3=c>k?H1nR}p)Fn8*}U#(n*0Et>lb+z9p4L0 zT<`^YpU2g94R2a=+K~>whw;2d2OMTlc(E}iKEi!c(kkKETaRQpZS~v4hT;!v*}e&2QXTXu-fC4 zb#V*FexyGN>Lo{P3oy9nZ$z%mwfa&d9nWOwcbGa1R9yaT^>MQ|uvdiI7}&Ulhr%_P z^!3vOH;hEsR~RJx2|ffTbVp2h&iiogr2UEqbCy%;=&#uW5xGYoz|Z@O>}Wk6NbWxO z*Qcf7B?c{Ql3aoIHmA3oMLD6!jLvSF=PUDfZS4BOwH}qhlP*N{`%xR*d)zl&*Vn9< zscyqWNmuKqW_j1@V;q*QmkHAyA)x%=en7kL{l%~PHqAlu2?W-;c^Je&>;P+Y)WDKR zhn)|sVC`%A1$crFR^?(#NP0S$Xp0h@#lh4gvsfbDV;XNn#5b77jmQ@;tF=tEvYok4 zKM(fKGvm86L}C~>NRf&H$u^9i8(tVa@hpT_j&32?!=yNu9LL_iGP>4jnG0sZ>d*E* zEbQ?jN1nkh0kC$Qp>7hpy?ZQ@AbBWB_TWg;S>N-~90Kjc!GBN-(B} zLfExMIN_B-r|)+=u^0)@ScX=EYSjG`)7nm|xmC#5k@|-hL>5LvpI;BAuiyKJpPtBq zbTo2`%@gGr#y7tMPS2i4%SqE^7tuo<)m?qq3k(5U+ZQxUz7rWN~2&)Rc5d zhf<^UX^+qAm>ELN4e`Tf1VsWAfI~BkUFV8+4Ibp$lq*`#t%yZiW46?ECYp6=i-~wr z-ArGyA?poNEjpcl{n#7oykcZF04W*|x-RgTXO_M8FzQ}}oF6My2{I>KJK>AG`mY62 zM&Iw@?K3xjWAVGyi#AghqyiHq-s}DrTB&WZOIx5oa?SgQsM59uCz;H4oW;4E3z2a! z(njKLZFYs^f<^6f6Bfv2mltUjxdEZn#Z&==rQ&?Fd9$>KN%T2EwfEEWby#Ux8A%%* zzQw`5%J&*o#vNMHjcwPp<)EW_|r~el`Bav34~{oanRuxQWQZ zwEeLC8(UfMc4}|6!7O@k!T9<9Vr6dZKKMxQ&*M4w+*fL@CuA<6G^WqX#>pdDd@46v zgYuZaFJnIKnsNmiK!oUYd0)~n8aA!8K#SS-dB16{qhwjQuZ<=<9?uZjKz=n{?)vSi zojqk2ZY9~FMn3mqC)GLyHKTx5bp*?IOwlj@`{IphxZ8p>09?x-9vb0Omo2Y z%LBKjihH2|@bsT0YNbBR7LqZh5GOEJ5i~8?@O&3x*Xz(1jW6VGHve@LWWh7hwoWi;mxHk zBi|sO_gZ|0(N??!KovhudW3+eW;I%3UC?g@vf{RF-1Vwm&JY3Dv+g11Z3JkR_N$g{ zW}^wF!=#?I(_}Zzi1>sN6M*$Ap!Y&X{1{|S)OZ#W;hu*hg5EZ-Pq%dx$^yHiVz%og zmi5K~(Dg{QE;a3dbOlZ8OX6_x9BUemc|{IlU&|B(oU@bF>4DPehbw&Sx;6fHIfATD zvx6L_iP>a`h(N@cwTK{%*6=x>tcHM-g2!6@9;CUC5o+f?9Ra~ZM?x@+&3D3J`eRCC6) z^KS5c`rWk*t@$y`4=+e*Wa^`dAED~C25G94TQGR;lN*%>nO&vQhWpIc+Wb>U_v4!a1JfqNSwO0vvs@>Zu2(A#tCi;5BKn9Y(U?^@ve|_ibMaEy89h2M#I%( zaRSU}T+<^kg7XAL6llD0O7MFx6j4A5(yIE%JL@yzoYHvX z&CAqO5dhEE7>oce9M%@SG@Ct354>2x8I5c7@f(;W0^&~dDN(WhuGBEQT4vxIxj_6q zRnC(}TO|-TbyTXRu{y{MHDDJe7Y8gw1h@%sS})&cm+eWqnbrwvd!fw)!rRjvHjPk3 zW=xQga-i~4e_@y*B+K@sLxr4D!B{SyzZ(@`x@|Ft7KcSWJzz%soV__LfDxdC{SMm* zxZoh*BjFxXnVjke;NT;HFAiyEJh>!@7kTT%rJH}3K!%q8dFs!5KLC~AjzhGOTh+{F zbMhmuG@@Qi=a3A^SO(}Q;Bq|)k+I(89)R$yV*#8jqe=sW_u-wyFdalQ_xg_yH4dM5 z9Rr%8TzU0rM`xKeMus#RoIzt7@7K!3R*J)ks5D9d{P+zInIdPg!>l|^tB{k_V-qU# zHUYXx>`}|cA5+>To5Y__H4cOmsskzc0rw-n1Ly#Y^br_UoNxfMo#1kKc~H|;SzbA(=#peHK`6tU-2}{y!aQkZ-WbNn~kZBEK9k}yIFlSa1*zh8Ovndq4hZ^x;5r; zR~S_${+<~$#s!ePMgn`+W9*axaW9exrqGI-XJGV?yP=6BS4KSU7e?mBUyu^~X?+bn zN_Hi^BaTeKG5iPSI+tko{i~%vDR*31f#*MW#l?e>!G-;R3_c_$LE1ha4sLw;=^A43 zw0ymrHd*{1d!f;PnmnO-yc!O~3o7{UKJDTHFrN{ktw~z~QP`hLyiP=@S6$BI_p4-$ z#}Kg($1AjMsO>$4otzx8R}&!m-G}jZy)cQ1OVTJqL_hIf`@~Vd3o&(c z;kF54Ljo?c7)8tm?-PL+CgAf7gs~!WkDE0s1Iz4zDjCHaLD)rN+}t(<)&XRMlI$3K zYfeM8C4!}#(wJ%OMXXVv1aPzMP*@wGL0oGTDU4>WZsic&@hZwd$VO^CGupR(>-h@V{tZ3vS{-b=KK!tGB|CN;UI$^Jyz4Xk>*t0>`g8YT>lLj$D0JA0BZRT3mhdT8WLe6H?3zge=N1t!ifa^8 zsy*+)BwpE{H7Jw)zTFcV3s8Sq6vpa1@p}8lC?rcI@V6(m6({D zgb#>avpo>2ys|^2r3bM|3);P;zw7Nh&g^Ac=Ktb{JZP1#`&LNjsNa2*O7McmcZE_v z)5V`FpslWwIgqMDsDu>?>m5=3bBZDG8dsWdedfxV96SL!f+PV{J~ zZNGI5-%n{oyW^JQS6~iDuqxW~p-(nceP-Gx7@m$#)DX-@^L>D;zOh8aN7KDa$>aW9XVO)?L%dRTGQQ0_XYjTyGyfwr5^S9P66B%7+;Rr@*|8&LD0RzQ!FSy|i2WxD29#olObol5Y(4oI4$PqTLi#G0psxkF87~yKHz?CDj1A}^=z-Bne<+9 zj!x|Lo)mZHl$9F3rSQVmoxIce;P(B`eZ;yQlEqr)<>VFB4=TcMGiE8n_1z|CuxS36 z2(8xI)ieC*JImm6Y>-yd=i!RJk+?wmOZ?3l;> zd%~@8fc`fISw*Mr`3XY1ugP_s$$b)LDmVF5U;)U<+gPpOK8~NTxhZU8oM1IH2>Imoz)a zwo6~7d}yye@T$rE6^=zYagmueo~_*2*P|7On^k`6c!tU?)kJ7{ z&J4xmlFHCDRoLB4D_POK7b7YQKY%z1J{`%o23*wtD(_6+4gz$JUDsao*?6aQ~^M;3Q9lETwpDo_tZfz3%S*MV}?vnW*(7xB&N_yWO zx%aBXU{6ZxdR+l#e*WHs)qM_T`eks<<=c-i64#hB^lXENWE(J05GGoCZ5HUYX-fSm z4qhcBZP4^H3$zE}hs%1ngz$iDK7F&Dsf+j(tW zz-xB2WxlV+bx0gw@qu&gqth5G9oP<#dB(3RWeWNV#HE2(^8XohY`P`muxC@>PNGUM zP-J3lHafulm@IOtPW=eq__SU~G4u1bKJz%q_x}7Agr|s%ll<;Loggc!xmJB!m>=Y5VJBp@-e%(|Bph857UZukKb<0pFonFmddK_H z>PQ!oRnRBr-v==(b(3!$=T(iiu&6}KIBt0>{E5=ooxd^x2)x4V7eo$RN_8lyBc5t^ zsp9Q+kgWGTO8!m@u?gEhgeqo4#C(Pt6>`I`j^c4!T66^>nNX3%jxU$HVmfnXl`ghx znskZDUGLgI*delld@QK0lb6ZrU{V=Wbjn!iT%PwYzeQ7EHaKcuVa#Y2!Nll+CkdTq zGK$SDOd^kt3Tn@@iRLC3b81s}nSC_wc|g6?*%~K63yCz|k?C;?GqIAGXKjL%DG>ao48rRdN^QqUm~L5R zn6Sqo5#;^Ci+f_(8@g>`We46hVz*J#2#hSoW-s9)68}u|C^w1beME7T#}1uPGLtcX zVSucam9Q9uG5M{3jus2BA@{~!&KNoggBF4-l2Y$+A}6he<2R16%`C6Q;YZNNz)ojv zdl_rRsksG4u+H#>)OO+F7u)Jun1*2!F>_!F=JwS|OFXM;%$LjFLL6K5dNp6;0im*i zx^C8Oqur5{{cKa);jzqy5O)JJ-U3B4vnqL04Qq%b>CdFab9^fDN)rK-E-9;G_)Zco9A;Vt z^Cj;W;*U*RDVem7^LR&8W@nY5H`_Q^9CcrJGCoMZevoM^Cu`q4*cC`+nfM%>F*SQ) zgje6++0aY>jI{>4Y~cxsryDaWwUd~Nz0vM<`d}->J^*{1ab6VqQK#=7LIiIlwIYhk z8QNGt$r{Wylqd99$Rl=&slew@6v#ERdr7*$^ca~MS+9fIMqrXBncnLyi=E^L252tH zW`Pn88+zgJAoz*5yA}(B>^$OihxE*}<|mui7?}uIZkyswv9{pKciQS+6llY6o+?mWr{Tcrxj*>MnA*_ooW4;t9}yrTW^~xea)21Dj72?`JEp9$ z9mV`^ZelW0S$M3QGm|QnWgOAn4G?Hdqpn!LXeb$0m`xtlqrj_^uzEDYqhfpQx$ao- zCtM?7B@5Nj=KnM+di8c2>WPgp>Y7uDX9m0NtLeA=aj6d3ce&9QNnyd zNI@%x(bLv7OkJ+|IIcbJ2shtgV^4;6*L)ic5!0x`-a;VG_Ut0Ccu=0KV9QbeQ%nx= zaeG>mRGf)C0e%O4sQd0mRUXz&G0v{CnPS@3M(hAds-9=oP)<0E3$wt zM=l3g!gp#fOc(&Ezxo3|CsX)TY)>xBDZ9$+T1$+7>+v#LpK#|~&F_((JgzQH-1Adg zWG}y$QnYYM)}A7h>V+jos^ifDNer5UR$o{mI88NAae&I`yqS*Tm3jPbRG*WF0TQN% zI(pzb&VK%Cd<_Al@Zep7Twr~&bGFYySaL*AqaH%VnKgCGItyEAn#<&=`Rt5UK-PAF zZ>)8PyPq_(XSV49o!0(Wh2U>QdY`Se<}7Xv@QZ?p|` zjAQ2+DecN}vasH5v(f#0UwkZV9H0p@6*yO8%a9K*ZS*^s$e+LA=C zE))9^GZfvzX=?nbK74$}4Q!klgP(c=71?#1r(Ik;VP%?J=H5 zl!o2OUhR={GplF-^$nX)7%@%(jHJKwrYuO!ghQ5~*6naS;T+q%%J1Mq1eSkll|t83 zH9_~m#0RCtuH5P>mUjCY+zblGyL#DZw1_Xv3B)S}Csyh9v}hotxU~Bjz_f3Pf`{JP zjv^|vCIpgK0OGU(O-UsTIr3T>T#DY`IR^!{A*$g7c+|-7?dY;p@f+o3mY?A2QyRf0-+n{d0g>bPUROi4dW z`e@scm2y+z`jzn`?Mltzf)bO~ubdyOK~a>7f!_dX8Y!tk2@o^78epf_N=6q5hy^cF z_jOSUb1t>O5mGwI6w8U=qpCY}XwlN3rAu}u_F{C-cpG~d>6QRrZh(y%Se0@q$l|CC z19jGNJ%$O1+tNF4Ji=4i0t-}4kLSAv)}v{V#)aND-~js%oymlH3M($Gw$G7l|$jg)7j>A~Jz7h}E% z1GsXX#h`uQ<*wheuwkE z;O7{fug;C#pJa`E`o*Oa=Xv6Kyclm%I82*(YDJf={le%1l(IJoP^epiTA*-y|LxpyoBGbvZ=J3dz(>AK!VT zjF$B%$z}T#Q_Z-`l)G|s(2)UQCM=L&DLhXblAIF$so__BDGBSDV3SPQ_4V*3V&8&s ziz9XHh-2tP0#S5-F9qUUS2vZXUK0X)->~15Wdw?Cen{C{%s3(JH4!=3nG&|wGwXQI zAiZRr7MrNF>XA$Rs3eqg=9>$_pOq+8AiDx{w)?%+{bdjpSW^A^BdIKmwiPB+#Tdz; z!F*2BtE~8HPOiGkIwi@&i;)Az2lWYbJL>spO?Y)U=NYSq*9bex$WbO$zio+WgBrea zB(;Xi4`Jxu;~egjN9REQ{stueW;^qjv~%aRPMap)FoPDr8~Yg1tcw)XV&aYV=Z=NJ!`VYf+>* zTfJW!fYvJb9W&d`xMi0*yXX5@nb@m9@~8UvC;7&mR3iSbH;y((q-IyaC3KPZtO72C z>1^Jk%mOM}@`X`HYq)*g>yOSB1hLcZvD%uA^u0qDu!ZI!(Fxj*rK_3f&vO2GkT!ELeYlAr48vZfo?WYi(+Iv16K{ImEPchM+1~~ znAHf{#Z+JoGlhcnkFZsrU_%fT;yct6D<@Z#g8GDAh{7@OU4Gu0ec1e-S6c9)5^1Qj zSL!49GciWtX%w6#f3OySw_bN0Ni${sH)!5sV`ln@lw$r`sZT3KF!I|Z=39LPLf7sg zTDpJAS9ERPa_4Hmg5IOfyb$j}`%TQzMLaDKHni zd{`yy$aI|AwBMa94~ONSs6=ACb3XjY&!HIK)Oa656!deVipTOUUKZX^YP&>M)DSRt zzQ2QvY1iY*IO0{86%e2bn4y-f002N$p|07y3j(8%Zuu@sGddsa z6D8NY++2OnkWk*zgMF2^N&<6DHyVN-`ZIM9urU*9h7y6!ytUVBj37swm^oABOB{>m zklN=oJ?ol>to#Q!(WvCimAqQ1o z#UQ>Log12%$ z=H8Jw%u{`%Jk1Lp2B%w8@7V$lpbtLB(&4`4$$-I21WYNsQL&Sy?NcP3OMs%NJ4wLp z#Yhc5svpfLq2f^1C$8+0d0v`LWeS-dG2ryB`6OH0_88o+GthcmdJDVQ-+A-xH!JQw#j`?(!-w>YYP#)6(@hs%u8he`BbX>^+&OG z2JMRIQK)Br>$E3+Y-QnJQ+wZm-H|PhTP%#XT((Ea8QwzjhsxGT(%OQa&g2W|MtG7^ zreOl3qGzANgb%E01GagO@dMaC4at5zm;&8k3kdG@(vw&#>cKDSC^p7;XHYJHGH46C z5CIx#(hBFSZ)aRY@N}4?i;>M z#>Au&*F%!EV%E+fk$2HQrJLKuo9bUQ&G_ zxb41`VC`0bo+E5fRpyal&Vf^slG%W10;lY2ic+-1GmSU1>Tv504Xu8>D!|*q-`ZtP zB5>I4xJFEtXE71rpZQ3?azQ#H)0SV=^z^83)=JlQFY1 zfoYiPwxpp9cK}1!h;b-pW@ln2R?6qGOt7I@|I1`P`0!}quFWh0kMN6DmJ24Mp}F+d z%-IIPG3fevjqz7*WO4TT)=bd&<_bNAk|_9Y3y|B~|}RWD6m(T&KJ)JA&fD(8uK< zbZQLOL=jDs)&_l#x6Jg5u1rA=AttimBtGWJAgQAVv*T`2n8Z<8A&Bv#gmqM3eW=|$8Bc6FMKkdB{s`j2yocEJpfJ^Mo1;r)| z%PuC_zoZ}a_EVY-OES~LGk!CBRq>F)=f z_|*1oAL>|#3u^7ow4;~0kQ8-ZClbbkw7#=2Ev|Zf?x<*oi-fPy2#8XExOA{mvk6aQW@*wcqJz&{QQ+}>PQN|6G)7*(=qIE$TrKo9P z;N#$yHDAn&h~jVP8*?D5ICV5)j|?40pbe+U@+wTI72D=IYN5)97?`RUIt3iZn;8Ty zbQ8BnD2^X|NQ3*T{%^P7d!3KJn^$1Z2L=s-;DjPmV3a2=X+x%7x9nIuDW+I&d6upv zCS*iF{3>q;`wyvz6C)$+^mA|MjLOGa@Ez68@-aF~wP|F!=Bz;Yp1A4`b$oox=@#GL zhJo~^Ew3j|+e5vF7u53e(28kY7m0yT*VBV~!0M#qujVWH^DqU6g^vN;{$@{)JjsFS z_&0xAjPFS7X*Z`)R`ms;UrM}sl+sl!O`v#~_mw;DAxkII>z+IV9+ZT#3;g18O}-6e z3=J?Y5^+5$Qd1NE9;JS(1lnQQnhXj@@6dMMWRz?H_C9c)FwM$Jy8Cs`6k6S&wqGl- zN8l%N1Rj8xCr=7?;?}>sKI8%&GddwT@mclP%O!!QC%6OFml9>eu2|+jv6MsSQ}C?u zt@!<+XuTgQ(5n=}6qUORemg}5vSWWlPAnQ7-W5|wM>Yv57AR^<+Zd#>AEPOq$(@WB z0I&u`1YI5M-)KJNwNz_&6rt5uBhS^NRjEy}o)u^cs|D(SKbu$Tk)`Cst$lY$8*Ri4 zh4`Ex??KA$%;$<&w90-FPcU)d+4ZP@ci&EQxg0QgBU>p~so0_OL1~Gp4Z!JBJ&^h- zCPtdgf!SJ`h4BEww3H7iAA(d4!5(Jr7|K$nJNLzHyyxSU@ z<~lN#=O@lwm~y{L+{_qvFCjkJ4VG{Z9AanzeUo(os2g)3?AGf5$P zRN=m!}XZ7b~A5ylo3-uC9h4G^!LisN#`IIt!Wpi4G}e-H=$L<*=oakFQ?+8% z$CWNalLHS8QPO};;{z3Vla;NfPT^dm=&bc}7SS_4h`R)U?fhTsTM;$)Gcm4hox6OF zu3q)VC6y%TgniSj(_-sc$JeHItfM=f9w%paNKvjK^sJddr|!U)_n%@WQw3jC!Uk1R!vg=utj5_n5>VRAqb7lFN&=Y(Yi_ z%(qgLB{*$~Jup?3PpgcO~#ZI?*pnvi>J!XW>Q@4uoih6 z1@`B&kkYtJ$%sC*z9wFLmf4dJfjZAVICr}F8{ye?H;Ot5oD9ADVz;SN6x1_6dAb*8 z4jG^QokY#IE3*5!ZO#mBT>?-WYv)BS4pa)(#Uer?Fi+HRlh!qIzd=+k@kxc zZ^~N~QnL+z>4?IS8J6Y0&4lr{D?Ly&mvty&PC7nsdlDvta?kSastBe!j0E5C7pg^R zcoutYg`xKxOZj?L=(+o%6NO9w-@ahT&`0raidH*Z}P zJv5>Ej-2z1h7`?gt<+$G2CLETx0x7CCRXUN`%i;xIx(%>_w?u9f7Z9Yx*U!U}{?a6T_S04Ly93J}r_Zv@s>AJq`1K`S}L9fbXi5Q&~nGO7iEnm~*S8A7|Y)5Z40Ieg;d;Fr+<6Wq5 zhq~(V14Aq$g(Y)Gu$o`G<<=20a?SlJP8on6%8P*?XyJgS?kfd`@>rk?_+oB7mpKip z8UqZJVxv8%{yK-eoTr)0^aa*7+h5bSDoFu<`dT>+RtDLgxWGrq!`yQsC*3k97Ggwn zQD(jj#S0wLDTOH9KtIexlN%HA&x$vn=@uBjEGG&!^=wcp2yd{z*8(UA>?KB+Ne)fk z(nV6>*``G6%cCtSSlW1R^v$| zpkji|?b45oB6+K)b!mE-6LA}A>H2WQNhPA>8D`MnwO0u}MiizP&93&W;7T7Yvl(n# zpJ_K)MX2XNpCfQ8@tkDA5Gd=^IsMwzHTYveBx1<9#C&0utR{@e9vPCP`mUEVlQ>L` z-a%?#KEQ!9Ovy1JS%bspE4V+%Orzr`ii7tp_sd_ zqu$BEu)96B19H8M7^f^3lM*Dk&~PSG7o5CP9<{UlV+bNr+`*PV$LFq0Z|)iwXYa7C zG_ulZtK!^=u2f-b3Zu6Li6e){S^`2cPL}?9R1NBdO_G4D{GIYB^jH-6pheqL5$Q#r z{}W6uv(b(ZbJ0Z2zxnBZCjR_L1txW5$Q)v=NF1513*LUS66@-b539=$WL+|TrH$1U z+K0Pg(n69-P45D*WKQM6?uYIqbJ{ML2`Xq@qL%z7B+Znxd0ovC7k{U1aZc%iB-=C$ z*OozY{gJO(@RTo(!;v@fITi7w%Kywi2uOB(oTej3ew)bL;8%R-Nm_Rjgdw6m4EK|N zY*v?V%6>xN zqJB)ie>COXU)^%MWe-_q%|GoMlzA0;>}W22dRh?brgZ}n>q2O zz#CdbT0nD8`3;uDn|DSV`K{8(V%t=z?(TYYu+ryldyec1;mGYKlN>m11(cznd>}^G`%JlO^ zj^8x6pm}^B6-fb%BqEjjRJ4SlgqCsJTNzFtAp-;orWus3{l!<#EWS9G;vJ~Uw?D4s z(JKCL8Zyf7EERGPx9KyQcw#16+g}wZWcgQYYV&X<-c&E{@Wmp1{ zl}4VHArDpHlrdk$?CLP_zgG=rMUsoPn1@P@W;{CTY`lG8;p7LkW2k@wLxByCBAAbz zmi2JS$p}`NxAh1GL!P}!*uZ z5nZwpvr(=nNJxIgpE7EzfDb>zpm_I9h9GmTh9O!Vq!R~^7k;973rh>Z{W{t`%gpjS zKN5|0w}b{q&mlu(g~`0^qO2zWw-?s{nzk=|(z3>7SX16A5ru%*G98EpbEXRS(c^67 z%?ji8aZ9-Dqrp`2YM(SB;!Se`(-NPwsa)b*bMsqdbWRqjAv#Aw(K@5T36QWt> z<|76EgY1V8FPuBCW6?U!t5qfjfQ=zDWf0XxFULhTZv%|LXht=P7XWfYb7cH(u%a%- zPqd^WvLsd-=g}?MY1>T!s$mFJ-sYDaWRx8INRFsP3_o$jXBlC3S_8~+Nk5lo1`##_ zjC`veB=A2%+MjrW7;~lo@lOJ)T*W7zvuAWx5Z(c(jYB5f?yc&+r0zb3NNg5-HwCl< z{zRxt7ul77Y^eVLX6S5*vFD1rq{#@g!u+u;VAD5JbR?SHe@!3(m@@|DfK4I7lhd>& zcQ~y?VW>Eo%)8_yq=30NV9ug7f76Q7GMsdZa3xEa<&ieshgf_jkW3YBzo?c0wf*fj z4TkWCwfxDTqC%?_rbQkp$ayP(xg?W(XHfE?Iu8>gCEg`}@*(FK(y#%0(VtDt{w8AF zO9OD>b?;R7b$V;B3Rsb;pV3bIc&pEgNf>$Xm&T(|DHwEX&!lJS#mku1POF*>^Z~H< zWG|5^-`wXR>unt>v{AuQwp5~O&~WP-HQ7mgA64Nfj28fu(}jh_K9{$A^7F{XQM34| zLX8mQ*|a>@XoXfh<}JRE;8Tuv%B|c+ygVtB6UGmJ@rkhFM^1=NS@C32WY=wQ$P+pq z|5qM^Bk`mk48+ak5h~%QPo2{9Vn(T?S1+kgmeF)~fQg@BvgYBeB>8e9dBl=mEcvt+ z<0yTZr6)+MAfq&=WdA=|zc+VUzeUNXln{Uh<3z@M$OKiR3iecZM$GcL3#La*tf$nssr{nJ%;XWOJb4+%?@u`X-iOH6U=0>^ zv?f#0Vmw~lr;q6wTqT!6yFAW2`IELzU{JuNXW^?LgMn>~zm$Dn_SV&_SNxSkzg*%w zqR=x3lo(re6&Z@m1URZZHIPohazwa`>b6X5D&QzzqRlF$o%YM+-%j}}2b^hGtX$j? zY8r4-Ij3*vuu#nD7KuE(ZcYb76Unr0Xg7AtE|yM{jF6vHWNt4K;2m^JiQLNH6nI8{ z@mq$|Arl!>;Pgk*Vzjep^urWm*7QboUnnTK4Fo9?=qNLOv*DJ0=XBjN`*5PmqzhTY z*E0IUI+6{@*l)${dj{_?jHPeN{;jN6nIEh044HSd05IB_lX+QNl~hK`$`#9HH7o{K zoW@N9`&$Z>(*L?(h_jnZ{Gq{WX08s1;QyIx7WkV6OZ@i9YePOJ$1SR9777r}o3zLX zf56-RmPtG}gOe0*0xh3NxG*Klfn|Dn13u`H=i}(+C8Tu;&{x3Y z-f=%shL{EiA^Xu_N|!!n9EePiC~!hntz z`;jd3GZp@f4l-)Ul?>lMOpSciPJjTY0#7rfK2G5NeQ_^TcyL}bh!Gf zfAN8KWSFDURX9RAu=w!3_s!aKu+%5fcLSKY)Irf;>L~nZF-?*9bwI%7K9lQblmeW~ zS%vfBK)}E)(;)LXqs>4DAMeXCFY}Oz7Q3p)6ue;KlNpL=jb_wQ;Th@*cW}wVYiBf= zn@nkVr7J*4kyGaOr*#pXxsFmLU^(VeoGT9t{#*zRKeSF}sso~pns>Z~C0)r$*(|Qg zS^kQTywJ#GStbQ1mY*yTUKn^DnXeZ<;Ta2C;Ec=LrJgA7qTJwlUhIb15vdmOAVeG$f;W>KxMQ6R}|5T!~L4siginM5`)R8k7<53L}|C3iEs;Y=!8{54dNZgd6=vg#!6 zE&k1Gf8ywmkd?|F+)yASzTKoYz2%WUOcrE6pdhW?@|Wz~5HtBiBTKx=*B+M%dVp!4 z<+}v;0Wg5@;rr4BlyNk6^1oMr^$jDd{@aYCfxS5fw)(XJjUj-QRpEfSz6tMg=r%&sn zH5cTk%+1TnQhkta=oHpCBY;O81PlFYODbt3UXtN^B;?JJbU>B2*156Tl2@fudO&t% z`Y{l|bwbvQM!C6{@N8mGb#Kc4KeF%2-a4nTpC5fZ#s+0?aU@v8k!tw0pO3+^qnn6i(yibS3G|q6M5zbZE#8Ew26U z`@~gFkj^OT1{(Vx@@PxI&Nq%DGC$^Z=Clq>7h~p3(%-{ zYDhm*j)0P((%WHVi-*G%JT3C1U+!H&1`i2_HbeNSk3L*n(USmPHetBL0JfO8OMnxp zsDq`$X=q*fSA}Re-xVem-JPeTGa7;b!B{jXE+&m0pv6zq&=Dnoko-c5|C@(cXJ9dt zpLqC_W}}}dbB9N4!C*Y$7lq{JKpshOSLl9644%a zGiWnTX8ar3cVus!`S|qWn!X9ai=!UH1+WH<;?bmK8JBdcx1!NN6rz$mUl9 zalOLy$8b_$50O$f0E|aT{o`!Pn&}l-@pEsvHunND7)ite;Ll~xQ?U0=yu0AJ=Jk3H zz>k@@BMM86t^|uHXM_g{Pjv?kC(FQtG0^Zp&V|s-FKSptq~R;JX>eL5U@AP7oQ?9x zr1`sW>IgMt7CF7pX*sYbf9Jta(s@Czl2&%=DA5|wqYTJsZR`Y*5pT*PzuQ||6&JMd z@{rZ_!>yur5_p#keX>MQz%=?QmOAo22c_Pv54oVZJVXLEJ!8)CtbAyNG#ve+Z}I&cn&O4 zWMe)if3!QEdoW1*Q`tY0Wk+{$^1TyMl~;^rzXu>1ouoBw)t~M#aS9L8@Dz)}`j2){ zN2ozj(*XCnwoPc1?jU+>Bfusa+Ci9*nRV#!N49~Z3$Ff=sO$llG^oCl&-{e<4EwEU zHXE-=b92X25;Njf`u32m>kyBkmjUMdd}+-~Ig=(n2N3Jw=>zWEVgN`pz00ZQy_($915zmR2Rxn#zRa!b_B z1L#Cn52Sff_E}}R+YeC>9I#qtW#rDH^JoPcQ%>4rcoYt0a;7-Rbvt&PMF_NJA-bAN^*MyT!>O2vODbUtCyc8Bw02%MX{wRryd7Z%5!d{U2A_Lv6W<%^fR zWy3G8`EeLGf~8A_JkAS`3qx*Ge#*f^-H5AlxGd&(u~Hs+uU@{gc>B$tdh2bk3k|s=1a2A%6>yz8oLf1J|e_Rd(gmZG_9(rLTU7? z$_|ghRsG>iagvvKkvzX4q@jzu7|n4_OJ%+?n6LVY?v84g)a_4aI9f1pzmrV}aKUOb z`IUztL__Y@OA|a8-nVzZHCnW&?k+X@VG@@g^sp8~gVOwJ z7t)~h04DbI=`p_t7fkqh-aU3@<+r(CkbzhP{hzYml6_wG*n215@vmc0sJ&{4e&~(r za~oDW+$+G8Ool}1khHBPoT@D!bz`oyPv1>tw4eH@J5SvCcl!7#RQkxE0=$tPV&&r( zWz?87DBsB^uhrifSp81^YF-js;3ETa8-+=Z3bx6OR3Y(FFP=r_Q4z_hQzgKucI@=` z3b1|v4nH>$mJtZRP(DxYJr84gAggHtrxWkbOpl-+krsrNz2_|Iq07ol66$RrF6o-7moU22CRuB;4q^tNig6 zjZaqPG=uv>m;9?(?H>fVOokb)n{9(mE4j*scNqX1LkKTqaKs6)akQB)bhB-92f23TGYy6Jf* zb5BMGHenem`2zV~f5tS=E&(U)K^t7v{Fr&z#~**(^D&-`|A{O^CECnOO}WF|uO{n+ zO#J^y_BmO8ec~H>mbS+G0M9%lm2p5zVPTLJSpa68HX6!+12<)s!wSvfl8D}6=)j=^ zm50IxfI5Ev`nthA^(j33$0eK1{Q?`JYyhn8AYCqB-2OZH06X7kmHfNrfp7rhOnk|W zlQ6(NdE&j>0l2`TArg&bP356+cfcks zmc>q1m-z}gH(plSq+yt3h^@I8dGSsN6aIH(msXVu+dL@9ZYuS=vVSQ1RoP>*&whOB z)UJK|GGE!DZ__fa^YubH*z+`BRqty7<23EbDH|L{w--8jv?_j z4M$UUNbM^d=ZK3T_l7cs8j;0^qvNE0WUc{P--I zO$HpCkp1_vyc@Eqd640<1(6G@P24ACnV;=vxxK!APm#$6pU1JS(#%&4sP zPA6nL15q>O&*U<*hH&+pPnV@Zb0JRCj%6;l8+W(_mg zL6bY|#!jp}Wx?P8nL(vcHsxSFq~>8^>Lk!@$mBhT(;k*Zl&F zPQ9cbDm$wkdw`2p&&m`vuQEt|r%Wl>a@$m`msPy#Y_6_IGu04DG*2rUVA5jj(DQUg z8mKiG8q2m;?7PuqO!(QNQDb=irm|a$N%JxfzMyYxFl@@8T;7!J!xK{%5j!)V7Gz|^ z4(|_T56bS9{jLge;N7<#ILrcZm9$)|}>~xGeg|HlV zl7>&RVJ^aE>IF3n4>QMm9+YX+G-7t8vo6lrlpc25C^?_FuM zmtHxpV4my)u{){&e+HU5#eHZFF82;FCjkTU7$8Pkg+*0&TAuD@EfB7HbCVu+V=_GO z6FV9%8W5HzLB6HMD&Umke z9*z8905hzt5|pE4SwA%3zyW!1XVUlr96<2*BBWtpV|d_WyL<>H^Ar`GbW}o`ul;z~ z=>`bo;_rm8wV}KFnud{^oJi3k#D>K3GUO~7%BMI>SiZX~mo#&8e{-;{0H(4DVC1?> zKlCtZv20neZQ<<;&%>Ass0CHFG1->}^N*{k?tsjKro*fpnD8S;BDOLQ3uMUehv@%8 zetyJ>-O|_eS-qqT1WmEWB?_ZC7OasI@s)iR(u&oMNs-4QX@xUD%q@x zpBv}4Omauhc}AJ$M9Gk>`HcP!ogTP# zWA@8^0vCH@r}Y$qIhqXnVyq^ADEpS|wpvW_540Iex~&Xql<}E@un=G$?SPi+I~hLq z>2ZvwHPQsrUCtdSE*bZO{8M`;kZ@5$68G>F|2#bT-MQ*tv`_MIz+qGB0$;4T0t(YA zt^C;}rJM|>#V>YG;-$5mUg37lQ(>g4R0beUn+FA$0VN@59a{kanm<~|5UDvBLnQM3 zV;F!-T8mXA3mR6EOc}D8+-nU-wHRu>nv@1(*k?6)@xsN$DQ&mN^kn~klAjeN^Kn;8 z?w01$Y+-CA6rk~$KhAhFYy!4}8q0TG)b_@K{ZexDvpb3MxtHmW6xSa4DSQ4aVvy#Z zs^MT%c=C&JDNLTu8;DIAR#~8tqQRE1t`xR-96N>KR$TuO1Ibgb(8k>(x=N*sulQ_M z%L?&chRBTo%g1o~WCYr)ze~Z*%$5Y&s(14N**^V@B7nZ3rKF_jfSvG5rXfnBW;lg?SUZXZ_ zHACvt1)fKV(x&@AT~Zw*XM`t`l8gxXCO@*a4nVZCtz=pjN~1 zt(MKSSsKeiOW8AB0NB{c*BDRdW6@xM%aeTVhhYF16MR4h!1&?Q089`6*$-nrra12@ zYA(PAD=SF@Os7ED7dw6GbiY%H(7%yIi~V1++pZ`TKg^>78EwNxEkOH7mM}njLXEU` zQ9xr`flg(L1lX7i$A~rm^xvE$e?`Q%5}x8nwAzWwVTHs#nT_FDR+hFDuEaycOqglg zgvoQcEGfm^G??QhcXNxIL^Bk}x!EOYKRizesp=23yHb4H!AD-76Zf1V5+RfDZv)>$O(E`Wv! zpaL}*hjw!S9(nM`m+J^maf#n9yb(|{ObodtdSkelNBk_YY1@Q1E1PMvG=#YWTK)hZ zo2$^(C$Oago zn4bsp8~v3Rn#nu&YFD1;W_UzzJT}t&EB1;2_FnIav55O~ z+5b-VhqCO(P8C()ZsxN98D#)y+zp&^V=?fe>`|$9pRcB2Sk-W+f+<_g5va)=G=vLt z@-4^RJ-iW6%NUUK{9ASh$kV2nSHr}aHWRiQ4v(lKu_bN^umLW~%p{+(<7W=WIk0T7 z^3mveP_5fD54_p)^BinXhDC-)9ZqtR7oNcJi5j31HGxyw=7KI{+#Vkwb%Jhy-A0LLM1$@NfW3 z^RV+e(ZZgX3}Y{&&+p6L*J@JyOXjl#85sjKZV@W*j4b2Hs!$B^#FhCX0n9)FNGki}SJegRa-~ikNa7JjIy!4K?P8| zPnX@p-Nc>9y8>voJJM=wDEdgWm>NX>(NjTm!jw@5N6Zr7&;}iWyD^NQi6wy%uEeY1 zNJ89*iHupea+?c>6d=u9Hm8`AMk`T102Zy5p^@V``P4nY2p`i1J%`ls7H?6g-2j(2 zSX+a64z}OmO1rX~uPKP+&tC>%cm!a~#by(ICiYD5|6AEVl)dkHn9>aMI6y|vFk~`6 z185ALtU7nIyUd-(mWGE=&DGq%(rj*cx)L2IAb};GMY?ypb5{TsE-~6XZh$f5QS}&u zMdj`lBNYk2dez8~DC?~Wov+vM)&}k6hui~P4X|h~&%p#XhE6}1tvMLSuNi8`+eUy( zmX+kY@4njr24MfMECBo8W#5;bGFRY!&Eo(WWdtgyUw}r-qtTA3kqc<-p=l_PR^!JH{NW z9vAgq7#a+K)&3fLn|~n-z?kU2E6Wt;Q<=vFG71gQc>L7wRWV2N)&`F=Xf(Pq!@^Ea zWZB!{&c5bvZ~!)0I!M+^%zdvek;bssS2_|o5@w@7{zuqbClxZY{7H{z_(IzdrWzBQ zbM7SK#XA9vvWVjOR{YGpSRwK?9d_%n)N!u402gl*_0Y)h=gn1VDkk<>J!X;*op`_f z?TywtQ6c%9%H?A%e6Wro5)F3Z#ED*^0S} z8Cl8#(2l4h)(kW?m<}ueaLO4dI)w!Trwtf}awh^hrGOn*AXFd9(4jaA$aNHC z`3z3`2_|O5S2&zg{KjzP>l)!oXJ9GpEePZ^4N#%Q3@i}%QQ00!NuN} z!R1Ljfa*OkhDe3=j_AI6OvGz#JW`@O-pS{49s!sn=md)1xMfRt%%$*;K zdE6kQ60~aXp%G?|_5?uVZeucwHk&M9TU#8^Tk8k)BL*zrdAWh5c=p;fyr>hsDg$5z zlxPriA0#?GfMc4JIL82!m`X>$w56~p0t@M4k)bde6dHeWJ+zw#u%oefcTtuh5sjrA z<+{o~-%O>Ro^vrQay+`gwP!c;t^jMl0oL=coTTuyf?a$~F*qPe{+7=kn5-Xm>v`lQ zoz}&o!Dd4w0OOhDKbQSm*=w>7&5S|hp-FsjL8z^7$o^j0Z^_+Hqd%$71)#xr=`@>( zoVVw>TfM9z9_AcuAYM{K-nny2;L|yE?Y+@q{(J&Y62zB>@>X^QDACj*)_%&+W*}_~ zfWcopIDkr-n&vQ?szGSr5!QT5TM_;4BR7Q8DLtJ4Fs!+xtr#mWMVArgQwMDhR}t@cpO=Luv~ z44{2Y_8-dr6WQ;`9*|ue)~65-A3j`@Ufr=wYNgSb*wQI|qJzHX)h)E(RW&dggSO`@ zJO-OP(}d6^+jBAlP;^jIhE78xv|;XNFcnj@7Qlg=INW@JQoxd*tr+(FIB7~+{@m!2 z4XD^w$d_}taRfB#B%pZ?CP4K>-+)q`GvAViLu(0mewn%sVv@Iy`$$vz1hD3=9wvP* zOeZR|$y%pdsS>NmAIUOA{;#q>mVKxiO!90V=E>NW`DtA4BJL(8ocO8q_hb)gCwd2W z& z^dhS~Bx?T#9(i z0p9R9uN89?gPHUQF_x&;EX3LBEV zVC#8{miE>_-bt@c6R&&EP?aQlvibpV$#;%SV2Y;lAD}HQYG7HjYFL!^iUnL~ z<_wKJ3^F`2k?#+n^b`T0x=t#DpJi%($Ep1K=@MkgOl9Kl$WS zUK9W{gUok+h8;RFLufjBz=5F*j99Y)GKM{MnuwmTs~0Dr!5DBw8@h)BHlUSYL{ljK z0GL}g!>~0MLoxs>%>^ysYL^#>r}LcjuOyg+>N ze<}MzS*9fYXiwfpYd-HF>)P*?=T+IiEBm{$-k%oyPgLkqH@cpQ%wm|wBBmirm@qn8xiZaY=c`U?p zNVL}vW#5r~Wb-e{-eA5cAfw<6pKR9tqU_(5{Y}|#$R3v6Mduzpddx#;h8@jidIc)C zJJQ;OP8YxagEiiD)4u_?1SUE-+5-^fWQg&kgd*ra=^_S!$c*d&Z5k#S9s@X5lg!Vu zy%Oz~VKfCIJ)%JuK1VlffI<62A8z68Zptguo80Vw{jltRkb6q@kq?i` zW64mfFOoqOF(*4N`x~+V4Xt)uc3sv(4q#i?=cE`ud(zBMgciw?Ka=eVaDa}~m;eQ6 z@uDT2j7i^tD|g~VFnR7r%c8yhwe0^b`JG8DR{Ko`TF-ktl%|sbU$6Xn{sUkp6W}F0qnB5)1ybA)aRahR zvk7(<(W2o&^AKjf=jW9IHLG9dUGt$4Kl82DWM}m&y?l8ZzA|X2GqOLD{Xb;?NcP9F zpU6Ja)uZHZYi2FBE#K!ga*qo3qAV-V-n{uyR;HLB74|ctygc>YMKvu zUrHcjb(c94KneH)7=_U~{8{^0*GcjOrhrEACbbKTQ<;@0tC6~(y?S`|%GN8|WpFV} zvMtdoNC0;B>^ZL(XU{mVNi^FM@5(Z{{{vZ8j_=EUrgJalx2Z`>Z5s83A@&ONxJvwO zS@zTzLSL7CTGopL0K>DtW5w+yKqH?+mM&Gc6BylEf!iBu7yKj{N+M z7M%P6C;TxUYQ>j_<X;LGxLAhshICTq@x5WvM83vKmh zW&c|4+p_0mhl-Q`v6|6DkF^vJCv(8Y)&`o5=bk^11#n-HWh0lloX0D`!<_Bt(W67V zq1p0?3eX8~fQ%KX{?LZm4gpB9t)&3j98~xX1R?~W)?Uo*pl7}{xtY`lU}K2Xrm(-n zsINU74DwHeI_oT@nmrUo0DinU_z zv1Q(shuDAzU_nEx@g3F++M#DVVg@X-W7uPE#Sr+WEGxx7mjztVnCuTE%Ky1CUq+C1 z0|Pc5t}|r5B>M}p%-H}Q^ES3a4$Gnehe3<+xQb7b`c;1Ut;wX>0M3}qd&~q@rP+pr zc+g=qZiA~e7<2&T%~L&F1&C83cxYxkk-JF;v?Fz5OkS+o{Ifa7>GfJ2jE4jx2tPKM3U zo;yjA`5`qEb;qJ2q_eVUt&e5jmi>_|8tYxzk7NNJE6Fd6`B?$kyh9i& z0oHS}Xfw3j>tz{Ei8~?-C;=V(54)WhTNwh;M1ba;>={{xzMsner2K%2=ZnO_|AjOU zyYaqAjX>SeaHt`)7~o=oz`_9y2lyCj0UL`30EfFzmKCe_F(Jh*%B6+hIUOnlF|4Imou}PTB_z1)#Rl zWN5UxW^2ubi@`;UwMCNwJT%^y4p6Go&&|(U;InUm{~u?=L0A41xC;OP002ovPDHLk FV1i2nEVKXs diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerLeftTrigger.png b/examples/gamepad/quickGamepad/qml/xboxControllerLeftTrigger.png deleted file mode 100644 index 1fd73246ac84f5162608503c32256c05ca6a48a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13918 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 diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerRightShoulder.png b/examples/gamepad/quickGamepad/qml/xboxControllerRightShoulder.png deleted file mode 100644 index a22c8caa8979d037e880865ba408975e7d7ece54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21209 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 FV1lr`YjXeq diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerRightTrigger.png b/examples/gamepad/quickGamepad/qml/xboxControllerRightTrigger.png deleted file mode 100644 index 717f7ab8e1921b8d47eb82783d1305d30c806b96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14152 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 CT}530 diff --git a/examples/gamepad/quickGamepad/qml/xboxControllerStart.png b/examples/gamepad/quickGamepad/qml/xboxControllerStart.png deleted file mode 100644 index 709459e29da998a6961eb49964f41d6b2d0ef848..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11271 zcmZ{K1yo$yvMufq+(Mw~;O_43?oOkPTaXZf1b4S!jk`n8Ai;vW2Dcy$!99F(?tS;2 zf5v@1#_ry`s%FiawbmNDw?wF^$YP?AqQStxV9Lu$X}tXEylg5cNH5=QGn=q5Flgdn zNl7(%NlAd3o3l08!3qXO4l_H|OG|T!Fl?few{sE~2%x?seUA#57L+4EP>+xgP=gB% zrty?Ql)=ZL*Rj;N$;*k+oPUVabK)uJ`L)xFYSL> zSh6|wTWEt(dkjM8_0WS2;DYGkpB(iV;o^<--M|rJ!(!>dc5hl+Bgo!L!OcE)3TI@L z$_+GJpRfd2wy!XCsnNL4Kl>*Dc_pckV9=!Jc!WOE5beSxYc}+ga6BUnU#8G=gtBuG zLQwN7f!lpG4%a1njP2jk(`a@er269|9b7rl?P_b8)SCs-2oR%m>J6KM56D)XTJo7N zyEk+*Gq+hvFl_i4rlb2b5Qhj3X?&8Ch;uj?l;l4C4mYf*JAT_781G`6ok)ZTc~CLV zLOOW&=aBXNS%c;sh@CO{oAPG3x6;IABStJ6Q9zAzsx&OMzGH@M0BwUZF$n#$nwn})9`+AxidNMgI2m8z!zm~%v! z#q@=ynp#J(*ITJ)&nV+VKGTzeMApS%ybLC(Wnq5L-)BPS0!g2hClfp6srIIX02 zi%W_XrA9|Fu+kZT*7K8{3(Rcb`$+_qARZSaBLv-UOc!*F09i4#&>lrL z*tI|~O3*KCf_(Avc*4S084~l@uMJRqB*oSE@ZtL{}0?pMG>(N$?YYFbNSdpY{cQjU5)VN)k1W8z|l9%O`0?B4u&=S)1X&9?!Q1E zD8Hilllhac$59M)(Z-`1AlL`JqD%!)IZ$a~lcMaSJO$(Qa;XQFs(JuJv3>fCK=gI7 zi{c&fWHc&C`0}AtL>g4|8I6Hj@^(OD8ey7F%B1fCma=Zd`eG)k)l|6vQ|ecVqH4)> zH2A6tWYQ8#D*OtqVm@L%l0_PrrB1VY<>_tN2CAJ>ehPl9vPqn27irtytCA`b>{E`? ze5qBF7t*}aOj&YiO)32qeiuKsz^V6$^=Jkb)apQFHXD0|L*%71^HV_KpiEE%=+hQ= zzdChCVqoGIT-7qMgW758B1%$;nIfO*mPX}9fn}>@wl}i8g%2}H2mO~6KRYi`t*EUG zcj|hBc6S+01S^HAsr0lcL+B<1V=NS|_$AR(NW_CeI!8DR&G`3?EW}Db^{l zDRJdW+Rk(MbJ^vN<*Ku6b~JY8c1v~-b1W4x6D1Q~ITP8YT+cg?VTZMC5${{>?XJEZ z3LhqsW|Dp-B_Y)&P2(EiCdqWl{GPd+xz9D&XlsDpgkZ31u-|0DmXdKYs%1^x5XBFv zs)m*@Pl*(+RtQ&Fls4$u6sRfC(6fs zSJqsdUDGman`oTCu-~(#;i}+nAIz`)p|4*lGoQ!*O=##tfzRhVMs(pQy{K%$RYFrH zD3d1h5fgm%sZ?T>t@lzlde73Zw}|^=Vr_JS@bqCtuJlejC{#@w*EN%IOcc( zItI}%qFH8Qw<*`n7BaU47E6|BQ*Rf@toBOEw!zW;sPaP0zGt6f-|C|9(o@R=<158i z39?ax$t6kqq!Z{S;b}Fx3A#035^q4KcBdsG0wNJ2F(Pjpo1)e&Vh=H_zvM)4{T3+5C!YBDV5PIA)Lgcq-Tf_DmR8P z!M!^%3lmo*&9P65w)aPGF9c?gw3K9DyIkDR^pI>+451>Sm&|wBe(5<`WocjOG-<^& zJtqBz9hqo@Xh5+rA;oI~Un)@OsO3m8vgITfKG>7LwY-9uoHl824k&jBl+T6A;pZ>w~AH()x@eEaa=@ z3FNooRK=S%-qo9)2kw+5$0rxibCyk&je&z3ZyRSMsLdm58I3uGX**fJaTTyhwhe>l zPPFmz#ikOJ=-ltWUSHET>Yn3~!K8mwcgFs|AiJ-rFpxAZbFcHz_X{+8d2nT+Yu(X*1~vx1A6bMPpRB`w=tj-HO5CyE z{KsbHw~3?t!?rFPe^Y-csN7k?glvdx(O_@fyE(zx1>RELWS-ub#DThP*Foo}jVnoC zyov)g&Vtrk1U^dsv#r5fiqjknp(US4zw!gxr`+r2NrOlO$o!A_h~`2bu&^yL3cuL)_iv5b{ zw|{T^z`Azb=C>RBoc$U;3hDlY<*V@98-$k#!uedRvmMe!|GW7nWvU|gqt`>H4d{E{FZ-#Z3{i!((y#pY^Vg31mOpo9yuhc$C6Q|t zUq!D2pCAtwmxBoh$EvrgDY-GCULQ~&&%J3Jt@qY%f-fF81oS_?{HH{9k<)jFfkDUn zv%$h-W)Z`{AOOKydLDYpN&*(njx6Su&LArmZ%3DxXc!nFZ-JLxM=K9=fVZQAle>Vo zFz~MkftUS1W>z5JuMiJ=VW6I}8bH$7%?iNH!o|V{6hQ+3077n-)&d$*GXI9Z90>z$ zJv>|lSXsTiyjZ+AS)AQ$SlRjc`B~XGSUEVDUm}>@eVjbZy_ucd-~KDf|KyRfa<^~; zyLf<|odAFGnuDC*c?bi6e~A9``B$ADVC(;7a&rH-tQUc-e>|-0ENra*4QAyH{y$)U zJpU)m(&9g=T;91k{H4j#g4N2w%F)Wn!~F%v{$J@{dix*X|5v29xy!%E{%YdCv4K#{u!_T-w6J0{2Sm;>jl)n-c}BJQs9?{{-uJCM~L;m zI{pcibarrd({wSnu=-QjUy#3<{u%ujjsE}A@bdkg=5LO_0WB>A+~0xhtSmhKHd-%Z z_Sf8(Ft=g-n^}nUzeWqa%me{tXG^fPkCeHGl?VqLI~Ow>H!~Zj7CXNH8@B*Amk{ee zV*XaaACIJ)mAQwro0hY)gUDYh9RC~wI9Xm)|I`0(s1WO)RrI%2^{*xSm-S`MilDt9 z|7ZP+pgsIp{0;;2MnqmpT+164n&so7v*0r@QDQ6s*NEN+tc&z(dSk(}Fc9JBpej_C z1jc1mo;i5VR-pwy>6XkKcudb8G|qsNxRUw~3c(Jb<7MKNe(SnAcH&VMu>b@V2;wA? z?a_trsc>$!h&-T{(5ATN>E{pMlh*y5iyt=~r@rID6zsg$xSDtxAs!If78Vbbt_6vb z0fp(y4LI{eHL4x7Rf$h(6vZ(LD+uS5qS8Nc0Xb>ELQ?90JhIWFcsi&fAz+E-03*V2 z)WHzd-~x$6u?(TjOqfkwgkckcWyGQ9-XT3~^gu6EQ@nXJO~ms=#6nG50v1%{U}1^S zS}i&pK(k3H&Nzxq2s&IQ7QlB@`MWLNh>Ho85Tg*K5>DdG^t6%5$FEq~6`e4$G#KyX z%JJA<$7j;#WyG&Axpc~x5&-Vv15yj1%)RNTJoa2xLFCO!ExL3Bi3^qb`_^MQ&_qoQ zBNflsdamm@a?jI_PHxZbftUz^U2=SY4hJ~V-oaK*<74W$cpc0XpO6wf&CZ+6g_Z8Wzin`0l#b}*uL7s7 zJ|i#4b%&s?@wS~kYYRFN3sqAiSHX7}n{Y9ax|a*0*3G1a>Wk>iKBKLfjmPk{`z3YXqAw-pXd!t&dx8o+dkr6~|L&QUGYKeVJ~a>xXkPYIb(zhV>p9 zU}xnkeVp5j$aJ&Uu3FU<6^vJha}`dZ;lXOFrzXk8U%oW8z72cTnnbIj7A<1#AHk(z zGg3IDMRi~zgKiBQ7NJJ08WBV8`O>2)nnoMyvMe=+n=p#Dv+col37nLioD&zdk<=QO zG?uwmcW!Qvbjm14C4zeNs7NDypH@bq>yPz=olU!#H%oy}Ia&nlvV-m*J{g(5ws%Ly znTJlL&fS!tP=SycI2^=cxFmKH0PX>{2=7vXGE*_kcB=y2=*UQ%m9646GB*C5 zM>!^bf*OzO-YLXYvsk66Ua-0ARHsJ&i1i_PkytQJ9|pxo2swWr%`gNC$0@kAvx4g| zWsAm1&9#|4InHE1Gs61$0)m5~zcokn`_NYeC>BN9N+bUkZ9|~$cj%BSTMR|u02tRU$1?yJjAG$4#-dc-74nwzRAjC`O(krz>1scotQY`lk@ZQA0L($ zs8T3D7S53zL^r7F~-v4|KJKmWi#?sKua= zG;v}yVx7045J#q5{J7fSNe&*swd+?7OxX%Teh^77mjtymEIZ11A;Y@xuMH$!BcrWU z`>kIMxxW`tvH-}sT3Qa73Zv*tpG|%{{vgZSw4bk@*#Q-2q<(4cIItei+&#ZQAI;Lr z7LXqrL?6_|4b3LBWgPqxO*{~!*E9l>CXFCuD;6d6M8S^CxE1Thm_@}975Fp>c@5`d zE0XAzU(X@qE%Wp0r2W+PX`>_I;cT$o_#l~Hh7HmGYMNC}X@30~Sw_GbUc>Z$cVhMT z(*xNN(dglcVdnsJwOy8SnShHZ2Lwk0hiPrug#Jke!$P`p*)ql=+!)smK~97*@4Ipk zZ8H9t2xZ<>^4oqLPObxQnbrO%`pr@Fhi>8OyTiF1tp0(9{n5GOihdfro$XpS5}401 z#XP*G+CLs61l=yf6Cy)Pii+>_GQ%y)Yo*dzv8&G<*Z{4i_e913G!Q#cFdT-mfC6zS ze21(aWir}jiL{t`G5XySKYz2DJM?|t#+v!&PIy=bR>RMW(S`~8PEc7zSsBk@i_6qj z%aWS#EnE)b9!jv~jw3FytF1EyiDC?NCY~~j?a?eO9y4*u!#OSP;I=g2+k>3gHl;w< z;cS_nm)942d&eeh$GP&kYRhv=cRgokzmd+%>50|lrlT>W?TupPT&E;#uBUZ^>O1Th zq9FYQ@W!q=?ypFBxFnS2Sy^}g+;Huc2NX{tU-XD{TqQ(O%%hSexUo`3BS2cYv{y7F~PkmM%8D+ z!r?8Lb7y4uk^6LKN|o5IzMF|CGfV<`xWJ8)rFl$eNk%8=m4JOEU_y)@GqH1yO}`V~4-12WUdx?VGCDfws$-DGwvIS0$It!C_NFGu-aLCw(csGI;Pdn$43J6=ki`~En@)hsihnTcR><0cr| zOCJb1MilhZ5v!={>d5m&lre-|A5PD%b0AR&)yM<8i80Jr5sppdirU0NAJ+YQdK;ZT z9+42e+ppb=_V`fv%v#@4P(Q zSP066JV&9+t>2)_O*6*j72D*Y!rwmB)M_u%XrbCVRR0Cc=7JcrOnxDX-r6K6z$t>Of%V=-7qgpyG5-*S`dlZ1Bp%-3&S9w~V)TcNwOodx~T1 z@rc5+-fd!h$eT_NRF;^^3xzMJH7E}VTscIGG?mZ z8!XbBO_rV3cMC_n?Exw7-r!;Ig+3j@@o>LZ4w)rj)NQ+r?`HCAa}--6=Q5tJOzC%-W>Rpu zqKO`x>5esn)1G301B+iTJH(HVoC_0(hd5?WSdMtSPj3FXR#VKrpsr2@IV~`}AHmE% z2j3dKjIX@Lc5gGRYe7q{$viG~Sq+L4v18qGt`DUM(c|(%1UF>&s-E5V&1}oh1Rm8hCRiZG7)9&LIT&00v8rd#Dri z)|gb#+9OekW#vL{D5A9-fRaSeqvK=Tj5o~%A<3s2W6WbGmj^S|^6hX_wpmy`BEtj= zKjJ5EeX?c)j2J5iFc`E#X0N|$w#zy zBy8@~)2%kb%+|=${+bYI{T>sl979DwT4`fj1!j*y8Bw3N=V6UUvOYkEJ*tCn=Cdv9 zQJX2sO6B*t38{7?{GhfJX>%<=eD?MZ?|=B5)LR^yiB@K!SY!H1&I*S_Gr+Uiz8|G3 zWTSj`BqTA*=ZBUl-1Ojo16W;y`}KYf`UUzsh~*< zI0MBx^E5yxYB@D79Z_usKfY*f> zVf}pTS2Xb!s1CZg3PywI$$`W}TD#(ynQv9GvhXoO8@t89x4z0LI*AK!kWOJKqh)y1 zY}Dc`*hwx-Y$cBT zX(Ly47<>R``4k~tEWw>Y^z|+G5Ed^lub@cMFUnI-lxENTqIh|`;KM8TY6}@b|D^+5 zG{3@{OMW}7ZzH*)XMJ`bmJi3Ziu5Z>>M!@hw8fO<%Fz&(mk9()yXEibiz%A@GK)>v zlg^i&X~dU5Cs4W-wPHuVooyzs>f&k98U6IpBEY!#YY!EGxy5cLl++GNm?FgpnwP<# z&(+q8Ny7G=TF?mm`l{U<)S!JqW!`~pk&t<%H3LH`15bUK(4AW(7}~LN;JEF5$KMQ4VMP$YT1Ei^0!2jCWzwFt1OTH)tsc8vix6HHDW`rzehBoEk zzT*vHLCs~x3kUWJ zy%I3kl6lw+ZFyyR>|}2z`it7cJWxu66{v3O4&1Wp{fd9{JEu}LcY8PVpc^kL+niwN zSlKlqS=V_HFC;ZnQ)6^EkLxvhnZPS+^-im>Wfoso1|>B49BjkIP(ApgSM=4I2p125 zJj!?OjaK0lc4jh@8-@}7u?D3g-~^rZT8V=hn_PaQGH3lvhQ9fD0XVyv%J2cuen-_& zEK^}RkNeD$eTj0a6WEsL`m$?3CCfSv*9yL)zY12 z)dGY;M_axhnwLx_*7Y(fZZ_EJI|qWIc(1tl85#$%vHb0eCNu>|w<4@We2f9g_F!-m zaT1UB^iO;|xC_zvk;5t5Mz&27j3;_dn-&c}dRyJfk>1!e6NyirgA;Q&K$2*takgaJ zT)(y2q8vRF{#+)x8NHY-*`7tMP|Cu5aqj~&oq~>lD|34k0v{mXUPc~cbdvmq8*N+S z7RcS`-7@tMNRFY`%p<63eTZy( zScVhcX^}o{HpCq!jzZepZHlhyEC?~_!y7SxR}c3}uVhuq*03A#S5B)*FQ!?uxGBf_ ztg@nrD#z{iPQ{cC&*|5O>y(JQNaa?;PZhS3g<9pPd*<%dmBHuy|z;v8DgnPVik+YtY(B=x@TI=`z^HP>&? z<)s1hv_8NxXhOa#3~)?R(L&!VzX4lJmJQuY!6|u`53*UiFQoe|XJUfPwA{HigWNGH zk~T@`trlzFGL)NKgEGzg^Y5Rxk9VY|(*HBKiwo#*IeB3*HpdB|64ae{_EmX`^cRKX zMJA!m-TR71CMKT*hDP!V2#Jy+h33h{V)rikm$j3s32N^LXbcsOs~|T+UBqt3{bFP& z@=bc5QDb_gsxK;a9P2AY49A$c0>4h%+>0DbnDsKxZG8XX%kXhP#SOrd}-tQW>N*iTCM0%<||g9T!mB6AQ>F zj#ZYu8oa7;nVrj^@5Y$ay;oWfGZv~tDE)veKxec?f4pb0odJd?MTB?&X3>t~V+-hS zFsXjhJ)fawjlYNX;eZs;ugczA`?T`+FSjY)tIS(ZkkqmW)wC3C~Ei>x}w}czaf&fpdP3zplnE$v^d6VXo`c)(;;4+0l%c* zN0{OYI&|RT2uHftQ8SW~57}XwFu?u3z zV@_{KOK_}g#F6ojLiO10B%ks)@0d!Z+Yt^PkmK1^71jIusY+BSoda^vaAU2$+gKb5$mg9a}4%Xs(JJ z!&aouu>FQ2z-;anyCV%KgAZzJY!1a65P6<84Ettb5JRSqtBs#Ii%L`JU`WFwmAqW;ul{#bu{ zR!vv9E zFmlI410Jut%L$(yb`*mLy#|#mF1@+@1XlFvTr9}?7>aMsAXs<@rdrut0!H+qk_D@^ zvjjyS)2V;qlVOa}(tw3>_3~X?zE^Id^p~`fDvTX-J%hvlcFsEJxLV);5mdAH9`Bc_ zfCvDC3~Dbx7_Q2@s6Hdjuf!oiN;iWA*vz8{a9UQVCFe^MF+f(2 zR}eq}gxOn*rjVBLQ3m(mQS@vym*ab^slS7JK=( zIEd?n(!ac?b`Xb53wg>l@aFzWAFRiP`+l1$v7{es`41X?eDuUha>aR==IO*8YrKoC8G`w$9k=TMs z5o0exj9v&bh>-gT<$IYM>afW&5m64aD{khr+{GwSWg25UkzQxSJNfiPh1-{6-UJv` zOEMrlED>B2%7!R+y1@Qc(iASMIU>7)Qmm-EA?#T9owu;Sp6ats(t&c^Y$$X@j9tQFT|!3Gv?kLuXLziGcKPD|4l8=&FqWny?$$rky> zwz>Wu^;&>s`h9SpOi)J3WCtB5K>w}8oswpTI&}TZf+x!%&nVGho9-fm173NsI<@x1 zMIe3H7ko03J+r`HV&P~-!B+AP36{JRuO}AY_Ir{eyr&#jW%9tTwbu204*p;ugB@z_ zSGyWdiao-v=wGQ(m)H9v*WV@p1ebtu;UA#;YAuXo!HU(Ewbs%_~;>UD_$p!POI-V1K&x| zrT*3{D#!Ok$M8pa!^u3?uzl_$_^QXJ*8^hI&E<_rUbF2AN7ayxEI4Mjtd@%!*f+B{ zXb)%EjK-%~1HpJ=*o>Z}i~e4_;QsJkO>pUSAUN7G+X7hI!`Gx?o*00Xl*VZ0F@wlS zq~J`A;hu%loWwe03nU%hPj-h>i4+R`@bbhlaTCb1OfM%RN$Ez#MVLRe!Ah24H}gCq c$N9@YVqW=T_YGp&pSLUIrB$S=CCq~UA9(}Q6951J diff --git a/examples/gamepad/quickGamepad/quickGamepad.pro b/examples/gamepad/quickGamepad/quickGamepad.pro deleted file mode 100644 index 176665c..0000000 --- a/examples/gamepad/quickGamepad/quickGamepad.pro +++ /dev/null @@ -1,13 +0,0 @@ -TEMPLATE = app - -QT += qml quick gamepad - -SOURCES += main.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/quickGamepad -INSTALLS += target diff --git a/examples/gamepad/quickGamepad/quickGamepad64.png b/examples/gamepad/quickGamepad/quickGamepad64.png deleted file mode 100644 index 707d5c4e85d82959740b243a8a36d5071c277299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3400 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 Jjgn>L{{TKddny0` diff --git a/examples/gamepad/simple/android/AndroidManifest.xml b/examples/gamepad/simple/android/AndroidManifest.xml deleted file mode 100644 index 37e238f..0000000 --- a/examples/gamepad/simple/android/AndroidManifest.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/gamepad/simple/doc/src/simpleexample.qdoc b/examples/gamepad/simple/doc/src/simpleexample.qdoc deleted file mode 100644 index b7ec648..0000000 --- a/examples/gamepad/simple/doc/src/simpleexample.qdoc +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! -\example simple -\ingroup qtgamepad-examples -\title Qt Gamepad Simple Example -\brief A simple example demonstrating the APIs in use. -\include examples-run.qdocinc -*/ diff --git a/examples/gamepad/simple/gamepadmonitor.cpp b/examples/gamepad/simple/gamepadmonitor.cpp deleted file mode 100644 index f0721ba..0000000 --- a/examples/gamepad/simple/gamepadmonitor.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "gamepadmonitor.h" -#include - -#include -#include - -GamepadMonitor::GamepadMonitor(QObject *parent) - : QObject(parent) - , m_gamepad(0) -{ - QLoggingCategory::setFilterRules(QStringLiteral("qt.gamepad.debug=true")); - - auto gamepads = QGamepadManager::instance()->connectedGamepads(); - if (gamepads.isEmpty()) { - qDebug() << "Did not find any connected gamepads"; - return; - } - - m_gamepad = new QGamepad(*gamepads.begin(), this); - connect(m_gamepad, &QGamepad::axisLeftXChanged, this, [](double value){ - qDebug() << "Left X" << value; - }); - connect(m_gamepad, &QGamepad::axisLeftYChanged, this, [](double value){ - qDebug() << "Left Y" << value; - }); - connect(m_gamepad, &QGamepad::axisRightXChanged, this, [](double value){ - qDebug() << "Right X" << value; - }); - connect(m_gamepad, &QGamepad::axisRightYChanged, this, [](double value){ - qDebug() << "Right Y" << value; - }); - connect(m_gamepad, &QGamepad::buttonAChanged, this, [](bool pressed){ - qDebug() << "Button A" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonBChanged, this, [](bool pressed){ - qDebug() << "Button B" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonXChanged, this, [](bool pressed){ - qDebug() << "Button X" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonYChanged, this, [](bool pressed){ - qDebug() << "Button Y" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonL1Changed, this, [](bool pressed){ - qDebug() << "Button L1" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonR1Changed, this, [](bool pressed){ - qDebug() << "Button R1" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonL2Changed, this, [](double value){ - qDebug() << "Button L2: " << value; - }); - connect(m_gamepad, &QGamepad::buttonR2Changed, this, [](double value){ - qDebug() << "Button R2: " << value; - }); - connect(m_gamepad, &QGamepad::buttonSelectChanged, this, [](bool pressed){ - qDebug() << "Button Select" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonStartChanged, this, [](bool pressed){ - qDebug() << "Button Start" << pressed; - }); - connect(m_gamepad, &QGamepad::buttonGuideChanged, this, [](bool pressed){ - qDebug() << "Button Guide" << pressed; - }); -} - -GamepadMonitor::~GamepadMonitor() -{ - delete m_gamepad; -} diff --git a/examples/gamepad/simple/gamepadmonitor.h b/examples/gamepad/simple/gamepadmonitor.h deleted file mode 100644 index 72350a0..0000000 --- a/examples/gamepad/simple/gamepadmonitor.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef GAMEPADMONITOR_H -#define GAMEPADMONITOR_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QGamepad; -QT_END_NAMESPACE - -class GamepadMonitor : public QObject -{ - Q_OBJECT -public: - explicit GamepadMonitor(QObject *parent = 0); - ~GamepadMonitor(); - -private: - QGamepad *m_gamepad; -}; - -#endif // GAMEPADMONITOR_H diff --git a/examples/gamepad/simple/main.cpp b/examples/gamepad/simple/main.cpp deleted file mode 100644 index 246923b..0000000 --- a/examples/gamepad/simple/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include "gamepadmonitor.h" - -int main(int argc, char **argv) -{ - QCoreApplication application(argc, argv); - - GamepadMonitor monitor; - - return application.exec(); -} diff --git a/examples/gamepad/simple/simple.pro b/examples/gamepad/simple/simple.pro deleted file mode 100644 index 1fde59e..0000000 --- a/examples/gamepad/simple/simple.pro +++ /dev/null @@ -1,17 +0,0 @@ -QT += gamepad - -CONFIG += c++11 - -SOURCES = main.cpp \ - gamepadmonitor.cpp - -HEADERS += \ - gamepadmonitor.h - -DISTFILES += \ - android/AndroidManifest.xml - -ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android - -target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/simple -INSTALLS += target diff --git a/examples/universalinput/CMakeLists.txt b/examples/universalinput/CMakeLists.txt new file mode 100644 index 0000000..b315f01 --- /dev/null +++ b/examples/universalinput/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_example(consolejoystickmonitor) +qt_internal_add_example(simple) +qt_internal_add_example(actionpong) +qt_internal_add_example(quickaction) +qt_internal_add_example(mousegrab) +qt_internal_add_example(virtualgamepad) diff --git a/examples/universalinput/actionpong/ActionMap.qml b/examples/universalinput/actionpong/ActionMap.qml new file mode 100644 index 0000000..e7a573a --- /dev/null +++ b/examples/universalinput/actionpong/ActionMap.qml @@ -0,0 +1,70 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtActionStore + +ActionStore { + id: actionStore + property int device: JoyAxisEvent.Device0 + + InputAction { + title: "MoveUp" + JoyAxisEvent { + device: actionStore.device + axis: JoyAxisEvent.LeftY + direction: JoyAxisEvent.Up + deadzone: 0 + } + JoyButtonEvent { + device: actionStore.device + button: JoyButtonEvent.DpadUp + isPressed: true + } + KeyboardEvent { + id: upKey + key: actionStore.device === 0 ? "Key_W" : "Key_Up" + isPressed: true + } + } + + InputAction { + title: "MoveDown" + JoyAxisEvent { + device: actionStore.device + axis: JoyAxisEvent.LeftY + direction: JoyAxisEvent.Down + deadzone: 0 + } + JoyButtonEvent { + device: actionStore.device + button: JoyButtonEvent.DpadDown + isPressed: true + } + KeyboardEvent { + key: actionStore.device === 0 ? "Key_S" : "Key_Down" + isPressed: true + } + } + + InputAction { + title: "MoveStop" + KeyboardEvent { + id: stopUp + key: actionStore.device === 0 ? "Key_W" : "Key_Up" + isPressed: false + } + KeyboardEvent { + key: actionStore.device === 0 ? "Key_S" : "Key_Down" + isPressed: false + } + } + + InputAction { + title: "ReleaseMouse" + KeyboardEvent { + key: "Key_Escape" + isPressed: true + } + } +} diff --git a/examples/universalinput/actionpong/Ball.qml b/examples/universalinput/actionpong/Ball.qml new file mode 100644 index 0000000..4f73f6c --- /dev/null +++ b/examples/universalinput/actionpong/Ball.qml @@ -0,0 +1,38 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Rectangle { + id: ball + color: "white" + width: 20 * scale + height: 20 * scale + + readonly property real topY: y - height * 0.5 + readonly property real bottomY: y + height * 0.5 + readonly property real leftX: x - width * 0.5 + readonly property real rightX: x + width * 0.5 + + property real lastDX: 0 + + transform: [ + Translate { x: -ball.width * 0.5; y: -ball.height * 0.5 } + ] + + property real scale: 1 + property real dx: 3 * 60 + property real dy: 3 * 60 + + function move(delta : real) : void { + const dx = ball.dx * scale * delta; + ball.x += dx + ball.lastDX = dx + ball.y += ball.dy * scale * delta + } + + function reset() : void { + ball.x = parent.width / 2 - ball.width / 2 + ball.y = parent.height / 2 - ball.height / 2 + } +} diff --git a/examples/universalinput/actionpong/CMakeLists.txt b/examples/universalinput/actionpong/CMakeLists.txt new file mode 100644 index 0000000..99a3b51 --- /dev/null +++ b/examples/universalinput/actionpong/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(actionpong LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/actionpong") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput Quick QuickActionStore QuickUniversalInput) + +qt_add_executable(actionpong + main.cpp +) + +qt_add_qml_module(actionpong + URI Example + VERSION 1.0 + QML_FILES main.qml + QML_FILES ActionMap.qml + QML_FILES Paddle.qml + QML_FILES Ball.qml + QML_FILES PaddleController.qml + NO_RESOURCE_TARGET_PATH +) + +set_target_properties(actionpong PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(actionpong PUBLIC + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::Quick + Qt::QuickActionStore + Qt::QuickUniversalInput +) + +install(TARGETS actionpong + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/universalinput/actionpong/Paddle.qml b/examples/universalinput/actionpong/Paddle.qml new file mode 100644 index 0000000..fe44247 --- /dev/null +++ b/examples/universalinput/actionpong/Paddle.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Rectangle { + id: paddle + color: "white" + height: 80 * scale + width: 10 * scale + + readonly property real topY: y - height * 0.5 + readonly property real bottomY: y + height * 0.5 + readonly property real leftX: x - width * 0.5 + readonly property real rightX: x + width * 0.5 + + transform: [ + Translate { x: -paddle.width * 0.5; y: -paddle.height * 0.5 } + ] + + property real scale: 1 + property real velocity: 0 + property real speed: 5 * 60 + + function move(delta : real) : void { + paddle.y += paddle.speed * scale * delta * paddle.velocity + } +} diff --git a/examples/universalinput/actionpong/PaddleController.qml b/examples/universalinput/actionpong/PaddleController.qml new file mode 100644 index 0000000..be208f4 --- /dev/null +++ b/examples/universalinput/actionpong/PaddleController.qml @@ -0,0 +1,44 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtActionStore + +Item { + id: paddleController + required property ActionMap actionMap + required property Paddle paddle + + ActionDispatch { + actionStore: paddleController.actionMap + + ActionHandler { + actionTitle: "MoveUp" + onTriggered: { + if (source === ActionHandler.Key) { + paddleController.paddle.velocity = -1 + } else if (source === ActionHandler.JoyAxis) { + paddleController.paddle.velocity = -value > 0.2 ? value : 0 + } + } + } + + ActionHandler { + actionTitle: "MoveDown" + onTriggered: { + if (source === ActionHandler.Key) { + paddleController.paddle.velocity = 1 + } else if (source === ActionHandler.JoyAxis) { + paddleController.paddle.velocity = value > 0.2 ? value : 0 + } + } + } + + ActionHandler { + actionTitle: "MoveStop" + onTriggered: { + paddleController.paddle.velocity = 0 + } + } + } +} diff --git a/examples/universalinput/actionpong/main.cpp b/examples/universalinput/actionpong/main.cpp new file mode 100644 index 0000000..913b563 --- /dev/null +++ b/examples/universalinput/actionpong/main.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + // window + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/universalinput/actionpong/main.qml b/examples/universalinput/actionpong/main.qml new file mode 100644 index 0000000..767f81c --- /dev/null +++ b/examples/universalinput/actionpong/main.qml @@ -0,0 +1,180 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtActionStore +import QtUniversalInput + +ApplicationWindow { + id: mainWindow + visible: true + width: 800 + height: 400 + title: "Paddles" + + property double scale: 1 + + function updateScale() : void { + scale = Math.min(mainWindow.width / 800, mainWindow.height / 400) + } + + onWidthChanged: updateScale() + onHeightChanged: updateScale() + + Rectangle { + id: gameArea + anchors.fill: parent + color: "black" + + property int player1Score: 0 + property int player2Score: 0 + + Paddle { + id: paddle1 + scale: mainWindow.scale + x: 10 + width * 0.5 + y: gameArea.height * 0.5 + } + + Paddle { + id: paddle2 + scale: mainWindow.scale + x: gameArea.width - 10 - width * 0.5 + y: gameArea.height * 0.5 + } + + Ball { + id: ball + scale: mainWindow.scale + x: gameArea.width * 0.5 + y: gameArea.height * 0.5 + } + + function handleCollisions(deltaTime : real) : void { + if (ball.topY <= 0 || ball.bottomY >= gameArea.height) + ball.dy = -ball.dy + + let ff_duration = 0.1 + let ff_strength = 0.5 + + let hit = false + let device = null + if (ball.leftX <= paddle1.rightX && ball.bottomY >= paddle1.topY && ball.topY <= paddle1.bottomY) { + hit = true + device = actionMapPlayer1.device + } + + if (ball.rightX >= paddle2.leftX && ball.bottomY >= paddle2.topY && ball.topY <= paddle2.bottomY) { + hit = true + device = actionMapPlayer2.device + } + + if (hit) { + ball.x -= ball.lastDX + ball.dx = -ball.dx + universalInput.addForce(device, Qt.vector2d(ff_strength, ff_strength), ff_duration) + } + + if (ball.leftX <= 0 || ball.rightX >= gameArea.width) { + if (ball.x <= 0) + gameArea.player2Score += 1 + else + gameArea.player1Score += 1 + + ball.reset() + } + + handlePaddleInBounds(paddle1) + handlePaddleInBounds(paddle2) + } + + function handlePaddleInBounds(paddle : Paddle) : void { + if (paddle.topY < 0) + paddle.y = paddle1.height * 0.5 + + if (paddle.bottomY >= gameArea.height) + paddle.y = gameArea.height - paddle.height * 0.5 + } + + FrameAnimation { + id: frameTimer + running: true + onTriggered: { + paddle1.move(frameTime) + paddle2.move(frameTime) + ball.move(frameTime) + gameArea.handleCollisions(frameTime) + } + } + + Label { + id: scoreLabel + anchors.horizontalCenter: parent.horizontalCenter + y: 20 + text: gameArea.player1Score + " - " + gameArea.player2Score + color: "white" + font.pixelSize: 40 + font.weight: Font.ExtraBold + } + + // Mouse solution. Have to propagate mouse events to actionStores + MouseArea { + anchors.fill: parent + onPressed: event => actionEventListener.sendMouseButtonEvent(event, true) + onReleased: event => actionEventListener.sendMouseButtonEvent(event, false) + } + } + + Label { + x: 10 + y: 10 + text: "Press ESC to release mouse" + color: "white" + } + + // Player 1 actions + ActionMap { + id: actionMapPlayer1 + device: ActionMap.Device0 + } + + PaddleController { + paddle: paddle1 + actionMap: actionMapPlayer1 + } + + + // Player 2 actions + ActionMap { + id: actionMapPlayer2 + device: ActionMap.Device1 + } + + PaddleController { + paddle: paddle2 + actionMap: actionMapPlayer2 + } + + // Distributes key and mouse events for actionStores + ActionStoreEventListener { + id: actionEventListener + actionStores: [actionMapPlayer1, actionMapPlayer2] + focus: true + } + + // Using actionMap to listen for mouse events such that we can release the mouse. + // Also an example of standalone ActionHandler. + ActionHandler { + actionStore: actionMapPlayer1 + actionTitle: "ReleaseMouse" + onTriggered: { + universalInput.mouseDisabled = false + } + } + + UniversalInput { + id: universalInput + mouseDisabled: true + } +} diff --git a/examples/universalinput/consolejoystickmonitor/CMakeLists.txt b/examples/universalinput/consolejoystickmonitor/CMakeLists.txt new file mode 100644 index 0000000..cf931bf --- /dev/null +++ b/examples/universalinput/consolejoystickmonitor/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(consolejoystickmonitor LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/consolejoystickmonitor") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput) + +qt_add_executable(consolejoystickmonitor + main.cpp +) + +set_target_properties(consolejoystickmonitor PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(consolejoystickmonitor PUBLIC + Qt::Core + Qt::Gui + Qt::UniversalInput +) + +install(TARGETS consolejoystickmonitor + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/universalinput/consolejoystickmonitor/main.cpp b/examples/universalinput/consolejoystickmonitor/main.cpp new file mode 100644 index 0000000..dd688d9 --- /dev/null +++ b/examples/universalinput/consolejoystickmonitor/main.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + auto input = QUniversalInput::instance(); + + QObject::connect(input, &QUniversalInput::joyConnectionChanged, [](int joyId, bool connected) { + qDebug() << "joyConnectionChanged!"; + qDebug() << "joy" << joyId << "connected:" << connected; + }); + QObject::connect(input, &QUniversalInput::joyButtonEvent, [&input](int device, JoyButton button, bool pressed) { + qDebug() << "Device: " << device << "button: " << int(button) << ( pressed ? "pressed" : "released") << "\n"; + input->addForce(0, QVector2D(1, 1), 1.0f); + }); + QObject::connect(input, &QUniversalInput::joyAxisEvent, [](int device, JoyAxis axis, float value) { + qDebug() << "Device: " << device << "axis: " << int(axis) << "value: " << value << "\n"; + }); + + qDebug() << "hello, this is a console joystick monitor"; + + return app.exec(); +} diff --git a/examples/universalinput/mousegrab/CMakeLists.txt b/examples/universalinput/mousegrab/CMakeLists.txt new file mode 100644 index 0000000..8da585c --- /dev/null +++ b/examples/universalinput/mousegrab/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(mousegrab LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/mousegrab") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput Quick QuickUniversalInput) + +qt_add_executable(mousegrab + main.cpp +) + +qt_add_qml_module(mousegrab + URI Example + VERSION 1.0 + QML_FILES main.qml + NO_RESOURCE_TARGET_PATH +) + +set_target_properties(mousegrab PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(mousegrab PUBLIC + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::Quick + Qt::QuickActionStore + Qt::QuickUniversalInput +) + +install(TARGETS mousegrab + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/universalinput/mousegrab/main.cpp b/examples/universalinput/mousegrab/main.cpp new file mode 100644 index 0000000..c8543cc --- /dev/null +++ b/examples/universalinput/mousegrab/main.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include + +#include + +#include +#include +#include +#include + + +using namespace Qt::Literals::StringLiterals; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + // window + QQmlApplicationEngine engine; + + const QUrl url(u"qrc:/main.qml"_s); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/examples/universalinput/mousegrab/main.qml b/examples/universalinput/mousegrab/main.qml new file mode 100644 index 0000000..37c9a06 --- /dev/null +++ b/examples/universalinput/mousegrab/main.qml @@ -0,0 +1,109 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtUniversalInput + +ApplicationWindow { + id: mainWindow + visible: true + width: 800 + height: 400 + title: "Mousegrab" + + Rectangle { + id: gameArea + width: parent.width + height: parent.height + color: "gray" + + Rectangle { + id: player + width: 10 + height: 10 + color: "red" + + Component.onCompleted: { + resetPosition() + } + + function resetPosition() { + x = parent.width / 2 - width / 2 + y = parent.height / 2 - height / 2 + } + + function move(amount) { + x += amount.x + y += amount.y + } + } + + Keys.onPressed: event => { + if (event.key === Qt.Key_Escape) { + gameArea.focus = false + } + } + + onFocusChanged: { + universalInput.mouseDisabled = focus + if (focus) { + player.resetPosition() + universalInput.firstFramesAfterFocus = true + } + + } + + MouseArea { + anchors.fill: parent + onPressed: { + gameArea.focus = true + } + } + + Label { + x: 10 + y: 10 + text: "Press ESC to release mouse" + } + + Label { + x: 10 + y: 30 + text: "Click to grab mouse" + } + + Label { + id: deltaLabel + x: 10 + y: 50 + text: "Mouse deltas: (0,0)" + } + } + + UniversalInput { + id: universalInput + mouseDisabled: gameArea.focus + + property bool firstFramesAfterFocus: false + property int frameCount: 0 + + onMouseDeltaChanged: delta => { + deltaLabel.text = "Mouse deltas: (" + delta.x + "," + delta.y + ")" + + if (mouseDisabled) { + // Big delta after focus is received, so delay the action + if (firstFramesAfterFocus) { + if (frameCount < 1) { + ++frameCount + return + } + frameCount = 0 + firstFramesAfterFocus = false + return + } + player.move(delta) + } + } + } +} diff --git a/examples/universalinput/quickaction/CMakeLists.txt b/examples/universalinput/quickaction/CMakeLists.txt new file mode 100644 index 0000000..264c752 --- /dev/null +++ b/examples/universalinput/quickaction/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(quickaction LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/quickaction") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput Quick QuickActionStore QuickUniversalInput) + +qt_add_executable(quickaction + main.cpp +) + +qt_add_qml_module(quickaction + URI Example + VERSION 1.0 + QML_FILES main.qml + QML_FILES Controller.qml + QML_FILES GameObject.qml + QML_FILES Player.qml + QML_FILES GameObjectList.qml + QML_FILES Platform.qml + NO_RESOURCE_TARGET_PATH +) + +set_target_properties(quickaction PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(quickaction PUBLIC + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::Quick + Qt::QuickActionStore + Qt::QuickUniversalInput +) + +install(TARGETS quickaction + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/universalinput/quickaction/Controller.qml b/examples/universalinput/quickaction/Controller.qml new file mode 100644 index 0000000..432f0fd --- /dev/null +++ b/examples/universalinput/quickaction/Controller.qml @@ -0,0 +1,93 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtActionStore + +ActionStore { + id: actionStore + property int device: JoyAxisEvent.Device0 + + InputAction { + title: "Left" + + JoyAxisEvent { + axis: JoyAxisEvent.LeftX + direction: JoyAxisEvent.Left + deadzone: 0 + } + + KeyboardEvent { + key: Qt.Key_A + isPressed: true + } + + KeyboardEvent { + key: Qt.Key_Left + isPressed: true + } + } + + InputAction { + title: "Right" + + JoyAxisEvent { + axis: JoyAxisEvent.LeftX + direction: JoyAxisEvent.Right + deadzone: 0 + } + + KeyboardEvent { + key: Qt.Key_D + isPressed: true + } + + KeyboardEvent { + key: Qt.Key_Right + isPressed: true + } + } + + InputAction { + title: "Up" + + JoyAxisEvent { + axis: JoyAxisEvent.LeftY + direction: JoyAxisEvent.Up + deadzone: 0 + } + } + + InputAction { + title: "Down" + + JoyAxisEvent { + axis: JoyAxisEvent.LeftY + direction: JoyAxisEvent.Down + deadzone: 0 + } + } + + InputAction { + title: "Shoot" + + JoyButtonEvent { + button: JoyButtonEvent.RightShoulder + isPressed: true + } + } + + InputAction { + title: "Jump" + + JoyButtonEvent { + button: JoyButtonEvent.A + isPressed: true + } + + KeyboardEvent { + key: Qt.Key_Space + isPressed: true + } + } +} diff --git a/examples/universalinput/quickaction/GameObject.qml b/examples/universalinput/quickaction/GameObject.qml new file mode 100644 index 0000000..66dd776 --- /dev/null +++ b/examples/universalinput/quickaction/GameObject.qml @@ -0,0 +1,31 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Rectangle { + property vector2d velocity: Qt.vector2d(0,0) + property double velocityY: velocity.y + property bool gravity: true + + function update() { + goUpdate() + } + + function goUpdate() { + x += velocity.x + y += velocity.y + } + + function colliding(other: GameObject): bool { + return x < other.x + other.width && + x + width > other.x && + y < other.y + other.height && + y + height > other.y + } + + onVelocityChanged: { + velocityY = velocity.y + } + +} diff --git a/examples/universalinput/quickaction/GameObjectList.qml b/examples/universalinput/quickaction/GameObjectList.qml new file mode 100644 index 0000000..f25233a --- /dev/null +++ b/examples/universalinput/quickaction/GameObjectList.qml @@ -0,0 +1,10 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + + property list gameObjects + +} diff --git a/examples/universalinput/quickaction/Platform.qml b/examples/universalinput/quickaction/Platform.qml new file mode 100644 index 0000000..9bb521e --- /dev/null +++ b/examples/universalinput/quickaction/Platform.qml @@ -0,0 +1,9 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +GameObject { + gravity: false + color: "green" +} diff --git a/examples/universalinput/quickaction/Player.qml b/examples/universalinput/quickaction/Player.qml new file mode 100644 index 0000000..d61887f --- /dev/null +++ b/examples/universalinput/quickaction/Player.qml @@ -0,0 +1,62 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtActionStore + +GameObject { + id: player + + property Controller controller + property double playerSpeed: 3 + + function update() { + goUpdate() // does GameObject update functionality + } + + ActionDispatch { + actionStore: controller + + ActionHandler { + actionTitle: "Left" + onTriggered: { + velocity.x = value * -playerSpeed + } + } + + ActionHandler { + actionTitle: "Right" + onTriggered: { + velocity.x = value * playerSpeed + } + } + + ActionHandler { + actionTitle: "Jump" + onTriggered: { + let force = -15 + velocity.y += force + } + } + } + + function handleCollision(other: GameObject) { + if (x + width > other.x && x < other.x) { + // Left + x = other.x - width + } else if (x < other.x + other.width && x + width > other.x + other.width) { + // Right + x = other.x + other.width + } + + if (y + height > other.y && y < other.y) { + // Top + y = other.y - height + velocity.y = 0 + } else if (y < other.y + other.height && y + height > other.y + other.height) { + // Bottom + y = other.y + other.height + velocity.y = 0 + } + } +} diff --git a/examples/universalinput/quickaction/main.cpp b/examples/universalinput/quickaction/main.cpp new file mode 100644 index 0000000..ed8c6e4 --- /dev/null +++ b/examples/universalinput/quickaction/main.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include + +#include + +#include +#include +#include +#include + + +using namespace Qt::Literals::StringLiterals; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + // window + QQmlApplicationEngine engine; + + + const QUrl url(u"qrc:/main.qml"_s); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/examples/universalinput/quickaction/main.qml b/examples/universalinput/quickaction/main.qml new file mode 100644 index 0000000..f1a7d0f --- /dev/null +++ b/examples/universalinput/quickaction/main.qml @@ -0,0 +1,114 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtActionStore + +ApplicationWindow { + id: mainWindow + visible: true + width: 800 + height: 600 + title: "Platforms" + + Rectangle { + id: gameArea + width: parent.width + height: parent.height + color: "black" + + property int paddleWidth: 10 + property int paddleHeight: 80 + property double gravity: 0.5 + + GameObjectList { + id: gameObjectList + gameObjects: [p1, p2, p3, p4, p5] + } + + Player { + id: player + width: 20 + height: 20 + color: "red" + controller: Controller {} + } + + Platform { + id: p1 + x: 0 + y: 575 + width: 800 + height: 50 + } + + Platform { + id: p2 + x: 30 + y: 500 + width: 300 + height: 50 + } + + Platform { + id: p3 + x: 100 + y: 400 + width: 300 + height: 50 + } + + Platform { + id: p4 + x: 0 + y: 300 + width: 300 + height: 50 + } + + Platform { + id: p5 + x: 300 + y: 200 + width: 300 + height: 50 + } + + function updateGame(delta : real) : void { + // Gravity + player.velocity.y += gravity + + // Updates position based on velocity + player.update() + + // Handle collisions + gameObjectList.gameObjects.forEach(gameObject => { + if (player.colliding(gameObject)) + player.handleCollision(gameObject) + }) + + // Player bounds check + if (player.x < 0) + player.x = 0 + else if (player.x > width - player.width) + player.x = width - player.width + + if (player.y < 0) + player.y = 0 + else if (player.y > height - player.height) + player.y = height - player.height + } + + FrameAnimation { + running: true + onTriggered: gameArea.updateGame(frameTime) + } + } + + ActionStoreEventListener { + id: actionEventListener + actionStores: [player.controller] + focus: true + } +} diff --git a/examples/universalinput/simple/CMakeLists.txt b/examples/universalinput/simple/CMakeLists.txt new file mode 100644 index 0000000..b91c73f --- /dev/null +++ b/examples/universalinput/simple/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(simple LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/consolejoystickmonitor") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput Gamepad) + +qt_add_executable(simple + main.cpp + gamepadmonitor.h + gamepadmonitor.cpp +) + +set_target_properties(simple PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(simple PUBLIC + Qt::Core + Qt::Gui + Qt::Gamepad +) + +#DISTFILES += android/AndroidManifest.xml +#ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android +#target.path = $$[QT_INSTALL_EXAMPLES]/gamepad/simple + +install(TARGETS simple + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) + + diff --git a/examples/gamepad/configureButtons/android/AndroidManifest.xml b/examples/universalinput/simple/android/AndroidManifest.xml similarity index 87% rename from examples/gamepad/configureButtons/android/AndroidManifest.xml rename to examples/universalinput/simple/android/AndroidManifest.xml index e3f5e51..e527361 100644 --- a/examples/gamepad/configureButtons/android/AndroidManifest.xml +++ b/examples/universalinput/simple/android/AndroidManifest.xml @@ -1,7 +1,7 @@ - - + + @@ -13,10 +13,12 @@ + + - + diff --git a/examples/universalinput/simple/gamepadmonitor.cpp b/examples/universalinput/simple/gamepadmonitor.cpp new file mode 100644 index 0000000..f67234d --- /dev/null +++ b/examples/universalinput/simple/gamepadmonitor.cpp @@ -0,0 +1,113 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "gamepadmonitor.h" +#include + +#include +#include +#include + +GamepadMonitor::GamepadMonitor(QObject *parent) + : QObject(parent) +{ + auto inputManager = QUniversalInput::instance(); + connect(inputManager, &QUniversalInput::joyConnectionChanged, this, [this](int index, bool isConnected) { + if (index < 0) + return; + + if (isConnected) { + qDebug() << "Gamepad connected:" << index; + connectGamepad(uint(index)); + } else { + qDebug() << "Gamepad disconnected:" << index; + disconnectGamepad(uint(index)); + } + }); +} + +GamepadMonitor::~GamepadMonitor() +{ + const auto keys = m_gamepads.keys(); + for (const auto key : keys) + disconnectGamepad(key); +} + +void GamepadMonitor::connectGamepad(uint deviceId) +{ + GamepadConnections gamepadData; + auto gamepad = new QGamepad(deviceId, this); + gamepadData.gamepad = gamepad; + gamepadData.connections.append(connect(gamepad, &QGamepad::axisLeftXChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Left X" << gamepad->axisLeftX(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::axisLeftYChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Left Y" << gamepad->axisLeftY(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::axisRightXChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Right X" << gamepad->axisRightX(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::axisRightYChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Right Y" << gamepad->axisRightY(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonAChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button A" << gamepad->buttonA(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonBChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button B" << gamepad->buttonB(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonXChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button X" << gamepad->buttonX(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonYChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Y" << gamepad->buttonY(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonL1Changed, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button L1" << gamepad->buttonL1(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonR1Changed, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button R1" << gamepad->buttonR1(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonL2Changed, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button L2: " << gamepad->buttonL2(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonR2Changed, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button R2: " << gamepad->buttonR2(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonSelectChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Select" << gamepad->buttonSelect(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonStartChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Start" << gamepad->buttonStart(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonGuideChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Guide" << gamepad->buttonGuide(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonRightChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Dpad Right" << gamepad->buttonRight(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonLeftChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Dpad Left" << gamepad->buttonLeft(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonUpChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Dpad Up" << gamepad->buttonUp(); + })); + gamepadData.connections.append(connect(gamepad, &QGamepad::buttonDownChanged, this, [gamepad, deviceId](){ + qDebug() << "Device: " << deviceId << " Button Dpad Down" << gamepad->buttonDown(); + })); + + m_gamepads.insert(deviceId, gamepadData); +} + +void GamepadMonitor::disconnectGamepad(uint deviceId) +{ + auto gamepadData = m_gamepads.find(deviceId); + + if (gamepadData != m_gamepads.end()) { + for (auto connection : gamepadData->connections) { + disconnect(connection); + } + delete gamepadData->gamepad; + m_gamepads.erase(gamepadData); + } +} diff --git a/examples/universalinput/simple/gamepadmonitor.h b/examples/universalinput/simple/gamepadmonitor.h new file mode 100644 index 0000000..2e25c98 --- /dev/null +++ b/examples/universalinput/simple/gamepadmonitor.h @@ -0,0 +1,35 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef GAMEPADMONITOR_H +#define GAMEPADMONITOR_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QGamepad; +QT_END_NAMESPACE + +class GamepadMonitor : public QObject +{ + Q_OBJECT +public: + explicit GamepadMonitor(QObject *parent = 0); + ~GamepadMonitor(); + +private: + struct GamepadConnections { + QGamepad *gamepad = nullptr; + QList connections; + }; + + void connectGamepad(uint deviceId); + void disconnectGamepad(uint deviceId); + + QHash m_gamepads; +}; + +#endif // GAMEPADMONITOR_H diff --git a/examples/universalinput/simple/main.cpp b/examples/universalinput/simple/main.cpp new file mode 100644 index 0000000..d56fc24 --- /dev/null +++ b/examples/universalinput/simple/main.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include "gamepadmonitor.h" + +int main(int argc, char **argv) +{ + QCoreApplication application(argc, argv); + + GamepadMonitor monitor; + + return application.exec(); +} diff --git a/examples/universalinput/virtualgamepad/ButtonIsland.qml b/examples/universalinput/virtualgamepad/ButtonIsland.qml new file mode 100644 index 0000000..f8d3eb5 --- /dev/null +++ b/examples/universalinput/virtualgamepad/ButtonIsland.qml @@ -0,0 +1,85 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + property alias buttonA: buttonA + property alias buttonB: buttonB + property alias buttonX: buttonX + property alias buttonY: buttonY + + width: 100 + height: 100 + + onScaleChanged: { + resize() + } + + onXChanged: { + resize() + } + + onYChanged: { + resize() + } + + onWidthChanged: { + resize() + } + + onHeightChanged: { + resize() + } + + function resize() { + let scale = Math.min(width, height) / 3 + + buttonA.width = scale + buttonA.height = scale + + buttonB.width = scale + buttonB.height = scale + + buttonX.width = scale + buttonX.height = scale + + buttonY.width = scale + buttonY.height = scale + + let middleX = (width - scale) / 2 + let middleY = (height - scale) / 2 + + buttonB.x = width - scale + buttonB.y = middleY + + buttonY.x = middleX + buttonY.y = 0 + + buttonX.x = 0 + buttonX.y = middleY + + buttonA.x = middleX + buttonA.y = height - scale + } + + JoyButton { + id: buttonA + text: "A" + } + + JoyButton { + id: buttonB + text: "B" + } + + JoyButton { + id: buttonX + text: "X" + } + + JoyButton { + id: buttonY + text: "Y" + } +} diff --git a/examples/universalinput/virtualgamepad/CMakeLists.txt b/examples/universalinput/virtualgamepad/CMakeLists.txt new file mode 100644 index 0000000..527713e --- /dev/null +++ b/examples/universalinput/virtualgamepad/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(virtualgamepad LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/universalinput/virtualgamepad") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui UniversalInput Quick QuickActionStore QuickUniversalInput) + +qt_add_executable(virtualgamepad + main.cpp +) + +qt_add_qml_module(virtualgamepad + URI Example + VERSION 1.0 + QML_FILES main.qml + NO_RESOURCE_TARGET_PATH + QML_FILES Joystick.qml + QML_FILES VirtualGamepad.qml + QML_FILES JoyButton.qml + QML_FILES ButtonIsland.qml +) + +set_target_properties(virtualgamepad PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(virtualgamepad PUBLIC + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::Quick + Qt::QuickActionStore + Qt::QuickUniversalInput +) + +install(TARGETS virtualgamepad + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/universalinput/virtualgamepad/JoyButton.qml b/examples/universalinput/virtualgamepad/JoyButton.qml new file mode 100644 index 0000000..765ba22 --- /dev/null +++ b/examples/universalinput/virtualgamepad/JoyButton.qml @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: joyButton + + width: 50 + height: 50 + + property string text: "" + + signal clicked() + + onTextChanged: { + textLabel.text = text + } + + Rectangle { + anchors.fill: parent + color: "gray" + opacity: 0.9 + radius: width/2 + + Text { + id: textLabel + anchors.centerIn: parent + text: "" + color: "#333333" + font.pixelSize: 20 + } + + MouseArea { + anchors.fill: parent + onClicked: { + joyButton.clicked() + } + } + } +} diff --git a/examples/universalinput/virtualgamepad/Joystick.qml b/examples/universalinput/virtualgamepad/Joystick.qml new file mode 100644 index 0000000..9b0fcc1 --- /dev/null +++ b/examples/universalinput/virtualgamepad/Joystick.qml @@ -0,0 +1,108 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick + +Item { + id: joystick + property real joystickRadius: width > height ? height * 0.5 : width * 0.5 + property real stickRadius: joystickRadius * 0.2 + property alias value: stick.position + + signal updateReady() + + width: 100 + height: 100 + + FrameAnimation { + running: true + + property vector2d previousPosition: Qt.vector2d(0, 0) + + onTriggered: { + // If the stick is not in the deadzone, update the value + const isInDeadzone = stick.position.length() < 0.05 + if (!isInDeadzone) + joystick.updateReady() + } + } + + + function normalizePosition(position) { + return Qt.vector2d(position.x / joystickRadius, -position.y / joystickRadius); + } + + Rectangle { + id: joystickBg + anchors.fill: parent + color: "transparent" + border.color: "black" + border.width: 3 + radius: joystick.joystickRadius + + Item { + id: stick + property real xPos: 0 + property real yPos: 0 + property vector2d position: Qt.vector2d(0, 0) + + function resetPosition() { + setPosition(Qt.point(0, 0)); + joystick.updateReady() + } + + function setPosition(point) { + xPos = point.x; + yPos = point.y; + position = normalizePosition(Qt.point(xPos, yPos)); + stickBg.x = xPos; + stickBg.y = yPos; + } + + width: 2 * joystick.stickRadius + height: 2 * joystick.stickRadius + anchors.centerIn: parent + + Rectangle { + id: stickBg + x: parent.width / 2 - width / 2 + y: parent.height / 2 - height / 2 + width: 2 * joystick.stickRadius + height: 2 * joystick.stickRadius + color: "gray" + border.color: "black" + border.width: 2 + radius: joystick.stickRadius + + MouseArea { + id: mouseArea + anchors.fill: parent + preventStealing: true + property real startX: 0 + property real startY: 0 + + onPressed: { + startX = mouseX; + startY = mouseY; + } + onPositionChanged: { + var deltaX = stick.xPos + (mouseX - startX); + var deltaY = stick.yPos + (mouseY - startY); + var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + + if (distance <= joystick.joystickRadius - joystick.stickRadius) { + stick.setPosition(Qt.point(deltaX, deltaY)); + } else { + var maxDeltaX = (joystick.joystickRadius - joystick.stickRadius) * deltaX / distance; + var maxDeltaY = (joystick.joystickRadius - joystick.stickRadius) * deltaY / distance; + stick.setPosition(Qt.point(maxDeltaX, maxDeltaY)); + } + } + onReleased: { + stick.resetPosition(); + } + } + } + } + } +} diff --git a/examples/universalinput/virtualgamepad/VirtualGamepad.qml b/examples/universalinput/virtualgamepad/VirtualGamepad.qml new file mode 100644 index 0000000..f69cad6 --- /dev/null +++ b/examples/universalinput/virtualgamepad/VirtualGamepad.qml @@ -0,0 +1,123 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Layouts +import QtUniversalInput + +Item { + onWidthChanged: { + resize() + } + + onHeightChanged: { + resize() + } + + function resize() { + let min = Math.min(width, height) * 0.35 + + // Sticks + + leftStick.width = min + leftStick.height = min + + rightStick.width = min + rightStick.height = min + + leftStick.x = 4 * min / 3 + rightStick.x = width - 7 * min / 3 + + leftStick.y = height - min - 10 + rightStick.y = height - min - 10 + + // Buttons + rightIsland.width = min + rightIsland.height = min + rightIsland.x = width - rightIsland.width - 20 + rightIsland.y = height - 5 * min / 3 + + leftIsland.width = min + leftIsland.height = min + leftIsland.x = 20 + leftIsland.y = height - 5 * min / 3 + } + + Joystick { + id: leftStick + + onUpdateReady: { + console.log("left:" + value.x + ", " + value.y ) + let device = 0 + let leftX = 0; + let leftY = 1; + input.joyAxis(device, leftX, value.x) + input.joyAxis(device, leftY, -value.y) + } + } + + Joystick { + id: rightStick + + onUpdateReady: { + let device = 0 + let rightX = 2; + let rightY = 3; + input.joyAxis(device, rightX, value.x) + input.joyAxis(device, rightY, -value.y) + } + } + + ButtonIsland { + id: rightIsland + + buttonA.onClicked: { + input.joyButton(0, 0, 1) + } + + buttonB.onClicked: { + input.joyButton(0, 1, 1) + } + + buttonX.onClicked: { + input.joyButton(0, 2, 1) + } + + buttonY.onClicked: { + input.joyButton(0, 3, 1) + } + } + + ButtonIsland { + id: leftIsland + + buttonB.text: "→" + buttonA.text: "↓" + buttonX.text: "←" + buttonY.text: "↑" + + buttonA.onClicked: { + input.joyHat(0, 4) + } + + buttonB.onClicked: { + input.joyHat(0, 2) + } + + buttonX.onClicked: { + input.joyHat(0, 8) + } + + buttonY.onClicked: { + input.joyHat(0, 1) + } + } + + UniversalInput { + id: input + } + + Component.onCompleted: { + resize() + } +} diff --git a/examples/universalinput/virtualgamepad/main.cpp b/examples/universalinput/virtualgamepad/main.cpp new file mode 100644 index 0000000..913b563 --- /dev/null +++ b/examples/universalinput/virtualgamepad/main.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include + +#include + +#include +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + // window + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/universalinput/virtualgamepad/main.qml b/examples/universalinput/virtualgamepad/main.qml new file mode 100644 index 0000000..1b8bd4e --- /dev/null +++ b/examples/universalinput/virtualgamepad/main.qml @@ -0,0 +1,74 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtUniversalInput + +ApplicationWindow { + id: mainWindow + visible: true + width: 800 + height: 400 + title: "Virtual Gamepad" + + Rectangle { + id: gameArea + anchors.fill: parent + color: "white" + + Rectangle { + id: player + width: 50 + height: 50 + color: "red" + + property double speed : 5 + property double velocityX : 0 + property double velocityY : 0 + } + + VirtualGamepad { + anchors.fill: parent + } + + FrameAnimation { + running: true + onTriggered: { + player.x += player.velocityX * player.speed + player.y += player.velocityY * player.speed + } + } + } + + UniversalInput { + onJoyButtonEvent: (device, button, isPressed) => { + if (button === 0) { + player.color = isPressed ? "blue" : "red"; + } else if (button === 1) { + player.color = isPressed ? "green" : "red"; + } + } + onJoyAxisEvent: (device, axis, value) => { + let leftX =0; + let leftY =1; + let rightX = 2; + let rightY = 3; + + //console.log(value) + + if (axis === leftX) { + player.velocityX = value; + } else if (axis === leftY) { + player.velocityY = value; + } + + if (axis === leftX && Math.abs(value) < 0.2) { + player.velocityX = 0; + } + if (axis === leftY && Math.abs(value) < 0.2) { + player.velocityY = 0; + } + } + } +} diff --git a/qtgamepad.pro b/qtgamepad.pro deleted file mode 100644 index 7d21914..0000000 --- a/qtgamepad.pro +++ /dev/null @@ -1,3 +0,0 @@ -load(qt_parts) - -requires(qtHaveModule(gui)) diff --git a/src/3rdparty/sdlgamecontrollerdb/LICENSE b/src/3rdparty/sdlgamecontrollerdb/LICENSE new file mode 100644 index 0000000..d94e03e --- /dev/null +++ b/src/3rdparty/sdlgamecontrollerdb/LICENSE @@ -0,0 +1,17 @@ +Copyright (C) 1997-2022 Sam Lantinga + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/src/3rdparty/sdlgamecontrollerdb/README.md b/src/3rdparty/sdlgamecontrollerdb/README.md new file mode 100644 index 0000000..0c9584f --- /dev/null +++ b/src/3rdparty/sdlgamecontrollerdb/README.md @@ -0,0 +1,57 @@ +# SDL_GameControllerDB + +A community sourced database of game controller mappings to be used with SDL2 Game Controller functionality. + +# Usage +Download gamecontrollerdb.txt, place it in your app's directory and load it. + +SDL2: +```c +SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); +``` + +SDL3: +```c +SDL_AddGamepadMappingsFromFile("gamecontrollerdb.txt"); +``` + +The database is compatible with SDL v2.0.10 and newer. + +## Create New Mappings +A mapping looks like this: +``` +030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +``` +It includes controller GUID (`030000004c050000c405000000010000`), a name (`PS4 Controller`), button / axis mappings (`leftshoulder:b4`) and a platform (`platform:Mac OS X`). + +Please make sure to check that the name is a good description of the controller. If relevant, include the controller's name and model number. + +## Mapping Guide + +![SDL Game Controller Mapping Guide](mapping_guide.png) + +## Mapping Tools +There are a few different tools that let you create mappings. + +### [SDL2 Gamepad Tool](http://www.generalarcade.com/gamepadtool/) +Third party cross-platform tool with GUI (Windows, macOS and Linux) + +#### Note: While convenient, this tool has fallen out of date as SDL has amended and added new features for gamepad support (see issue [#478](https://github.com/gabomdq/SDL_GameControllerDB/issues/476)). As such, maps authored with this tool require greater scrutiny to ensure they will not break support for explicit mappings the SDL project provides. + +### [SDL2 Gamepad Mapper](https://gitlab.com/ryochan7/sdl2-gamepad-mapper/-/releases) +Open source GUI app for authoring mappings. Builds available for Windows and Linux. + +### [SDL](https://github.com/libsdl-org/SDL/releases/latest) +[testcontroller (SDL3)](https://github.com/libsdl-org/SDL/blob/main/test/testcontroller.c) and [controllermap (SDL2)](https://github.com/libsdl-org/SDL/blob/SDL2/test/controllermap.c) utilities are the official tools to create these mappings on all SDL supported platforms (Windows, Mac, Linux, iOS, Android, etc). + +### [Steam](http://store.steampowered.com) +In Steam's Big Picture mode, configure your gamepad. Then look in `[steam_installation_directory]/config/config.vdf` in your Steam installation directory for the `SDL_GamepadBind` entry. It is one of the last entries, it will look something like this: + +``` +"SDL_GamepadBind" "030000004c050000c405000000010000,PS4 Controller,platform:Windows,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3," +``` + +## Resources + +* [SDL2](http://www.libsdl.org) +* [SDL_GameControllerAddMappingsFromFile](http://wiki.libsdl.org/SDL_GameControllerAddMappingsFromFile) diff --git a/src/3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt b/src/3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt new file mode 100644 index 0000000..31b1f5a --- /dev/null +++ b/src/3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt @@ -0,0 +1,2052 @@ +# Game Controller DB for SDL in 2.0.16 format +# Source: https://github.com/gabomdq/SDL_GameControllerDB + +# Windows +03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, +03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, +03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows, +03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows, +03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows, +03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows, +03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows, +03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows, +03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows, +03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows, +03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows, +030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows, +0300000008100000e501000000000000,Anbernic Game Pad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows, +03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows, +03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows, +030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows, +030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows, +030000008a3500000402000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows, +03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, +030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows, +030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, +030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, +030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, +030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, +030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows, +030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows, +030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows, +030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000bc2000000091000000000000,EasySMX Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, +03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, +03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows, +03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows, +03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows, +03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows, +03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows, +03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows, +0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows, +03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows, +03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows, +030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000c9110000f055000000000000,GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows, +030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, +030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows, +030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows, +030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows, +030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows, +03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows, +03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, +03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows, +03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows, +03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows, +03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows, +03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,platform:Windows, +03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows, +03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows, +03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows, +030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, +03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows, +03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows, +03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows, +030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows, +030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, +03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows, +030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, +03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows, +030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, +0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows, +030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows, +030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows, +03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows, +03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows, +03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows, +03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, +030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows, +030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows, +0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows, +03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows, +03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows, +03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows, +03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, +030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, +030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows, +03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, +03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows, +030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000004b120000014d000000000000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows, +030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, +03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows, +03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, +03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows, +030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows, +03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows, +03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows, +03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows, +03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows, +03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows, +03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, +030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows, +030000009b280000d000000000000000,Raphnet Dreamcast Adapter,a:b1,b:b0,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,lefttrigger:+a5,leftx:a0,lefty:a1,righttrigger:+a2,start:b3,x:b5,y:b4,platform:Windows, +030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, +030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, +030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows, +030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000009b2800002600000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002e00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002f00000000000000,Raphnet SNES Adapter,a:b1,b:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows, +030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows, +03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows, +03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, +03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows, +0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows, +030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows, +030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, +03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows, +03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows, +03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows, +03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows, +03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows, +03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows, +03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows, +03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows, +03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows, +03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows, +030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows, +03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, +030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows, +03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows, +030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows, +03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows, +03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows, +03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, +03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, +030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows, +03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows, +03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows, +03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows, +03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows, +03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, +03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,platform:Windows, +03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000a102000000000000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows, +03000000300f00008888000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:b13,dpleft:b10,dpright:b11,dpup:b12,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00006300000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows, +03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows, +030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows, +03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, +03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, + +# Mac OS X +030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002690000000010000,8BitDo NEOGEO,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X, +03000000c82d00003028000000010000,8Bitdo SFC30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +0300000008100000e501000019040000,Anbernic Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X, +03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X, +030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, +030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, +030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000008a3500000302000000010000,Backbone One PlayStationÆ Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X, +03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X, +030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Mac OS X, +03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, +03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X, +030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X, +030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X, +03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X, +03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X, +03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, +03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X, +0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, +03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X, +03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X, +030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X, +030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X, +030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, +030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, +050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, +030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X, +030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, +030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X, +030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000009b2800005600000020020000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Mac OS X, +030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X, +030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X, +03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X, +0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X, +03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X, +030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X, +030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X, +03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X, +03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, +050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, +03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, +03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, +03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, +03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X, +030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, +050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, +030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, + +# Linux +03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux, +03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000a20000000020000,8BitDo M30 Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux, +03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux, +05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux, +05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, +030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, +05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +0300000008100000e501000001010000,Anbernic Gamepad,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a4,start:b11,x:b3,y:b4,platform:Linux, +03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +03000000503200000110000011010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000044010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000046010000,Atari VCS Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, +03000000503200000210000011010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000045010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000046010000,Atari VCS Modern Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, +030000008a3500000201000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000008a3500000202000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux, +030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, +03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux, +190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux, +190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux, +03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000001010000,GPD Win Max 2 (6800U) Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, +030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux, +030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux, +030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux, +03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux, +03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux, +03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux, +050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, +03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Linux, +03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux, +030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux, +05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, +0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux, +030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, +030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux, +030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux, +030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux, +03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux, +060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, +03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux, +060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux, +030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, +05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, +030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux, +050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, +19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux, +05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux, +03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, +03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, +030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, +03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux, +03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux, +0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, +03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux, +0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux, +0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux, +03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux, +030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, +03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, +03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, +03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux, +03000000952e00004b43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000952e00004d43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux, +03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux, +03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, +030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux, +03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux, +03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux, +03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, +03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux, +03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux, +03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux, +03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, +030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux, +030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, +030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, +03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, +030000005e0400008e02000020010000,XInput Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, + +# Android +38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android, +38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, +32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android, +38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android, +64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android, +66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android, +66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android, +38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android, +38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android, +32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android, +38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +61333362366131643730353063616330,8BitDo Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android, +38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android, +61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android, +05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, +33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android, +417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, +35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,platform:Android, +32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4f64696e20436f6e74726f6c6c657200,AYN Odin,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b14,dpright:b13,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:+a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android, +05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android, +66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, +65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b18,platform:Android, +31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android, +62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android, +31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android, +5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android, +64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android, +532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android, +65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android, +33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, +64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, +6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android, +436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android, +31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, +37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b9,x:b2,y:b3,platform:Android, +33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android, +30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android, +32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android, +050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, +34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android, +36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, +4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, +534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android, +37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, +62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, +536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android, +32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android, +050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android, +31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android, +32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android, +61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android, +526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,platform:Android, +37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, +5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, +526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android, +64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android, +37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android, +36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android, +32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, +38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android, +61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, +30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android, +63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android, +476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android, +35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android, +33313930373536613937326534303931,Taito Egret II Mini Control Panel,a:b25,b:b23,back:b27,guide:b30,leftx:a0,lefty:a1,rightshoulder:b21,righttrigger:b22,start:b28,x:b29,y:b24,platform:Android, +54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android, +38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android, +050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e00200000ffe3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android, +050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, +35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, + +# iOS +05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, +4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, +050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, +050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS, +050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, +050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS, +050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, +050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,platform:iOS, +050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS, +05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, diff --git a/src/3rdparty/sdlgamecontrollerdb/import_from_sdlgamecontrollerdb_tarball.sh b/src/3rdparty/sdlgamecontrollerdb/import_from_sdlgamecontrollerdb_tarball.sh new file mode 100755 index 0000000..cdd7339 --- /dev/null +++ b/src/3rdparty/sdlgamecontrollerdb/import_from_sdlgamecontrollerdb_tarball.sh @@ -0,0 +1,50 @@ +#! /bin/sh + +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +# +# This is a small script to copy the required files from a sdlgamecontrollerdb tarball +# into 3rdparty/sdlgamecontrollerdb/ . Documentation, tests, demos etc. are not imported. + +if [ $# -ne 2 ]; then + echo "Usage: $0 openxr_tarball_dir/ \$QTDIR/src/3rdparty/sdlgamecontrollerdb/" + exit 1 +fi + +SRC_DIR=$1 +TARGET_DIR=$2 + +if [ ! -d "$SRC_DIR" -o ! -r "$SRC_DIR" -o ! -d "$TARGET_DIR" -o ! -w "$TARGET_DIR" ]; then + echo "Either the sdlgamecontrollerdb source dir or the target dir do not exist," + echo "are not directories or have the wrong permissions." + exit 2 +fi + +# with 1 argument, copies SRC_DIR/$1 to TARGET_DIR/$1 +# with 2 arguments, copies SRC_DIR/$1 to TARGET_DIR/$2 +copy_file_or_dir() { + if [ $# -lt 1 -o $# -gt 2 ]; then + echo "Wrong number of arguments to copy_file_or_dir" + exit 3 + fi + + SOURCE_FILE=$1 + if [ -n "$2" ]; then + DEST_FILE=$2 + else + DEST_FILE=$1 + fi + + mkdir -p "$TARGET_DIR/$(dirname "$SOURCE_FILE")" + cp -R "$SRC_DIR/$SOURCE_FILE" "$TARGET_DIR/$DEST_FILE" +} + +FILES=" + README.md + LICENSE + gamecontrollerdb.txt +" + +for i in $FILES; do + copy_file_or_dir "$i" +done diff --git a/src/3rdparty/sdlgamecontrollerdb/qt_attribution.json b/src/3rdparty/sdlgamecontrollerdb/qt_attribution.json new file mode 100644 index 0000000..0fabf4b --- /dev/null +++ b/src/3rdparty/sdlgamecontrollerdb/qt_attribution.json @@ -0,0 +1,15 @@ +[ + { + "Id": "sdlgamecontrollerdb", + "Name": "SDLGameControllerDB", + "QDocModule": "qtuniveralinput", + "QtUsage": "Provides button and axis mappings for game controllers to the QGamepad layout.", + "Description": "A community sourced database of game controller mappings to be used with SDL2 Game Controller functionality.", + "Homepage": "https://github.com/mdqinc/SDL_GameControllerDB", + "Version": "9055df09a2bdd56339096639168c8bcdc6c0edc2", + "License": "zlib License", + "LicenseId": "zlib", + "LicenseFile": "LICENSE", + "Copyright": "Copyright (C) 1997-2022 Sam Lantinga " + } +] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..b3f3bb7 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(universalinput) +add_subdirectory(gamepad) +if(TARGET Qt::Quick) + add_subdirectory(quickgamepad) + add_subdirectory(quickactionstore) + add_subdirectory(quickuniversalinput) +endif() +add_subdirectory(plugins) diff --git a/src/gamepad/CMakeLists.txt b/src/gamepad/CMakeLists.txt new file mode 100644 index 0000000..aed9930 --- /dev/null +++ b/src/gamepad/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_module(Gamepad + SOURCES + qgamepad.cpp qgamepad.h + DEFINES + QT_BUILD_GAMEPAD_LIB + LIBRARIES + Qt::CorePrivate + Qt::GuiPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + Qt::GuiPrivate + GENERATE_CPP_EXPORTS +) diff --git a/src/gamepad/configure.json b/src/gamepad/configure.json deleted file mode 100644 index fef25d3..0000000 --- a/src/gamepad/configure.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "module": "gamepad", - "testDir": "../../config.tests", - - "libraries": { - "sdl2": { - "label": "SDL2", - "test": "sdl", - "sources": [ - { "type": "pkgConfig", "args": "sdl2" }, - { - "libs": "-F/Library/Frameworks/ -framework SDL2", - "includedir": "/Library/Frameworks/SDL2.framework/Headers", - "condition": "config.darwin" - }, - { "libs": "-lSDL2 -lSDL2main", "condition": "config.win32" }, - { "libs": "-lSDL2", "condition": "config.unix && !config.darwin" } - ] - } - }, - - "features": { - "sdl2": { - "label": "SDL2", - "condition": "libs.sdl2", - "output": [ "privateFeature" ] - } - }, - - "report": [ - ], - - "summary": [ - { - "section": "Qt Gamepad", - "entries": [ - "sdl2" - ] - } - ] -} diff --git a/src/gamepad/doc/qtgamepad.qdocconf b/src/gamepad/doc/qtgamepad.qdocconf deleted file mode 100644 index db7f3b5..0000000 --- a/src/gamepad/doc/qtgamepad.qdocconf +++ /dev/null @@ -1,55 +0,0 @@ -include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) -include($QT_INSTALL_DOCS/config/exampleurl-qtgamepad.qdocconf) - -project = QtGamepad -description = Qt Gamepad Reference Documentation -version = $QT_VERSION - -examplesinstallpath = gamepad - -qhp.projects = QtGamepad - -qhp.QtGamepad.file = qtgamepad.qhp -qhp.QtGamepad.namespace = org.qt-project.qtgamepad.$QT_VERSION_TAG -qhp.QtGamepad.virtualFolder = qtgamepad -qhp.QtGamepad.indexTitle = Qt Gamepad -qhp.QtGamepad.indexRoot = -qhp.QtGamepad.filterAttributes = qtgamepad $QT_VERSION qtrefdoc -qhp.QtGamepad.customFilters.Qt.name = QtGamepad $QT_VERSION -qhp.QtGamepad.customFilters.Qt.filterAttributes = qtgamepad $QT_VERSION - -qhp.QtGamepad.subprojects = qmltypes classes examples -qhp.QtGamepad.subprojects.qmltypes.title = QML Types -qhp.QtGamepad.subprojects.qmltypes.indexTitle = Qt Gamepad QML Types -qhp.QtGamepad.subprojects.qmltypes.selectors = qmlclass -qhp.QtGamepad.subprojects.qmltypes.sortPages = true -qhp.QtGamepad.subprojects.classes.title = C++ Classes -qhp.QtGamepad.subprojects.classes.indexTitle = Qt Gamepad C++ Classes -qhp.QtGamepad.subprojects.classes.selectors = class fake:headerfile -qhp.QtGamepad.subprojects.classes.sortPages = true -qhp.QtGamepad.subprojects.examples.title = Examples -qhp.QtGamepad.subprojects.examples.indexTitle = Qt Gamepad Examples -qhp.QtGamepad.subprojects.examples.selectors = fake:example -qhp.QtGamepad.subprojects.examples.sortPages = true - -depends = qtcore qtdoc qmake - -headerdirs += ../ \ - ../../plugins - -sourcedirs += ../ \ - ../../plugins - -exampledirs += ../../../examples/gamepad - -imagedirs += images - -Cpp.ignoretokens += Q_GAMEPAD_EXPORT -Cpp.ignoredirectives += Q_DECLARE_LOGGING_CATEGORY - -navigation.landingpage = "Qt Gamepad" -navigation.qmltypespage = "Qt Gamepad QML Types" -navigation.cppclassespage = "Qt Gamepad C++ Classes" - -manifestmeta.thumbnail.names = "QtGamepad/Qt Gamepad Mouse Item Example" \ - "QtGamepad/Qt Gamepad Simple Example" diff --git a/src/gamepad/doc/src/qtgamepad-cpp.qdoc b/src/gamepad/doc/src/qtgamepad-cpp.qdoc deleted file mode 100644 index 7e90ed7..0000000 --- a/src/gamepad/doc/src/qtgamepad-cpp.qdoc +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \module QtGamepad - \title Qt Gamepad C++ Classes - \ingroup modules - \qtvariable gamepad - - \brief Provides C++ classes for using gamepads. - - To include the definitions of the module's classes, use the following directive: - - \code - #include - \endcode - - To link against the module, add this line to your \l qmake \c .pro file: - - \code - QT += gamepad - \endcode - - For more information about using these classes in your application, - see the \l{Qt Gamepad} documentation. -*/ diff --git a/src/gamepad/doc/src/qtgamepad-examples.qdoc b/src/gamepad/doc/src/qtgamepad-examples.qdoc deleted file mode 100644 index e9a677e..0000000 --- a/src/gamepad/doc/src/qtgamepad-examples.qdoc +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \group qtgamepad-examples - \title Qt Gamepad Examples - \brief Examples for the Qt Gamepad module - - These are the Qt Gamepad examples. - -*/ - diff --git a/src/gamepad/doc/src/qtgamepad-index.qdoc b/src/gamepad/doc/src/qtgamepad-index.qdoc deleted file mode 100644 index 146cb49..0000000 --- a/src/gamepad/doc/src/qtgamepad-index.qdoc +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \page qtgamepad-index.html - \title Qt Gamepad - \brief A cross-platform library to facilitate the use of gamepad hardware in Qt and Qt Quick applications. - - Qt Gamepad is an add-on library that enables Qt applications to support the - use of gamepad hardware and in some cases remote control equipment. The - module provides both QML and C++ interfaces. The primary target audience are - embedded devices with fullscreen user interfaces, and mobile applications - targeting TV-like form factors. - - The currently supported platforms are: - - \list - \li Windows (Win32 desktop, via XInput 1.3 & 1.4) - \li Linux (evdev) - \li Linux (SDL2) - \li Android - \li macOS, iOS, tvOS (including the tvOS remote) - \endlist - - This module provides classes that can: - - \list - \li Read input events from game controllers (Button and Axis events), - \li expose these events both to C++ and Qt Quick (QML), - \li provide basic gamepad layout configurability, and - \li provide optional key and mouse event generation upon gamepad button presses. - \endlist - - \note The API is designed with XBox and similar controllers in mind. Joysticks - are not in scope for this module. A number of third-party gamepads may be - supported as well, however, some of these may need custom configuration steps - in order to map the button/trigger codes the device or driver in question - provides onto what QtGamepad expects. This can be done by the - \l{Qt Gamepad Configure Buttons Example}{configureButtons} example that can also - save the generated layout persistently for use by other applications. - - \section1 Getting Started - - Before you start using the APIs provided by this module, ensure that the - gamepad is detected by your development environment. - - \section2 Linux - - On standard Linux distributions such as Ubuntu, gamepads such as XBox or - PlayStation controllers are detected out-of-the-box. To check if the - gamepad is detected, \c grep the \c dmesg logs using: - - \badcode - dmesg | grep "" - \endcode - - If you do not see the entries for the gamepad you are using, check if - the \c joystick package is installed. If not, install the package and \c grep - the \c dmesg logs again. - - It is strongly recommended to verify that the gamepad's input device is - present, and is sending events, via the \c lsinput and \c evtest utilities. - - PlayStation controllers will likely need the help of an additional tool like - \l{https://github.com/xboxdrv/xboxdrv}{xboxdrv}. Once installed, and having a - PS3 controller connected via USB, the following will ensure correct operation - with QtGamepad: - - \badcode - sudo xboxdrv --detach-kernel-driver --mimic-xpad -s - \endcode - - Qt Gamepad uses a plugin-based, multi-backend architecture. This means that on - some platforms, like Linux, there are multiple backends available. In case of - Linux, the choices are: - - \list - - \li \c evdev - a backend reading events directly from the evdev input device - - \li \c sdl2 - a backend using the Gamepad module of SDL2. This plugin is only - built when SDL2 is present at build time, and therefore will typically be - missing from the pre-built Qt packages. This backend likely has broader - support for various hardware, at the expense of an additional third-party - dependency. - - \endlist - - To force a given backend, set the \c QT_GAMEPAD environment variable to the - name of the desired backend. - - The availability of gamepad devices is monitored via \c libudev, assuming Qt - was built with libudev support enabled. This means that connecting wired - gamepads or wireless dongles is possible also while an application is - running. - - \note wireless dongles may report one or more input devices even when no - actual controllers have been connected to them. Qt Gamepad will interpret this - as having connected gamepads present. - - With the \c evdev backend, to explicitly specify the input device to use, set - the environment variable \c{QT_GAMEPAD_DEVICE} to the desired - /dev/input/event* node. This should not be needed normally, but can be useful - in case multiple gamepads are connected and only one of them is interesting to - the application. - - \section2 Windows - - The Windows Plug-n-Play service automatically installs the necessary drivers - when the gamepad is connected through a USB port for the first time. Once the - drivers are installed, select \uicontrol{Control Panel > Device and Printers} - and check if the gamepad is listed under the \uicontrol Devices section. - - To test whether gamepad input is detected, select - \uicontrol {Gamepad Controller Settings} from the context menu, select - \uicontrol {Properties > Test}, and start testing. You can also run the - \l{Qt Gamepad Qt Quick Example}{quickGamepad} example to test. - - \section2 Android - - The Android backend uses the \c InputDevice API. - - \section2 macOS, iOS, tvOS - - This backend uses the \c GCController API. - - Besides game controllers, it also supports the tvOS remote (microGamepad). The - mapping for this is the following: - - \list - \li \c{X button} - play/pause - \li \c{A button} - pressing the touch area - \li \c{left thumbstick} - the touch area - \endlist - - \section2 Troubleshooting - - Some backends (\c evdev on Linux and \c xinput on Windows) and the plugin - loader utilize the logging category \c{qt.gamepad}. Enabling this will print - useful information on the debug output. - - \section1 Examples - - The \l{Qt Gamepad Examples}{examples} demonstrate how to handle input from a - gamepad using the QML and C++ APIs. - - \section1 API Reference - - \list - \li \l{Qt Gamepad QML Types} - \li \l{Qt Gamepad C++ Classes} - \endlist - -*/ diff --git a/src/gamepad/doc/src/qtgamepad-qmltypes.qdoc b/src/gamepad/doc/src/qtgamepad-qmltypes.qdoc deleted file mode 100644 index c136864..0000000 --- a/src/gamepad/doc/src/qtgamepad-qmltypes.qdoc +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \qmlmodule QtGamepad 1.\QtMinorVersion - \title Qt Gamepad QML Types - \ingroup qmlmodules - \brief Provides QML types for using gamepad hardware. - - The Qt Gamepad module provides QML types that can be used to access the - state of gamepad hardware that may be available on a system. - - The QML types can be imported into your application using the following - import statement: - - \qml \QtMinorVersion - import QtGamepad 1.\1 - \endqml - - To link against the module, add this line to your \l qmake \c .pro file: - - \code - QT += gamepad - \endcode - - For more information about using these types in your application, - see the \l{Qt Gamepad} documentation. -*/ diff --git a/src/gamepad/gamepad.pro b/src/gamepad/gamepad.pro deleted file mode 100644 index 5151d95..0000000 --- a/src/gamepad/gamepad.pro +++ /dev/null @@ -1,36 +0,0 @@ -TARGET = QtGamepad -QT = core-private core gui - -MODULE_PLUGIN_TYPES = gamepads - -load(qt_module) - -DEFINES += QT_BUILD_GAMEPAD_LIB - -QMAKE_DOCS = $$PWD/doc/qtgamepad.qdocconf - -HEADERS += \ - qtgamepadglobal.h \ - qgamepadmanager.h \ - qgamepad.h \ - qgamepadbackend_p.h \ - qgamepadbackendfactory_p.h \ - qgamepadkeynavigation.h \ - qgamepadbackendplugin_p.h -SOURCES += \ - qgamepadmanager.cpp \ - qgamepad.cpp \ - qgamepadbackend.cpp \ - qgamepadbackendfactory.cpp \ - qgamepadkeynavigation.cpp \ - qgamepadbackendplugin.cpp - - -ANDROID_BUNDLED_JAR_DEPENDENCIES = \ - jar/Qt$${QT_MAJOR_VERSION}AndroidGamepad.jar - -ANDROID_LIB_DEPENDENCIES = \ - plugins/gamepads/libplugins_gamepads_androidgamepad.so - -ANDROID_FEATURES = \ - android.hardware.gamepad diff --git a/src/gamepad/qgamepad.cpp b/src/gamepad/qgamepad.cpp index ff57db6..f092a18 100644 --- a/src/gamepad/qgamepad.cpp +++ b/src/gamepad/qgamepad.cpp @@ -1,38 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qgamepad.h" @@ -47,69 +14,40 @@ class QGamepadPrivate : public QObjectPrivate public: QGamepadPrivate(int deviceId) : deviceId(deviceId) - , connected(false) - , axisLeftX(0.0) - , axisLeftY(0.0) - , axisRightX(0.0) - , axisRightY(0.0) - , buttonA(false) - , buttonB(false) - , buttonX(false) - , buttonY(false) - , buttonL1(false) - , buttonR1(false) - , buttonL2(0.0) - , buttonR2(0.0) - , buttonSelect(false) - , buttonStart(false) - , buttonL3(false) - , buttonR3(false) - , buttonUp(false) - , buttonDown(false) - , buttonLeft(false) - , buttonRight(false) - , buttonCenter(false) - , buttonGuide(false) { } - QGamepadManager *gamepadManager; - - int deviceId; - bool connected; + int deviceId = -1; + bool connected = false; QString name; - double axisLeftX; - double axisLeftY; - double axisRightX; - double axisRightY; - bool buttonA; - bool buttonB; - bool buttonX; - bool buttonY; - bool buttonL1; - bool buttonR1; - double buttonL2; - double buttonR2; - bool buttonSelect; - bool buttonStart; - bool buttonL3; - bool buttonR3; - bool buttonUp; - bool buttonDown; - bool buttonLeft; - bool buttonRight; - bool buttonCenter; - bool buttonGuide; + float axisLeftX = 0.0f; + float axisLeftY = 0.0f; + float axisRightX = 0.0f; + float axisRightY = 0.0f; + bool buttonA = false; + bool buttonB = false; + bool buttonX = false; + bool buttonY = false; + bool buttonL1 = false; + bool buttonR1 = false; + float buttonL2 = 0.0f; + float buttonR2 = 0.0f; + bool buttonSelect = false; + bool buttonStart = false; + bool buttonL3 = false; + bool buttonR3 = false; + bool buttonUp = false; + bool buttonDown = false; + bool buttonLeft = false; + bool buttonRight = false; + bool buttonGuide = false; void setConnected(bool isConnected); void setName(const QString &name); - void _q_handleGamepadConnected(int id); - void _q_handleGamepadNameChanged(int id, const QString &name); - void _q_handleGamepadDisconnected(int id); - void _q_handleGamepadAxisEvent(int id, QGamepadManager::GamepadAxis axis, double value); - void _q_handleGamepadButtonPressEvent(int id, QGamepadManager::GamepadButton button, double value); - void _q_handleGamepadButtonReleaseEvent(int id, QGamepadManager::GamepadButton button); + void _q_handleGamepadConnectionChangedEvent(int index, bool isConnected); + void _q_handleGamepadAxisEvent(int device, JoyAxis axis, float value); + void _q_handleGamepadButtonEvent(int device, JoyButton button, bool isPressed); }; void QGamepadPrivate::setConnected(bool isConnected) @@ -117,7 +55,7 @@ void QGamepadPrivate::setConnected(bool isConnected) Q_Q(QGamepad); if (connected != isConnected) { connected = isConnected; - emit q->connectedChanged(connected); + emit q->connectedChanged(); } } @@ -126,245 +64,134 @@ void QGamepadPrivate::setName(const QString &theName) Q_Q(QGamepad); if (name != theName) { name = theName; - emit q->nameChanged(name); + emit q->nameChanged(); } } /*! * \internal */\ -void QGamepadPrivate::_q_handleGamepadConnected(int id) +void QGamepadPrivate::_q_handleGamepadConnectionChangedEvent(int index, bool isConnected) { - if (id == deviceId) { - setConnected(true); - } + if (index == deviceId) + setConnected(isConnected); } /*! * \internal */\ -void QGamepadPrivate::_q_handleGamepadNameChanged(int id, const QString &name) -{ - if (id == deviceId) - setName(name); -} - -/*! - * \internal - */\ -void QGamepadPrivate::_q_handleGamepadDisconnected(int id) -{ - if (id == deviceId) { - setConnected(false); - } -} - -/*! - * \internal - */\ -void QGamepadPrivate::_q_handleGamepadAxisEvent(int id, QGamepadManager::GamepadAxis axis, double value) +void QGamepadPrivate::_q_handleGamepadAxisEvent(int device, JoyAxis axis, float value) { Q_Q(QGamepad); - if (id != deviceId) + if (device != deviceId) return; switch (axis) { - case QGamepadManager::AxisLeftX: + case JoyAxis::LeftX: axisLeftX = value; - emit q->axisLeftXChanged(value); + emit q->axisLeftXChanged(); break; - case QGamepadManager::AxisLeftY: + case JoyAxis::LeftY: axisLeftY = value; - emit q->axisLeftYChanged(value); + emit q->axisLeftYChanged(); break; - case QGamepadManager::AxisRightX: + case JoyAxis::RightX: axisRightX = value; - emit q->axisRightXChanged(value); + emit q->axisRightXChanged(); break; - case QGamepadManager::AxisRightY: + case JoyAxis::RightY: axisRightY = value; - emit q->axisRightYChanged(value); - break; - default: - break; - } -} - -/*! - * \internal - */\ -void QGamepadPrivate::_q_handleGamepadButtonPressEvent(int id, QGamepadManager::GamepadButton button, double value) -{ - Q_Q(QGamepad); - if (id != deviceId) - return; - - switch (button) { - case QGamepadManager::ButtonA: - buttonA = true; - emit q->buttonAChanged(true); - break; - case QGamepadManager::ButtonB: - buttonB = true; - emit q->buttonBChanged(true); - break; - case QGamepadManager::ButtonX: - buttonX = true; - emit q->buttonXChanged(true); - break; - case QGamepadManager::ButtonY: - buttonY = true; - emit q->buttonYChanged(true); - break; - case QGamepadManager::ButtonL1: - buttonL1 = true; - emit q->buttonL1Changed(true); + emit q->axisRightYChanged(); break; - case QGamepadManager::ButtonR1: - buttonR1 = true; - emit q->buttonR1Changed(true); - break; - case QGamepadManager::ButtonL2: + case JoyAxis::TriggerLeft: buttonL2 = value; - emit q->buttonL2Changed(value); + emit q->buttonL2Changed(); break; - case QGamepadManager::ButtonR2: + case JoyAxis::TriggerRight: buttonR2 = value; - emit q->buttonR2Changed(value); - break; - case QGamepadManager::ButtonL3: - buttonL3 = true; - emit q->buttonL3Changed(true); - break; - case QGamepadManager::ButtonR3: - buttonR3 = true; - emit q->buttonR3Changed(true); - break; - case QGamepadManager::ButtonSelect: - buttonSelect = true; - emit q->buttonSelectChanged(true); - break; - case QGamepadManager::ButtonStart: - buttonStart = true; - emit q->buttonStartChanged(true); - break; - case QGamepadManager::ButtonUp: - buttonUp = true; - emit q->buttonUpChanged(true); - break; - case QGamepadManager::ButtonDown: - buttonDown = true; - emit q->buttonDownChanged(true); - break; - case QGamepadManager::ButtonLeft: - buttonLeft = true; - emit q->buttonLeftChanged(true); - break; - case QGamepadManager::ButtonRight: - buttonRight = true; - emit q->buttonRightChanged(true); - break; - case QGamepadManager::ButtonCenter: - buttonCenter = true; - emit q->buttonCenterChanged(true); - break; - case QGamepadManager::ButtonGuide: - buttonGuide = true; - emit q->buttonGuideChanged(true); + emit q->buttonR2Changed(); break; default: break; } - } /*! * \internal */\ -void QGamepadPrivate::_q_handleGamepadButtonReleaseEvent(int id, QGamepadManager::GamepadButton button) +void QGamepadPrivate::_q_handleGamepadButtonEvent(int device, JoyButton button, bool isPressed) { Q_Q(QGamepad); - if (id != deviceId) + if (device != deviceId) return; switch (button) { - case QGamepadManager::ButtonA: - buttonA = false; - emit q->buttonAChanged(false); + case JoyButton::A: + buttonA = isPressed; + emit q->buttonAChanged(); break; - case QGamepadManager::ButtonB: - buttonB = false; - emit q->buttonBChanged(false); + case JoyButton::B: + buttonB = isPressed; + emit q->buttonBChanged(); break; - case QGamepadManager::ButtonX: - buttonX = false; - emit q->buttonXChanged(false); + case JoyButton::X: + buttonX = isPressed; + emit q->buttonXChanged(); break; - case QGamepadManager::ButtonY: - buttonY = false; - emit q->buttonYChanged(false); + case JoyButton::Y: + buttonY = isPressed; + emit q->buttonYChanged(); break; - case QGamepadManager::ButtonL1: - buttonL1 = false; - emit q->buttonL1Changed(false); + case JoyButton::LeftShoulder: + buttonL1 = isPressed; + emit q->buttonL1Changed(); break; - case QGamepadManager::ButtonR1: - buttonR1 = false; - emit q->buttonR1Changed(false); + case JoyButton::RightShoulder: + buttonR1 = isPressed; + emit q->buttonR1Changed(); break; - case QGamepadManager::ButtonL2: - buttonL2 = 0.0; - emit q->buttonL2Changed(0.0); + case JoyButton::LeftStick: + buttonL3 = isPressed; + emit q->buttonL3Changed(); break; - case QGamepadManager::ButtonR2: - buttonR2 = 0.0; - emit q->buttonR2Changed(0.0); + case JoyButton::RightStick: + buttonR3 = isPressed; + emit q->buttonR3Changed(); break; - case QGamepadManager::ButtonL3: - buttonL3 = false; - emit q->buttonL3Changed(false); + case JoyButton::Back: + buttonSelect = isPressed; + emit q->buttonSelectChanged(); break; - case QGamepadManager::ButtonR3: - buttonR3 = false; - emit q->buttonR3Changed(false); + case JoyButton::Start: + buttonStart = isPressed; + emit q->buttonStartChanged(); break; - case QGamepadManager::ButtonSelect: - buttonSelect = false; - emit q->buttonSelectChanged(false); + case JoyButton::DpadUp: + buttonUp = isPressed; + emit q->buttonUpChanged(); break; - case QGamepadManager::ButtonStart: - buttonStart = false; - emit q->buttonStartChanged(false); + case JoyButton::DpadDown: + buttonDown = isPressed; + emit q->buttonDownChanged(); break; - case QGamepadManager::ButtonUp: - buttonUp = false; - emit q->buttonUpChanged(false); + case JoyButton::DpadLeft: + buttonLeft = isPressed; + emit q->buttonLeftChanged(); break; - case QGamepadManager::ButtonDown: - buttonDown = false; - emit q->buttonDownChanged(false); + case JoyButton::DpadRight: + buttonRight = isPressed; + emit q->buttonRightChanged(); break; - case QGamepadManager::ButtonLeft: - buttonLeft = false; - emit q->buttonLeftChanged(false); - break; - case QGamepadManager::ButtonRight: - buttonRight = false; - emit q->buttonRightChanged(false); - break; - case QGamepadManager::ButtonCenter: - buttonCenter = false; - emit q->buttonCenterChanged(false); - break; - case QGamepadManager::ButtonGuide: - buttonGuide = false; - emit q->buttonGuideChanged(false); + case JoyButton::Guide: + buttonGuide = isPressed; + emit q->buttonGuideChanged(); break; default: break; } } + /*! \class QGamepad \inmodule QtGamepad @@ -390,17 +217,15 @@ void QGamepadPrivate::_q_handleGamepadButtonReleaseEvent(int id, QGamepadManager QGamepad::QGamepad(int deviceId, QObject *parent) : QObject(*new QGamepadPrivate(deviceId), parent) { - Q_D(QGamepad); - d->gamepadManager = QGamepadManager::instance(); - connect(d->gamepadManager, SIGNAL(gamepadConnected(int)), this, SLOT(_q_handleGamepadConnected(int))); - connect(d->gamepadManager, SIGNAL(gamepadNameChanged(int, QString)), this, SLOT(_q_handleGamepadNameChanged(int, QString))); - connect(d->gamepadManager, SIGNAL(gamepadDisconnected(int)), this, SLOT(_q_handleGamepadDisconnected(int))); - connect(d->gamepadManager, SIGNAL(gamepadAxisEvent(int,QGamepadManager::GamepadAxis,double)), this, SLOT(_q_handleGamepadAxisEvent(int,QGamepadManager::GamepadAxis,double))); - connect(d->gamepadManager, SIGNAL(gamepadButtonPressEvent(int,QGamepadManager::GamepadButton,double)), this, SLOT(_q_handleGamepadButtonPressEvent(int,QGamepadManager::GamepadButton,double))); - connect(d->gamepadManager, SIGNAL(gamepadButtonReleaseEvent(int,QGamepadManager::GamepadButton)), this, SLOT(_q_handleGamepadButtonReleaseEvent(int,QGamepadManager::GamepadButton))); + auto* input = QUniversalInput::instance(); + + connect(input, SIGNAL(joyConnectionChanged(int,bool)), this, SLOT(_q_handleGamepadConnectionChangedEvent(int, bool))); + connect(input, SIGNAL(joyAxisEvent(int,JoyAxis,float)), this, SLOT(_q_handleGamepadAxisEvent(int, JoyAxis, float))); + connect(input, SIGNAL(joyButtonEvent(int,JoyButton,bool)), this, SLOT(_q_handleGamepadButtonEvent(int, JoyButton, bool))); - d->setConnected(d->gamepadManager->isGamepadConnected(deviceId)); - d->setName(d->gamepadManager->gamepadName(deviceId)); + Q_D(QGamepad); + d->setConnected(input->isJoyConnected(deviceId)); + d->setName(input->getJoyName(deviceId)); } QGamepad::~QGamepad() @@ -472,13 +297,13 @@ QString QGamepad::name() const * The axis values range from -1.0 to 1.0. */ /*! - * \qmlproperty double Gamepad::axisLeftX + * \qmlproperty float Gamepad::axisLeftX * \readonly * * The value of the left thumbstick's X axis. * The axis values range from -1.0 to 1.0. */ -double QGamepad::axisLeftX() const +float QGamepad::axisLeftX() const { Q_D(const QGamepad); return d->axisLeftX; @@ -491,13 +316,13 @@ double QGamepad::axisLeftX() const * The axis values range from -1.0 to 1.0. */ /*! - * \qmlproperty double Gamepad::axisLeftY + * \qmlproperty float Gamepad::axisLeftY * \readonly * * The value of the left thumbstick's Y axis. * The axis values range from -1.0 to 1.0. */ -double QGamepad::axisLeftY() const +float QGamepad::axisLeftY() const { Q_D(const QGamepad); return d->axisLeftY; @@ -510,13 +335,13 @@ double QGamepad::axisLeftY() const * The axis values range from -1.0 to 1.0. */ /*! - * \qmlproperty double Gamepad::axisRightX + * \qmlproperty float Gamepad::axisRightX * \readonly * * This value of the right thumbstick's X axis. * The axis values range from -1.0 to 1.0. */ -double QGamepad::axisRightX() const +float QGamepad::axisRightX() const { Q_D(const QGamepad); return d->axisRightX; @@ -529,13 +354,13 @@ double QGamepad::axisRightX() const * The axis values range from -1.0 to 1.0. */ /*! - * \qmlproperty double Gamepad::axisRightY + * \qmlproperty float Gamepad::axisRightY * \readonly * * This value of the right thumbstick's Y axis. * The axis values range from -1.0 to 1.0. */ -double QGamepad::axisRightY() const +float QGamepad::axisRightY() const { Q_D(const QGamepad); return d->axisRightY; @@ -663,14 +488,14 @@ bool QGamepad::buttonR1() const * when pressed completely. */ /*! - * \qmlproperty double Gamepad::buttonL2 + * \qmlproperty float Gamepad::buttonL2 * \readonly * * The value of the left trigger button. * This trigger value ranges from 0.0 when not pressed to 1.0 * when pressed completely. */ -double QGamepad::buttonL2() const +float QGamepad::buttonL2() const { Q_D(const QGamepad); return d->buttonL2; @@ -684,14 +509,14 @@ double QGamepad::buttonL2() const * when pressed completely. */ /*! - * \qmlproperty double Gamepad::buttonR2 + * \qmlproperty float Gamepad::buttonR2 * \readonly * * The value of the right trigger button. * This trigger value ranges from 0.0 when not pressed to 1.0 * when pressed completely. */ -double QGamepad::buttonR2() const +float QGamepad::buttonR2() const { Q_D(const QGamepad); return d->buttonR2; @@ -857,25 +682,6 @@ bool QGamepad::buttonRight() const return d->buttonRight; } -/*! - * \property QGamepad::buttonCenter - * - * The state of the center button. - * The value is \c true when pressed, and \c false when not pressed. - */ -/* - * \qmlproperty bool Gamepad::buttonCenter - * \readonly - * - * The state of the center button. - * The value is \c true when pressed, and \c false when not pressed. - */ -bool QGamepad::buttonCenter() const -{ - Q_D(const QGamepad); - return d->buttonCenter; -} - /*! * \property QGamepad::buttonGuide * @@ -905,8 +711,10 @@ void QGamepad::setDeviceId(int number) Q_D(QGamepad); if (d->deviceId != number) { d->deviceId = number; - emit deviceIdChanged(number); - d->setConnected(d->gamepadManager->isGamepadConnected(d->deviceId)); + emit deviceIdChanged(); + auto input = QUniversalInput::instance(); + d->setName(input->getJoyName(d->deviceId)); + d->setConnected(input->isJoyConnected(d->deviceId)); } } diff --git a/src/gamepad/qgamepad.h b/src/gamepad/qgamepad.h index 33390f8..b53519a 100644 --- a/src/gamepad/qgamepad.h +++ b/src/gamepad/qgamepad.h @@ -1,45 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QGAMEPAD_H #define QGAMEPAD_H #include -#include -#include +#include QT_BEGIN_NAMESPACE @@ -51,18 +17,18 @@ class Q_GAMEPAD_EXPORT QGamepad : public QObject Q_PROPERTY(int deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged) Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged) Q_PROPERTY(QString name READ name NOTIFY nameChanged) - Q_PROPERTY(double axisLeftX READ axisLeftX NOTIFY axisLeftXChanged) - Q_PROPERTY(double axisLeftY READ axisLeftY NOTIFY axisLeftYChanged) - Q_PROPERTY(double axisRightX READ axisRightX NOTIFY axisRightXChanged) - Q_PROPERTY(double axisRightY READ axisRightY NOTIFY axisRightYChanged) + Q_PROPERTY(float axisLeftX READ axisLeftX NOTIFY axisLeftXChanged) + Q_PROPERTY(float axisLeftY READ axisLeftY NOTIFY axisLeftYChanged) + Q_PROPERTY(float axisRightX READ axisRightX NOTIFY axisRightXChanged) + Q_PROPERTY(float axisRightY READ axisRightY NOTIFY axisRightYChanged) Q_PROPERTY(bool buttonA READ buttonA NOTIFY buttonAChanged) Q_PROPERTY(bool buttonB READ buttonB NOTIFY buttonBChanged) Q_PROPERTY(bool buttonX READ buttonX NOTIFY buttonXChanged) Q_PROPERTY(bool buttonY READ buttonY NOTIFY buttonYChanged) Q_PROPERTY(bool buttonL1 READ buttonL1 NOTIFY buttonL1Changed) Q_PROPERTY(bool buttonR1 READ buttonR1 NOTIFY buttonR1Changed) - Q_PROPERTY(double buttonL2 READ buttonL2 NOTIFY buttonL2Changed) - Q_PROPERTY(double buttonR2 READ buttonR2 NOTIFY buttonR2Changed) + Q_PROPERTY(float buttonL2 READ buttonL2 NOTIFY buttonL2Changed) + Q_PROPERTY(float buttonR2 READ buttonR2 NOTIFY buttonR2Changed) Q_PROPERTY(bool buttonSelect READ buttonSelect NOTIFY buttonSelectChanged) Q_PROPERTY(bool buttonStart READ buttonStart NOTIFY buttonStartChanged) Q_PROPERTY(bool buttonL3 READ buttonL3 NOTIFY buttonL3Changed) @@ -71,30 +37,30 @@ class Q_GAMEPAD_EXPORT QGamepad : public QObject Q_PROPERTY(bool buttonDown READ buttonDown NOTIFY buttonDownChanged) Q_PROPERTY(bool buttonLeft READ buttonLeft NOTIFY buttonLeftChanged) Q_PROPERTY(bool buttonRight READ buttonRight NOTIFY buttonRightChanged) - Q_PROPERTY(bool buttonCenter READ buttonCenter NOTIFY buttonCenterChanged) Q_PROPERTY(bool buttonGuide READ buttonGuide NOTIFY buttonGuideChanged) public: explicit QGamepad(int deviceId = 0, QObject *parent = nullptr); ~QGamepad(); int deviceId() const; + void setDeviceId(int number); bool isConnected() const; QString name() const; - double axisLeftX() const; - double axisLeftY() const; - double axisRightX() const; - double axisRightY() const; + float axisLeftX() const; + float axisLeftY() const; + float axisRightX() const; + float axisRightY() const; bool buttonA() const; bool buttonB() const; bool buttonX() const; bool buttonY() const; bool buttonL1() const; bool buttonR1() const; - double buttonL2() const; - double buttonR2() const; + float buttonL2() const; + float buttonR2() const; bool buttonSelect() const; bool buttonStart() const; bool buttonL3() const; @@ -103,50 +69,41 @@ class Q_GAMEPAD_EXPORT QGamepad : public QObject bool buttonDown() const; bool buttonLeft() const; bool buttonRight() const; - bool buttonCenter() const; bool buttonGuide() const; Q_SIGNALS: - void deviceIdChanged(int value); - void connectedChanged(bool value); - void nameChanged(QString value); - void axisLeftXChanged(double value); - void axisLeftYChanged(double value); - void axisRightXChanged(double value); - void axisRightYChanged(double value); - void buttonAChanged(bool value); - void buttonBChanged(bool value); - void buttonXChanged(bool value); - void buttonYChanged(bool value); - void buttonL1Changed(bool value); - void buttonR1Changed(bool value); - void buttonL2Changed(double value); - void buttonR2Changed(double value); - void buttonSelectChanged(bool value); - void buttonStartChanged(bool value); - void buttonL3Changed(bool value); - void buttonR3Changed(bool value); - void buttonUpChanged(bool value); - void buttonDownChanged(bool value); - void buttonLeftChanged(bool value); - void buttonRightChanged(bool value); - void buttonCenterChanged(bool value); - void buttonGuideChanged(bool value); - -public Q_SLOTS: - - void setDeviceId(int number); + void deviceIdChanged(); + void connectedChanged(); + void nameChanged(); + void axisLeftXChanged(); + void axisLeftYChanged(); + void axisRightXChanged(); + void axisRightYChanged(); + void buttonAChanged(); + void buttonBChanged(); + void buttonXChanged(); + void buttonYChanged(); + void buttonL1Changed(); + void buttonR1Changed(); + void buttonL2Changed(); + void buttonR2Changed(); + void buttonSelectChanged(); + void buttonStartChanged(); + void buttonL3Changed(); + void buttonR3Changed(); + void buttonUpChanged(); + void buttonDownChanged(); + void buttonLeftChanged(); + void buttonRightChanged(); + void buttonGuideChanged(); private: Q_DECLARE_PRIVATE(QGamepad) Q_DISABLE_COPY(QGamepad) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadConnected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadNameChanged(int, const QString &)) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadDisconnected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadAxisEvent(int, QGamepadManager::GamepadAxis, double)) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadButtonPressEvent(int, QGamepadManager::GamepadButton, double)) - Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadButtonReleaseEvent(int, QGamepadManager::GamepadButton)) + Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadConnectionChangedEvent(int, bool)) + Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadAxisEvent(int, JoyAxis, float)) + Q_PRIVATE_SLOT(d_func(), void _q_handleGamepadButtonEvent(int, JoyButton, bool)) }; QT_END_NAMESPACE diff --git a/src/gamepad/qgamepadbackend.cpp b/src/gamepad/qgamepadbackend.cpp deleted file mode 100644 index 2b74634..0000000 --- a/src/gamepad/qgamepadbackend.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadbackend_p.h" -#include - -QT_BEGIN_NAMESPACE - -static const QLatin1String GAMEPAD_GROUP("___gamepad_saved_states_v2"); - -QGamepadBackend::QGamepadBackend(QObject *parent) : - QObject(parent) -{ -} - -bool QGamepadBackend::isConfigurationNeeded(int /*deviceId*/) -{ - return false; -} - -void QGamepadBackend::resetConfiguration(int /*deviceId*/) -{ -} - -bool QGamepadBackend::configureButton(int /*deviceId*/, QGamepadManager::GamepadButton /*button*/) -{ - return false; -} - -bool QGamepadBackend::configureAxis(int /*deviceId*/, QGamepadManager::GamepadAxis /*axis*/) -{ - return false; -} - -bool QGamepadBackend::setCancelConfigureButton(int /*deviceId*/, QGamepadManager::GamepadButton /*button*/) -{ - return false; -} - -void QGamepadBackend::setSettingsFile(const QString &file) -{ - m_settingsFilePath = file; -} - -void QGamepadBackend::saveSettings(int productId, const QVariant &value) -{ - QScopedPointer s; - if (m_settingsFilePath.isNull()) - s.reset(new QSettings()); - else - s.reset(new QSettings(m_settingsFilePath)); - s->beginGroup(GAMEPAD_GROUP); - QString key = QString::fromLatin1("id_%1").arg(productId); - if (value.isNull()) - s->remove(key); - else - s->setValue(key, value); -} - -QVariant QGamepadBackend::readSettings(int productId) -{ - QScopedPointer s; - if (m_settingsFilePath.isNull()) - s.reset(new QSettings()); - else - s.reset(new QSettings(m_settingsFilePath)); - s->beginGroup(GAMEPAD_GROUP); - return s->value(QString::fromLatin1("id_%1").arg(productId)); -} - -bool QGamepadBackend::start() -{ - return true; -} - -void QGamepadBackend::stop() -{ - -} - -QT_END_NAMESPACE diff --git a/src/gamepad/qgamepadbackend_p.h b/src/gamepad/qgamepadbackend_p.h deleted file mode 100644 index 4c5d276..0000000 --- a/src/gamepad/qgamepadbackend_p.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADBACKEND_P_H -#define QGAMEPADBACKEND_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Q_GAMEPAD_EXPORT QGamepadBackend : public QObject -{ - Q_OBJECT -public: - template - struct AxisInfo { - AxisInfo(T minValue = 0, T maxValue = 1, QGamepadManager::GamepadAxis gamepadAxis = QGamepadManager::AxisInvalid) - : minValue(minValue) - , maxValue(maxValue) - , gamepadAxis(gamepadAxis) - {} - - virtual double normalized(T value) const - { - if (gamepadAxis == QGamepadManager::AxisInvalid && minValue >= 0) { - // case 0.0 - 1.0 - return double(value - minValue) / double(maxValue - minValue); - } else { - // case -1.0 - 1.0 - return 2.0 * double(value - minValue) / double(maxValue - minValue) - 1.0; - } - } - T minValue; - T maxValue; - QGamepadManager::GamepadAxis gamepadAxis; - }; - -public: - explicit QGamepadBackend(QObject *parent = nullptr); - virtual bool isConfigurationNeeded(int deviceId); - virtual void resetConfiguration(int deviceId); - virtual bool configureButton(int deviceId, QGamepadManager::GamepadButton button); - virtual bool configureAxis(int deviceId, QGamepadManager::GamepadAxis axis); - virtual bool setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button); - virtual void setSettingsFile(const QString &file); - virtual void saveSettings(int productId, const QVariant &value); - virtual QVariant readSettings(int productId); - -public Q_SLOTS: - virtual bool start(); - virtual void stop(); - -Q_SIGNALS: - void buttonConfigured(int deviceId, QGamepadManager::GamepadButton button); - void axisConfigured(int deviceId, QGamepadManager::GamepadAxis axis); - void configurationCanceled(int deviceId); - void gamepadAdded(int deviceId); - void gamepadNamed(int deviceId, const QString &name); - void gamepadRemoved(int deviceId); - void gamepadAxisMoved(int deviceId, QGamepadManager::GamepadAxis axis, double value); - void gamepadButtonPressed(int deviceId, QGamepadManager::GamepadButton button, double value); - void gamepadButtonReleased(int deviceId, QGamepadManager::GamepadButton button); - -protected: - QString m_settingsFilePath; -}; - -QT_END_NAMESPACE - -#endif // QGAMEPADBACKEND_P_H diff --git a/src/gamepad/qgamepadbackendfactory.cpp b/src/gamepad/qgamepadbackendfactory.cpp deleted file mode 100644 index a899cf0..0000000 --- a/src/gamepad/qgamepadbackendfactory.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadbackendfactory_p.h" -#include "qgamepadbackendplugin_p.h" -#include "qgamepadbackend_p.h" - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QtGamepadBackendFactoryInterface_iid, QLatin1String("/gamepads"), Qt::CaseInsensitive)) - -QStringList QGamepadBackendFactory::keys() -{ - return loader->keyMap().values(); -} - -QGamepadBackend *QGamepadBackendFactory::create(const QString &name, const QStringList &args) -{ - return qLoadPlugin(loader(), name, args); -} - -QT_END_NAMESPACE diff --git a/src/gamepad/qgamepadbackendfactory_p.h b/src/gamepad/qgamepadbackendfactory_p.h deleted file mode 100644 index 7782158..0000000 --- a/src/gamepad/qgamepadbackendfactory_p.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADBACKENDFACTORY_P_H -#define QGAMEPADBACKENDFACTORY_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGamepadBackend; - -class Q_GAMEPAD_EXPORT QGamepadBackendFactory -{ -public: - static QStringList keys(); - static QGamepadBackend *create(const QString &name, const QStringList &args); -}; - -QT_END_NAMESPACE - -#endif // QGAMEPADBACKENDFACTORY_P_H diff --git a/src/gamepad/qgamepadbackendplugin.cpp b/src/gamepad/qgamepadbackendplugin.cpp deleted file mode 100644 index a06a287..0000000 --- a/src/gamepad/qgamepadbackendplugin.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadbackendplugin_p.h" - -QT_BEGIN_NAMESPACE - -QGamepadBackendPlugin::QGamepadBackendPlugin(QObject *parent) : QObject(parent) -{ - -} - -QGamepadBackendPlugin::~QGamepadBackendPlugin() -{ - -} - -QT_END_NAMESPACE - diff --git a/src/gamepad/qgamepadbackendplugin_p.h b/src/gamepad/qgamepadbackendplugin_p.h deleted file mode 100644 index 813259c..0000000 --- a/src/gamepad/qgamepadbackendplugin_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADBACKENDPLUGIN_P_H -#define QGAMEPADBACKENDPLUGIN_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGamepadBackend; - -#define QtGamepadBackendFactoryInterface_iid "org.qt-project.Qt.Gamepad.QtGamepadBackendFactoryInterface.5.9" - -class Q_GAMEPAD_EXPORT QGamepadBackendPlugin : public QObject -{ - Q_OBJECT -public: - explicit QGamepadBackendPlugin(QObject *parent = nullptr); - ~QGamepadBackendPlugin(); - - virtual QGamepadBackend *create(const QString &key, const QStringList ¶mList) = 0; - -signals: - -public slots: -}; - -QT_END_NAMESPACE - -#endif // QGAMEPADBACKENDPLUGIN_P_H diff --git a/src/gamepad/qgamepadkeynavigation.cpp b/src/gamepad/qgamepadkeynavigation.cpp deleted file mode 100644 index 66c6906..0000000 --- a/src/gamepad/qgamepadkeynavigation.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadkeynavigation.h" -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QGamepadKeyNavigationPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGamepadKeyNavigation) -public: - QGamepadKeyNavigationPrivate() - : active(true) - , gamepad(nullptr) - , buttonL2Pressed(false) - , buttonR2Pressed(false) - { - } - - void sendGeneratedKeyEvent(QKeyEvent *event); - - bool active; - QGamepad *gamepad; - QGamepadManager *gamepadManger; - bool buttonL2Pressed; - bool buttonR2Pressed; - QMap keyMapping; - - void _q_processGamepadButtonPressEvent(int index, QGamepadManager::GamepadButton button, double value); - void _q_processGamepadButtonReleaseEvent(int index, QGamepadManager::GamepadButton button); -}; - -void QGamepadKeyNavigationPrivate::sendGeneratedKeyEvent(QKeyEvent *event) -{ - if (!active) { - delete event; - return; - } - const QGuiApplication *app = qApp; - QWindow *focusWindow = app ? app->focusWindow() : nullptr; - if (focusWindow) - QGuiApplication::sendEvent(focusWindow, event); -} - -void QGamepadKeyNavigationPrivate::_q_processGamepadButtonPressEvent(int index, QGamepadManager::GamepadButton button, double value) -{ - Q_UNUSED(value); - // If a gamepad has been set then, only use the events of that gamepad - if (gamepad && gamepad->deviceId() != index) - return; - - // Trigger buttons are a special case as they get multiple press events as the value changes - if (button == QGamepadManager::ButtonL2 && buttonL2Pressed) - return; - else - buttonL2Pressed = true; - if (button == QGamepadManager::ButtonR2 && buttonR2Pressed) - return; - else - buttonR2Pressed = true; - - QKeyEvent *event = new QKeyEvent(QEvent::KeyPress, keyMapping[button], Qt::NoModifier); - sendGeneratedKeyEvent(event); -} - -void QGamepadKeyNavigationPrivate::_q_processGamepadButtonReleaseEvent(int index, QGamepadManager::GamepadButton button) -{ - // If a gamepad has been set then, only use the events of that gamepad - if (gamepad && gamepad->deviceId() != index) - return; - - // Free the trigger buttons if necessary - if (button == QGamepadManager::ButtonL2) - buttonL2Pressed = false; - if (button == QGamepadManager::ButtonR2) - buttonR2Pressed = false; - - QKeyEvent *event = new QKeyEvent(QEvent::KeyRelease, keyMapping[button], Qt::NoModifier); - sendGeneratedKeyEvent(event); -} - -/*! - \class QGamepadKeyNavigation - \inmodule QtGamepad - \brief Provides support for keyboard events triggered by gamepads. - - QGamepadKeyNavigation provides support for keyboard events triggered by - gamepads. - */ - -/*! - * Constructs a QGamepadNavigation object with the given \a parent. - */ - -QGamepadKeyNavigation::QGamepadKeyNavigation(QObject *parent) - : QObject(*new QGamepadKeyNavigationPrivate(), parent) -{ - Q_D(QGamepadKeyNavigation); - d->gamepadManger = QGamepadManager::instance(); - - // Default keymap - d->keyMapping.insert(QGamepadManager::ButtonUp, Qt::Key_Up); - d->keyMapping.insert(QGamepadManager::ButtonDown, Qt::Key_Down); - d->keyMapping.insert(QGamepadManager::ButtonLeft, Qt::Key_Left); - d->keyMapping.insert(QGamepadManager::ButtonRight, Qt::Key_Right); - d->keyMapping.insert(QGamepadManager::ButtonA, Qt::Key_Return); - d->keyMapping.insert(QGamepadManager::ButtonB, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonX, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonY, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonSelect, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonStart, Qt::Key_Return); - d->keyMapping.insert(QGamepadManager::ButtonGuide, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonL1, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonR1, Qt::Key_Forward); - d->keyMapping.insert(QGamepadManager::ButtonL2, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonR2, Qt::Key_Forward); - d->keyMapping.insert(QGamepadManager::ButtonL3, Qt::Key_Back); - d->keyMapping.insert(QGamepadManager::ButtonR3, Qt::Key_Forward); - - connect(d->gamepadManger, SIGNAL(gamepadButtonPressEvent(int,QGamepadManager::GamepadButton,double)), - this, SLOT(_q_processGamepadButtonPressEvent(int,QGamepadManager::GamepadButton,double))); - connect(d->gamepadManger, SIGNAL(gamepadButtonReleaseEvent(int,QGamepadManager::GamepadButton)), - this, SLOT(_q_processGamepadButtonReleaseEvent(int,QGamepadManager::GamepadButton))); -} - -/*! - * Returns whether key navigation on the gamepad is active or not. -*/ -bool QGamepadKeyNavigation::active() const -{ - Q_D(const QGamepadKeyNavigation); - return d->active; -} - -/*! - * Returns a pointer the current QGamepad - */ -QGamepad *QGamepadKeyNavigation::gamepad() const -{ - Q_D(const QGamepadKeyNavigation); - return d->gamepad; -} - -/*! - * Returns the key mapping of the Up button. - */ -Qt::Key QGamepadKeyNavigation::upKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonUp]; -} - -/*! - * Returns the key mapping of the Down button. - */ -Qt::Key QGamepadKeyNavigation::downKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonDown]; -} - -/*! - * Returns the key mapping of the Left button. - */ -Qt::Key QGamepadKeyNavigation::leftKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonLeft]; -} - -/*! - * Returns the key mapping of the Right button. - */ -Qt::Key QGamepadKeyNavigation::rightKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonRight]; -} - -/*! - * Returns the key mapping of A button. - */ -Qt::Key QGamepadKeyNavigation::buttonAKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonA]; -} - -/*! - * Returns the key mapping of the B button. - */ -Qt::Key QGamepadKeyNavigation::buttonBKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonB]; -} - -/*! - * Returns the key mapping of the X button. - */ -Qt::Key QGamepadKeyNavigation::buttonXKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonX]; -} - -/*! - * Returns the key mapping of the Y button. - */ -Qt::Key QGamepadKeyNavigation::buttonYKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonY]; -} - -/*! - * Returns the key mapping of the Select button. - */ -Qt::Key QGamepadKeyNavigation::buttonSelectKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonSelect]; -} - -/*! - * Returns the key mapping of the Start button. - */ -Qt::Key QGamepadKeyNavigation::buttonStartKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonStart]; -} - -/*! - * Returns the key mapping of the Guide button. - */ -Qt::Key QGamepadKeyNavigation::buttonGuideKey() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonGuide]; -} - -/*! - * Returns the key mapping of the left shoulder button. - */ -Qt::Key QGamepadKeyNavigation::buttonL1Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL1]; -} - -/*! - * Returns the key mapping of the Right shoulder button. - */ -Qt::Key QGamepadKeyNavigation::buttonR1Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL2]; -} - -/*! - * Returns the key mapping of the left trigger button. - */ -Qt::Key QGamepadKeyNavigation::buttonL2Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL2]; -} - -/*! - * Returns the key mapping of the Right trigger button. - */ -Qt::Key QGamepadKeyNavigation::buttonR2Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL2]; -} - -/*! - * Returns the key mapping of the left stick button. - */ -Qt::Key QGamepadKeyNavigation::buttonL3Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL3]; -} - -/*! - * Returns the key mapping of the right stick button. - */ -Qt::Key QGamepadKeyNavigation::buttonR3Key() const -{ - Q_D(const QGamepadKeyNavigation); - return d->keyMapping[QGamepadManager::ButtonL3]; -} - -/*! - * Activates key navigation if \a isActive is true, - * disables it otherwise. - */ -void QGamepadKeyNavigation::setActive(bool isActive) -{ - Q_D(QGamepadKeyNavigation); - if (d->active != isActive) { - d->active = isActive; - emit activeChanged(isActive); - } -} - -/*! - * Selects the specified \a gamepad. -*/ -void QGamepadKeyNavigation::setGamepad(QGamepad *gamepad) -{ - Q_D(QGamepadKeyNavigation); - if (d->gamepad != gamepad) { - d->gamepad = gamepad; - emit gamepadChanged(gamepad); - } -} - -/*! - * Sets the mapping of the Up button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setUpKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonUp] != key) { - d->keyMapping[QGamepadManager::ButtonUp] = key; - emit upKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Down button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setDownKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonDown] != key) { - d->keyMapping[QGamepadManager::ButtonDown] = key; - emit downKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Left button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setLeftKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonLeft] != key) { - d->keyMapping[QGamepadManager::ButtonLeft] = key; - emit leftKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Right button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setRightKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonRight] != key) { - d->keyMapping[QGamepadManager::ButtonRight] = key; - emit rightKeyChanged(key); - } -} - -/*! - * Sets the mapping of the A button with the keycode - * specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonAKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonA] != key) { - d->keyMapping[QGamepadManager::ButtonA] = key; - emit buttonAKeyChanged(key); - } -} - -/*! - * Sets the mapping of the B button with the keycode - * specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonBKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonB] != key) { - d->keyMapping[QGamepadManager::ButtonB] = key; - emit buttonBKeyChanged(key); - } -} - -/*! - * Sets the mapping of the X button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonXKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonX] != key) { - d->keyMapping[QGamepadManager::ButtonX] = key; - emit buttonXKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Y button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonYKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonY] != key) { - d->keyMapping[QGamepadManager::ButtonY] = key; - emit buttonYKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Select button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonSelectKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonSelect] != key) { - d->keyMapping[QGamepadManager::ButtonSelect] = key; - emit buttonSelectKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Start button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonStartKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonStart] != key) { - d->keyMapping[QGamepadManager::ButtonStart] = key; - emit buttonStartKeyChanged(key); - } -} - -/*! - * Sets the mapping of the Guide button with the keycode - * specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonGuideKey(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonGuide] != key) { - d->keyMapping[QGamepadManager::ButtonGuide] = key; - emit buttonGuideKeyChanged(key); - } -} - -/*! - * Sets the mapping of the left shoulder button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonL1Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonL1] != key) { - d->keyMapping[QGamepadManager::ButtonL1] = key; - emit buttonL1KeyChanged(key); - } -} - -/*! - * Sets the mapping of the right shoulder button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonR1Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonR1] != key) { - d->keyMapping[QGamepadManager::ButtonR1] = key; - emit buttonR1KeyChanged(key); - } -} - -/*! - * Sets the mapping of the left trigger button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonL2Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonL2] != key) { - d->keyMapping[QGamepadManager::ButtonL2] = key; - emit buttonL1KeyChanged(key); - } -} - -/*! - * Sets the mapping of the right trigger button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonR2Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonR2] != key) { - d->keyMapping[QGamepadManager::ButtonR2] = key; - emit buttonR1KeyChanged(key); - } -} - -/*! - * Sets the mapping of the left stick button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonL3Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonL3] != key) { - d->keyMapping[QGamepadManager::ButtonL3] = key; - emit buttonL1KeyChanged(key); - } -} - -/*! - * Sets the mapping of the right stick button with the - * keycode specified in \a key. -*/ -void QGamepadKeyNavigation::setButtonR3Key(Qt::Key key) -{ - Q_D(QGamepadKeyNavigation); - if (d->keyMapping[QGamepadManager::ButtonR3] != key) { - d->keyMapping[QGamepadManager::ButtonR3] = key; - emit buttonR1KeyChanged(key); - } -} - -QT_END_NAMESPACE - -#include "moc_qgamepadkeynavigation.cpp" diff --git a/src/gamepad/qgamepadkeynavigation.h b/src/gamepad/qgamepadkeynavigation.h deleted file mode 100644 index fca7714..0000000 --- a/src/gamepad/qgamepadkeynavigation.h +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADKEYNAVIGATION_H -#define QGAMEPADKEYNAVIGATION_H - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QKeyEvent; -class QGamepad; -class QGamepadKeyNavigationPrivate; -class Q_GAMEPAD_EXPORT QGamepadKeyNavigation : public QObject -{ - Q_OBJECT - Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) - Q_PROPERTY(QGamepad *gamepad READ gamepad WRITE setGamepad NOTIFY gamepadChanged) - Q_PROPERTY(Qt::Key upKey READ upKey WRITE setUpKey NOTIFY upKeyChanged) - Q_PROPERTY(Qt::Key downKey READ downKey WRITE setDownKey NOTIFY downKeyChanged) - Q_PROPERTY(Qt::Key leftKey READ leftKey WRITE setLeftKey NOTIFY leftKeyChanged) - Q_PROPERTY(Qt::Key rightKey READ rightKey WRITE setRightKey NOTIFY rightKeyChanged) - Q_PROPERTY(Qt::Key buttonAKey READ buttonAKey WRITE setButtonAKey NOTIFY buttonAKeyChanged) - Q_PROPERTY(Qt::Key buttonBKey READ buttonBKey WRITE setButtonBKey NOTIFY buttonBKeyChanged) - Q_PROPERTY(Qt::Key buttonXKey READ buttonXKey WRITE setButtonXKey NOTIFY buttonXKeyChanged) - Q_PROPERTY(Qt::Key buttonYKey READ buttonYKey WRITE setButtonYKey NOTIFY buttonYKeyChanged) - Q_PROPERTY(Qt::Key buttonSelectKey READ buttonSelectKey WRITE setButtonSelectKey NOTIFY buttonSelectKeyChanged) - Q_PROPERTY(Qt::Key buttonStartKey READ buttonStartKey WRITE setButtonStartKey NOTIFY buttonStartKeyChanged) - Q_PROPERTY(Qt::Key buttonGuideKey READ buttonGuideKey WRITE setButtonGuideKey NOTIFY buttonGuideKeyChanged) - Q_PROPERTY(Qt::Key buttonL1Key READ buttonL1Key WRITE setButtonL1Key NOTIFY buttonL1KeyChanged) - Q_PROPERTY(Qt::Key buttonR1Key READ buttonR1Key WRITE setButtonR1Key NOTIFY buttonR1KeyChanged) - Q_PROPERTY(Qt::Key buttonL2Key READ buttonL2Key WRITE setButtonL2Key NOTIFY buttonL2KeyChanged) - Q_PROPERTY(Qt::Key buttonR2Key READ buttonR2Key WRITE setButtonR2Key NOTIFY buttonR2KeyChanged) - Q_PROPERTY(Qt::Key buttonL3Key READ buttonL3Key WRITE setButtonL3Key NOTIFY buttonL3KeyChanged) - Q_PROPERTY(Qt::Key buttonR3Key READ buttonR3Key WRITE setButtonR3Key NOTIFY buttonR3KeyChanged) -public: - explicit QGamepadKeyNavigation(QObject *parent = nullptr); - - bool active() const; - QGamepad *gamepad() const; - - Qt::Key upKey() const; - Qt::Key downKey() const; - Qt::Key leftKey() const; - Qt::Key rightKey() const; - Qt::Key buttonAKey() const; - Qt::Key buttonBKey() const; - Qt::Key buttonXKey() const; - Qt::Key buttonYKey() const; - Qt::Key buttonSelectKey() const; - Qt::Key buttonStartKey() const; - Qt::Key buttonGuideKey() const; - Qt::Key buttonL1Key() const; - Qt::Key buttonR1Key() const; - Qt::Key buttonL2Key() const; - Qt::Key buttonR2Key() const; - Qt::Key buttonL3Key() const; - Qt::Key buttonR3Key() const; - -Q_SIGNALS: - void activeChanged(bool isActive); - void gamepadChanged(QGamepad *gamepad); - - void upKeyChanged(Qt::Key key); - void downKeyChanged(Qt::Key key); - void leftKeyChanged(Qt::Key key); - void rightKeyChanged(Qt::Key key); - void buttonAKeyChanged(Qt::Key key); - void buttonBKeyChanged(Qt::Key key); - void buttonXKeyChanged(Qt::Key key); - void buttonYKeyChanged(Qt::Key key); - void buttonSelectKeyChanged(Qt::Key key); - void buttonStartKeyChanged(Qt::Key key); - void buttonGuideKeyChanged(Qt::Key key); - void buttonL1KeyChanged(Qt::Key key); - void buttonR1KeyChanged(Qt::Key key); - void buttonL2KeyChanged(Qt::Key key); - void buttonR2KeyChanged(Qt::Key key); - void buttonL3KeyChanged(Qt::Key key); - void buttonR3KeyChanged(Qt::Key key); - -public Q_SLOTS: - void setActive(bool isActive); - void setGamepad(QGamepad *gamepad); - - void setUpKey(Qt::Key key); - void setDownKey(Qt::Key key); - void setLeftKey(Qt::Key key); - void setRightKey(Qt::Key key); - void setButtonAKey(Qt::Key key); - void setButtonBKey(Qt::Key key); - void setButtonXKey(Qt::Key key); - void setButtonYKey(Qt::Key key); - void setButtonSelectKey(Qt::Key key); - void setButtonStartKey(Qt::Key key); - void setButtonGuideKey(Qt::Key key); - void setButtonL1Key(Qt::Key key); - void setButtonR1Key(Qt::Key key); - void setButtonL2Key(Qt::Key key); - void setButtonR2Key(Qt::Key key); - void setButtonL3Key(Qt::Key key); - void setButtonR3Key(Qt::Key key); - -private: - Q_DECLARE_PRIVATE(QGamepadKeyNavigation) - Q_DISABLE_COPY(QGamepadKeyNavigation) - Q_PRIVATE_SLOT(d_func(), void _q_processGamepadButtonPressEvent(int, QGamepadManager::GamepadButton, double)) - Q_PRIVATE_SLOT(d_func(), void _q_processGamepadButtonReleaseEvent(int, QGamepadManager::GamepadButton)) -}; - -QT_END_NAMESPACE - -#endif // QGAMEPADKEYNAVIGATION_H diff --git a/src/gamepad/qgamepadmanager.cpp b/src/gamepad/qgamepadmanager.cpp deleted file mode 100644 index c1dc740..0000000 --- a/src/gamepad/qgamepadmanager.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadmanager.h" - -#include "qgamepadbackend_p.h" -#include "qgamepadbackendfactory_p.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(gp, "qt.gamepad") - -class QGamepadManagerPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGamepadManager) -public: - QGamepadManagerPrivate() - : gamepadBackend(nullptr) - { - loadBackend(); - } - - void loadBackend(); - - QGamepadBackend *gamepadBackend; - QMap connectedGamepads; - - // private slots - void _q_forwardGamepadConnected(int deviceId); - void _q_forwardGamepadNameChanged(int deviceId, const QString &name); - void _q_forwardGamepadDisconnected(int deviceId); - void _q_forwardGamepadAxisEvent(int deviceId, QGamepadManager::GamepadAxis axis, double value); - void _q_forwardGamepadButtonPressEvent(int deviceId, QGamepadManager::GamepadButton button, double value); - void _q_forwardGamepadButtonReleaseEvent(int deviceId, QGamepadManager::GamepadButton button); -}; - -void QGamepadManagerPrivate::_q_forwardGamepadConnected(int deviceId) -{ - Q_Q(QGamepadManager); - connectedGamepads.insert(deviceId, QString()); - emit q->gamepadConnected(deviceId); - emit q->connectedGamepadsChanged(); -} - -void QGamepadManagerPrivate::_q_forwardGamepadNameChanged(int deviceId, const QString &name) -{ - Q_Q(QGamepadManager); - connectedGamepads.insert(deviceId, name); - emit q->gamepadNameChanged(deviceId, name); -} - -void QGamepadManagerPrivate::_q_forwardGamepadDisconnected(int deviceId) -{ - Q_Q(QGamepadManager); - connectedGamepads.remove(deviceId); - emit q->gamepadDisconnected(deviceId); - emit q->connectedGamepadsChanged(); -} - -void QGamepadManagerPrivate::_q_forwardGamepadAxisEvent(int deviceId, QGamepadManager::GamepadAxis axis, double value) -{ - Q_Q(QGamepadManager); - emit q->gamepadAxisEvent(deviceId, axis, value); -} - -void QGamepadManagerPrivate::_q_forwardGamepadButtonPressEvent(int deviceId, QGamepadManager::GamepadButton button, double value) -{ - Q_Q(QGamepadManager); - emit q->gamepadButtonPressEvent(deviceId, button, value); -} - -void QGamepadManagerPrivate::_q_forwardGamepadButtonReleaseEvent(int deviceId, QGamepadManager::GamepadButton button) -{ - Q_Q(QGamepadManager); - emit q->gamepadButtonReleaseEvent(deviceId, button); -} - -void QGamepadManagerPrivate::loadBackend() -{ - QStringList keys = QGamepadBackendFactory::keys(); - qCDebug(gp) << "Available backends:" << keys; - if (!keys.isEmpty()) { - QString requestedKey = QString::fromUtf8(qgetenv("QT_GAMEPAD")); - QString targetKey = keys.first(); - if (!requestedKey.isEmpty() && keys.contains(requestedKey)) - targetKey = requestedKey; - if (!targetKey.isEmpty()) { - qCDebug(gp) << "Loading backend" << targetKey; - gamepadBackend = QGamepadBackendFactory::create(targetKey, QStringList()); - } - } - - if (!gamepadBackend) { - // Use dummy backend - gamepadBackend = new QGamepadBackend(); - qCDebug(gp) << "Using dummy backend"; - } -} - -/*! - \class QGamepadManager - \inmodule QtGamepad - \brief Queries attached gamepads and related events. - - QGamepadManager provides a high-level interface for querying the attached - gamepads and events related to all of the connected devices. - */ - -/*! - * \qmltype GamepadManager - * \inqmlmodule QtGamepad - * \instantiates QGamepadManager - * \brief Queries attached gamepads and related events. - * - * GamepadManager QML type provides a high-level interface for - * querying the attached gamepads and events related to all of the - * connected devices. - */ - -/*! - * Constructor for QGamepadManager. - */ - -QGamepadManager::QGamepadManager() : - QObject(*new QGamepadManagerPrivate(), nullptr) -{ - Q_D(QGamepadManager); - - qRegisterMetaType("QGamepadManager::GamepadButton"); - qRegisterMetaType("QGamepadManager::GamepadAxis"); - - connect(d->gamepadBackend, SIGNAL(gamepadAdded(int)), this, SLOT(_q_forwardGamepadConnected(int))); - connect(d->gamepadBackend, SIGNAL(gamepadNamed(int, QString)), this, SLOT(_q_forwardGamepadNameChanged(int, QString))); - connect(d->gamepadBackend, SIGNAL(gamepadRemoved(int)), this, SLOT(_q_forwardGamepadDisconnected(int))); - connect(d->gamepadBackend, SIGNAL(gamepadAxisMoved(int,QGamepadManager::GamepadAxis,double)), this, SLOT(_q_forwardGamepadAxisEvent(int,QGamepadManager::GamepadAxis,double))); - connect(d->gamepadBackend, SIGNAL(gamepadButtonPressed(int,QGamepadManager::GamepadButton,double)), this, SLOT(_q_forwardGamepadButtonPressEvent(int,QGamepadManager::GamepadButton,double))); - connect(d->gamepadBackend, SIGNAL(gamepadButtonReleased(int,QGamepadManager::GamepadButton)), this, SLOT(_q_forwardGamepadButtonReleaseEvent(int,QGamepadManager::GamepadButton))); - - connect(d->gamepadBackend, &QGamepadBackend::buttonConfigured, this, &QGamepadManager::buttonConfigured); - connect(d->gamepadBackend, &QGamepadBackend::axisConfigured, this, &QGamepadManager::axisConfigured); - connect(d->gamepadBackend, &QGamepadBackend::configurationCanceled, this, &QGamepadManager::configurationCanceled); - - if (!d->gamepadBackend->start()) - qCWarning(gp) << "Failed to start gamepad backend"; -} - -/*! - * Destructor for QGamepadManager. - */ - -QGamepadManager::~QGamepadManager() -{ - Q_D(QGamepadManager); - d->gamepadBackend->stop(); - d->gamepadBackend->deleteLater(); -} - -/*! - Returns the instance of the QGamepadManager. -*/ -QGamepadManager *QGamepadManager::instance() -{ - static QGamepadManager instance; - return &instance; -} - -/*! - Returns a boolean indicating whether the gamepad with - the specified \a deviceId is connected or not. -*/ -bool QGamepadManager::isGamepadConnected(int deviceId) const -{ - Q_D(const QGamepadManager); - return d->connectedGamepads.contains(deviceId); -} - -/*! - Returns the name of the gamepad identified by \a deviceId. - If \a deviceId does not identify a connected gamepad, returns an empty string. - - \since 5.11 -*/ -QString QGamepadManager::gamepadName(int deviceId) const -{ - Q_D(const QGamepadManager); - return d->connectedGamepads.value(deviceId); -} - -/*! - \qmlproperty var GamepadManager::connectedGamepads - \readonly - - Returns a list of integers containing the \l {QGamepad::}{deviceId} - values of the connected gamepads. -*/ - -/*! - Returns a list of integers containing the \l {QGamepad::}{deviceId} - values of the connected gamepads. -*/ -const QList QGamepadManager::connectedGamepads() const -{ - Q_D(const QGamepadManager); - return d->connectedGamepads.keys(); -} - -/*! - Returns a boolean indicating whether configuration - is needed for the specified \a deviceId. -*/ -bool QGamepadManager::isConfigurationNeeded(int deviceId) const -{ - Q_D(const QGamepadManager); - return d->gamepadBackend->isConfigurationNeeded(deviceId); -} - -/*! - Configures the specified \a button on the gamepad with - this \a deviceId. - Returns \c true in case of success. -*/ -bool QGamepadManager::configureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - Q_D(QGamepadManager); - return d->gamepadBackend->configureButton(deviceId, button); -} - -/*! - Configures \a axis on the gamepad with the specified \a deviceId. - Returns \c true in case of success. -*/ -bool QGamepadManager::configureAxis(int deviceId, QGamepadManager::GamepadAxis axis) -{ - Q_D(QGamepadManager); - return d->gamepadBackend->configureAxis(deviceId, axis); -} - -/*! - Configures \a button as the cancel button on the gamepad with - id \a deviceId. - Returns \c true in case of success. -*/ -bool QGamepadManager::setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - Q_D(QGamepadManager); - return d->gamepadBackend->setCancelConfigureButton(deviceId, button); -} - -/*! - Resets the configuration on the gamepad with the - specified \a deviceId. -*/ -void QGamepadManager::resetConfiguration(int deviceId) -{ - Q_D(QGamepadManager); - d->gamepadBackend->resetConfiguration(deviceId); -} - -/*! - Sets the name of the \a file that stores the button and axis - configuration data. -*/ -void QGamepadManager::setSettingsFile(const QString &file) -{ - Q_D(QGamepadManager); - d->gamepadBackend->setSettingsFile(file); -} - -QT_END_NAMESPACE - -#include "moc_qgamepadmanager.cpp" diff --git a/src/gamepad/qgamepadmanager.h b/src/gamepad/qgamepadmanager.h deleted file mode 100644 index 56b6e6f..0000000 --- a/src/gamepad/qgamepadmanager.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADMANAGER_H -#define QGAMEPADMANAGER_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGamepadBackend; -class QGamepad; -class QGamepadManagerPrivate; - -class Q_GAMEPAD_EXPORT QGamepadManager : public QObject -{ - Q_OBJECT - Q_FLAGS(GamepadButton GamepadButtons) - Q_FLAGS(GamepadAxis GamepadAxes) - Q_PROPERTY(QList connectedGamepads READ connectedGamepads NOTIFY connectedGamepadsChanged) - -public: - enum GamepadButton { - ButtonInvalid = -1, - ButtonA = 0, - ButtonB, - ButtonX, - ButtonY, - ButtonL1, - ButtonR1, - ButtonL2, - ButtonR2, - ButtonSelect, - ButtonStart, - ButtonL3, - ButtonR3, - ButtonUp, - ButtonDown, - ButtonRight, - ButtonLeft, - ButtonCenter, - ButtonGuide - }; - Q_DECLARE_FLAGS(GamepadButtons, GamepadButton) - - enum GamepadAxis { - AxisInvalid = -1, - AxisLeftX = 0, - AxisLeftY, - AxisRightX, - AxisRightY - }; - Q_DECLARE_FLAGS(GamepadAxes, GamepadAxis) - - static QGamepadManager* instance(); - - bool isGamepadConnected(int deviceId) const; - QString gamepadName(int deviceId) const; - const QList connectedGamepads() const; - -public Q_SLOTS: - bool isConfigurationNeeded(int deviceId) const; - bool configureButton(int deviceId, GamepadButton button); - bool configureAxis(int deviceId, GamepadAxis axis); - bool setCancelConfigureButton(int deviceId, GamepadButton button); - void resetConfiguration(int deviceId); - void setSettingsFile(const QString &file); - -Q_SIGNALS: - void connectedGamepadsChanged(); - void gamepadConnected(int deviceId); - void gamepadNameChanged(int deviceId, const QString &name); - void gamepadDisconnected(int deviceId); - void gamepadAxisEvent(int deviceId, QGamepadManager::GamepadAxis axis, double value); - void gamepadButtonPressEvent(int deviceId, QGamepadManager::GamepadButton button, double value); - void gamepadButtonReleaseEvent(int deviceId, QGamepadManager::GamepadButton button); - void buttonConfigured(int deviceId, QGamepadManager::GamepadButton button); - void axisConfigured(int deviceId, QGamepadManager::GamepadAxis axis); - void configurationCanceled(int deviceId); - -private: - QGamepadManager(); - ~QGamepadManager(); - - Q_DECLARE_PRIVATE(QGamepadManager) - Q_DISABLE_COPY(QGamepadManager) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadConnected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadNameChanged(int, const QString&)) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadDisconnected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadAxisEvent(int, QGamepadManager::GamepadAxis, double)) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadButtonPressEvent(int, QGamepadManager::GamepadButton, double)) - Q_PRIVATE_SLOT(d_func(), void _q_forwardGamepadButtonReleaseEvent(int, QGamepadManager::GamepadButton)) -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QGamepadManager::GamepadButton) -Q_DECLARE_METATYPE(QGamepadManager::GamepadAxis) - -#endif // QGAMEPADMANAGER_H diff --git a/src/gamepad/qtgamepadglobal.h b/src/gamepad/qtgamepadglobal.h deleted file mode 100644 index 22d1f03..0000000 --- a/src/gamepad/qtgamepadglobal.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTGAMEPADGLOBAL_H -#define QTGAMEPADGLOBAL_H - -#include - -QT_BEGIN_NAMESPACE - -#ifndef Q_GAMEPAD_EXPORT -# ifndef QT_STATIC -# if defined(QT_BUILD_GAMEPAD_LIB) -# define Q_GAMEPAD_EXPORT Q_DECL_EXPORT -# else -# define Q_GAMEPAD_EXPORT Q_DECL_IMPORT -# endif -# else -# define Q_GAMEPAD_EXPORT -# endif -#endif - -QT_END_NAMESPACE - -#endif diff --git a/src/imports/gamepad/gamepad.pro b/src/imports/gamepad/gamepad.pro deleted file mode 100644 index e518f10..0000000 --- a/src/imports/gamepad/gamepad.pro +++ /dev/null @@ -1,17 +0,0 @@ -CXX_MODULE = gamepad -TARGET = declarative_gamepad -TARGETPATH = QtGamepad -IMPORT_VERSION = 1.$$QT_MINOR_VERSION - -QT += qml quick gamepad - -load(qml_plugin) - -OTHER_FILES += qmldir - -SOURCES += \ - qtgamepad.cpp \ - qgamepadmouseitem.cpp - -HEADERS += \ - qgamepadmouseitem.h diff --git a/src/imports/gamepad/plugins.qmltypes b/src/imports/gamepad/plugins.qmltypes deleted file mode 100644 index ef1fa4b..0000000 --- a/src/imports/gamepad/plugins.qmltypes +++ /dev/null @@ -1,539 +0,0 @@ -import QtQuick.tooling 1.2 - -// This file describes the plugin-supplied types contained in the library. -// It is used for QML tooling purposes only. -// -// This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtGamepad 1.15' - -Module { - dependencies: ["QtQuick 2.0"] - Component { - name: "QGamepad" - prototype: "QObject" - exports: ["QtGamepad/Gamepad 1.0"] - exportMetaObjectRevisions: [0] - Property { name: "deviceId"; type: "int" } - Property { name: "connected"; type: "bool"; isReadonly: true } - Property { name: "name"; type: "string"; isReadonly: true } - Property { name: "axisLeftX"; type: "double"; isReadonly: true } - Property { name: "axisLeftY"; type: "double"; isReadonly: true } - Property { name: "axisRightX"; type: "double"; isReadonly: true } - Property { name: "axisRightY"; type: "double"; isReadonly: true } - Property { name: "buttonA"; type: "bool"; isReadonly: true } - Property { name: "buttonB"; type: "bool"; isReadonly: true } - Property { name: "buttonX"; type: "bool"; isReadonly: true } - Property { name: "buttonY"; type: "bool"; isReadonly: true } - Property { name: "buttonL1"; type: "bool"; isReadonly: true } - Property { name: "buttonR1"; type: "bool"; isReadonly: true } - Property { name: "buttonL2"; type: "double"; isReadonly: true } - Property { name: "buttonR2"; type: "double"; isReadonly: true } - Property { name: "buttonSelect"; type: "bool"; isReadonly: true } - Property { name: "buttonStart"; type: "bool"; isReadonly: true } - Property { name: "buttonL3"; type: "bool"; isReadonly: true } - Property { name: "buttonR3"; type: "bool"; isReadonly: true } - Property { name: "buttonUp"; type: "bool"; isReadonly: true } - Property { name: "buttonDown"; type: "bool"; isReadonly: true } - Property { name: "buttonLeft"; type: "bool"; isReadonly: true } - Property { name: "buttonRight"; type: "bool"; isReadonly: true } - Property { name: "buttonCenter"; type: "bool"; isReadonly: true } - Property { name: "buttonGuide"; type: "bool"; isReadonly: true } - Signal { - name: "deviceIdChanged" - Parameter { name: "value"; type: "int" } - } - Signal { - name: "connectedChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "nameChanged" - Parameter { name: "value"; type: "string" } - } - Signal { - name: "axisLeftXChanged" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "axisLeftYChanged" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "axisRightXChanged" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "axisRightYChanged" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "buttonAChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonBChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonXChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonYChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonL1Changed" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonR1Changed" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonL2Changed" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "buttonR2Changed" - Parameter { name: "value"; type: "double" } - } - Signal { - name: "buttonSelectChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonStartChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonL3Changed" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonR3Changed" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonUpChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonDownChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonLeftChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonRightChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonCenterChanged" - Parameter { name: "value"; type: "bool" } - } - Signal { - name: "buttonGuideChanged" - Parameter { name: "value"; type: "bool" } - } - Method { - name: "setDeviceId" - Parameter { name: "number"; type: "int" } - } - } - Component { - name: "QGamepadKeyNavigation" - prototype: "QObject" - exports: ["QtGamepad/GamepadKeyNavigation 1.0"] - exportMetaObjectRevisions: [0] - Property { name: "active"; type: "bool" } - Property { name: "gamepad"; type: "QGamepad"; isPointer: true } - Property { name: "upKey"; type: "Qt::Key" } - Property { name: "downKey"; type: "Qt::Key" } - Property { name: "leftKey"; type: "Qt::Key" } - Property { name: "rightKey"; type: "Qt::Key" } - Property { name: "buttonAKey"; type: "Qt::Key" } - Property { name: "buttonBKey"; type: "Qt::Key" } - Property { name: "buttonXKey"; type: "Qt::Key" } - Property { name: "buttonYKey"; type: "Qt::Key" } - Property { name: "buttonSelectKey"; type: "Qt::Key" } - Property { name: "buttonStartKey"; type: "Qt::Key" } - Property { name: "buttonGuideKey"; type: "Qt::Key" } - Property { name: "buttonL1Key"; type: "Qt::Key" } - Property { name: "buttonR1Key"; type: "Qt::Key" } - Property { name: "buttonL2Key"; type: "Qt::Key" } - Property { name: "buttonR2Key"; type: "Qt::Key" } - Property { name: "buttonL3Key"; type: "Qt::Key" } - Property { name: "buttonR3Key"; type: "Qt::Key" } - Signal { - name: "activeChanged" - Parameter { name: "isActive"; type: "bool" } - } - Signal { - name: "gamepadChanged" - Parameter { name: "gamepad"; type: "QGamepad"; isPointer: true } - } - Signal { - name: "upKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "downKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "leftKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "rightKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonAKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonBKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonXKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonYKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonSelectKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonStartKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonGuideKeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonL1KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonR1KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonL2KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonR2KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonL3KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Signal { - name: "buttonR3KeyChanged" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setActive" - Parameter { name: "isActive"; type: "bool" } - } - Method { - name: "setGamepad" - Parameter { name: "gamepad"; type: "QGamepad"; isPointer: true } - } - Method { - name: "setUpKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setDownKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setLeftKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setRightKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonAKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonBKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonXKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonYKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonSelectKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonStartKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonGuideKey" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonL1Key" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonR1Key" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonL2Key" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonR2Key" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonL3Key" - Parameter { name: "key"; type: "Qt::Key" } - } - Method { - name: "setButtonR3Key" - Parameter { name: "key"; type: "Qt::Key" } - } - } - Component { - name: "QGamepadManager" - prototype: "QObject" - exports: ["QtGamepad/GamepadManager 1.0"] - isCreatable: false - isSingleton: true - exportMetaObjectRevisions: [0] - Enum { - name: "GamepadButton" - values: { - "ButtonInvalid": -1, - "ButtonA": 0, - "ButtonB": 1, - "ButtonX": 2, - "ButtonY": 3, - "ButtonL1": 4, - "ButtonR1": 5, - "ButtonL2": 6, - "ButtonR2": 7, - "ButtonSelect": 8, - "ButtonStart": 9, - "ButtonL3": 10, - "ButtonR3": 11, - "ButtonUp": 12, - "ButtonDown": 13, - "ButtonRight": 14, - "ButtonLeft": 15, - "ButtonCenter": 16, - "ButtonGuide": 17 - } - } - Enum { - name: "GamepadButtons" - values: { - "ButtonInvalid": -1, - "ButtonA": 0, - "ButtonB": 1, - "ButtonX": 2, - "ButtonY": 3, - "ButtonL1": 4, - "ButtonR1": 5, - "ButtonL2": 6, - "ButtonR2": 7, - "ButtonSelect": 8, - "ButtonStart": 9, - "ButtonL3": 10, - "ButtonR3": 11, - "ButtonUp": 12, - "ButtonDown": 13, - "ButtonRight": 14, - "ButtonLeft": 15, - "ButtonCenter": 16, - "ButtonGuide": 17 - } - } - Enum { - name: "GamepadAxis" - values: { - "AxisInvalid": -1, - "AxisLeftX": 0, - "AxisLeftY": 1, - "AxisRightX": 2, - "AxisRightY": 3 - } - } - Enum { - name: "GamepadAxes" - values: { - "AxisInvalid": -1, - "AxisLeftX": 0, - "AxisLeftY": 1, - "AxisRightX": 2, - "AxisRightY": 3 - } - } - Property { name: "connectedGamepads"; type: "QList"; isReadonly: true } - Signal { - name: "gamepadConnected" - Parameter { name: "deviceId"; type: "int" } - } - Signal { - name: "gamepadNameChanged" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "name"; type: "string" } - } - Signal { - name: "gamepadDisconnected" - Parameter { name: "deviceId"; type: "int" } - } - Signal { - name: "gamepadAxisEvent" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "axis"; type: "QGamepadManager::GamepadAxis" } - Parameter { name: "value"; type: "double" } - } - Signal { - name: "gamepadButtonPressEvent" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "button"; type: "QGamepadManager::GamepadButton" } - Parameter { name: "value"; type: "double" } - } - Signal { - name: "gamepadButtonReleaseEvent" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "button"; type: "QGamepadManager::GamepadButton" } - } - Signal { - name: "buttonConfigured" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "button"; type: "QGamepadManager::GamepadButton" } - } - Signal { - name: "axisConfigured" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "axis"; type: "QGamepadManager::GamepadAxis" } - } - Signal { - name: "configurationCanceled" - Parameter { name: "deviceId"; type: "int" } - } - Method { - name: "isConfigurationNeeded" - type: "bool" - Parameter { name: "deviceId"; type: "int" } - } - Method { - name: "configureButton" - type: "bool" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "button"; type: "GamepadButton" } - } - Method { - name: "configureAxis" - type: "bool" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "axis"; type: "GamepadAxis" } - } - Method { - name: "setCancelConfigureButton" - type: "bool" - Parameter { name: "deviceId"; type: "int" } - Parameter { name: "button"; type: "GamepadButton" } - } - Method { - name: "resetConfiguration" - Parameter { name: "deviceId"; type: "int" } - } - Method { - name: "setSettingsFile" - Parameter { name: "file"; type: "string" } - } - } - Component { - name: "QGamepadMouseItem" - defaultProperty: "data" - prototype: "QQuickItem" - exports: ["QtGamepad/GamepadMouseItem 1.0"] - exportMetaObjectRevisions: [0] - Enum { - name: "GamepadJoystick" - values: { - "LeftStick": 0, - "RightStick": 1, - "Both": 2 - } - } - Property { name: "active"; type: "bool" } - Property { name: "gamepad"; type: "QGamepad"; isPointer: true } - Property { name: "joystick"; type: "GamepadJoystick" } - Property { name: "deadZoneSize"; type: "double" } - Property { name: "mousePosition"; type: "QPointF"; isReadonly: true } - Signal { - name: "activeChanged" - Parameter { name: "isActive"; type: "bool" } - } - Signal { - name: "gamepadChanged" - Parameter { name: "gamepad"; type: "QGamepad"; isPointer: true } - } - Signal { - name: "joystickChanged" - Parameter { name: "joystick"; type: "GamepadJoystick" } - } - Signal { - name: "deadZoneSizeChanged" - Parameter { name: "size"; type: "double" } - } - Signal { - name: "mousePositionChanged" - Parameter { name: "position"; type: "QPointF" } - } - Method { - name: "setActive" - Parameter { name: "arg"; type: "bool" } - } - Method { - name: "setGamepad" - Parameter { name: "gamepad"; type: "QGamepad"; isPointer: true } - } - Method { - name: "setJoystick" - Parameter { name: "joystick"; type: "GamepadJoystick" } - } - Method { - name: "setDeadZoneSize" - Parameter { name: "size"; type: "double" } - } - Method { - name: "mouseButtonPressed" - Parameter { name: "button"; type: "int" } - } - Method { - name: "mouseButtonReleased" - Parameter { name: "button"; type: "int" } - } - } -} diff --git a/src/imports/gamepad/qgamepadmouseitem.cpp b/src/imports/gamepad/qgamepadmouseitem.cpp deleted file mode 100644 index 8baa159..0000000 --- a/src/imports/gamepad/qgamepadmouseitem.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgamepadmouseitem.h" -#include - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -QGamepadMouseItem::QGamepadMouseItem(QQuickItem *parent) - : QQuickItem(parent) - , m_active(false) - , m_gamepad(nullptr) - , m_joystick(QGamepadMouseItem::LeftStick) - , m_deadZoneSize(0.1) -{ - m_updateTimer.setInterval(16); - connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateMousePostion())); -} - -bool QGamepadMouseItem::active() const -{ - return m_active; -} - -QGamepad *QGamepadMouseItem::gamepad() const -{ - return m_gamepad; -} - -QGamepadMouseItem::GamepadJoystick QGamepadMouseItem::joystick() const -{ - return m_joystick; -} - -double QGamepadMouseItem::deadZoneSize() const -{ - return m_deadZoneSize; -} - -QPointF QGamepadMouseItem::mousePosition() const -{ - return m_mousePosition; -} - -void QGamepadMouseItem::setActive(bool arg) -{ - if (m_active != arg) { - m_active = arg; - if (m_active) { - m_deltaTimer.start(); - m_updateTimer.start(); - } else { - m_updateTimer.stop(); - m_deltaTimer.invalidate(); - } - emit activeChanged(arg); - } -} - -void QGamepadMouseItem::setGamepad(QGamepad *gamepad) -{ - if (m_gamepad != gamepad) { - m_gamepad = gamepad; - emit gamepadChanged(gamepad); - } -} - -void QGamepadMouseItem::setJoystick(QGamepadMouseItem::GamepadJoystick joystick) -{ - if (m_joystick != joystick) { - m_joystick = joystick; - emit joystickChanged(joystick); - } -} - -void QGamepadMouseItem::setDeadZoneSize(double size) -{ - if (m_deadZoneSize != size) { - m_deadZoneSize = size; - emit deadZoneSizeChanged(size); - } -} - -void QGamepadMouseItem::mouseButtonPressed(int button) -{ - processMouseButtonEvent(true, (Qt::MouseButton)button); -} - -void QGamepadMouseItem::mouseButtonReleased(int button) -{ - processMouseButtonEvent(false, (Qt::MouseButton)button); -} - -void QGamepadMouseItem::updateMousePostion() -{ - // Get the delta from the last call - qint64 delta = m_deltaTimer.restart(); - - // Don't bother when there is not gamepad to read from - if (!m_gamepad || !m_gamepad->isConnected()) - return; - - double xVelocity = 0.0; - double yVelocity = 0.0; - - if (m_joystick == QGamepadMouseItem::LeftStick) { - xVelocity = m_gamepad->axisLeftX(); - yVelocity = m_gamepad->axisLeftY(); - } else if (m_joystick == QGamepadMouseItem::RightStick) { - xVelocity = m_gamepad->axisRightX(); - yVelocity = m_gamepad->axisRightY(); - } else { // The greatest of both - if (std::abs(m_gamepad->axisLeftX()) > std::abs(m_gamepad->axisRightX())) - xVelocity = m_gamepad->axisLeftX(); - else - xVelocity = m_gamepad->axisRightX(); - if (std::abs(m_gamepad->axisLeftY()) > std::abs(m_gamepad->axisRightY())) - yVelocity = m_gamepad->axisLeftY(); - else - yVelocity = m_gamepad->axisRightY(); - } - - // Check for deadzone limits] - if (std::abs(xVelocity) < m_deadZoneSize) - xVelocity = 0.0; - if (std::abs(yVelocity) < m_deadZoneSize) - yVelocity = 0.0; - if (xVelocity == 0.0 && yVelocity == 0.0) - return; - - double newXPosition = m_mousePosition.x() + xVelocity * delta; - double newYPosition = m_mousePosition.y() + yVelocity * delta; - // Check bounds - if (newXPosition < 0) - newXPosition = 0; - else if (newXPosition > width()) - newXPosition = width(); - - if (newYPosition < 0) - newYPosition = 0; - else if (newYPosition > height()) - newYPosition = height(); - - m_mousePosition = QPointF(newXPosition, newYPosition); - emit mousePositionChanged(m_mousePosition); -} - -void QGamepadMouseItem::processMouseMoveEvent(QPointF position) -{ - QMouseEvent *mouseEvent = new QMouseEvent(QEvent::MouseMove, mapToScene(position), Qt::NoButton, m_mouseButtons, Qt::NoModifier); - sendGeneratedMouseEvent(mouseEvent); -} - -void QGamepadMouseItem::processMouseButtonEvent(bool isPressed, Qt::MouseButton button) -{ - QMouseEvent *event; - if (isPressed) { - m_mouseButtons |= button; - event = new QMouseEvent(QEvent::MouseButtonPress, mapToScene(m_mousePosition), button, m_mouseButtons, Qt::NoModifier); - } else { - m_mouseButtons ^= button; - event = new QMouseEvent(QEvent::MouseButtonRelease, mapToScene(m_mousePosition), button, m_mouseButtons, Qt::NoModifier); - } - - sendGeneratedMouseEvent(event); -} - -void QGamepadMouseItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - QQuickItem::geometryChanged(newGeometry, oldGeometry); - - m_mousePosition = newGeometry.center(); -} - -void QGamepadMouseItem::sendGeneratedMouseEvent(QMouseEvent *event) -{ - if (!m_active || !this->window()) { - delete event; - return; - } - - QWindow *window = qobject_cast(this->window()); - if (window) - QGuiApplication::sendEvent(window, event); -} - -QT_END_NAMESPACE diff --git a/src/imports/gamepad/qgamepadmouseitem.h b/src/imports/gamepad/qgamepadmouseitem.h deleted file mode 100644 index d1c507e..0000000 --- a/src/imports/gamepad/qgamepadmouseitem.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGAMEPADMOUSEITEM_H -#define QGAMEPADMOUSEITEM_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QGamepadManager; -class QGamepadMouseItem : public QQuickItem -{ - Q_OBJECT - Q_ENUMS(GamepadJoystick) - Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) - Q_PROPERTY(QGamepad* gamepad READ gamepad WRITE setGamepad NOTIFY gamepadChanged) - Q_PROPERTY(GamepadJoystick joystick READ joystick WRITE setJoystick NOTIFY joystickChanged) - Q_PROPERTY(double deadZoneSize READ deadZoneSize WRITE setDeadZoneSize NOTIFY deadZoneSizeChanged) - Q_PROPERTY(QPointF mousePosition READ mousePosition NOTIFY mousePositionChanged) - -public: - enum GamepadJoystick { - LeftStick, - RightStick, - Both - }; - - explicit QGamepadMouseItem(QQuickItem *parent = nullptr); - - bool active() const; - QGamepad* gamepad() const; - GamepadJoystick joystick() const; - double deadZoneSize() const; - QPointF mousePosition() const; - -signals: - - void activeChanged(bool isActive); - void gamepadChanged(QGamepad* gamepad); - void joystickChanged(GamepadJoystick joystick); - void deadZoneSizeChanged(double size); - void mousePositionChanged(QPointF position); - -public slots: - - void setActive(bool arg); - void setGamepad(QGamepad* gamepad); - void setJoystick(GamepadJoystick joystick); - void setDeadZoneSize(double size); - - void mouseButtonPressed(int button); - void mouseButtonReleased(int button); - -private slots: - void updateMousePostion(); - void processMouseMoveEvent(QPointF position); - void processMouseButtonEvent(bool isPressed, Qt::MouseButton button = Qt::LeftButton); - -protected: - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; - -private: - void sendGeneratedMouseEvent(QMouseEvent *event); - - QPointF m_mousePosition; - QTimer m_updateTimer; - QElapsedTimer m_deltaTimer; - Qt::MouseButtons m_mouseButtons; - - bool m_active; - QGamepad* m_gamepad; - GamepadJoystick m_joystick; - double m_deadZoneSize; - - -}; - -QT_END_NAMESPACE - -#endif // QGAMEPADMOUSEITEM_H diff --git a/src/imports/gamepad/qmldir b/src/imports/gamepad/qmldir deleted file mode 100644 index fa9e6e4..0000000 --- a/src/imports/gamepad/qmldir +++ /dev/null @@ -1,4 +0,0 @@ -module QtGamepad -plugin declarative_gamepad -typeinfo plugins.qmltypes -classname QGamepadModule diff --git a/src/imports/gamepad/qtgamepad.cpp b/src/imports/gamepad/qtgamepad.cpp deleted file mode 100644 index 347e38a..0000000 --- a/src/imports/gamepad/qtgamepad.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -#include -#include - -#include "qgamepadmouseitem.h" - -QT_BEGIN_NAMESPACE - -static QObject *gamepadmanager_singletontype_provider(QQmlEngine * /* engine */, QJSEngine * /* scriptEngine */) -{ - QGamepadManager *manager = QGamepadManager::instance(); - QQmlEngine::setObjectOwnership(manager, QQmlEngine::CppOwnership); - return manager; -} - -class QGamepadModule : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) -public: - QGamepadModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { } - void registerTypes(const char *uri) override - { - Q_ASSERT(QLatin1String(uri) == QLatin1String("QtGamepad")); - - // @uri QtGamepad - - qmlRegisterSingletonType(uri, 1, 0, "GamepadManager", &gamepadmanager_singletontype_provider); - qmlRegisterType(uri, 1, 0, "Gamepad"); - qmlRegisterType(uri, 1, 0, "GamepadKeyNavigation"); - qmlRegisterType(uri, 1, 0, "GamepadMouseItem"); - - // Register the latest Qt version as QML type version - qmlRegisterModule(uri, 1, QT_VERSION_MINOR); - } - - void initializeEngine(QQmlEngine *engine, const char *uri) override - { - Q_UNUSED(uri); - Q_UNUSED(engine); - } -}; - -QT_END_NAMESPACE - -#include "qtgamepad.moc" diff --git a/src/imports/imports.pro b/src/imports/imports.pro deleted file mode 100644 index 72acdb0..0000000 --- a/src/imports/imports.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += gamepad diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt new file mode 100644 index 0000000..d4856bd --- /dev/null +++ b/src/plugins/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +add_subdirectory(joystickinputs) +add_subdirectory(mouseinputs) diff --git a/src/plugins/gamepads/android/android.pro b/src/plugins/gamepads/android/android.pro deleted file mode 100644 index 6ad7e3b..0000000 --- a/src/plugins/gamepads/android/android.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS += jar src diff --git a/src/plugins/gamepads/android/jar/jar.pro b/src/plugins/gamepads/android/jar/jar.pro deleted file mode 100644 index 879bbd9..0000000 --- a/src/plugins/gamepads/android/jar/jar.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = Qt$${QT_MAJOR_VERSION}AndroidGamepad - -load(qt_build_paths) -CONFIG += java - -DESTDIR = $$MODULE_BASE_OUTDIR/jar - -API_VERSION = android-16 - -JAVACLASSPATH += $$PWD/src - -JAVASOURCES += $$PWD/src/org/qtproject/qt/android/gamepad/QtGamepad.java - -# install -target.path = $$[QT_INSTALL_PREFIX]/jar -INSTALLS += target - -OTHER_FILES += $$JAVASOURCES diff --git a/src/plugins/gamepads/android/jar/src/org/qtproject/qt/android/gamepad/QtGamepad.java b/src/plugins/gamepads/android/jar/src/org/qtproject/qt/android/gamepad/QtGamepad.java deleted file mode 100644 index 94ffa9f..0000000 --- a/src/plugins/gamepads/android/jar/src/org/qtproject/qt/android/gamepad/QtGamepad.java +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -package org.qtproject.qt.android.gamepad; - -import android.app.Activity; -import android.content.Context; -import android.hardware.input.InputManager; -import android.os.Handler; - - -public class QtGamepad { - private long m_nativePtr = 0; - private InputManager m_manager; - Activity m_activity; - private InputManager.InputDeviceListener m_listener = new InputManager.InputDeviceListener() { - @Override - public void onInputDeviceAdded(int i) { - synchronized (QtGamepad.this) { - QtGamepad.onInputDeviceAdded(m_nativePtr, i); - } - } - - @Override - public void onInputDeviceRemoved(int i) { - synchronized (QtGamepad.this) { - QtGamepad.onInputDeviceRemoved(m_nativePtr, i); - } - } - - @Override - public void onInputDeviceChanged(int i) { - synchronized (QtGamepad.this) { - QtGamepad.onInputDeviceChanged(m_nativePtr, i); - } - } - }; - - QtGamepad(Activity activity) - { - m_manager = (InputManager) activity.getSystemService(Context.INPUT_SERVICE); - m_activity = activity; - } - - public void register(long nativePtr) - { - synchronized (this) { - if (m_manager != null) { - m_nativePtr = nativePtr; - m_activity.runOnUiThread(new Runnable() { - @Override - public void run() { - try { - m_manager.registerInputDeviceListener(m_listener, new Handler()); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - } - } - - public void unregister() - { - synchronized (this) { - if (m_manager != null) { - m_nativePtr = 0; - m_manager.unregisterInputDeviceListener(m_listener); - } - } - } - - private static native void onInputDeviceAdded(long nativePtr, int deviceId); - private static native void onInputDeviceRemoved(long nativePtr, int deviceId); - private static native void onInputDeviceChanged(long nativePtr, int deviceId); -} diff --git a/src/plugins/gamepads/android/src/main.cpp b/src/plugins/gamepads/android/src/main.cpp deleted file mode 100644 index 97af630..0000000 --- a/src/plugins/gamepads/android/src/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qandroidgamepadbackend_p.h" - -QT_BEGIN_NAMESPACE - -class QAndroidGamepadBackendPlugin : public QGamepadBackendPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QtGamepadBackendFactoryInterface_iid FILE "android.json") -public: - QGamepadBackend *create(const QString &key, const QStringList ¶mList) override; -}; - -QGamepadBackend *QAndroidGamepadBackendPlugin::create(const QString &key, const QStringList ¶mList) { - Q_UNUSED(key); - Q_UNUSED(paramList); - - return new QAndroidGamepadBackend(); -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/gamepads/android/src/qandroidgamepadbackend.cpp b/src/plugins/gamepads/android/src/qandroidgamepadbackend.cpp deleted file mode 100644 index eae0e6a..0000000 --- a/src/plugins/gamepads/android/src/qandroidgamepadbackend.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qandroidgamepadbackend_p.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE -namespace { - const QLatin1String AXES_KEY("axes"); - const QLatin1String BUTTONS_KEY("buttons"); - - class FunctionEvent : public QEvent - { - typedef std::function Function; - public: - explicit FunctionEvent(const Function &func) - : QEvent(QEvent::User) - , m_function(func) - {} - inline void call() { m_function(); } - static inline void runOnQtThread(QObject *receiver, const Function &func) { - if (qApp->thread() == QThread::currentThread()) - func(); - else - qApp->postEvent(receiver, new FunctionEvent(func)); - } - - private: - Function m_function; - }; - - const char keyEventClass[] = "android/view/KeyEvent"; - inline int keyField(const char *field) - { - return QJNIObjectPrivate::getStaticField(keyEventClass, field); - } - - const char motionEventClass[] = "android/view/MotionEvent"; - inline int motionField(const char *field) - { - return QJNIObjectPrivate::getStaticField(motionEventClass, field); - } - - const char inputDeviceClass[] = "android/view/InputDevice"; - inline int inputDeviceField(const char *field) - { - return QJNIObjectPrivate::getStaticField(inputDeviceClass, field); - } - - - struct DefaultMapping : public QAndroidGamepadBackend::Mapping { - DefaultMapping() - { - buttonsMap[keyField("KEYCODE_BUTTON_A")] = QGamepadManager::ButtonA; - buttonsMap[keyField("KEYCODE_BUTTON_B")] = QGamepadManager::ButtonB; - buttonsMap[keyField("KEYCODE_BUTTON_X")] = QGamepadManager::ButtonX; - buttonsMap[keyField("KEYCODE_BUTTON_Y")] = QGamepadManager::ButtonY; - buttonsMap[keyField("KEYCODE_BUTTON_L1")] = QGamepadManager::ButtonL1; - buttonsMap[keyField("KEYCODE_BUTTON_R1")] = QGamepadManager::ButtonR1; - buttonsMap[keyField("KEYCODE_BUTTON_L2")] = QGamepadManager::ButtonL2; - buttonsMap[keyField("KEYCODE_BUTTON_R2")] = QGamepadManager::ButtonR2; - buttonsMap[keyField("KEYCODE_BUTTON_SELECT")] = QGamepadManager::ButtonSelect; - buttonsMap[keyField("KEYCODE_BUTTON_START")] = QGamepadManager::ButtonStart; - buttonsMap[keyField("KEYCODE_BUTTON_THUMBL")] = QGamepadManager::ButtonL3; - buttonsMap[keyField("KEYCODE_BUTTON_THUMBR")] = QGamepadManager::ButtonR3; - buttonsMap[keyField("KEYCODE_DPAD_UP")] = QGamepadManager::ButtonUp; - buttonsMap[keyField("KEYCODE_DPAD_DOWN")] = QGamepadManager::ButtonDown; - buttonsMap[keyField("KEYCODE_DPAD_RIGHT")] = QGamepadManager::ButtonRight; - buttonsMap[keyField("KEYCODE_DPAD_LEFT")] = QGamepadManager::ButtonLeft; - buttonsMap[keyField("KEYCODE_DPAD_CENTER")] = QGamepadManager::ButtonCenter; - buttonsMap[keyField("KEYCODE_BUTTON_MODE")] = QGamepadManager::ButtonGuide; - - if (QtAndroidPrivate::androidSdkVersion() >= 12) { - axisMap[motionField("AXIS_X")].gamepadAxis = QGamepadManager::AxisLeftX; - axisMap[motionField("AXIS_Y")].gamepadAxis = QGamepadManager::AxisLeftY; - axisMap[motionField("AXIS_HAT_X")].gamepadAxis = QGamepadManager::AxisLeftX; - axisMap[motionField("AXIS_HAT_Y")].gamepadAxis = QGamepadManager::AxisLeftY; - axisMap[motionField("AXIS_Z")].gamepadAxis = QGamepadManager::AxisRightX; - axisMap[motionField("AXIS_RZ")].gamepadAxis = QGamepadManager::AxisRightY; - { - auto &axis = axisMap[motionField("AXIS_LTRIGGER")]; - axis.gamepadAxis = QGamepadManager::AxisInvalid; - axis.gamepadMinButton = QGamepadManager::ButtonL2; - axis.gamepadMaxButton = QGamepadManager::ButtonL2; - } - { - auto &axis = axisMap[motionField("AXIS_RTRIGGER")]; - axis.gamepadAxis = QGamepadManager::AxisInvalid; - axis.gamepadMinButton = QGamepadManager::ButtonR2; - axis.gamepadMaxButton = QGamepadManager::ButtonR2; - } - - allAndroidAxes.push_back(motionField("AXIS_X")); - allAndroidAxes.push_back(motionField("AXIS_Y")); - allAndroidAxes.push_back(motionField("AXIS_Z")); - allAndroidAxes.push_back(motionField("AXIS_RZ")); - allAndroidAxes.push_back(motionField("AXIS_BRAKE")); - allAndroidAxes.push_back(motionField("AXIS_GAS")); - - for (int i = 1; i < 16; ++i) - allAndroidAxes.push_back(motionField(QByteArray("AXIS_GENERIC_").append(QByteArray::number(i)).constData())); - - allAndroidAxes.push_back(motionField("AXIS_HAT_X")); - allAndroidAxes.push_back(motionField("AXIS_HAT_Y")); - allAndroidAxes.push_back(motionField("AXIS_LTRIGGER")); - allAndroidAxes.push_back(motionField("AXIS_RTRIGGER")); - allAndroidAxes.push_back(motionField("AXIS_RUDDER")); - allAndroidAxes.push_back(motionField("AXIS_THROTTLE")); - allAndroidAxes.push_back(motionField("AXIS_WHEEL")); - } - - if (QtAndroidPrivate::androidSdkVersion() >= 12) { - acceptedSources.push_back(inputDeviceField("SOURCE_GAMEPAD")); - acceptedSources.push_back(inputDeviceField("SOURCE_CLASS_JOYSTICK")); - if (QtAndroidPrivate::androidSdkVersion() >= 21) { - acceptedSources.push_back(inputDeviceField("SOURCE_HDMI")); - } - } else { - acceptedSources.push_back(inputDeviceField("SOURCE_DPAD")); - } - - ACTION_DOWN = keyField("ACTION_DOWN"); - ACTION_UP = keyField("ACTION_UP"); - ACTION_MULTIPLE = keyField("ACTION_MULTIPLE"); - FLAG_LONG_PRESS = keyField("FLAG_LONG_PRESS"); - } - std::vector acceptedSources; - std::vector allAndroidAxes; - int ACTION_DOWN, ACTION_MULTIPLE, ACTION_UP, FLAG_LONG_PRESS; - }; - - void onInputDeviceAdded(JNIEnv *, jclass, jlong qtNativePtr, int deviceId) - { - if (!qtNativePtr) - return; - reinterpret_cast(qtNativePtr)->addDevice(deviceId); - } - void onInputDeviceRemoved(JNIEnv *, jclass, jlong qtNativePtr, int deviceId) - { - if (!qtNativePtr) - return; - reinterpret_cast(qtNativePtr)->removeDevice(deviceId); - } - void onInputDeviceChanged(JNIEnv *, jclass, jlong qtNativePtr, int deviceId) - { - if (!qtNativePtr) - return; - reinterpret_cast(qtNativePtr)->updateDevice(deviceId); - } - - static JNINativeMethod methods[] = { - {"onInputDeviceAdded", "(JI)V", (void *)onInputDeviceAdded}, - {"onInputDeviceRemoved", "(JI)V", (void *)onInputDeviceRemoved}, - {"onInputDeviceChanged", "(JI)V", (void *)onInputDeviceChanged} - }; - - const char qtGamePadClassName[] = "org/qtproject/qt/android/gamepad/QtGamepad"; - - inline void setAxisInfo(QJNIObjectPrivate &event, int axis, QAndroidGamepadBackend::Mapping::AndroidAxisInfo &info) - { - QJNIObjectPrivate device(event.callObjectMethod("getDevice", "()Landroid/view/InputDevice;")); - if (device.isValid()) { - const int source = event.callMethod("getSource", "()I"); - QJNIObjectPrivate motionRange = device.callObjectMethod("getMotionRange","(II)Landroid/view/InputDevice$MotionRange;", axis, source); - if (motionRange.isValid()) { - info.flatArea = motionRange.callMethod("getFlat", "()F"); - info.minValue = motionRange.callMethod("getMin", "()F"); - info.maxValue = motionRange.callMethod("getMax", "()F"); - info.fuzz = motionRange.callMethod("getFuzz", "()F"); - return; - } - } - info.flatArea = 0; - } - -} // namespace - -Q_GLOBAL_STATIC(DefaultMapping, g_defaultMapping) - -void QAndroidGamepadBackend::Mapping::AndroidAxisInfo::restoreSavedData(const QVariantMap &value) -{ - gamepadAxis = QGamepadManager::GamepadAxis(value[QLatin1String("axis")].toInt()); - gamepadMinButton = QGamepadManager::GamepadButton(value[QLatin1String("minButton")].toInt()); - gamepadMaxButton = QGamepadManager::GamepadButton(value[QLatin1String("maxButton")].toInt()); -} - -QVariantMap QAndroidGamepadBackend::Mapping::AndroidAxisInfo::dataToSave() const -{ - QVariantMap data; - data[QLatin1String("axis")] = gamepadAxis; - data[QLatin1String("minButton")] = gamepadMinButton; - data[QLatin1String("maxButton")] = gamepadMaxButton; - return data; -} - -QAndroidGamepadBackend::QAndroidGamepadBackend(QObject *parent) - : QGamepadBackend(parent) -{ - QtAndroidPrivate::registerGenericMotionEventListener(this); - QtAndroidPrivate::registerKeyEventListener(this); -} - -QAndroidGamepadBackend::~QAndroidGamepadBackend() -{ - QtAndroidPrivate::unregisterGenericMotionEventListener(this); - QtAndroidPrivate::unregisterKeyEventListener(this); -} - -void QAndroidGamepadBackend::addDevice(int deviceId) -{ - if (deviceId == -1) - return; - - QMutexLocker lock(&m_mutex); - QJNIObjectPrivate inputDevice = QJNIObjectPrivate::callStaticObjectMethod(inputDeviceClass, "getDevice", "(I)Landroid/view/InputDevice;", deviceId); - int sources = inputDevice.callMethod("getSources", "()I"); - bool acceptable = false; - for (int source : g_defaultMapping()->acceptedSources) { - if ( (source & sources) == source) { - acceptable = true; - break; - } - } - - if (acceptable) { - m_devices.insert(deviceId, *g_defaultMapping()); - int productId = qHash(inputDevice.callObjectMethod("getDescriptor", "()Ljava/lang/String;").toString()); - m_devices[deviceId].productId = productId; - if (productId) { - QVariant settings = readSettings(productId); - if (!settings.isNull()) { - auto &deviceInfo = m_devices[deviceId]; - deviceInfo.needsConfigure = false; - - QVariantMap data = settings.toMap()[AXES_KEY].toMap(); - for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it) - deviceInfo.axisMap[it.key().toInt()].restoreSavedData(it.value().toMap()); - - data = settings.toMap()[BUTTONS_KEY].toMap(); - for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it) - deviceInfo.buttonsMap[it.key().toInt()] = QGamepadManager::GamepadButton(it.value().toInt()); - } - } - FunctionEvent::runOnQtThread(this, [this, deviceId]{ - emit gamepadAdded(deviceId); - }); - } -} - -void QAndroidGamepadBackend::updateDevice(int deviceId) -{ - Q_UNUSED(deviceId); - //QMutexLocker lock(&m_mutex); -} - -void QAndroidGamepadBackend::removeDevice(int deviceId) -{ - QMutexLocker lock(&m_mutex); - if (m_devices.remove(deviceId)) { - FunctionEvent::runOnQtThread(this, [this, deviceId]{ - emit gamepadRemoved(deviceId); - }); - } -} - -bool QAndroidGamepadBackend::event(QEvent *ev) -{ - if (ev->type() == QEvent::User) { - static_cast(ev)->call(); - return true; - } - return QGamepadBackend::event(ev); -} - -bool QAndroidGamepadBackend::isConfigurationNeeded(int deviceId) -{ - QMutexLocker lock(&m_mutex); - auto it = m_devices.find(deviceId); - if (it == m_devices.end()) - return false; - return it->needsConfigure; -} - -bool QAndroidGamepadBackend::configureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - QMutexLocker lock(&m_mutex); - auto it = m_devices.find(deviceId); - if (it == m_devices.end()) - return false; - - it.value().calibrateButton = button; - return true; -} - -bool QAndroidGamepadBackend::configureAxis(int deviceId, QGamepadManager::GamepadAxis axis) -{ - QMutexLocker lock(&m_mutex); - auto it = m_devices.find(deviceId); - if (it == m_devices.end()) - return false; - - it.value().calibrateAxis = axis; - return true; -} - -bool QAndroidGamepadBackend::setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - QMutexLocker lock(&m_mutex); - auto it = m_devices.find(deviceId); - if (it == m_devices.end()) - return false; - - it.value().cancelConfigurationButton = button; - return true; -} - -void QAndroidGamepadBackend::resetConfiguration(int deviceId) -{ - QMutexLocker lock(&m_mutex); - auto it = m_devices.find(deviceId); - if (it == m_devices.end()) - return; - - it.value().axisMap.clear(); - it.value().buttonsMap.clear(); - it.value().calibrateButton = QGamepadManager::ButtonInvalid; - it.value().calibrateAxis = QGamepadManager::AxisInvalid; - it.value().cancelConfigurationButton = QGamepadManager::ButtonInvalid; - it.value().needsConfigure = false; -} - -bool QAndroidGamepadBackend::handleKeyEvent(jobject event) -{ - QJNIObjectPrivate ev(event); - QMutexLocker lock(&m_mutex); - const int deviceId = ev.callMethod("getDeviceId", "()I"); - const auto deviceIt = m_devices.find(deviceId); - if (deviceIt == m_devices.end()) - return false; - - const int action = ev.callMethod("getAction", "()I"); - if (action != g_defaultMapping()->ACTION_DOWN && - action != g_defaultMapping()->ACTION_UP) { - return false; - } - const int flags = ev.callMethod("getFlags", "()I"); - if ((flags & g_defaultMapping()->FLAG_LONG_PRESS) == g_defaultMapping()->FLAG_LONG_PRESS) - return false; - - const int keyCode = ev.callMethod("getKeyCode", "()I"); - auto &deviceMap = deviceIt.value(); - - if (deviceMap.cancelConfigurationButton != QGamepadManager::ButtonInvalid && - (deviceMap.calibrateButton != QGamepadManager::ButtonInvalid || - deviceMap.calibrateAxis != QGamepadManager::AxisInvalid)) { - - const auto buttonsMapIt = deviceMap.buttonsMap.find(keyCode); - if (buttonsMapIt != deviceMap.buttonsMap.end() && - deviceMap.cancelConfigurationButton == buttonsMapIt.value()) { - deviceMap.calibrateButton = QGamepadManager::ButtonInvalid; - deviceMap.calibrateAxis = QGamepadManager::AxisInvalid; - FunctionEvent::runOnQtThread(this, [this, deviceId]{ - emit configurationCanceled(deviceId); - }); - return true; - } - } - - if (deviceMap.calibrateButton != QGamepadManager::ButtonInvalid) { - deviceMap.buttonsMap[keyCode] = deviceMap.calibrateButton; - auto but = deviceMap.calibrateButton; - deviceMap.calibrateButton = QGamepadManager::ButtonInvalid; - saveData(deviceMap); - FunctionEvent::runOnQtThread(this, [this, deviceId, but]{ - emit buttonConfigured(deviceId, but); - }); - } - - const auto buttonsMapIt = deviceMap.buttonsMap.find(keyCode); - if (buttonsMapIt == deviceMap.buttonsMap.end()) - return false; - - const auto button = buttonsMapIt.value(); - if (action == g_defaultMapping()->ACTION_DOWN) { - FunctionEvent::runOnQtThread(this, [this, deviceId, button]{ - emit gamepadButtonPressed(deviceId, button, 1.0); - }); - } else { - FunctionEvent::runOnQtThread(this, [this, deviceId, button]{ - emit gamepadButtonReleased(deviceId, button); - }); - } - return true; -} - -bool QAndroidGamepadBackend::handleGenericMotionEvent(jobject event) -{ - // GenericMotionEvent was introduced in API-12 - Q_ASSERT(QtAndroidPrivate::androidSdkVersion() >= 12); - - QJNIObjectPrivate ev(event); - QMutexLocker lock(&m_mutex); - const int deviceId = ev.callMethod("getDeviceId", "()I"); - const auto deviceIt = m_devices.find(deviceId); - if (deviceIt == m_devices.end()) - return false; - - auto &deviceMap = deviceIt.value(); - if (deviceMap.calibrateAxis != QGamepadManager::AxisInvalid || - deviceMap.calibrateButton != QGamepadManager::ButtonInvalid) { - double lastValue = 0; - int lastAxis = -1; - for (int axis : g_defaultMapping()->allAndroidAxes) { - double value = ev.callMethod("getAxisValue", "(I)F", axis); - if (fabs(value) > fabs(lastValue)) { - lastValue = value; - lastAxis = axis; - } - } - - if (!lastValue || lastAxis == -1) - return false; - - if (deviceMap.calibrateAxis != QGamepadManager::AxisInvalid) { - deviceMap.axisMap[lastAxis].gamepadAxis = deviceMap.calibrateAxis; - auto axis = deviceMap.calibrateAxis; - deviceMap.calibrateAxis = QGamepadManager::AxisInvalid; - saveData(deviceMap); - FunctionEvent::runOnQtThread(this, [this, deviceId, axis]{ - emit axisConfigured(deviceId, axis); - }); - } else if (deviceMap.calibrateButton != QGamepadManager::ButtonInvalid && - deviceMap.calibrateButton != QGamepadManager::ButtonUp && - deviceMap.calibrateButton != QGamepadManager::ButtonDown && - deviceMap.calibrateButton != QGamepadManager::ButtonLeft && - deviceMap.calibrateButton != QGamepadManager::ButtonRight) { - auto &axis = deviceMap.axisMap[lastAxis]; - axis.gamepadAxis = QGamepadManager::AxisInvalid; - setAxisInfo(ev, lastAxis, axis); - bool save = false; - if (lastValue == axis.minValue) { - axis.gamepadMinButton = deviceMap.calibrateButton; - if (axis.gamepadMaxButton == QGamepadManager::ButtonInvalid) - axis.gamepadMaxButton = deviceMap.calibrateButton; - save = true; - } else if (lastValue == axis.maxValue) { - axis.gamepadMaxButton = deviceMap.calibrateButton; - if (axis.gamepadMinButton == QGamepadManager::ButtonInvalid) - axis.gamepadMinButton = deviceMap.calibrateButton; - save = true; - } - - if (save) { - auto but = deviceMap.calibrateButton; - deviceMap.calibrateButton = QGamepadManager::ButtonInvalid; - saveData(deviceMap); - FunctionEvent::runOnQtThread(this, [this, deviceId, but]{ - emit buttonConfigured(deviceId, but); - }); - } - } - } - - typedef QPair GamepadAxisValue; - QList axisValues; - typedef QPair GamepadButtonValue; - QList buttonValues; - auto setValue = [&axisValues, &buttonValues](Mapping::AndroidAxisInfo &axisInfo, double value) { - if (axisInfo.setValue(value)) { - if (axisInfo.gamepadAxis != QGamepadManager::AxisInvalid) { - axisValues.push_back(GamepadAxisValue(axisInfo.gamepadAxis, axisInfo.lastValue)); - } else { - if (axisInfo.lastValue < 0) { - buttonValues.push_back(GamepadButtonValue(axisInfo.gamepadMinButton, axisInfo.lastValue)); - axisInfo.gamepadLastButton = axisInfo.gamepadMinButton; - } else if (axisInfo.lastValue > 0) { - buttonValues.push_back(GamepadButtonValue(axisInfo.gamepadMaxButton, axisInfo.lastValue)); - axisInfo.gamepadLastButton = axisInfo.gamepadMaxButton; - } else { - buttonValues.push_back(GamepadButtonValue(axisInfo.gamepadLastButton, 0.0)); - axisInfo.gamepadLastButton = QGamepadManager::ButtonInvalid; - } - } - } - }; - for (auto it = deviceMap.axisMap.begin(); it != deviceMap.axisMap.end(); ++it) { - auto &axisInfo = it.value(); - if (axisInfo.flatArea == -1) - setAxisInfo(ev, it.key(), axisInfo); - const int historicalValues = ev.callMethod("getHistorySize", "()I"); - for (int i = 0; i < historicalValues; ++i) { - double value = ev.callMethod("getHistoricalAxisValue", "(II)F", it.key(), i); - setValue(axisInfo, value); - } - double value = ev.callMethod("getAxisValue", "(I)F", it.key()); - setValue(axisInfo, value); - } - - if (!axisValues.isEmpty()) { - FunctionEvent::runOnQtThread(this, [this, deviceId, axisValues]{ - for (const auto &axisValue : axisValues) - emit gamepadAxisMoved(deviceId, axisValue.first, axisValue.second); - }); - } - - if (!buttonValues.isEmpty()) { - FunctionEvent::runOnQtThread(this, [this, deviceId, buttonValues]{ - for (const auto &buttonValue : buttonValues) - if (buttonValue.second) - emit gamepadButtonPressed(deviceId, buttonValue.first, fabs(buttonValue.second)); - else - emit gamepadButtonReleased(deviceId, buttonValue.first); - }); - } - - return false; -} - -bool QAndroidGamepadBackend::start() -{ - { - QMutexLocker lock(&m_mutex); - if (QtAndroidPrivate::androidSdkVersion() >= 16) { - if (!m_qtGamepad.isValid()) - m_qtGamepad = QJNIObjectPrivate(qtGamePadClassName, "(Landroid/app/Activity;)V", QtAndroidPrivate::activity()); - m_qtGamepad.callMethod("register", "(J)V", jlong(this)); - } - } - - QJNIObjectPrivate ids = QJNIObjectPrivate::callStaticObjectMethod(inputDeviceClass, "getDeviceIds", "()[I"); - jintArray jarr = jintArray(ids.object()); - QJNIEnvironmentPrivate env; - size_t sz = env->GetArrayLength(jarr); - jint *buff = env->GetIntArrayElements(jarr, nullptr); - for (size_t i = 0; i < sz; ++i) - addDevice(buff[i]); - env->ReleaseIntArrayElements(jarr, buff, 0); - return true; -} - -void QAndroidGamepadBackend::stop() -{ - QMutexLocker lock(&m_mutex); - if (QtAndroidPrivate::androidSdkVersion() >= 16 && m_qtGamepad.isValid()) - m_qtGamepad.callMethod("unregister", "()V"); -} - -void QAndroidGamepadBackend::saveData(const QAndroidGamepadBackend::Mapping &deviceInfo) -{ - if (!deviceInfo.productId) - return ; - - QVariantMap settings, data; - for (auto it = deviceInfo.axisMap.begin(); it != deviceInfo.axisMap.end(); ++it) - data[QString::number(it.key())] = it.value().dataToSave(); - settings[AXES_KEY] = data; - - data.clear(); - for (auto it = deviceInfo.buttonsMap.begin(); it != deviceInfo.buttonsMap.end(); ++it) - data[QString::number(it.key())] = it.value(); - settings[BUTTONS_KEY] = data; - - saveSettings(deviceInfo.productId, settings); -} - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) -{ - static bool initialized = false; - if (initialized) - return JNI_VERSION_1_6; - initialized = true; - - JNIEnv* env; - // get the JNIEnv pointer. - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) - return JNI_ERR; - - // search for Java class which declares the native methods - jclass javaClass = env->FindClass("org/qtproject/qt/android/gamepad/QtGamepad"); - if (!javaClass) - return JNI_ERR; - - // register our native methods - if (env->RegisterNatives(javaClass, methods, - sizeof(methods) / sizeof(methods[0])) < 0) { - return JNI_ERR; - } - return JNI_VERSION_1_6; -} - -QT_END_NAMESPACE diff --git a/src/plugins/gamepads/android/src/qandroidgamepadbackend_p.h b/src/plugins/gamepads/android/src/qandroidgamepadbackend_p.h deleted file mode 100644 index b54f569..0000000 --- a/src/plugins/gamepads/android/src/qandroidgamepadbackend_p.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QANDROIDGAMEPADBACKEND_P_H -#define QANDROIDGAMEPADBACKEND_P_H - -#include -#include -#include - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QAndroidGamepadBackend : public QGamepadBackend, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener -{ - Q_OBJECT -public: - explicit QAndroidGamepadBackend(QObject *parent = nullptr); - ~QAndroidGamepadBackend(); - - void addDevice(int deviceId); - void updateDevice(int deviceId); - void removeDevice(int deviceId); - - // QObject interface - bool event(QEvent *) override; - - // QGamepadBackend interface - bool isConfigurationNeeded(int deviceId) override; - bool configureButton(int deviceId, QGamepadManager::GamepadButton button) override; - bool configureAxis(int deviceId, QGamepadManager::GamepadAxis axis) override; - bool setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button) override; - void resetConfiguration(int deviceId) override; - - - // KeyEventListener interface - bool handleKeyEvent(jobject event) override; - - // GenericMotionEventListener interface - bool handleGenericMotionEvent(jobject event) override; - -protected: - bool start() override; - void stop() override; - -public: - struct Mapping { - struct AndroidAxisInfo : public AxisInfo { - AndroidAxisInfo() : AxisInfo(-1.0, 1.0) { } - AndroidAxisInfo(double minValue, double maxValue) : AxisInfo(minValue, maxValue) { } - - inline bool setValue(double value) - { - if (minValue != -1.0 && maxValue != 1.0) - value = AxisInfo::normalized(value); - - if (qAbs(value) <= flatArea) - value = 0; - - if (qAbs(qAbs(value) - qAbs(lastValue)) <= fuzz) - return false; - - lastValue = value; - return true; - } - void restoreSavedData(const QVariantMap &value); - QVariantMap dataToSave() const; - - double flatArea = -1; - double fuzz = 0; - double lastValue = 0; - QGamepadManager::GamepadButton gamepadMinButton = QGamepadManager::ButtonInvalid; - QGamepadManager::GamepadButton gamepadMaxButton = QGamepadManager::ButtonInvalid; - QGamepadManager::GamepadButton gamepadLastButton = QGamepadManager::ButtonInvalid; - }; - QHash axisMap; - QHash buttonsMap; - - QGamepadManager::GamepadButton calibrateButton = QGamepadManager::ButtonInvalid; - QGamepadManager::GamepadAxis calibrateAxis = QGamepadManager::AxisInvalid; - QGamepadManager::GamepadButton cancelConfigurationButton = QGamepadManager::ButtonInvalid; - int productId = 0; - bool needsConfigure = false; - }; - -private: - void saveData(const Mapping &deviceInfo); - -private: - QMutex m_mutex; - QJNIObjectPrivate m_qtGamepad; - QHash m_devices; -}; - -QT_END_NAMESPACE - -#endif // QANDROIDGAMEPADBACKEND_P_H diff --git a/src/plugins/gamepads/android/src/src.pro b/src/plugins/gamepads/android/src/src.pro deleted file mode 100644 index 31f8a28..0000000 --- a/src/plugins/gamepads/android/src/src.pro +++ /dev/null @@ -1,17 +0,0 @@ -TARGET = androidgamepad -QT += core-private gamepad gamepad-private - -PLUGIN_TYPE = gamepads -PLUGIN_CLASS_NAME = QAndroidGamepadBackendPlugin - -load(qt_plugin) - -HEADERS += \ - qandroidgamepadbackend_p.h - -SOURCES += \ - main.cpp \ - qandroidgamepadbackend.cpp - -DISTFILES += \ - android.json diff --git a/src/plugins/gamepads/darwin/darwin.json b/src/plugins/gamepads/darwin/darwin.json deleted file mode 100644 index f72350b..0000000 --- a/src/plugins/gamepads/darwin/darwin.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "darwin" ] -} diff --git a/src/plugins/gamepads/darwin/darwin.pro b/src/plugins/gamepads/darwin/darwin.pro deleted file mode 100644 index 9a35c75..0000000 --- a/src/plugins/gamepads/darwin/darwin.pro +++ /dev/null @@ -1,19 +0,0 @@ -TARGET = darwingamepad -QT += gamepad gamepad-private - -PLUGIN_TYPE = gamepads -PLUGIN_EXTENDS = gamepad -PLUGIN_CLASS_NAME = QDarwinGamepadBackendPlugin -load(qt_plugin) - -LIBS += -framework GameController -framework Foundation - -HEADERS += qdarwingamepadbackend_p.h -OBJECTIVE_SOURCES += \ - qdarwingamepadbackend.mm - -SOURCES += \ - main.cpp - -OTHER_FILES += \ - darwin.json diff --git a/src/plugins/gamepads/darwin/main.cpp b/src/plugins/gamepads/darwin/main.cpp deleted file mode 100644 index 87afec1..0000000 --- a/src/plugins/gamepads/darwin/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qdarwingamepadbackend_p.h" - -QT_BEGIN_NAMESPACE - -class QDarwinGamepadBackendPlugin : public QGamepadBackendPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QtGamepadBackendFactoryInterface_iid FILE "darwin.json") -public: - QGamepadBackend *create(const QString &key, const QStringList ¶mList) override; -}; - -QGamepadBackend *QDarwinGamepadBackendPlugin::create(const QString &key, const QStringList ¶mList) { - Q_UNUSED(key); - Q_UNUSED(paramList); - - return new QDarwinGamepadBackend(); -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/gamepads/darwin/qdarwingamepadbackend.mm b/src/plugins/gamepads/darwin/qdarwingamepadbackend.mm deleted file mode 100644 index 6094a99..0000000 --- a/src/plugins/gamepads/darwin/qdarwingamepadbackend.mm +++ /dev/null @@ -1,570 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qdarwingamepadbackend_p.h" - -#include - -#import - -@interface QT_MANGLE_NAMESPACE(DarwinGamepadManager) : NSObject - -@property (nonatomic, strong) id connectObserver; -@property (nonatomic, strong) id disconnectObserver; - -@end - -@implementation QT_MANGLE_NAMESPACE(DarwinGamepadManager) -{ - QDarwinGamepadBackend *backend; - NSMutableArray *connectedControllers; -} - --(instancetype)initWithBackend:(QDarwinGamepadBackend *)gamepadBackend -{ - if ((self = [self init])) { - backend = gamepadBackend; - connectedControllers = [[NSMutableArray alloc] init]; - //Setup observers for monitoring controller connections/disconnections - self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification *note) { - GCController *controller = (GCController*)note.object; - [self addMonitoredController:controller]; - - }]; - self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification *note) { - GCController *controller = (GCController*)note.object; - [self removeMonitoredController:controller]; - }]; - //Set initial controller values - for (int i = 0; i < 4; ++i) - [connectedControllers addObject:[NSNull null]]; - - //Add monitoring for any alrready connected controllers - for (NSUInteger i = 0; i < [[GCController controllers] count]; ++i) { - [self addMonitoredController:[GCController controllers][i]]; - } - } - return self; -} - --(void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver]; - [[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver]; - [connectedControllers release]; - [super dealloc]; -} - --(void)addMonitoredController:(GCController *)controller -{ - int index = -1; - for (int i = 0; i < 4; ++i) { - if (connectedControllers[i] == [NSNull null]) { - [connectedControllers replaceObjectAtIndex: i withObject: controller]; - index = i; - break; - } - } - - controller.playerIndex = GCControllerPlayerIndex(index); - - QMetaObject::invokeMethod(backend, "darwinGamepadAdded", Qt::AutoConnection, Q_ARG(int, index)); - - //Pause button handler - [controller setControllerPausedHandler:^(GCController *controller) { - Q_UNUSED(controller); - QMetaObject::invokeMethod(backend, "handlePauseButton", Qt::AutoConnection, Q_ARG(int, index)); - }]; - - if (controller.extendedGamepad) { - //leftShoulder - [controller.extendedGamepad.leftShoulder setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL1), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL1)); - } - }]; - //rightShoulder - [controller.extendedGamepad.rightShoulder setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR1), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR1)); - } - }]; - //dpad - [controller.extendedGamepad.dpad setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue) { - Q_UNUSED(dpad); - if (xValue > 0) { - //right - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonRight), - Q_ARG(double, 1)); - } else if (xValue < 0) { - //left - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonLeft), - Q_ARG(double, 1)); - } else { - //released - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonRight)); - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonLeft)); - } - if (yValue > 0) { - //up - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonUp), - Q_ARG(double, 1)); - } else if (yValue < 0) { - //down - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonDown), - Q_ARG(double, 1)); - } else { - //released - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonUp)); - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonDown)); - } - }]; - //buttonA - [controller.extendedGamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA)); - } - }]; - //buttonB - [controller.extendedGamepad.buttonB setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonB), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonB)); - } - }]; - //buttonX - [controller.extendedGamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX)); - } - }]; - //buttonY - [controller.extendedGamepad.buttonY setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - //Invoke slot - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonY), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonY)); - } - }]; - - //leftThumbstick - [controller.extendedGamepad.leftThumbstick setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue) { - Q_UNUSED(dpad); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisLeftX), - Q_ARG(double, xValue)); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisLeftY), - Q_ARG(double, -yValue)); - }]; - //rightTumbstick - [controller.extendedGamepad.rightThumbstick setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue) { - Q_UNUSED(dpad); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisRightX), - Q_ARG(double, xValue)); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisRightY), - Q_ARG(double, -yValue)); - }]; - //leftTrigger - [controller.extendedGamepad.leftTrigger setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL2), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL2)); - } - }]; - //rightTrigger - [controller.extendedGamepad.rightTrigger setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR2), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR2)); - } - - }]; - } else if (controller.gamepad) { - //leftShoulder - [controller.gamepad.leftShoulder setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL1), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonL1)); - } - }]; - //rightShoulder - [controller.gamepad.rightShoulder setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR1), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonR1)); - } - }]; - //dpad - [controller.gamepad.dpad setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue) { - Q_UNUSED(dpad); - if (xValue > 0) { - //right - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonRight), - Q_ARG(double, 1)); - } else if (xValue < 0) { - //left - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonLeft), - Q_ARG(double, 1)); - } else { - //released - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonRight)); - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonLeft)); - } - if (yValue > 0) { - //up - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonUp), - Q_ARG(double, 1)); - } else if (yValue < 0) { - //down - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonDown), - Q_ARG(double, 1)); - } else { - //released - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonUp)); - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonDown)); - } - }]; - //buttonA - [controller.gamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA)); - } - }]; - //buttonB - [controller.gamepad.buttonB setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonB), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonB)); - } - }]; - //buttonX - [controller.gamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX)); - } - }]; - //buttonY - [controller.gamepad.buttonY setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonY), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonY)); - } - }]; - } -#ifdef Q_OS_TVOS - else if (controller.microGamepad) { - //leftThumbstick - [controller.microGamepad.dpad setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue) { - Q_UNUSED(dpad); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisLeftX), - Q_ARG(double, xValue)); - QMetaObject::invokeMethod(backend, "darwinGamepadAxisMoved", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadAxis, QGamepadManager::AxisLeftY), - Q_ARG(double, -yValue)); - }]; - //buttonA - [controller.microGamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonA)); - } - }]; - //buttonX - [controller.microGamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { - Q_UNUSED(button); - if (pressed) { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonPressed", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX), - Q_ARG(double, value)); - } else { - QMetaObject::invokeMethod(backend, "darwinGamepadButtonReleased", Qt::AutoConnection, - Q_ARG(int, index), - Q_ARG(QGamepadManager::GamepadButton, QGamepadManager::ButtonX)); - } - }]; - } -#endif -} - --(void)removeMonitoredController:(GCController *)controller -{ - int index = -1; - for (int i = 0; i < 4; ++i) { - if (connectedControllers[i] == controller) { - [connectedControllers replaceObjectAtIndex: i withObject: [NSNull null]]; - index = i; - break; - } - } - - QMetaObject::invokeMethod(backend, "darwinGamepadRemoved", Qt::AutoConnection, Q_ARG(int, index)); -} - -@end - -QT_BEGIN_NAMESPACE - -QDarwinGamepadBackend::QDarwinGamepadBackend(QObject *parent) - : QGamepadBackend(parent) - , m_darwinGamepadManager(nullptr) - , m_isMonitoringActive(false) -{ - m_darwinGamepadManager = [[QT_MANGLE_NAMESPACE(DarwinGamepadManager) alloc] initWithBackend:this]; -} - -QDarwinGamepadBackend::~QDarwinGamepadBackend() -{ - [m_darwinGamepadManager release]; -} - -bool QDarwinGamepadBackend::start() -{ - m_isMonitoringActive = true; - return true; -} - -void QDarwinGamepadBackend::stop() -{ - m_isMonitoringActive = false; -} - -void QDarwinGamepadBackend::darwinGamepadAdded(int index) -{ - if (m_isMonitoringActive) { - emit gamepadAdded(index); - m_pauseButtonMap.insert(index, false); - } -} - -void QDarwinGamepadBackend::darwinGamepadRemoved(int index) -{ - if (m_isMonitoringActive) { - emit gamepadRemoved(index); - m_pauseButtonMap.remove(index); - } -} - -void QDarwinGamepadBackend::darwinGamepadAxisMoved(int index, QGamepadManager::GamepadAxis axis, double value) -{ - if (m_isMonitoringActive) - emit gamepadAxisMoved(index, axis, value); -} - -void QDarwinGamepadBackend::darwinGamepadButtonPressed(int index, QGamepadManager::GamepadButton button, double value) -{ - if (m_isMonitoringActive) - emit gamepadButtonPressed(index, button, value); -} - -void QDarwinGamepadBackend::darwinGamepadButtonReleased(int index, QGamepadManager::GamepadButton button) -{ - if (m_isMonitoringActive) - emit gamepadButtonReleased(index, button); -} - -void QDarwinGamepadBackend::handlePauseButton(int index) -{ - //If already pressed - if (m_pauseButtonMap.value(index)) { - emit gamepadButtonReleased(index, QGamepadManager::ButtonStart); - m_pauseButtonMap[index] = false; - } else { - //If not currently pressed - emit gamepadButtonPressed(index, QGamepadManager::ButtonStart, 1.0); - m_pauseButtonMap[index] = true; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/gamepads/darwin/qdarwingamepadbackend_p.h b/src/plugins/gamepads/darwin/qdarwingamepadbackend_p.h deleted file mode 100644 index 326ccaf..0000000 --- a/src/plugins/gamepads/darwin/qdarwingamepadbackend_p.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDARWINGAMEPADBACKEND_P_H -#define QDARWINGAMEPADBACKEND_P_H - -#include -#include - -#include -#include - -Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(DarwinGamepadManager)); - -QT_BEGIN_NAMESPACE - -class QDarwinGamepadBackend : public QGamepadBackend -{ - Q_OBJECT -public: - explicit QDarwinGamepadBackend(QObject *parent = nullptr); - ~QDarwinGamepadBackend(); - -protected: - bool start() override; - void stop() override; - -public Q_SLOTS: - void darwinGamepadAdded(int index); - void darwinGamepadRemoved(int index); - void darwinGamepadAxisMoved(int index, QGamepadManager::GamepadAxis axis, double value); - void darwinGamepadButtonPressed(int index, QGamepadManager::GamepadButton button, double value); - void darwinGamepadButtonReleased(int index, QGamepadManager::GamepadButton button); - void handlePauseButton(int index); - -private: - QT_MANGLE_NAMESPACE(DarwinGamepadManager) *m_darwinGamepadManager; - bool m_isMonitoringActive; - QMap m_pauseButtonMap; -}; - -QT_END_NAMESPACE - -#endif // QDARWINGAMEPADBACKEND_P_H diff --git a/src/plugins/gamepads/evdev/evdev.json b/src/plugins/gamepads/evdev/evdev.json deleted file mode 100644 index 90c6d7d..0000000 --- a/src/plugins/gamepads/evdev/evdev.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "evdev" ] -} diff --git a/src/plugins/gamepads/evdev/evdev.pro b/src/plugins/gamepads/evdev/evdev.pro deleted file mode 100644 index d819de4..0000000 --- a/src/plugins/gamepads/evdev/evdev.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = evdevgamepad -QT += core-private devicediscovery_support-private gamepad gamepad-private - -PLUGIN_TYPE = gamepads -PLUGIN_CLASS_NAME = QEvdevGamepadBackendPlugin -load(qt_plugin) - -HEADERS += qevdevgamepadbackend_p.h -SOURCES += \ - qevdevgamepadbackend.cpp \ - main.cpp - -OTHER_FILES += \ - evdev.json diff --git a/src/plugins/gamepads/evdev/main.cpp b/src/plugins/gamepads/evdev/main.cpp deleted file mode 100644 index 1832ea5..0000000 --- a/src/plugins/gamepads/evdev/main.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qevdevgamepadbackend_p.h" - -QT_BEGIN_NAMESPACE - -class QEvdevGamepadBackendPlugin : public QGamepadBackendPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QtGamepadBackendFactoryInterface_iid FILE "evdev.json") -public: - QGamepadBackend *create(const QString &key, const QStringList ¶mList) override; -}; - -QGamepadBackend *QEvdevGamepadBackendPlugin::create(const QString &key, const QStringList ¶mList) -{ - Q_UNUSED(key); - Q_UNUSED(paramList); - - return new QEvdevGamepadBackend; -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/gamepads/evdev/qevdevgamepadbackend.cpp b/src/plugins/gamepads/evdev/qevdevgamepadbackend.cpp deleted file mode 100644 index e57b2c8..0000000 --- a/src/plugins/gamepads/evdev/qevdevgamepadbackend.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // GCC warnings don't make sense, so disable - -#include "qevdevgamepadbackend_p.h" -#include -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcEGB, "qt.gamepad") - -#ifndef BTN_TRIGGER_HAPPY1 -# define BTN_TRIGGER_HAPPY1 0x2c0 -#endif -#ifndef BTN_TRIGGER_HAPPY2 -# define BTN_TRIGGER_HAPPY2 0x2c1 -#endif -#ifndef BTN_TRIGGER_HAPPY3 -# define BTN_TRIGGER_HAPPY3 0x2c2 -#endif -#ifndef BTN_TRIGGER_HAPPY4 -# define BTN_TRIGGER_HAPPY4 0x2c3 -#endif - -QEvdevGamepadDevice::EvdevAxisInfo::EvdevAxisInfo() - : QGamepadBackend::AxisInfo(0, 1, QGamepadManager::AxisInvalid) -{ -} - -QEvdevGamepadDevice::EvdevAxisInfo::EvdevAxisInfo(int fd, quint16 abs, int min, int max, QGamepadManager::GamepadAxis gamepadAxis) - : QGamepadBackend::AxisInfo(min, max, gamepadAxis) - , flat(0) - , gamepadMinButton(QGamepadManager::ButtonInvalid) - , gamepadMaxButton(QGamepadManager::ButtonInvalid) - , gamepadLastButton(QGamepadManager::ButtonInvalid) -{ - setAbsInfo(fd, abs); -} - -double QEvdevGamepadDevice::EvdevAxisInfo::normalized(int value) const -{ - double val = AxisInfo::normalized(value); - if (qAbs(val) <= flat) - val = 0; - return val; -} - -void QEvdevGamepadDevice::EvdevAxisInfo::setAbsInfo(int fd, int abs) -{ - input_absinfo absInfo; - memset(&absInfo, 0, sizeof(input_absinfo)); - if (ioctl(fd, EVIOCGABS(abs), &absInfo) >= 0) { - minValue = absInfo.minimum; - maxValue = absInfo.maximum; - if (maxValue - minValue) - flat = std::abs(absInfo.flat / double(maxValue - minValue)); - } -} - -void QEvdevGamepadDevice::EvdevAxisInfo::restoreSavedData(int fd, int abs, const QVariantMap &value) -{ - gamepadAxis = QGamepadManager::GamepadAxis(value[QLatin1String("axis")].toInt()); - gamepadMinButton = QGamepadManager::GamepadButton(value[QLatin1String("minButton")].toInt()); - gamepadMaxButton = QGamepadManager::GamepadButton(value[QLatin1String("maxButton")].toInt()); - setAbsInfo(fd, abs); -} - -QVariantMap QEvdevGamepadDevice::EvdevAxisInfo::dataToSave() const -{ - QVariantMap data; - data[QLatin1String("axis")] = gamepadAxis; - data[QLatin1String("minButton")] = gamepadMinButton; - data[QLatin1String("maxButton")] = gamepadMaxButton; - return data; -} - -QEvdevGamepadBackend::QEvdevGamepadBackend() -{ -} - -bool QEvdevGamepadBackend::start() -{ - qCDebug(lcEGB) << "start"; - QByteArray device = qgetenv("QT_GAMEPAD_DEVICE"); - if (device.isEmpty()) { - qCDebug(lcEGB) << "Using device discovery"; - m_discovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Joystick, this); - if (m_discovery) { - const QStringList devices = m_discovery->scanConnectedDevices(); - for (const QString &devStr : devices) { - device = devStr.toUtf8(); - m_devices.append(newDevice(device)); - } - connect(m_discovery, SIGNAL(deviceDetected(QString)), this, SLOT(handleAddedDevice(QString))); - connect(m_discovery, SIGNAL(deviceRemoved(QString)), this, SLOT(handleRemovedDevice(QString))); - } else { - qWarning("No device specified, set QT_GAMEPAD_DEVICE"); - return false; - } - } else { - qCDebug(lcEGB) << "Using device" << device; - m_devices.append(newDevice(device)); - } - - return true; -} - -QEvdevGamepadDevice *QEvdevGamepadBackend::newDevice(const QByteArray &device) -{ - qCDebug(lcEGB) << "Opening device" << device; - return new QEvdevGamepadDevice(device, this); -} - -QEvdevGamepadDevice *QEvdevGamepadBackend::device(int deviceId) -{ - for (QEvdevGamepadDevice *device : qAsConst(m_devices)) - if (device->deviceId() == deviceId) - return device; - return nullptr; -} - -void QEvdevGamepadBackend::resetConfiguration(int deviceId) -{ - if (QEvdevGamepadDevice *dev = device(deviceId)) - return dev->resetConfiguration(); -} - -bool QEvdevGamepadBackend::isConfigurationNeeded(int deviceId) -{ - if (QEvdevGamepadDevice *dev = device(deviceId)) - return dev->isConfigurationNeeded(); - return false; -} - -bool QEvdevGamepadBackend::configureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - if (QEvdevGamepadDevice *dev = device(deviceId)) - return dev->configureButton(button); - return false; -} - -bool QEvdevGamepadBackend::configureAxis(int deviceId, QGamepadManager::GamepadAxis axis) -{ - if (QEvdevGamepadDevice *dev = device(deviceId)) - return dev->configureAxis(axis); - return false; -} - -bool QEvdevGamepadBackend::setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button) -{ - if (QEvdevGamepadDevice *dev = device(deviceId)) - return dev->setCancelConfigureButton(button); - return false; -} - -void QEvdevGamepadBackend::stop() -{ - qCDebug(lcEGB) << "stop"; - qDeleteAll(m_devices); - m_devices.clear(); -} - -void QEvdevGamepadBackend::handleAddedDevice(const QString &device) -{ - // This does not imply that an actual controller is connected. - // When connecting the wireless receiver 4 devices will show up right away. - // Therefore gamepadAdded() will be emitted only later, when something is read. - qCDebug(lcEGB) << "Connected device" << device; - m_devices.append(newDevice(device.toUtf8())); -} - -void QEvdevGamepadBackend::handleRemovedDevice(const QString &device) -{ - qCDebug(lcEGB) << "Disconnected device" << device; - QByteArray dev = device.toUtf8(); - for (int i = 0; i < m_devices.count(); ++i) { - if (m_devices[i]->deviceName() == dev) { - delete m_devices[i]; - m_devices.removeAt(i); - break; - } - } -} - -QEvdevGamepadDevice::QEvdevGamepadDevice(const QByteArray &dev, QEvdevGamepadBackend *backend) - : m_dev(dev), - m_backend(backend), - m_fd(-1), - m_productId(0), - m_needsConfigure(true), - m_notifier(0), - m_configureButton(QGamepadManager::ButtonInvalid), - m_configureAxis(QGamepadManager::AxisInvalid) -{ - openDevice(dev); -} - -QEvdevGamepadDevice::~QEvdevGamepadDevice() -{ - if (m_fd != -1) - QT_CLOSE(m_fd); - - if (m_productId) - emit m_backend->gamepadRemoved(m_productId); -} - -void QEvdevGamepadDevice::resetConfiguration() -{ - m_axisMap.insert(ABS_X, EvdevAxisInfo(m_fd, ABS_X, -32768, 32767, QGamepadManager::AxisLeftX)); - m_axisMap.insert(ABS_Y, EvdevAxisInfo(m_fd, ABS_Y, -32768, 32767, QGamepadManager::AxisLeftY)); - m_axisMap.insert(ABS_RX, EvdevAxisInfo(m_fd, ABS_RX, -32768, 32767, QGamepadManager::AxisRightX)); - m_axisMap.insert(ABS_RY, EvdevAxisInfo(m_fd, ABS_RY, -32768, 32767, QGamepadManager::AxisRightY)); - m_axisMap.insert(ABS_Z, EvdevAxisInfo(m_fd, ABS_Z, 0, 255)); - m_axisMap[ABS_Z].gamepadMinButton = QGamepadManager::ButtonL2; - m_axisMap[ABS_Z].gamepadMaxButton = QGamepadManager::ButtonL2; - - m_axisMap.insert(ABS_RZ, EvdevAxisInfo(m_fd, ABS_RZ, 0, 255)); - m_axisMap[ABS_RZ].gamepadMinButton = QGamepadManager::ButtonR2; - m_axisMap[ABS_RZ].gamepadMaxButton = QGamepadManager::ButtonR2; - - m_axisMap.insert(ABS_HAT0X, EvdevAxisInfo(m_fd, ABS_HAT0X, -1, 1)); - m_axisMap[ABS_HAT0X].gamepadMinButton = QGamepadManager::ButtonLeft; - m_axisMap[ABS_HAT0X].gamepadMaxButton = QGamepadManager::ButtonRight; - - m_axisMap.insert(ABS_HAT0Y, EvdevAxisInfo(m_fd, ABS_HAT0Y, -1, 1)); - m_axisMap[ABS_HAT0Y].gamepadMinButton = QGamepadManager::ButtonUp; - m_axisMap[ABS_HAT0Y].gamepadMaxButton = QGamepadManager::ButtonDown; - - m_buttonsMap[BTN_START] = QGamepadManager::ButtonStart; - m_buttonsMap[BTN_SELECT] = QGamepadManager::ButtonSelect; - m_buttonsMap[BTN_MODE] = QGamepadManager::ButtonGuide; - m_buttonsMap[BTN_X] = QGamepadManager::ButtonX; - m_buttonsMap[BTN_Y] = QGamepadManager::ButtonY; - m_buttonsMap[BTN_A] = QGamepadManager::ButtonA; - m_buttonsMap[BTN_B] = QGamepadManager::ButtonB; - m_buttonsMap[BTN_TL] = QGamepadManager::ButtonL1; - m_buttonsMap[BTN_TR] = QGamepadManager::ButtonR1; - m_buttonsMap[BTN_TL2] = QGamepadManager::ButtonL2; - m_buttonsMap[BTN_TR2] = QGamepadManager::ButtonR2; - m_buttonsMap[BTN_THUMB] = m_buttonsMap[BTN_THUMBL] = QGamepadManager::ButtonL3; - m_buttonsMap[BTN_THUMBR] = QGamepadManager::ButtonR3; - m_buttonsMap[BTN_TRIGGER_HAPPY1] = QGamepadManager::ButtonLeft; - m_buttonsMap[BTN_TRIGGER_HAPPY2] = QGamepadManager::ButtonRight; - m_buttonsMap[BTN_TRIGGER_HAPPY3] = QGamepadManager::ButtonUp; - m_buttonsMap[BTN_TRIGGER_HAPPY4] = QGamepadManager::ButtonDown; - - if (m_productId) - m_backend->saveSettings(m_productId, QVariant()); -} - -bool QEvdevGamepadDevice::isConfigurationNeeded() -{ - return m_needsConfigure; -} - -bool QEvdevGamepadDevice::configureButton(QGamepadManager::GamepadButton button) -{ - m_configureButton = button; - return true; -} - -bool QEvdevGamepadDevice::configureAxis(QGamepadManager::GamepadAxis axis) -{ - m_configureAxis = axis; - return true; -} - -bool QEvdevGamepadDevice::setCancelConfigureButton(QGamepadManager::GamepadButton button) -{ - m_configureCancelButton = button; - return true; -} - -bool QEvdevGamepadDevice::openDevice(const QByteArray &dev) -{ - m_fd = QT_OPEN(dev.constData(), O_RDONLY | O_NDELAY, 0); - - if (m_fd >= 0) { - m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); - connect(m_notifier, SIGNAL(activated(int)), this, SLOT(readData())); - qCDebug(lcEGB) << "Successfully opened" << dev; - } else { - qErrnoWarning(errno, "Gamepad: Cannot open input device %s", qPrintable(dev)); - return false; - } - - input_id id; - if (ioctl(m_fd, EVIOCGID, &id) >= 0) { - m_productId = id.product; - - QVariant settings = m_backend->readSettings(m_productId); - if (!settings.isNull()) { - m_needsConfigure = false; - QVariantMap data = settings.toMap()[QLatin1String("axes")].toMap(); - for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it) { - const int key = it.key().toInt(); - m_axisMap[key].restoreSavedData(m_fd, key, it.value().toMap()); - } - - data = settings.toMap()[QLatin1String("buttons")].toMap(); - for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it) - m_buttonsMap[it.key().toInt()] = QGamepadManager::GamepadButton(it.value().toInt()); - } - - emit m_backend->gamepadAdded(m_productId); - - // same as libevdev::libevdev_set_fd() in libevdev.c - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - if (ioctl(m_fd, EVIOCGNAME(sizeof(buffer) - 1), buffer) >= 0) - emit m_backend->gamepadNamed(m_productId, QString::fromUtf8(buffer)); - - } else { - QT_CLOSE(m_fd); - m_fd = -1; - return false; - } - - if (m_needsConfigure) - resetConfiguration(); - - qCDebug(lcEGB) << "Axis limits:" << m_axisMap; - - return true; -} - -QDebug operator<<(QDebug dbg, const QEvdevGamepadDevice::EvdevAxisInfo &axisInfo) -{ - dbg.nospace() << "AxisInfo(min=" << axisInfo.minValue << ", max=" << axisInfo.maxValue << ")"; - return dbg.space(); -} - -void QEvdevGamepadDevice::readData() -{ - input_event buffer[32]; - int events = 0, n = 0; - for (; ;) { - events = QT_READ(m_fd, reinterpret_cast(buffer) + n, sizeof(buffer) - n); - if (events <= 0) - goto err; - n += events; - if (n % sizeof(::input_event) == 0) - break; - } - - n /= sizeof(::input_event); - - for (int i = 0; i < n; ++i) - processInputEvent(&buffer[i]); - - return; - -err: - if (!events) { - qWarning("Gamepad: Got EOF from input device"); - return; - } else if (events < 0) { - if (errno != EINTR && errno != EAGAIN) { - qErrnoWarning(errno, "Gamepad: Could not read from input device"); - if (errno == ENODEV) { // device got disconnected -> stop reading - delete m_notifier; - m_notifier = 0; - QT_CLOSE(m_fd); - m_fd = -1; - } - } - } -} - -void QEvdevGamepadDevice::saveData() -{ - if (!m_productId) - return ; - - QVariantMap settings, data; - for (AxisMap::const_iterator it = m_axisMap.begin(); it != m_axisMap.end(); ++it) - data[QString::number(it.key())] = it.value().dataToSave(); - settings[QLatin1String("axes")] = data; - - data.clear(); - for (ButtonsMap::const_iterator it = m_buttonsMap.begin(); it != m_buttonsMap.end(); ++it) - data[QString::number(it.key())] = it.value(); - - settings[QLatin1String("buttons")] = data; - - m_backend->saveSettings(m_productId, settings); -} - -void QEvdevGamepadDevice::processInputEvent(input_event *e) -{ - if (e->type == EV_KEY) { - QGamepadManager::GamepadButton btn = QGamepadManager::ButtonInvalid; - ButtonsMap::const_iterator it = m_buttonsMap.find(e->code); - if (it != m_buttonsMap.end()) - btn = it.value(); - - const bool pressed = e->value; - if (m_configureCancelButton != QGamepadManager::ButtonInvalid && - m_configureCancelButton != m_configureButton && - !pressed && btn == m_configureCancelButton && - (m_configureButton != QGamepadManager::ButtonInvalid || - m_configureAxis != QGamepadManager::AxisInvalid)) { - m_configureButton = QGamepadManager::ButtonInvalid; - m_configureAxis = QGamepadManager::AxisInvalid; - emit m_backend->configurationCanceled(m_productId); - return; - } - - if (!pressed && m_configureButton != QGamepadManager::ButtonInvalid) { - m_buttonsMap[e->code] = m_configureButton; - QGamepadManager::GamepadButton but = m_configureButton; - m_configureButton = QGamepadManager::ButtonInvalid; - saveData(); - emit m_backend->buttonConfigured(m_productId, but); - } - - it = m_buttonsMap.find(e->code); - if (it != m_buttonsMap.end()) - btn = it.value(); - - if (btn != QGamepadManager::ButtonInvalid) { - if (pressed) - emit m_backend->gamepadButtonPressed(m_productId, btn, 1.0); - else - emit m_backend->gamepadButtonReleased(m_productId, btn); - } - } else if (e->type == EV_ABS) { - if (m_configureAxis != QGamepadManager::AxisInvalid) { - EvdevAxisInfo inf(m_fd, e->code, -32768, 32767, m_configureAxis); - if (std::abs(inf.normalized(e->value)) == 1) { - m_axisMap.insert(e->code, EvdevAxisInfo(m_fd, e->code, -32768, 32767, m_configureAxis)); - - QGamepadManager::GamepadAxis axis = m_configureAxis; - m_configureAxis = QGamepadManager::AxisInvalid; - - saveData(); - emit m_backend->axisConfigured(m_productId, axis); - } else { - return; - } - } - - AxisMap::iterator it = m_axisMap.find(e->code); - if (m_configureButton != QGamepadManager::ButtonInvalid) { - EvdevAxisInfo axisInfo; - if (it != m_axisMap.end()) - axisInfo = it.value(); - else - axisInfo = EvdevAxisInfo(m_fd, e->code); - - axisInfo.gamepadAxis = QGamepadManager::AxisInvalid; - - bool save = false; - if (e->value == axisInfo.minValue) { - axisInfo.gamepadMinButton = m_configureButton; - if (axisInfo.gamepadMaxButton != QGamepadManager::ButtonInvalid) - axisInfo.gamepadMaxButton = m_configureButton; - save = true; - } else if (e->value == axisInfo.maxValue) { - axisInfo.gamepadMaxButton = m_configureButton; - if (axisInfo.gamepadMinButton != QGamepadManager::ButtonInvalid) - axisInfo.gamepadMinButton = m_configureButton; - save = true; - } - - if (save) { - QGamepadManager::GamepadButton but = m_configureButton; - m_configureButton = QGamepadManager::ButtonInvalid; - if (but == QGamepadManager::ButtonL2 || but == QGamepadManager::ButtonR2) - m_axisMap.insert(e->code, axisInfo); - saveData(); - emit m_backend->buttonConfigured(m_productId, but); - } - } - - it = m_axisMap.find(e->code); - if (it == m_axisMap.end()) - return; - - EvdevAxisInfo &info = it.value(); - - double val = info.normalized(e->value); - - if (info.gamepadAxis != QGamepadManager::AxisInvalid) - emit m_backend->gamepadAxisMoved(m_productId, info.gamepadAxis, val); - - if (info.gamepadMaxButton == info.gamepadMinButton && - info.gamepadMaxButton != QGamepadManager::ButtonInvalid) { - if (val) - emit m_backend->gamepadButtonPressed(m_productId, info.gamepadMaxButton, std::abs(val)); - else - emit m_backend->gamepadButtonReleased(m_productId, info.gamepadMaxButton); - } else { - if (info.gamepadMaxButton != QGamepadManager::ButtonInvalid - && val == 1.0) { - info.gamepadLastButton = info.gamepadMaxButton; - emit m_backend->gamepadButtonPressed(m_productId, info.gamepadMaxButton, val); - } else if (info.gamepadMinButton != QGamepadManager::ButtonInvalid - && val == -1.0) { - info.gamepadLastButton = info.gamepadMinButton; - emit m_backend->gamepadButtonPressed(m_productId, info.gamepadMinButton, -val); - } else if (!val && info.gamepadLastButton != QGamepadManager::ButtonInvalid) { - QGamepadManager::GamepadButton but = info.gamepadLastButton; - info.gamepadLastButton = QGamepadManager::ButtonInvalid; - emit m_backend->gamepadButtonReleased(m_productId, but); - } - } - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/gamepads/evdev/qevdevgamepadbackend_p.h b/src/plugins/gamepads/evdev/qevdevgamepadbackend_p.h deleted file mode 100644 index 35e2fbd..0000000 --- a/src/plugins/gamepads/evdev/qevdevgamepadbackend_p.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEVDEVGAMEPADBACKEND_P_H -#define QEVDEVGAMEPADBACKEND_P_H - -#include -#include -#include -#include - -struct input_event; - -QT_BEGIN_NAMESPACE - -class QSocketNotifier; -class QDeviceDiscovery; -class QEvdevGamepadBackend; - -class QEvdevGamepadDevice : public QObject -{ - Q_OBJECT - -public: - QEvdevGamepadDevice(const QByteArray &dev, QEvdevGamepadBackend *backend); - ~QEvdevGamepadDevice(); - QByteArray deviceName() const { return m_dev; } - int deviceId() const { return m_productId; } - void resetConfiguration(); - bool isConfigurationNeeded(); - bool configureButton(QGamepadManager::GamepadButton button); - bool configureAxis(QGamepadManager::GamepadAxis axis); - bool setCancelConfigureButton(QGamepadManager::GamepadButton button); - -private Q_SLOTS: - void readData(); - -private: - void saveData(); - void processInputEvent(input_event *e); - bool openDevice(const QByteArray &dev); - - QByteArray m_dev; - QEvdevGamepadBackend *m_backend; - int m_fd; - int m_productId; - bool m_needsConfigure; - QSocketNotifier *m_notifier; - struct EvdevAxisInfo : public QGamepadBackend::AxisInfo - { - EvdevAxisInfo(); - EvdevAxisInfo(int fd, quint16 abs, int minValue = 0, int maxValue = 1, QGamepadManager::GamepadAxis gamepadAxis = QGamepadManager::AxisInvalid); - double normalized(int value) const override; - void setAbsInfo(int fd, int abs); - void restoreSavedData(int fd, int abs, const QVariantMap &value); - QVariantMap dataToSave() const; - double flat; - QGamepadManager::GamepadButton gamepadMinButton; - QGamepadManager::GamepadButton gamepadMaxButton; - QGamepadManager::GamepadButton gamepadLastButton; - }; - typedef QHash AxisMap; - AxisMap m_axisMap; - - friend QDebug operator<<(QDebug dbg, const QEvdevGamepadDevice::EvdevAxisInfo &axisInfo); - - typedef QHash ButtonsMap; - ButtonsMap m_buttonsMap; - - QGamepadManager::GamepadButton m_configureButton; - QGamepadManager::GamepadAxis m_configureAxis; - QGamepadManager::GamepadButton m_configureCancelButton; -}; - -QDebug operator<<(QDebug dbg, const QEvdevGamepadDevice::EvdevAxisInfo &axisInfo); - -class QEvdevGamepadBackend : public QGamepadBackend -{ - Q_OBJECT - -public: - QEvdevGamepadBackend(); - bool start() override; - void stop() override; - void resetConfiguration(int deviceId) override; - bool isConfigurationNeeded(int deviceId) override; - bool configureButton(int deviceId, QGamepadManager::GamepadButton button) override; - bool configureAxis(int deviceId, QGamepadManager::GamepadAxis axis) override; - bool setCancelConfigureButton(int deviceId, QGamepadManager::GamepadButton button) override; - -private slots: - void handleAddedDevice(const QString &device); - void handleRemovedDevice(const QString &device); - -private: - QEvdevGamepadDevice *newDevice(const QByteArray &device); - QEvdevGamepadDevice *device(int deviceId); - - QDeviceDiscovery *m_discovery; - QList m_devices; -}; - -QT_END_NAMESPACE - -#endif // QEVDEVGAMEPADBACKEND_P_H diff --git a/src/plugins/gamepads/gamepads.pro b/src/plugins/gamepads/gamepads.pro deleted file mode 100644 index 2151b79..0000000 --- a/src/plugins/gamepads/gamepads.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = subdirs -QT_FOR_CONFIG += gui-private gamepad-private -qtConfig(sdl2): SUBDIRS += sdl2 -!android: qtConfig(evdev): SUBDIRS += evdev -win32: SUBDIRS += xinput -darwin: !watchos: SUBDIRS += darwin -android: !android-embedded: SUBDIRS += android diff --git a/src/plugins/gamepads/sdl2/main.cpp b/src/plugins/gamepads/sdl2/main.cpp deleted file mode 100644 index 30b0ceb..0000000 --- a/src/plugins/gamepads/sdl2/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qsdlgamepadbackend_p.h" - -QT_BEGIN_NAMESPACE - -class QSdl2GamepadBackendPlugin : public QGamepadBackendPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QtGamepadBackendFactoryInterface_iid FILE "sdl2.json") -public: - QGamepadBackend *create(const QString &key, const QStringList ¶mList) override; -}; - -QGamepadBackend *QSdl2GamepadBackendPlugin::create(const QString &key, const QStringList ¶mList) { - Q_UNUSED(key); - Q_UNUSED(paramList); - - return new QSdlGamepadBackend(); -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/gamepads/sdl2/qsdlgamepadbackend.cpp b/src/plugins/gamepads/sdl2/qsdlgamepadbackend.cpp deleted file mode 100644 index 6a7cee6..0000000 --- a/src/plugins/gamepads/sdl2/qsdlgamepadbackend.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qsdlgamepadbackend_p.h" - -#include - -#include -// Reset bool redefinition from SDL header -#undef bool - -QT_BEGIN_NAMESPACE - -QSdlGamepadBackend::QSdlGamepadBackend(QObject *parent) - : QGamepadBackend(parent) -{ - connect(&m_eventLoopTimer, SIGNAL(timeout()), this, SLOT(pumpSdlEventLoop())); -} - -QSdlGamepadBackend::~QSdlGamepadBackend() -{ -} - -void QSdlGamepadBackend::pumpSdlEventLoop() -{ - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_CONTROLLERAXISMOTION) { - SDL_ControllerAxisEvent axisEvent = event.caxis; - //qDebug() << axisEvent.timestamp << "Axis Event: " << axisEvent.which << axisEvent.axis << axisEvent.value; - double value; - if (axisEvent.value >= 0) - value = axisEvent.value / 32767.0; - else - value = axisEvent.value / 32768.0; - switch (axisEvent.axis) { - case SDL_CONTROLLER_AXIS_LEFTX: - emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisLeftX, value); - break; - case SDL_CONTROLLER_AXIS_LEFTY: - emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisLeftY, value); - break; - case SDL_CONTROLLER_AXIS_RIGHTX: - emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisRightX, value); - break; - case SDL_CONTROLLER_AXIS_RIGHTY: - emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisRightY, value); - break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: - if (value == 0) - emit gamepadButtonReleased(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonL2); - else - emit gamepadButtonPressed(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonL2, value); - break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - if (value == 0) - emit gamepadButtonReleased(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonR2); - else - emit gamepadButtonPressed(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonR2, value); - break; - default: - break; - } - - } else if (event.type == SDL_CONTROLLERBUTTONDOWN) { - SDL_ControllerButtonEvent buttonEvent = event.cbutton; - //qDebug() << buttonEvent.timestamp << "Button Press: " << buttonEvent.which << buttonEvent.button << buttonEvent.state; - emit gamepadButtonPressed(m_instanceIdForIndex[buttonEvent.which], translateButton(buttonEvent.button), 1.0); - } else if (event.type == SDL_CONTROLLERBUTTONUP) { - SDL_ControllerButtonEvent buttonEvent = event.cbutton; - //qDebug() << buttonEvent.timestamp << "Button Release: " << buttonEvent.which << buttonEvent.button << buttonEvent.state; - emit gamepadButtonReleased(m_instanceIdForIndex[buttonEvent.which], translateButton(buttonEvent.button)); - } else if (event.type == SDL_CONTROLLERDEVICEADDED) { - SDL_ControllerDeviceEvent deviceEvent = event.cdevice; - //qDebug() << deviceEvent.timestamp << "Controller Added: " << deviceEvent.which; - addController(deviceEvent.which); - } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) { - SDL_ControllerDeviceEvent deviceEvent = event.cdevice; - - int index = m_instanceIdForIndex[deviceEvent.which]; - SDL_GameControllerClose(m_indexForController[index]); - emit gamepadRemoved(index); - m_indexForController.remove(index); - m_instanceIdForIndex.remove(deviceEvent.which); - - } else if (event.type == SDL_CONTROLLERDEVICEREMAPPED) { - //SDL_ControllerDeviceEvent deviceEvent = event.cdevice; - //qDebug() << deviceEvent.timestamp << "Controller Remapped: " << deviceEvent.which; - } - } -} - -bool QSdlGamepadBackend::start() -{ - //Initialize SDL with necessary subsystems for gamepad support - if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK)) { - qDebug() << SDL_GetError(); - return false; - } - - m_eventLoopTimer.start(16); - for (int i = 0; i < SDL_NumJoysticks() ; i++) - addController(i); - - return true; -} - -void QSdlGamepadBackend::stop() -{ - m_eventLoopTimer.stop(); - SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK); -} - -QGamepadManager::GamepadButton QSdlGamepadBackend::translateButton(int button) -{ - switch (button) { - case SDL_CONTROLLER_BUTTON_A: - return QGamepadManager::ButtonA; - case SDL_CONTROLLER_BUTTON_B: - return QGamepadManager::ButtonB; - case SDL_CONTROLLER_BUTTON_X: - return QGamepadManager::ButtonX; - case SDL_CONTROLLER_BUTTON_Y: - return QGamepadManager::ButtonY; - case SDL_CONTROLLER_BUTTON_BACK: - return QGamepadManager::ButtonSelect; - case SDL_CONTROLLER_BUTTON_GUIDE: - return QGamepadManager::ButtonGuide; - case SDL_CONTROLLER_BUTTON_START: - return QGamepadManager::ButtonStart; - case SDL_CONTROLLER_BUTTON_LEFTSTICK: - return QGamepadManager::ButtonL3; - case SDL_CONTROLLER_BUTTON_RIGHTSTICK: - return QGamepadManager::ButtonR3; - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: - return QGamepadManager::ButtonL1; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: - return QGamepadManager::ButtonR1; - case SDL_CONTROLLER_BUTTON_DPAD_UP: - return QGamepadManager::ButtonUp; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: - return QGamepadManager::ButtonDown; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: - return QGamepadManager::ButtonLeft; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: - return QGamepadManager::ButtonRight; - default: - return QGamepadManager::ButtonInvalid; - } -} - -void QSdlGamepadBackend::addController(int index) -{ - char GUID[100]; - SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(index), GUID, 100); - if (!SDL_IsGameController(index)) - return; - - SDL_GameController *controller = SDL_GameControllerOpen(index); - if (controller) { - m_indexForController.insert(index, controller); - - SDL_Joystick *joystick = SDL_GameControllerGetJoystick(controller); - - int instanceID = SDL_JoystickInstanceID(joystick); - m_instanceIdForIndex.insert(instanceID, index); - - const char *name = SDL_JoystickName(joystick); - - //qDebug() << "Controller " << index << " added with instanceId: " << instanceID; - emit gamepadAdded(index); - - if (name) - emit gamepadNamed(index, QString::fromUtf8(name)); - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/gamepads/sdl2/qsdlgamepadbackend_p.h b/src/plugins/gamepads/sdl2/qsdlgamepadbackend_p.h deleted file mode 100644 index dfd7176..0000000 --- a/src/plugins/gamepads/sdl2/qsdlgamepadbackend_p.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSDLGAMEPADBACKEND_P_H -#define QSDLGAMEPADBACKEND_P_H - -#include -#include - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QSdlGamepadBackend : public QGamepadBackend -{ - Q_OBJECT -public: - explicit QSdlGamepadBackend(QObject *parent = nullptr); - ~QSdlGamepadBackend(); - -private Q_SLOTS: - void pumpSdlEventLoop(); - -protected: - bool start() override; - void stop() override; - -private: - QGamepadManager::GamepadButton translateButton(int button); - void addController(int index); - QTimer m_eventLoopTimer; - QMap m_indexForController; - QMap m_instanceIdForIndex; -}; - -QT_END_NAMESPACE - -#endif // QSDLGAMEPADBACKEND_P_H diff --git a/src/plugins/gamepads/sdl2/sdl2.json b/src/plugins/gamepads/sdl2/sdl2.json deleted file mode 100644 index d2bd585..0000000 --- a/src/plugins/gamepads/sdl2/sdl2.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "sdl2" ] -} diff --git a/src/plugins/gamepads/sdl2/sdl2.pro b/src/plugins/gamepads/sdl2/sdl2.pro deleted file mode 100644 index 91715a3..0000000 --- a/src/plugins/gamepads/sdl2/sdl2.pro +++ /dev/null @@ -1,17 +0,0 @@ -TARGET = sdl2gamepad -QT += gamepad gamepad-private - -PLUGIN_TYPE = gamepads -PLUGIN_CLASS_NAME = QSdl2GamepadBackendPlugin -load(qt_plugin) - -QMAKE_USE += sdl2 - -HEADERS += qsdlgamepadbackend_p.h -SOURCES += \ - qsdlgamepadbackend.cpp \ - main.cpp - -OTHER_FILES += \ - sdl2.json - diff --git a/src/plugins/gamepads/xinput/main.cpp b/src/plugins/gamepads/xinput/main.cpp deleted file mode 100644 index c157cfd..0000000 --- a/src/plugins/gamepads/xinput/main.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -#include "qxinputgamepadbackend_p.h" - -QT_BEGIN_NAMESPACE - -class QXInputGamepadBackendPlugin : public QGamepadBackendPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QtGamepadBackendFactoryInterface_iid FILE "xinput.json") -public: - QGamepadBackend *create(const QString &key, const QStringList ¶mList) override; -}; - -QGamepadBackend *QXInputGamepadBackendPlugin::create(const QString &key, const QStringList ¶mList) -{ - Q_UNUSED(key); - Q_UNUSED(paramList); - - return new QXInputGamepadBackend; -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/gamepads/xinput/qxinputgamepadbackend.cpp b/src/plugins/gamepads/xinput/qxinputgamepadbackend.cpp deleted file mode 100644 index 4d042c9..0000000 --- a/src/plugins/gamepads/xinput/qxinputgamepadbackend.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "qxinputgamepadbackend_p.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcXGB, "qt.gamepad") - -#define POLL_SLEEP_MS 5 -#define POLL_SLOT_CHECK_MS 4000 - -#define XUSER_MAX_COUNT 4 - -#define XINPUT_GAMEPAD_DPAD_UP 0x0001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 -#define XINPUT_GAMEPAD_START 0x0010 -#define XINPUT_GAMEPAD_BACK 0x0020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 -#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 -#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 -#define XINPUT_GAMEPAD_A 0x1000 -#define XINPUT_GAMEPAD_B 0x2000 -#define XINPUT_GAMEPAD_X 0x4000 -#define XINPUT_GAMEPAD_Y 0x8000 - -#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 -#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 -#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30 - -struct XINPUT_GAMEPAD -{ - unsigned short wButtons; - unsigned char bLeftTrigger; - unsigned char bRightTrigger; - short sThumbLX; - short sThumbLY; - short sThumbRX; - short sThumbRY; -}; - -struct XINPUT_STATE -{ - unsigned long dwPacketNumber; - XINPUT_GAMEPAD Gamepad; -}; - -typedef DWORD (WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); -static XInputGetState_t XInputGetState; - -class QXInputThread : public QThread -{ -public: - QXInputThread(QXInputGamepadBackend *backend); - void run() override; - void signalQuit() { m_quit.fetchAndStoreAcquire(1); } - -private: - void dispatch(int idx, XINPUT_GAMEPAD *state); - - QXInputGamepadBackend *m_backend; - QAtomicInt m_quit; - struct Controller { - bool connected; - int skippedPolls; - unsigned long lastPacketNumber; - // State cache. Only want to emit signals for values that really change. - unsigned short buttons; - unsigned char triggers[2]; - double axis[2][2]; - } m_controllers[XUSER_MAX_COUNT]; -}; - -QXInputThread::QXInputThread(QXInputGamepadBackend *backend) - : m_backend(backend), - m_quit(false) -{ - memset(m_controllers, 0, sizeof(m_controllers)); -} - -void QXInputThread::dispatch(int idx, XINPUT_GAMEPAD *state) -{ - static const struct ButtonMap { - unsigned short xbutton; - QGamepadManager::GamepadButton qbutton; - } buttonMap[] = { - { XINPUT_GAMEPAD_DPAD_UP, QGamepadManager::ButtonUp }, - { XINPUT_GAMEPAD_DPAD_DOWN, QGamepadManager::ButtonDown }, - { XINPUT_GAMEPAD_DPAD_LEFT, QGamepadManager::ButtonLeft }, - { XINPUT_GAMEPAD_DPAD_RIGHT, QGamepadManager::ButtonRight }, - { XINPUT_GAMEPAD_START, QGamepadManager::ButtonStart }, - { XINPUT_GAMEPAD_BACK, QGamepadManager::ButtonSelect }, - { XINPUT_GAMEPAD_LEFT_SHOULDER, QGamepadManager::ButtonL1 }, - { XINPUT_GAMEPAD_RIGHT_SHOULDER, QGamepadManager::ButtonR1 }, - { XINPUT_GAMEPAD_LEFT_THUMB, QGamepadManager::ButtonL3 }, - { XINPUT_GAMEPAD_RIGHT_THUMB, QGamepadManager::ButtonR3 }, - { XINPUT_GAMEPAD_A, QGamepadManager::ButtonA }, - { XINPUT_GAMEPAD_B, QGamepadManager::ButtonB }, - { XINPUT_GAMEPAD_X, QGamepadManager::ButtonX }, - { XINPUT_GAMEPAD_Y, QGamepadManager::ButtonY } - }; - for (uint i = 0; i < sizeof(buttonMap) / sizeof(ButtonMap); ++i) { - const unsigned short xb = buttonMap[i].xbutton; - unsigned short isDown = state->wButtons & xb; - if (isDown != (m_controllers[idx].buttons & xb)) { - if (isDown) { - m_controllers[idx].buttons |= xb; - emit m_backend->gamepadButtonPressed(idx, buttonMap[i].qbutton, 1); - } else { - m_controllers[idx].buttons &= ~xb; - emit m_backend->gamepadButtonReleased(idx, buttonMap[i].qbutton); - } - } - } - - if (m_controllers[idx].triggers[0] != state->bLeftTrigger) { - m_controllers[idx].triggers[0] = state->bLeftTrigger; - const double value = state->bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD - ? (state->bLeftTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - / (255.0 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - : 0.0; - if (!qFuzzyIsNull(value)) - emit m_backend->gamepadButtonPressed(idx, QGamepadManager::ButtonL2, value); - else - emit m_backend->gamepadButtonReleased(idx, QGamepadManager::ButtonL2); - } - if (m_controllers[idx].triggers[1] != state->bRightTrigger) { - m_controllers[idx].triggers[1] = state->bRightTrigger; - const double value = state->bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD - ? (state->bRightTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - / (255.0 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD) - : 0.0; - if (!qFuzzyIsNull(value)) - emit m_backend->gamepadButtonPressed(idx, QGamepadManager::ButtonR2, value); - else - emit m_backend->gamepadButtonReleased(idx, QGamepadManager::ButtonR2); - } - - double x, y; - if (qSqrt(state->sThumbLX * state->sThumbLX + state->sThumbLY * state->sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - x = 2 * (state->sThumbLX + 32768.0) / 65535.0 - 1.0; - y = 2 * (-state->sThumbLY + 32768.0) / 65535.0 - 1.0; - } else { - x = y = 0; - } - if (m_controllers[idx].axis[0][0] != x) { - m_controllers[idx].axis[0][0] = x; - emit m_backend->gamepadAxisMoved(idx, QGamepadManager::AxisLeftX, x); - } - if (m_controllers[idx].axis[0][1] != y) { - m_controllers[idx].axis[0][1] = y; - emit m_backend->gamepadAxisMoved(idx, QGamepadManager::AxisLeftY, y); - } - if (qSqrt(state->sThumbRX * state->sThumbRX + state->sThumbRY * state->sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - x = 2 * (state->sThumbRX + 32768.0) / 65535.0 - 1.0; - y = 2 * (-state->sThumbRY + 32768.0) / 65535.0 - 1.0; - } else { - x = y = 0; - } - if (m_controllers[idx].axis[1][0] != x) { - m_controllers[idx].axis[1][0] = x; - emit m_backend->gamepadAxisMoved(idx, QGamepadManager::AxisRightX, x); - } - if (m_controllers[idx].axis[1][1] != y) { - m_controllers[idx].axis[1][1] = y; - emit m_backend->gamepadAxisMoved(idx, QGamepadManager::AxisRightY, y); - } -} - -void QXInputThread::run() -{ - qCDebug(lcXGB, "XInput thread running"); - bool firstPoll = true; - while (!m_quit.testAndSetAcquire(1, 0)) { - for (int i = 0; i < XUSER_MAX_COUNT; ++i) { - Controller *controller = m_controllers + i; - - if (!firstPoll && !controller->connected && controller->skippedPolls < POLL_SLOT_CHECK_MS / POLL_SLEEP_MS) { - controller->skippedPolls++; - continue; - } - - firstPoll = false; - controller->skippedPolls = 0; - XINPUT_STATE state; - memset(&state, 0, sizeof(state)); - - if (XInputGetState(i, &state) == ERROR_SUCCESS) { - if (controller->connected) { - if (controller->lastPacketNumber != state.dwPacketNumber) { - controller->lastPacketNumber = state.dwPacketNumber; - dispatch(i, &state.Gamepad); - } - } else { - controller->connected = true; - controller->lastPacketNumber = state.dwPacketNumber; - emit m_backend->gamepadAdded(i); - dispatch(i, &state.Gamepad); - } - } else { - if (controller->connected) { - controller->connected = false; - emit m_backend->gamepadRemoved(i); - } - } - } - - Sleep(POLL_SLEEP_MS); - } - qCDebug(lcXGB, "XInput thread stopping"); -} - -QXInputGamepadBackend::QXInputGamepadBackend() - : m_thread(0) -{ -} - -bool QXInputGamepadBackend::start() -{ - qCDebug(lcXGB) << "start"; - - m_lib.setFileName(QStringLiteral("xinput1_4.dll")); - if (!m_lib.load()) { - m_lib.setFileName(QStringLiteral("xinput1_3.dll")); - m_lib.load(); - } - - if (m_lib.isLoaded()) { - qCDebug(lcXGB, "Loaded XInput library %s", qPrintable(m_lib.fileName())); - XInputGetState = (XInputGetState_t) m_lib.resolve("XInputGetState"); - if (XInputGetState) { - m_thread = new QXInputThread(this); - m_thread->start(); - } else { - qWarning("Failed to resolve XInputGetState"); - } - } else { - qWarning("Failed to load XInput library %s", qPrintable(m_lib.fileName())); - } - - return m_lib.isLoaded(); -} - -void QXInputGamepadBackend::stop() -{ - qCDebug(lcXGB) << "stop"; - m_thread->signalQuit(); - m_thread->wait(); - XInputGetState = 0; -} - -QT_END_NAMESPACE diff --git a/src/plugins/gamepads/xinput/qxinputgamepadbackend_p.h b/src/plugins/gamepads/xinput/qxinputgamepadbackend_p.h deleted file mode 100644 index 28f5b23..0000000 --- a/src/plugins/gamepads/xinput/qxinputgamepadbackend_p.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Gamepad module -** -** $QT_BEGIN_LICENSE:LGPL3$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QXINPUTGAMEPADBACKEND_P_H -#define QXINPUTGAMEPADBACKEND_P_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QXInputThread; - -class QXInputGamepadBackend : public QGamepadBackend -{ - Q_OBJECT - -public: - QXInputGamepadBackend(); - bool start() override; - void stop() override; - -private: - QXInputThread *m_thread; - QLibrary m_lib; -}; - -QT_END_NAMESPACE - -#endif // QXINPUTGAMEPADBACKEND_P_H diff --git a/src/plugins/gamepads/xinput/xinput.json b/src/plugins/gamepads/xinput/xinput.json deleted file mode 100644 index f8e3fb2..0000000 --- a/src/plugins/gamepads/xinput/xinput.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "xinput" ] -} diff --git a/src/plugins/gamepads/xinput/xinput.pro b/src/plugins/gamepads/xinput/xinput.pro deleted file mode 100644 index 5dac854..0000000 --- a/src/plugins/gamepads/xinput/xinput.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = xinputgamepad -QT += gamepad gamepad-private - -PLUGIN_TYPE = gamepads -PLUGIN_CLASS_NAME = QXInputGamepadBackendPlugin -load(qt_plugin) - -HEADERS += qxinputgamepadbackend_p.h -SOURCES += \ - qxinputgamepadbackend.cpp \ - main.cpp - -OTHER_FILES += \ - xinput.json diff --git a/src/plugins/joystickinputs/CMakeLists.txt b/src/plugins/joystickinputs/CMakeLists.txt new file mode 100644 index 0000000..1641f8f --- /dev/null +++ b/src/plugins/joystickinputs/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# for each platform, add a subdirectory with the platform name +if(ANDROID) + add_subdirectory(android) +endif() +if(MACOS) + add_subdirectory(macos) +endif() +if(IOS) + add_subdirectory(ios) +endif() +if(WIN32) + add_subdirectory(windows) +endif() +if(LINUX) + add_subdirectory(linux) +endif() + +#add_subdirectory(macos) +#add_subdirectory(ios) +#add_subdirectory(windows) diff --git a/src/plugins/joystickinputs/android/CMakeLists.txt b/src/plugins/joystickinputs/android/CMakeLists.txt new file mode 100644 index 0000000..d55aae7 --- /dev/null +++ b/src/plugins/joystickinputs/android/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +set(java_sources + jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java + jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java +) + +qt_internal_add_jar(Qt${QtUniversalInput_VERSION_MAJOR}AndroidJoystickInput + INCLUDE_JARS ${QT_ANDROID_JAR} + SOURCES ${java_sources} + OUTPUT_DIR "${QT_BUILD_DIR}/jar" +) + +qt_path_join(destination ${INSTALL_DATADIR} "jar") + +install_jar(Qt${QtUniversalInput_VERSION_MAJOR}AndroidJoystickInput + DESTINATION ${destination} + COMPONENT Devel +) + + +qt_internal_add_plugin(AndroidJoystickInputPlugin + OUTPUT_NAME androidjoystickinput + PLUGIN_TYPE joystickinputs + DEFAULT_IF ANDROID + SOURCES + androidjoystickinput.cpp androidjoystickinput.h + androidjoystickinputplugin.cpp androidjoystickinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + +) + +set_property( + TARGET + AndroidJoystickInputPlugin + APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES + jar/Qt${QtUniversalInput_VERSION_MAJOR}AndroidJoystickInput.jar +) diff --git a/src/plugins/gamepads/android/src/android.json b/src/plugins/joystickinputs/android/android.json similarity index 100% rename from src/plugins/gamepads/android/src/android.json rename to src/plugins/joystickinputs/android/android.json diff --git a/src/plugins/joystickinputs/android/androidjoystickinput.cpp b/src/plugins/joystickinputs/android/androidjoystickinput.cpp new file mode 100644 index 0000000..861c1d8 --- /dev/null +++ b/src/plugins/joystickinputs/android/androidjoystickinput.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/android/java_godot_lib_jni.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "androidjoystickinput.h" +#include +#include + + + +using namespace QtJniTypes; + +Q_DECLARE_JNI_CLASS(KeyEvent, "android/view/KeyEvent") +Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent") + +static void joyConnectionChanged(JNIEnv *, jclass, int deviceId, bool connected, jstring name) +{ + QUniversalInput::instance()->updateJoyConnection(deviceId, connected, QJniObject(name).toString()); +} +Q_DECLARE_JNI_NATIVE_METHOD(joyConnectionChanged) + +static void joyButton(JNIEnv *, jclass, int deviceId, int button, bool pressed) +{ + qDebug() << "joyButton" << deviceId << button << pressed; + QUniversalInput::instance()->joyButton(deviceId, JoyButton(button), pressed); +} +Q_DECLARE_JNI_NATIVE_METHOD(joyButton) + +static void joyAxis(JNIEnv *, jclass, int deviceId, int axis, float value) +{ + QUniversalInput::instance()->joyAxis(deviceId, JoyAxis(axis), value); +} +Q_DECLARE_JNI_NATIVE_METHOD(joyAxis) + +static void joyHat(JNIEnv *, jclass, int deviceId, int hatX, int hatY) +{ + HatMask hat = HatMask::Center; + if (hatX != 0) { + if (hatX < 0) + hat |= HatMask::Left; + else + hat |= HatMask::Right; + } + if (hatY != 0) { + if (hatY < 0) + hat |= HatMask::Up; + else + hat |= HatMask::Down; + } + + QUniversalInput::instance()->joyHat(deviceId, hat); +} +Q_DECLARE_JNI_NATIVE_METHOD(joyHat) + +QT_BEGIN_NAMESPACE + +const char keyEventClass[] = "android/view/KeyEvent"; +inline int keyField(const char *field) +{ + return QJniObject::getStaticField(keyEventClass, field); +} + + +static void initJNI() +{ + static bool initialized = false; + if (initialized) + return; + initialized = true; + + qWarning() << "initJNI called in Qt Joystick Input Handler"; + + if (!QtJoystickInputHandler::registerNativeMethods({ + Q_JNI_NATIVE_METHOD(joyConnectionChanged), + Q_JNI_NATIVE_METHOD(joyButton), + Q_JNI_NATIVE_METHOD(joyAxis), + Q_JNI_NATIVE_METHOD(joyHat)})) + qCritical("Failed to register native methods for QtJoystickInputHandler"); +} + +AndroidJoystickInput::AndroidJoystickInput() +{ + initJNI(); + m_qtJoystickInputHandler = QtJoystickInputHandler(QtAndroidPrivate::activity()); + QtAndroidPrivate::registerGenericMotionEventListener(this); + QtAndroidPrivate::registerKeyEventListener(this); + start(); +} + +AndroidJoystickInput::~AndroidJoystickInput() +{ + stop(); + QtAndroidPrivate::unregisterGenericMotionEventListener(this); + QtAndroidPrivate::unregisterKeyEventListener(this); +} + +bool AndroidJoystickInput::handleKeyEvent(jobject event) +{ + static int ACTION_DOWN = keyField("ACTION_DOWN"); + static int ACTION_UP = keyField("ACTION_UP"); + QJniObject ev(event); + + // Pass the event to the QtJoystickInputHandler Java class. + if (m_qtJoystickInputHandler.isValid()) { + const int keyCode = ev.callMethod("getKeyCode", "()I"); + const int action = ev.callMethod("getAction", "()I"); + + if (action == ACTION_UP) + return m_qtJoystickInputHandler.callMethod("onKeyUp", keyCode, KeyEvent(event)); + else if (action == ACTION_DOWN) + return m_qtJoystickInputHandler.callMethod("onKeyDown", keyCode, KeyEvent(event)); + } + + return false; +} + +bool AndroidJoystickInput::handleGenericMotionEvent(jobject event) +{ + if (m_qtJoystickInputHandler.isValid()) + return m_qtJoystickInputHandler.callMethod("onGenericMotionEvent", MotionEvent(event)); + + return false; +} + +void AndroidJoystickInput::start() +{ + if (QtAndroidPrivate::androidSdkVersion() >= 16) + m_qtJoystickInputHandler.callMethod("register", jlong(this)); +} + +void AndroidJoystickInput::stop() +{ + if (QtAndroidPrivate::androidSdkVersion() >= 16) + m_qtJoystickInputHandler.callMethod("unregister"); +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/android/androidjoystickinput.h b/src/plugins/joystickinputs/android/androidjoystickinput.h new file mode 100644 index 0000000..d79fb43 --- /dev/null +++ b/src/plugins/joystickinputs/android/androidjoystickinput.h @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef ANDROIDJOYSTICKINPUT_H +#define ANDROIDJOYSTICKINPUT_H + +#include +#include +#include +#include +#include + +Q_DECLARE_JNI_CLASS(QtJoystickInputHandler, "org/qtproject/qt/android/universalinput/QtJoystickInputHandler"); + +QT_BEGIN_NAMESPACE + +class AndroidJoystickInput : public QJoystickInput, public QtAndroidPrivate::GenericMotionEventListener, public QtAndroidPrivate::KeyEventListener +{ + Q_OBJECT +public: + AndroidJoystickInput(); + ~AndroidJoystickInput(); + + // KeyEventListener interface + bool handleKeyEvent(jobject event) override; + + // GenericMotionEventListener interface + bool handleGenericMotionEvent(jobject event) override; + +private: + void start(); + void stop(); + + QtJniTypes::QtJoystickInputHandler m_qtJoystickInputHandler; +}; + +QT_END_NAMESPACE + +#endif // ANDROIDJOYSTICKINPUT_H diff --git a/src/plugins/joystickinputs/android/androidjoystickinputplugin.cpp b/src/plugins/joystickinputs/android/androidjoystickinputplugin.cpp new file mode 100644 index 0000000..7fc2440 --- /dev/null +++ b/src/plugins/joystickinputs/android/androidjoystickinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "androidjoystickinputplugin.h" +#include "androidjoystickinput.h" + +QT_BEGIN_NAMESPACE + +QJoystickInput *AndroidJoystickInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("android")) + return new AndroidJoystickInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/android/androidjoystickinputplugin.h b/src/plugins/joystickinputs/android/androidjoystickinputplugin.h new file mode 100644 index 0000000..a39c440 --- /dev/null +++ b/src/plugins/joystickinputs/android/androidjoystickinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef ANDROIDJOYSTICKINPUTPLUGIN_H +#define ANDROIDJOYSTICKINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class AndroidJoystickInputPlugin : public QJoystickInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QJoystickInputFactoryInterface_iid FILE "android.json") + +public: + QJoystickInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // ANDROIDJOYSTICKINPUTPLUGIN_H diff --git a/src/plugins/joystickinputs/android/jar/AndroidManifest.xml b/src/plugins/joystickinputs/android/jar/AndroidManifest.xml new file mode 100644 index 0000000..4636623 --- /dev/null +++ b/src/plugins/joystickinputs/android/jar/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + diff --git a/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java b/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java new file mode 100644 index 0000000..29a39d6 --- /dev/null +++ b/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java @@ -0,0 +1,28 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +package org.qtproject.qt.android.universalinput; + +import android.util.SparseArray; + +import java.util.ArrayList; +import java.util.List; + +class Joystick { + int device_id; + String name; + List axes = new ArrayList<>(); + protected boolean hasAxisHat = false; + /* + * Keep track of values so we can prevent flooding the engine with useless events. + */ + protected final SparseArray axesValues = new SparseArray<>(4); + protected int hatX; + protected int hatY; +} diff --git a/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java b/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java new file mode 100644 index 0000000..b57f34b --- /dev/null +++ b/src/plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java @@ -0,0 +1,308 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +package org.qtproject.qt.android.universalinput; + +import android.app.Activity; +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.Build; +import android.util.Log; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class QtJoystickInputHandler implements InputManager.InputDeviceListener { + + private final SparseIntArray m_joystickIds = new SparseIntArray(4); + private final SparseArray m_joystickDevices = new SparseArray<>(4); + private final InputManager m_inputManager; + Activity m_activity; + private long m_nativePtr = 0; + + public QtJoystickInputHandler(Activity activity) { + m_activity = activity; + m_inputManager = (InputManager)activity.getSystemService(Context.INPUT_SERVICE); + } + + public void register(long nativePtr) + { + synchronized (this) { + if (m_inputManager != null) { + m_nativePtr = nativePtr; + m_activity.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + m_inputManager.registerInputDeviceListener(QtJoystickInputHandler.this, null); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + initInputDevices(); + } + } + } + + public void unregister() + { + synchronized (this) { + if (m_inputManager != null) { + m_nativePtr = 0; + m_inputManager.unregisterInputDeviceListener(this); + } + } + } + + private boolean isKeyEventGameDevice(int source) { + if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) + return false; + return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; + } + + public boolean onKeyUp(final int keyCode, KeyEvent event) { + int source = event.getSource(); + if (isKeyEventGameDevice(source)) { + // Check if the device exists + final int deviceId = event.getDeviceId(); + if (m_joystickIds.indexOfKey(deviceId) >= 0) { + final int button = getButtonValue(keyCode); + final int joyId = m_joystickIds.get(deviceId); + joyButton(joyId, button, false); + return true; + } + } + + return false; + } + + public boolean onKeyDown(final int keyCode, KeyEvent event) { + int source = event.getSource(); + final int deviceId = event.getDeviceId(); + // Check if source is a game device and that the device is a registered gamepad + if (isKeyEventGameDevice(source)) { + if (event.getRepeatCount() > 0) // ignore key echo + return true; + + if (m_joystickIds.indexOfKey(deviceId) >= 0) { + final int button = getButtonValue(keyCode); + final int joyId = m_joystickIds.get(deviceId); + joyButton(joyId, button, true); + return true; + } + } + + return false; + } + + public boolean onGenericMotionEvent(MotionEvent event) { + if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) { + // Check if the device exists + final int deviceId = event.getDeviceId(); + if (m_joystickIds.indexOfKey(deviceId) >= 0) { + final int joyId = m_joystickIds.get(deviceId); + Joystick joystick = m_joystickDevices.get(deviceId); + if (joystick == null) { + return true; + } + + for (int i = 0; i < joystick.axes.size(); i++) { + final int axis = joystick.axes.get(i); + final float value = event.getAxisValue(axis); + /* + As all axes are polled for each event, only fire an axis event if the value has actually changed. + Prevents flooding Godot with repeated events. + */ + if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) { + // save value to prevent repeats + joystick.axesValues.put(axis, value); + joyAxis(joyId, i, value); + } + } + + if (joystick.hasAxisHat) { + final int hatX = Math.round(event.getAxisValue(MotionEvent.AXIS_HAT_X)); + final int hatY = Math.round(event.getAxisValue(MotionEvent.AXIS_HAT_Y)); + if (joystick.hatX != hatX || joystick.hatY != hatY) { + joystick.hatX = hatX; + joystick.hatY = hatY; + joyHat(joyId, hatX, hatY); + } + } + return true; + } + } + + return false; + } + + public void initInputDevices() { + int[] deviceIds = m_inputManager.getInputDeviceIds(); + for (int deviceId : deviceIds) { + InputDevice device = m_inputManager.getInputDevice(deviceId); + onInputDeviceAdded(deviceId); + } + } + + private int assignJoystickIdNumber(int deviceId) { + int joyId = 0; + while (m_joystickIds.indexOfValue(joyId) >= 0) { + joyId++; + } + m_joystickIds.put(deviceId, joyId); + return joyId; + } + + @Override + public void onInputDeviceAdded(int deviceId) { + // Check if the device has not been already added + + if (m_joystickIds.indexOfKey(deviceId) >= 0) { + return; + } + + InputDevice device = m_inputManager.getInputDevice(deviceId); + //device can be null if deviceId is not found + if (device == null) { + return; + } + + int sources = device.getSources(); + + // Device may not be a joystick or gamepad + if ((sources & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD && + (sources & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK) { + return; + } + + // Assign first available number. Re-use numbers where possible. + final int id = assignJoystickIdNumber(deviceId); + + final Joystick joystick = new Joystick(); + joystick.device_id = deviceId; + joystick.name = device.getName(); + + Set already = new HashSet<>(); + for (InputDevice.MotionRange range : device.getMotionRanges()) { + boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK); + boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD); + if (!isJoystick && !isGamepad) { + continue; + } + final int axis = range.getAxis(); + if (axis == MotionEvent.AXIS_HAT_X || axis == MotionEvent.AXIS_HAT_Y) { + joystick.hasAxisHat = true; + } else { + if (!already.contains(axis)) { + already.add(axis); + joystick.axes.add(axis); + } + } + } + Collections.sort(joystick.axes); + m_joystickDevices.put(deviceId, joystick); + + joyConnectionChanged(id, true, joystick.name); + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + // Check if the device has not been already removed + if (m_joystickIds.indexOfKey(deviceId) < 0) { + return; + } + final int joyId = m_joystickIds.get(deviceId); + m_joystickIds.delete(deviceId); + m_joystickDevices.delete(deviceId); + joyConnectionChanged(joyId, false, ""); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + onInputDeviceRemoved(deviceId); + onInputDeviceAdded(deviceId); + } + + public static int getButtonValue(int keyCode) { + int button; + switch (keyCode) { + case KeyEvent.KEYCODE_BUTTON_A: + button = 0; + break; + case KeyEvent.KEYCODE_BUTTON_B: + button = 1; + break; + case KeyEvent.KEYCODE_BUTTON_X: + button = 2; + break; + case KeyEvent.KEYCODE_BUTTON_Y: + button = 3; + break; + case KeyEvent.KEYCODE_BUTTON_L1: + button = 9; + break; + case KeyEvent.KEYCODE_BUTTON_L2: + button = 15; + break; + case KeyEvent.KEYCODE_BUTTON_R1: + button = 10; + break; + case KeyEvent.KEYCODE_BUTTON_R2: + button = 16; + break; + case KeyEvent.KEYCODE_BUTTON_SELECT: + button = 4; + break; + case KeyEvent.KEYCODE_BUTTON_START: + button = 6; + break; + case KeyEvent.KEYCODE_BUTTON_THUMBL: + button = 7; + break; + case KeyEvent.KEYCODE_BUTTON_THUMBR: + button = 8; + break; + case KeyEvent.KEYCODE_DPAD_UP: + button = 11; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + button = 12; + break; + case KeyEvent.KEYCODE_DPAD_LEFT: + button = 13; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + button = 14; + break; + case KeyEvent.KEYCODE_BUTTON_C: + button = 17; + break; + case KeyEvent.KEYCODE_BUTTON_Z: + button = 18; + break; + + default: + button = keyCode - KeyEvent.KEYCODE_BUTTON_1 + 20; + break; + } + return button; + } + + private static native void joyConnectionChanged(int id, boolean connected, String name); + private static native void joyButton(int id, int button, boolean pressed); + private static native void joyAxis(int id, int axis, float value); + private static native void joyHat(int id, int hatX, int hatY); +} diff --git a/src/plugins/joystickinputs/ios/CMakeLists.txt b/src/plugins/joystickinputs/ios/CMakeLists.txt new file mode 100644 index 0000000..6ee106c --- /dev/null +++ b/src/plugins/joystickinputs/ios/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(IosJoystickInputPlugin + OUTPUT_NAME iosjoystickinput + PLUGIN_TYPE joystickinputs + SOURCES + iosjoystickinput.mm iosjoystickinput.h + iosjoystickinputplugin.cpp iosjoystickinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + ${FWFoundation} + ${FWGameController} +) diff --git a/src/plugins/joystickinputs/ios/ios.json b/src/plugins/joystickinputs/ios/ios.json new file mode 100644 index 0000000..f0b766d --- /dev/null +++ b/src/plugins/joystickinputs/ios/ios.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "ios" ] +} diff --git a/src/plugins/joystickinputs/ios/iosjoystickinput.h b/src/plugins/joystickinputs/ios/iosjoystickinput.h new file mode 100644 index 0000000..e1cf1c0 --- /dev/null +++ b/src/plugins/joystickinputs/ios/iosjoystickinput.h @@ -0,0 +1,27 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef IOSJOYSTICKINPUT_H +#define IOSJOYSTICKINPUT_H + +#include +#include + +Q_FORWARD_DECLARE_OBJC_CLASS(JoypadIOSObserver); + +QT_BEGIN_NAMESPACE + +class IosJoystickInput : public QJoystickInput{ +public: + IosJoystickInput(); + ~IosJoystickInput(); + + void startProcessing(); + +private: + JoypadIOSObserver *m_observer; +}; + +QT_END_NAMESPACE + +#endif // IOSJOYSTICKINPUT_H diff --git a/src/plugins/joystickinputs/ios/iosjoystickinput.mm b/src/plugins/joystickinputs/ios/iosjoystickinput.mm new file mode 100644 index 0000000..218f195 --- /dev/null +++ b/src/plugins/joystickinputs/ios/iosjoystickinput.mm @@ -0,0 +1,318 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/ios/joypad_ios.mm" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "iosjoystickinput.h" + +#import + +@interface JoypadIOSObserver : NSObject + +- (void)startObserving; +- (void)startProcessing; +- (void)finishObserving; + +@property(assign, nonatomic) BOOL isObserving; +@property(assign, nonatomic) BOOL isProcessing; +@property(strong, nonatomic) NSMutableDictionary *connectedJoypads; +@property(strong, nonatomic) NSMutableArray *joypadsQueue; + +@end + +@implementation JoypadIOSObserver + +- (instancetype)init +{ + self = [super init]; + + if (self) { + self.isObserving = NO; + self.isProcessing = NO; + } + + return self; +} + +- (void)startProcessing +{ + self.isProcessing = YES; + + for (GCController *controller in self.joypadsQueue) { + [self addiOSJoypad:controller]; + } + + [self.joypadsQueue removeAllObjects]; +} + +- (void)startObserving +{ + if (self.isObserving) + return; + + self.isObserving = YES; + + self.connectedJoypads = [NSMutableDictionary dictionary]; + self.joypadsQueue = [NSMutableArray array]; + + // get told when controllers connect, this will be called right away for + // already connected controllers + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(controllerWasConnected:) + name:GCControllerDidConnectNotification + object:nil]; + + // get told when controllers disconnect + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(controllerWasDisconnected:) + name:GCControllerDidDisconnectNotification + object:nil]; +} + +- (void)finishObserving +{ + if (self.isObserving) + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + self.isObserving = NO; + self.isProcessing = NO; + + self.connectedJoypads = nil; + self.joypadsQueue = nil; +} + +- (void)dealloc +{ + [self finishObserving]; + [super dealloc]; +} + +- (int)getJoyIdForController:(GCController *)controller +{ + NSArray *keys = [self.connectedJoypads allKeysForObject:controller]; + + for (NSNumber *key in keys) { + int joy_id = [key intValue]; + return joy_id; + } + + return -1; +} + +- (void)addiOSJoypad:(GCController *)controller +{ + // get a new id for our controller + int joy_id = QUniversalInput::instance()->getUnusedJoyId(); + + if (joy_id == -1) { + printf("Couldn't retrieve new joy id\n"); + return; + } + + // assign our player index + if (controller.playerIndex == GCControllerPlayerIndexUnset) + controller.playerIndex = [self getFreePlayerIndex]; + + + // Report the new controller + QUniversalInput::instance()->updateJoyConnection(joy_id, true, QString::fromUtf8([controller.vendorName UTF8String])); + + // add it to our dictionary, this will retain our controllers + [self.connectedJoypads setObject:controller forKey:[NSNumber numberWithInt:joy_id]]; + + // set our input handler + [self setControllerInputHandler:controller]; +} + +- (void)controllerWasConnected:(NSNotification *)notification +{ + // get our controller + GCController *controller = (GCController *)notification.object; + + if (!controller) { + printf("Couldn't retrieve new controller\n"); + return; + } + + if ([[self.connectedJoypads allKeysForObject:controller] count] > 0) { + printf("Controller is already registered\n"); + } else if (!self.isProcessing) { + [self.joypadsQueue addObject:controller]; + } else { + [self addiOSJoypad:controller]; + } +} + +- (void)controllerWasDisconnected:(NSNotification *)notification +{ + // find our joystick, there should be only one in our dictionary + GCController *controller = (GCController *)notification.object; + + if (!controller) + return; + + NSArray *keys = [self.connectedJoypads allKeysForObject:controller]; + for (NSNumber *key in keys) { + // Report this joystick is no longer there + int joy_id = [key intValue]; + QUniversalInput::instance()->updateJoyConnection(joy_id, false, ""); + + // and remove it from our dictionary + [self.connectedJoypads removeObjectForKey:key]; + } +} + +- (GCControllerPlayerIndex)getFreePlayerIndex { + bool have_player_1 = false; + bool have_player_2 = false; + bool have_player_3 = false; + bool have_player_4 = false; + + if (self.connectedJoypads == nil) { + NSArray *keys = [self.connectedJoypads allKeys]; + for (NSNumber *key in keys) { + GCController *controller = [self.connectedJoypads objectForKey:key]; + if (controller.playerIndex == GCControllerPlayerIndex1) { + have_player_1 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex2) { + have_player_2 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex3) { + have_player_3 = true; + } else if (controller.playerIndex == GCControllerPlayerIndex4) { + have_player_4 = true; + } + } + } + + if (!have_player_1) { + return GCControllerPlayerIndex1; + } else if (!have_player_2) { + return GCControllerPlayerIndex2; + } else if (!have_player_3) { + return GCControllerPlayerIndex3; + } else if (!have_player_4) { + return GCControllerPlayerIndex4; + } else { + return GCControllerPlayerIndexUnset; + } +} + +- (void)setControllerInputHandler:(GCController *)controller +{ + // Hook in the callback handler for the correct gamepad profile. + // This is a bit of a weird design choice on Apples part. + // You need to select the most capable gamepad profile for the + // gamepad attached. + if (controller.extendedGamepad != nil) { + // The extended gamepad profile has all the input you could possibly find on + // a gamepad but will only be active if your gamepad actually has all of + // these... + + controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { + + int joy_id = [self getJoyIdForController:controller]; + + if (element == gamepad.buttonA) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::A, + gamepad.buttonA.isPressed); + } else if (element == gamepad.buttonB) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::B, + gamepad.buttonB.isPressed); + } else if (element == gamepad.buttonX) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::X, + gamepad.buttonX.isPressed); + } else if (element == gamepad.buttonY) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::Y, + gamepad.buttonY.isPressed); + } else if (element == gamepad.leftShoulder) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::LeftShoulder, + gamepad.leftShoulder.isPressed); + } else if (element == gamepad.rightShoulder) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::RightShoulder, + gamepad.rightShoulder.isPressed); + } else if (element == gamepad.dpad) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadUp, + gamepad.dpad.up.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadDown, + gamepad.dpad.down.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadLeft, + gamepad.dpad.left.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadRight, + gamepad.dpad.right.isPressed); + } + + if (element == gamepad.leftThumbstick) { + float value = gamepad.leftThumbstick.xAxis.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::LeftX, value); + value = -gamepad.leftThumbstick.yAxis.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::LeftY, value); + } else if (element == gamepad.rightThumbstick) { + float value = gamepad.rightThumbstick.xAxis.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::RightX, value); + value = -gamepad.rightThumbstick.yAxis.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::RightY, value); + } else if (element == gamepad.leftTrigger) { + float value = gamepad.leftTrigger.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::TriggerLeft, value); + } else if (element == gamepad.rightTrigger) { + float value = gamepad.rightTrigger.value; + QUniversalInput::instance()->joyAxis(joy_id, JoyAxis::TriggerRight, value); + } + }; + } else if (controller.microGamepad != nil) { + // micro gamepads were added in OS 9 and feature just 2 buttons and a d-pad + + controller.microGamepad.valueChangedHandler = ^(GCMicroGamepad *gamepad, GCControllerElement *element) { + + int joy_id = [self getJoyIdForController:controller]; + + if (element == gamepad.buttonA) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::A, + gamepad.buttonA.isPressed); + } else if (element == gamepad.buttonX) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::X, + gamepad.buttonX.isPressed); + } else if (element == gamepad.dpad) { + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadUp, + gamepad.dpad.up.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadDown, + gamepad.dpad.down.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadLeft, gamepad.dpad.left.isPressed); + QUniversalInput::instance()->joyButton(joy_id, JoyButton::DpadRight, gamepad.dpad.right.isPressed); + } + }; + } +} + +@end + +QT_BEGIN_NAMESPACE + +IosJoystickInput::IosJoystickInput() +{ + m_observer = [[JoypadIOSObserver alloc] init]; + [m_observer startObserving]; + startProcessing(); +} + +IosJoystickInput::~IosJoystickInput() +{ + if (m_observer) { + [m_observer finishObserving]; + m_observer = nil; + } +} + +void IosJoystickInput::startProcessing() +{ + if (m_observer) + [m_observer startProcessing]; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/ios/iosjoystickinputplugin.cpp b/src/plugins/joystickinputs/ios/iosjoystickinputplugin.cpp new file mode 100644 index 0000000..7952f87 --- /dev/null +++ b/src/plugins/joystickinputs/ios/iosjoystickinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "iosjoystickinputplugin.h" +#include "iosjoystickinput.h" + +QT_BEGIN_NAMESPACE + +QJoystickInput *IosJoystickInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("ios")) + return new IosJoystickInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/ios/iosjoystickinputplugin.h b/src/plugins/joystickinputs/ios/iosjoystickinputplugin.h new file mode 100644 index 0000000..c4e04f0 --- /dev/null +++ b/src/plugins/joystickinputs/ios/iosjoystickinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef IOSJOYSTICKINPUTPLUGIN_H +#define IOSJOYSTICKINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class IosJoystickInputPlugin : public QJoystickInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QJoystickInputFactoryInterface_iid FILE "ios.json") + +public: + QJoystickInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // IOSJOYSTICKINPUTPLUGIN_H diff --git a/src/plugins/joystickinputs/linux/CMakeLists.txt b/src/plugins/joystickinputs/linux/CMakeLists.txt new file mode 100644 index 0000000..7bc01e9 --- /dev/null +++ b/src/plugins/joystickinputs/linux/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(LinuxJoystickInputPlugin + OUTPUT_NAME linuxjoystickinput + PLUGIN_TYPE joystickinputs + SOURCES + linuxjoystickinput.cpp linuxjoystickinput.h + linuxjoystickinputplugin.cpp linuxjoystickinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + # todo: do the dependency check in cmake + udev +) diff --git a/src/plugins/joystickinputs/linux/linux.json b/src/plugins/joystickinputs/linux/linux.json new file mode 100644 index 0000000..8165d39 --- /dev/null +++ b/src/plugins/joystickinputs/linux/linux.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "linux" ] +} diff --git a/src/plugins/joystickinputs/linux/linuxjoystickinput.cpp b/src/plugins/joystickinputs/linux/linuxjoystickinput.cpp new file mode 100644 index 0000000..321c62f --- /dev/null +++ b/src/plugins/joystickinputs/linux/linuxjoystickinput.cpp @@ -0,0 +1,453 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/linuxbsd/joypad_linux.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "linuxjoystickinput.h" + +#include + +#include +#include +#include +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +QT_BEGIN_NAMESPACE + +// GODOT begin +#define LONG_BITS (sizeof(long) * 8) +#define NBITS(x) ((((x)-1) / LONG_BITS) + 1) +#define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0) + +static QString ignore_str = u"js"_s; +// GODOT end + +LinuxJoystickInput::LinuxJoystickInput() + : m_udev(nullptr) +{ + m_udev = udev_new(); + if (!m_udev) { + qWarning() << "Could not initialize udev"; + m_udev = nullptr; // ensure udev is nullptr + } + + probeJoypads(); + + m_elapsedTimer.start(); + + // ### Replace with Thread later + startTimer(1); +} + +LinuxJoystickInput::~LinuxJoystickInput() +{ + if (m_udev) + udev_unref(m_udev); + + m_udev = nullptr; +} + +void LinuxJoystickInput::probeJoypads() +{ + if (!m_udev) { + qWarning() << "Could not probe joypads, udev is not initialized"; + return; + } + + struct udev_enumerate *enumerate = udev_enumerate_new(m_udev); + udev_enumerate_add_match_subsystem(enumerate, "input"); + + udev_enumerate_scan_devices(enumerate); + struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); + struct udev_list_entry *entry = nullptr; + udev_list_entry_foreach(entry, devices) { + const char *path = udev_list_entry_get_name(entry); + udev_device *dev = udev_device_new_from_syspath(m_udev, path); + // QString action = udev_device_get_action(dev); + const char *devnode = udev_device_get_devnode(dev); + + if (devnode) { + QString devnode_str = devnode; + + // check if exists + if (std::find(m_attached_devices.begin(), m_attached_devices.end(), devnode_str) != m_attached_devices.end()) + continue; + + if (!devnode_str.contains(ignore_str)) + setupJoypadObject(devnode_str); + } + + udev_device_unref(dev); + } + udev_enumerate_unref(enumerate); +} + +static inline uint16_t BSWAP16(uint16_t x) +{ + return (x >> 8) | (x << 8); +} + +static inline QString _hex_str(QChar c) +{ + QString str; + str = QString("%1").arg(c.unicode(), 0, 16); + return str; +} + +void LinuxJoystickInput::setupJoypadObject(const QString &device) +{ + auto input = QUniversalInput::instance(); + int id = input->getUnusedJoyId(); + if (id == -1) { + qWarning() << "Could not find unused joypad"; + return; + } + + // GODOT begin ; dont know what is godot and what is ours now + // tries to open the device to check if it's a joystick + int fd = open(device.toUtf8().constData(), O_RDWR | O_NONBLOCK); + if (fd == -1) { + // qWarning() << "Could not open device" << device << "for reading"; + // race condition? the only one that can be opened is xbox360 controller + return; + } + + unsigned long evbit[NBITS(EV_MAX)] = { 0 }; + unsigned long keybit[NBITS(MAX_KEY)] = { 0 }; + unsigned long absbit[NBITS(MAX_ABS)] = { 0 }; + + // add to attached devices so we don't try to open it again + m_attached_devices.push_back(device); + + if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || + (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || + (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { + close(fd); + return; + } + + // Check if the device supports basic gamepad events + bool has_abs_left = (test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit)); + bool has_abs_right = (test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit)); + if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && (has_abs_left || has_abs_right))) { + close(fd); + return; + } + + char namebuf[128]; + QString name = ""; + if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) + name = namebuf; + + + input_id inpid; + if (ioctl(fd, EVIOCGID, &inpid) < 0) { + close(fd); + return; + } + + // reset gamepad + m_joypads[id] = gamepad(); + auto& joy = m_joypads[id]; + joy.fd = fd; + joy.devpath = QString(device); + joy.attached = true; + joy.id = id; + joy.vibrating = false; + + setupJoypadProperties(&joy); + + char uid[64]; + sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0); + if (inpid.vendor && inpid.product && inpid.version) { + uint16_t vendor = BSWAP16(inpid.vendor); + uint16_t product = BSWAP16(inpid.product); + uint16_t version = BSWAP16(inpid.version); + + sprintf(uid + QString(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0); + input->updateJoyConnection(id, true, "Udev Joypad", uid); + } else { + QString uidname = uid; + int uidlen = std::min((int)name.length(), 11); + for (int i = 0; i < uidlen; i++) { + uidname = uidname + _hex_str(name[i]); + } + uidname += "00"; + input->updateJoyConnection(id, true, "Udev Joypad", uidname); + } + + // GODOT end +} + +void LinuxJoystickInput::setupJoypadProperties(gamepad* joy) +{ + // GODOT begin + unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; + unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; + + int num_buttons = 0; + int num_axes = 0; + + if ((ioctl(joy->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || + (ioctl(joy->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { + return; + } + for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) + if (test_bit(i, keybit)) + joy->key_map[i] = num_buttons++; + + for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) + if (test_bit(i, keybit)) + joy->key_map[i] = num_buttons++; + + for (int i = 0; i < ABS_MISC; ++i) { + /* Skip hats */ + if (i == ABS_HAT0X) { + i = ABS_HAT3Y; + continue; + } + if (test_bit(i, absbit)) { + joy->joy_axis[i] = num_axes++; + joy->abs_info[i] = new input_absinfo; + if (ioctl(joy->fd, EVIOCGABS(i), joy->abs_info[i]) < 0) { + delete joy->abs_info[i]; + joy->abs_info[i] = nullptr; + } + } + } + + joy->force_feedback = false; + unsigned long ffbit[NBITS(FF_CNT)]; + if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) + if (test_bit(FF_RUMBLE, ffbit)) + joy->force_feedback = true; + + + // GODOT end +} + +void LinuxJoystickInput::closeJoypads() +{ + for (int i = 0; i < JOYPADS_MAX; i++) { + gamepad &joypad = m_joypads[i]; + closeJoypad(joypad, i); + } +} + +void LinuxJoystickInput::closeJoypad(const char *p_devpath) +{ + for (int i = 0; i < JOYPADS_MAX; i++) { + gamepad &joypad = m_joypads[i]; + if (m_joypads[i].devpath == p_devpath) + closeJoypad(joypad, i); + } +} + +void LinuxJoystickInput::closeJoypad(gamepad &p_joypad, int p_id) +{ + auto input = QUniversalInput::instance(); + + if (p_joypad.fd != -1) { + close(p_joypad.fd); + p_joypad.fd = -1; + m_attached_devices.erase(std::find(m_attached_devices.begin(), m_attached_devices.end(), p_joypad.devpath)); + input->updateJoyConnection(p_id, false, ""); + } +} + +static inline float axisCorrect(int value, int min, int max) +{ + return 2.0f * (value - min) / (max - min) - 1.0f; +} + +void LinuxJoystickInput::processJoypads() +{ + auto input = QUniversalInput::instance(); + + for (int i = 0; i < JOYPADS_MAX; i++) { + gamepad& joy = m_joypads[i]; + if (!joy.attached) + continue; + + // get joypad events + input_event event; + std::vector events; + while (read(joy.fd, &event, sizeof(event)) > 0) { + events.push_back(event); + } + + if (errno != EAGAIN) { + closeJoypad(joy, i); + continue; + } + + // GODOT begin + + for (const auto& event : events) { + // event may be tainted and out of MAX_KEY range, which will cause + // joy.key_map[event.code] to crash + if (event.code >= MAX_KEY) { + qDebug() << "Joypad event code out of range:" << event.code; + continue; + } + + switch (event.type) { + case EV_KEY: + input->joyButton(joy.id, (JoyButton)joy.key_map[event.code], event.value); + break; + + case EV_ABS: + switch (event.code) { + case ABS_HAT0X: + if (event.value != 0) { + if (event.value < 0) { + joy.dpad = HatMask::Left; + } else { + joy.dpad = HatMask::Right; + } + } else { + joy.dpad = HatMask::Center; + } + input->joyHat(i, joy.dpad); + break; + + case ABS_HAT0Y: + if (event.value != 0) { + if (event.value < 0) { + joy.dpad = HatMask::Up; + } else { + joy.dpad = HatMask::Down; + } + } else { + joy.dpad = HatMask::Center; + } + input->joyHat(i, joy.dpad); + break; + + default: + if (event.code >= MAX_ABS) { + continue; + } + if (joy.abs_info[event.code]) { + // using the min/max values from the device + auto min = joy.abs_info[event.code]->minimum; + auto max = joy.abs_info[event.code]->maximum; + + float value = event.value; + value = axisCorrect(value, min, max); + + JoyAxis axis = JoyAxis::Invalid; + + switch (event.code) { + case ABS_X: + axis = JoyAxis::LeftX; + break; + case ABS_Y: + axis = JoyAxis::LeftY; + break; + case ABS_RX: + axis = JoyAxis::RightX; + break; + case ABS_RY: + axis = JoyAxis::RightY; + break; + case ABS_Z: + axis = JoyAxis::TriggerLeft; + break; + case ABS_RZ: + axis = JoyAxis::TriggerRight; + break; + } + + input->joyAxis(joy.id, axis, value); + } + break; + } + break; + } + } + + if (joy.force_feedback) { + uint64_t timestamp = input->getJoyVibrationTimestamp(joy.id); + float duration = input->getJoyVibrationDuration(joy.id) * 1000.f; + QVector2D strength = input->getJoyVibrationStrength(joy.id); + uint64_t currentTimestamp = QDateTime::currentMSecsSinceEpoch(); + if (currentTimestamp - timestamp <= duration) { + if (!joy.vibrating) + joypadVibrationStart(joy, strength.x(), strength.y(), duration, timestamp); + } else if (joy.vibrating) { + joypadVibrationStop(joy, 0); + } + } + + // GODOT end + } +} + +void LinuxJoystickInput::joypadVibrationStart(gamepad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) +{ + // GODOT start + + if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) + return; + + if (p_joypad.ff_effect_id != -1) + joypadVibrationStop(p_joypad, p_timestamp); + + struct ff_effect effect; + effect.type = FF_RUMBLE; + effect.id = -1; + effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff); + effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff); + effect.replay.length = floor(p_duration); + effect.replay.delay = 0; + + if (ioctl(p_joypad.fd, EVIOCSFF, &effect) < 0) + return; + + struct input_event play; + play.type = EV_FF; + play.code = effect.id; + play.value = 1; + if (write(p_joypad.fd, (const void *)&play, sizeof(play)) == -1) + qWarning() << "Couldn't write to Joypad device."; + + p_joypad.ff_effect_id = effect.id; + + // GODOT end +} + +void LinuxJoystickInput::joypadVibrationStop(gamepad &p_joypad, uint64_t p_timestamp) +{ + Q_UNUSED(p_timestamp); + + // GODOT start + if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_joypad.ff_effect_id == -1) + return; + + if (ioctl(p_joypad.fd, EVIOCRMFF, p_joypad.ff_effect_id) < 0) { + return; + } + + p_joypad.ff_effect_id = -1; + p_joypad.vibrating = false; + // GODOT end +} + +void LinuxJoystickInput::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + probeJoypads(); + processJoypads(); +} + + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/linux/linuxjoystickinput.h b/src/plugins/joystickinputs/linux/linuxjoystickinput.h new file mode 100644 index 0000000..a6cc278 --- /dev/null +++ b/src/plugins/joystickinputs/linux/linuxjoystickinput.h @@ -0,0 +1,101 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/linuxbsd/joypad_linux.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef LINUXJOYSTICKINPUT_H +#define LINUXJOYSTICKINPUT_H + +#include + +#include +#include +#include + +#include + +// for JoypadEvent +#include +#include + +struct udev; +struct input_absinfo; + +QT_BEGIN_NAMESPACE + +class LinuxJoystickInput : public QJoystickInput +{ + Q_OBJECT +public: + LinuxJoystickInput(); + ~LinuxJoystickInput(); + + void probeJoypads(); + void processJoypads(); + +protected: + void timerEvent(QTimerEvent *event) override; + +private: + enum { + JOYPADS_MAX = 16, + JOY_AXIS_COUNT = 6, + MIN_JOY_AXIS = 10, + MAX_JOY_AXIS = 32768, + MAX_JOY_BUTTONS = 128, + KEY_EVENT_BUFFER_SIZE = 512, + MAX_TRIGGER = 1023, // was 255, but xbox one controller max is 1023 + + // from godot linux_joystick.h + MAX_ABS = 63, + MAX_KEY = 767, // Hack because can't be included here + }; + + struct gamepad { + int id; + bool attached; + bool confirmed; + int key_map[MAX_KEY]; + int joy_axis[JOY_AXIS_COUNT]; + + HatMask dpad; + + int fd; + QString devpath; + + input_absinfo *abs_info[MAX_ABS] = {}; + + bool force_feedback; + int ff_effect_id; + bool vibrating = false; + + gamepad() { + id = -1; + attached = false; + confirmed = false; + fd = -1; + } + }; + + void setupJoypadObject(const QString& name); + void setupJoypadProperties(gamepad* joy); + void closeJoypads(); + void closeJoypad(const char *p_devpath); + void closeJoypad(gamepad &p_joypad, int p_id); + + void joypadVibrationStart(gamepad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); + void joypadVibrationStop(gamepad &p_joypad, uint64_t p_timestamp); + + struct udev *m_udev = nullptr; + gamepad m_joypads[JOYPADS_MAX]; // joypad joystick gamestick tomatoe potatoe + std::vector m_attached_devices; + QElapsedTimer m_elapsedTimer; +}; + +QT_END_NAMESPACE + +#endif // LINUXJOYSTICKINPUT_H diff --git a/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.cpp b/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.cpp new file mode 100644 index 0000000..c234a26 --- /dev/null +++ b/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "linuxjoystickinputplugin.h" +#include "linuxjoystickinput.h" + +QT_BEGIN_NAMESPACE + +QJoystickInput *LinuxJoystickInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("linux")) + return new LinuxJoystickInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.h b/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.h new file mode 100644 index 0000000..7260fa8 --- /dev/null +++ b/src/plugins/joystickinputs/linux/linuxjoystickinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef LINUXJOYSTICKINPUTPLUGIN_H +#define LINUXJOYSTICKINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class LinuxJoystickInputPlugin : public QJoystickInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QJoystickInputFactoryInterface_iid FILE "linux.json") + +public: + QJoystickInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // LINUXJOYSTICKINPUTPLUGIN_H diff --git a/src/plugins/joystickinputs/macos/CMakeLists.txt b/src/plugins/joystickinputs/macos/CMakeLists.txt new file mode 100644 index 0000000..0e82dfd --- /dev/null +++ b/src/plugins/joystickinputs/macos/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_find_apple_system_framework(FWForceFeedback ForceFeedback) + +qt_internal_add_plugin(MacOSJoystickInputPlugin + OUTPUT_NAME macosjoystickinput + PLUGIN_TYPE joystickinputs + SOURCES + macosjoystickinput.mm macosjoystickinput.h + macosjoystickinputplugin.cpp macosjoystickinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + ${FWIOKit} + ${FWForceFeedback} +) diff --git a/src/plugins/joystickinputs/macos/macos.json b/src/plugins/joystickinputs/macos/macos.json new file mode 100644 index 0000000..a3f3787 --- /dev/null +++ b/src/plugins/joystickinputs/macos/macos.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "macos" ] +} diff --git a/src/plugins/joystickinputs/macos/macosjoystickinput.h b/src/plugins/joystickinputs/macos/macosjoystickinput.h new file mode 100644 index 0000000..a313d4e --- /dev/null +++ b/src/plugins/joystickinputs/macos/macosjoystickinput.h @@ -0,0 +1,104 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef MACOSJOYSTICKINPUT_H +#define MACOSJOYSTICKINPUT_H + +#include +#include + +#import +#import +#import +#import + +QT_BEGIN_NAMESPACE + +struct RecElement { + IOHIDElementRef ref; + IOHIDElementCookie cookie; + + uint32_t usage = 0; + + int min = 0; + int max = 0; + + struct Comparator { + bool operator()(const RecElement p_a, const RecElement p_b) const { return p_a.usage < p_b.usage; } + }; +}; + +struct Joypad { + IOHIDDeviceRef deviceRef = nullptr; + + QVector axisElements; + QVector buttonElements; + QVector hatElements; + + int id = 0; + bool offsetHat = false; + + io_service_t forceFeedbackService = 0; + FFCONSTANTFORCE forceFeedbackConstantForce; + FFDeviceObjectReference forceFeedbackDevice = nullptr; + FFEffectObjectReference forcefeedbackObject = nullptr; + quint64 forceFeedbackTimestamp = 0; + LONG *forceFeedbackDirections = nullptr; + FFEFFECT forceFeedbackEffect; + DWORD *forceFeedbackAxes = nullptr; + + void add_hid_elements(CFArrayRef p_array); + void add_hid_element(IOHIDElementRef p_element); + + bool has_element(IOHIDElementCookie p_cookie, QVector *p_list) const; + bool config_force_feedback(io_service_t p_service); + bool check_ff_features(); + + int get_hid_element_state(RecElement *p_element) const; + + void free(); + Joypad(); +}; + +class MacOsJoystickInput : public QJoystickInput +{ + Q_OBJECT +public: + MacOsJoystickInput(); + ~MacOsJoystickInput(); + + void processJoypads(); + + void deviceAdded(IOReturn p_res, IOHIDDeviceRef p_devic); + void deviceRemoved(IOReturn p_res, IOHIDDeviceRef p_device); + +protected: + void timerEvent(QTimerEvent *event) override; + +private: + bool have_device(IOHIDDeviceRef p_device) const; + bool configure_joypad(IOHIDDeviceRef p_device_ref, Joypad *p_joy); + + int get_joy_index(int p_id) const; + int get_joy_ref(IOHIDDeviceRef p_device) const; + + void poll_joypads() const; + void config_hid_manager(CFArrayRef p_matching_array) const; + + void joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp); + void joypad_vibration_stop(int p_id, uint64_t p_timestamp); + + + IOHIDManagerRef m_hidManager; + QVector m_deviceList; +}; + +QT_END_NAMESPACE + +#endif // MACOSJOYSTICKINPUT_H diff --git a/src/plugins/joystickinputs/macos/macosjoystickinput.mm b/src/plugins/joystickinputs/macos/macosjoystickinput.mm new file mode 100644 index 0000000..0a4767a --- /dev/null +++ b/src/plugins/joystickinputs/macos/macosjoystickinput.mm @@ -0,0 +1,623 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "macosjoystickinput.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#define JOYPAD_LOOP_RUN_MODE CFSTR("QtUniversalInput") + +static MacOsJoystickInput *self = nullptr; + +Joypad::Joypad() +{ + forceFeedbackConstantForce.lMagnitude = 10000; + forceFeedbackEffect.dwDuration = 0; + forceFeedbackEffect.dwSamplePeriod = 0; + forceFeedbackEffect.dwGain = 10000; + forceFeedbackEffect.dwFlags = FFEFF_OBJECTOFFSETS; + forceFeedbackEffect.dwTriggerButton = FFEB_NOTRIGGER; + forceFeedbackEffect.dwStartDelay = 0; + forceFeedbackEffect.dwTriggerRepeatInterval = 0; + forceFeedbackEffect.lpEnvelope = nullptr; + forceFeedbackEffect.cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); + forceFeedbackEffect.lpvTypeSpecificParams = &forceFeedbackConstantForce; + forceFeedbackEffect.dwSize = sizeof(forceFeedbackEffect); +} + +void Joypad::free() +{ + if (deviceRef) + IOHIDDeviceUnscheduleFromRunLoop(deviceRef, CFRunLoopGetCurrent(), JOYPAD_LOOP_RUN_MODE); + + if (forceFeedbackDevice) { + FFDeviceReleaseEffect(forceFeedbackDevice, forcefeedbackObject); + FFReleaseDevice(forceFeedbackDevice); + forceFeedbackDevice = nullptr; + ::free(forceFeedbackAxes); + ::free(forceFeedbackDirections); + } +} + +bool Joypad::has_element(IOHIDElementCookie p_cookie, QVector *p_list) const +{ + for (int i = 0; i < p_list->size(); i++) + if (p_cookie == p_list->at(i).cookie) + return true; + + return false; +} + +int Joypad::get_hid_element_state(RecElement *p_element) const +{ + int value = 0; + if (p_element && p_element->ref) { + IOHIDValueRef valueRef; + if (IOHIDDeviceGetValue(deviceRef, p_element->ref, &valueRef) == kIOReturnSuccess) { + value = SInt32(IOHIDValueGetIntegerValue(valueRef)); + + // Record min and max for auto calibration. + if (value < p_element->min) + p_element->min = value; + + if (value > p_element->max) + p_element->max = value; + } + } + return value; +} + +void Joypad::add_hid_element(IOHIDElementRef p_element) +{ + const CFTypeID elementTypeID = p_element ? CFGetTypeID(p_element) : 0; + + if (p_element && (elementTypeID == IOHIDElementGetTypeID())) { + const IOHIDElementCookie cookie = IOHIDElementGetCookie(p_element); + const uint32_t usagePage = IOHIDElementGetUsagePage(p_element); + const uint32_t usage = IOHIDElementGetUsage(p_element); + QVector *list = nullptr; + + switch (IOHIDElementGetType(p_element)) { + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: { + switch (usagePage) { + case kHIDPage_GenericDesktop: + switch (usage) { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + if (!has_element(cookie, &axisElements)) + list = &axisElements; + break; + + case kHIDUsage_GD_Hatswitch: + if (!has_element(cookie, &hatElements)) + list = &hatElements; + break; + case kHIDUsage_GD_DPadUp: + case kHIDUsage_GD_DPadDown: + case kHIDUsage_GD_DPadRight: + case kHIDUsage_GD_DPadLeft: + case kHIDUsage_GD_Start: + case kHIDUsage_GD_Select: + if (!has_element(cookie, &buttonElements)) + list = &buttonElements; + break; + } + break; + + case kHIDPage_Simulation: + switch (usage) { + case kHIDUsage_Sim_Rudder: + case kHIDUsage_Sim_Throttle: + case kHIDUsage_Sim_Accelerator: + case kHIDUsage_Sim_Brake: + if (!has_element(cookie, &axisElements)) + list = &axisElements; + break; + + default: + break; + } + break; + + case kHIDPage_Button: + case kHIDPage_Consumer: + if (!has_element(cookie, &buttonElements)) + list = &buttonElements; + break; + + default: + break; + } + } break; + + case kIOHIDElementTypeCollection: { + CFArrayRef array = IOHIDElementGetChildren(p_element); + if (array) + add_hid_elements(array); + } break; + + default: + break; + } + + if (list) { // Add to list. + RecElement element; + + element.ref = p_element; + element.usage = usage; + + element.min = (SInt32)IOHIDElementGetLogicalMin(p_element); + element.max = (SInt32)IOHIDElementGetLogicalMax(p_element); + element.cookie = IOHIDElementGetCookie(p_element); + list->push_back(element); + std::sort(list->begin(), list->end(), RecElement::Comparator()); + // list->sort_custom(); + } + } +} + +static void hid_element_added(const void *p_value, void *p_parameter) +{ + Joypad *joy = static_cast(p_parameter); + joy->add_hid_element(IOHIDElementRef(p_value)); +} + +void Joypad::add_hid_elements(CFArrayRef p_array) +{ + CFRange range = { 0, CFArrayGetCount(p_array) }; + CFArrayApplyFunction(p_array, range, hid_element_added, this); +} + +static void joypad_removed_callback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) +{ + Q_UNUSED(ctx); + Q_UNUSED(sender); + self->deviceRemoved(res, ioHIDDeviceObject); +} + +static void joypad_added_callback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) +{ + Q_UNUSED(ctx); + Q_UNUSED(sender); + self->deviceAdded(res, ioHIDDeviceObject); +} + +static bool is_joypad(IOHIDDeviceRef p_device_ref) +{ + int usage_page = 0; + int usage = 0; + CFTypeRef refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsagePageKey)); + if (refCF) + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &usage_page); + + if (usage_page != kHIDPage_GenericDesktop) + return false; + + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDPrimaryUsageKey)); + if (refCF) + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &usage); + + if ((usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController)) + return false; + + return true; +} + +void MacOsJoystickInput::deviceAdded(IOReturn p_res, IOHIDDeviceRef p_device) +{ + if (p_res != kIOReturnSuccess || have_device(p_device)) + return; + + Joypad new_joypad; + if (is_joypad(p_device)) { + configure_joypad(p_device, &new_joypad); + const io_service_t ioservice = IOHIDDeviceGetService(p_device); + if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK) && new_joypad.config_force_feedback(ioservice)) + new_joypad.forceFeedbackService = ioservice; + m_deviceList.push_back(new_joypad); + } + IOHIDDeviceScheduleWithRunLoop(p_device, CFRunLoopGetCurrent(), JOYPAD_LOOP_RUN_MODE); +} + +void MacOsJoystickInput::deviceRemoved(IOReturn p_res, IOHIDDeviceRef p_device) +{ + Q_UNUSED(p_res); + int device = get_joy_ref(p_device); + Q_ASSERT(device != -1); + + auto input = QUniversalInput::instance(); + + input->updateJoyConnection(m_deviceList[device].id, false, ""); + m_deviceList[device].free(); + m_deviceList.removeAt(device); +} + +static QByteArray _hex_str(uint8_t p_byte) +{ + static const char *dict = "0123456789abcdef"; + char ret[3]; + ret[2] = 0; + + ret[0] = dict[p_byte >> 4]; + ret[1] = dict[p_byte & 0xF]; + + return ret; +} + +bool MacOsJoystickInput::configure_joypad(IOHIDDeviceRef p_device_ref, Joypad *p_joy) +{ + p_joy->deviceRef = p_device_ref; + // Get device name. + QByteArray name; + char c_name[256]; + CFTypeRef refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductKey)); + if (!refCF) + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDManufacturerKey)); + + if ((!refCF) || (!CFStringGetCString((CFStringRef)refCF, c_name, sizeof(c_name), kCFStringEncodingUTF8))) + name = "Unidentified Joypad"; + else + name = c_name; + + auto input = QUniversalInput::instance(); + + int id = input->getUnusedJoyId(); + if (id == -1) + return false; + + p_joy->id = id; + int vendor = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVendorIDKey)); + if (refCF) + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &vendor); + + int product_id = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDProductIDKey)); + if (refCF) + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &product_id); + + int version = 0; + refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVersionNumberKey)); + if (refCF) + CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &version); + + if (vendor && product_id) { + uint32_t big3 = qToBigEndian(3); + uint32_t bigVendor = qToBigEndian(vendor); + uint32_t bigProductId = qToBigEndian(product_id); + uint32_t bigVersion = qToBigEndian(version); + + QString uid = QString("%1%2%3%4").arg(big3, 8, 16, QChar('0')).arg(bigVendor, 8, 16, QChar('0')).arg(bigProductId, 8, 16, QChar('0')).arg(bigVersion, 8, 16, QChar('0')); + input->updateJoyConnection(id, true, name, uid); + } else { + // Bluetooth device. + QByteArray guid = "05000000"; + for (int i = 0; i < 12; i++) { + if (i < name.size()) + guid += _hex_str(name[i]); + else + guid += "00"; + } + input->updateJoyConnection(id, true, name, guid); + } + + CFArrayRef array = IOHIDDeviceCopyMatchingElements(p_device_ref, nullptr, kIOHIDOptionsTypeNone); + if (array) { + p_joy->add_hid_elements(array); + CFRelease(array); + } + // Xbox controller hat values start at 1 rather than 0. + p_joy->offsetHat = vendor == 0x45e && + (product_id == 0x0b05 || + product_id == 0x02e0 || + product_id == 0x02fd || + product_id == 0x0b13); + + return true; +} + +#define FF_ERR() \ + { \ + if (ret != FF_OK) { \ + FFReleaseDevice(forceFeedbackDevice); \ + forceFeedbackDevice = nullptr; \ + return false; \ + } \ + } +bool Joypad::config_force_feedback(io_service_t p_service) +{ + HRESULT ret = FFCreateDevice(p_service, &forceFeedbackDevice); + + if (ret != FF_OK) + return false; + + ret = FFDeviceSendForceFeedbackCommand(forceFeedbackDevice, FFSFFC_RESET); + FF_ERR(); + + ret = FFDeviceSendForceFeedbackCommand(forceFeedbackDevice, FFSFFC_SETACTUATORSON); + FF_ERR(); + + if (check_ff_features()) { + ret = FFDeviceCreateEffect(forceFeedbackDevice, kFFEffectType_ConstantForce_ID, &forceFeedbackEffect, &forcefeedbackObject); + FF_ERR(); + return true; + } + FFReleaseDevice(forceFeedbackDevice); + forceFeedbackDevice = nullptr; + return false; +} +#undef FF_ERR + +#define TEST_FF(ff) (features.supportedEffects & (ff)) +bool Joypad::check_ff_features() +{ + FFCAPABILITIES features; + HRESULT ret = FFDeviceGetForceFeedbackCapabilities(forceFeedbackDevice, &features); + if (ret == FF_OK && (features.supportedEffects & FFCAP_ET_CONSTANTFORCE)) { + uint32_t val; + ret = FFDeviceGetForceFeedbackProperty(forceFeedbackDevice, FFPROP_FFGAIN, &val, sizeof(val)); + if (ret != FF_OK) { + return false; + } + int num_axes = features.numFfAxes; + forceFeedbackAxes = (DWORD *)::malloc(sizeof(DWORD) * num_axes); + forceFeedbackDirections = (LONG *)::malloc(sizeof(LONG) * num_axes); + + for (int i = 0; i < num_axes; i++) { + forceFeedbackAxes[i] = features.ffAxes[i]; + forceFeedbackDirections[i] = 0; + } + + forceFeedbackEffect.cAxes = num_axes; + forceFeedbackEffect.rgdwAxes = forceFeedbackAxes; + forceFeedbackEffect.rglDirection = forceFeedbackDirections; + return true; + } + return false; +} + +static HatMask process_hat_value(int p_min, int p_max, int p_value, bool p_offset_hat) +{ + int range = (p_max - p_min + 1); + int value = p_value - p_min; + HatMask hat_value = HatMask::Center; + if (range == 4) + value *= 2; + + if (p_offset_hat) + value -= 1; + + switch (value) { + case 0: + hat_value = HatMask::Up; + break; + case 1: + hat_value = (HatMask::Up | HatMask::Right); + break; + case 2: + hat_value = HatMask::Right; + break; + case 3: + hat_value = (HatMask::Down | HatMask::Right); + break; + case 4: + hat_value = HatMask::Down; + break; + case 5: + hat_value = (HatMask::Down | HatMask::Left); + break; + case 6: + hat_value = HatMask::Left; + break; + case 7: + hat_value = (HatMask::Up | HatMask::Left); + break; + default: + hat_value = HatMask::Center; + break; + } + return hat_value; +} + +void MacOsJoystickInput::poll_joypads() const +{ + while (CFRunLoopRunInMode(JOYPAD_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { + // No-op. Pending callbacks will fire. + } +} + +static float axis_correct(int p_value, int p_min, int p_max) +{ + // Convert to a value between -1.0f and 1.0f. + return 2.0f * (p_value - p_min) / (p_max - p_min) - 1.0f; +} + +void MacOsJoystickInput::processJoypads() +{ + auto input = QUniversalInput::instance(); + poll_joypads(); + + for (auto &joy : m_deviceList) { + for (int j = 0; j < joy.axisElements.size(); j++) { + RecElement &elem = joy.axisElements[j]; + int value = joy.get_hid_element_state(&elem); + input->joyAxis(joy.id, JoyAxis(j), axis_correct(value, elem.min, elem.max)); + } + for (int j = 0; j < joy.buttonElements.size(); j++) { + int value = joy.get_hid_element_state(&joy.buttonElements[j]); + input->joyButton(joy.id, JoyButton(j), (value >= 1)); + } + for (int j = 0; j < joy.hatElements.size(); j++) { + RecElement &elem = joy.hatElements[j]; + int value = joy.get_hid_element_state(&elem); + HatMask hat_value = process_hat_value(elem.min, elem.max, value, joy.offsetHat); + input->joyHat(joy.id, hat_value); + } + + if (joy.forceFeedbackService) { + uint64_t timestamp = input->getJoyVibrationTimestamp(joy.id); + if (timestamp > joy.forceFeedbackTimestamp) { + QVector2D strength = input->getJoyVibrationStrength(joy.id); + float duration = input->getJoyVibrationDuration(joy.id); + if (strength.x() == 0 && strength.y() == 0) { + joypad_vibration_stop(joy.id, timestamp); + } else { + float gain = qMax(strength.x(), strength.y()); + joypad_vibration_start(joy.id, gain, duration, timestamp); + } + } + } + + } +} + +void MacOsJoystickInput::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) +{ + Joypad *joy = &m_deviceList[get_joy_index(p_id)]; + joy->forceFeedbackTimestamp = p_timestamp; + joy->forceFeedbackEffect.dwDuration = p_duration * FF_SECONDS; + joy->forceFeedbackEffect.dwGain = p_magnitude * FF_FFNOMINALMAX; + FFEffectSetParameters(joy->forcefeedbackObject, &joy->forceFeedbackEffect, FFEP_DURATION | FFEP_GAIN); + FFEffectStart(joy->forcefeedbackObject, 1, 0); +} + +void MacOsJoystickInput::joypad_vibration_stop(int p_id, uint64_t p_timestamp) +{ + Joypad *joy = &m_deviceList[get_joy_index(p_id)]; + joy->forceFeedbackTimestamp = p_timestamp; + FFEffectStop(joy->forcefeedbackObject); +} + +int MacOsJoystickInput::get_joy_index(int p_id) const +{ + for (int i = 0; i < m_deviceList.size(); i++) + if (m_deviceList[i].id == p_id) + return i; + + return -1; +} + +int MacOsJoystickInput::get_joy_ref(IOHIDDeviceRef p_device) const +{ + for (int i = 0; i < m_deviceList.size(); i++) + if (m_deviceList[i].deviceRef == p_device) + return i; + + return -1; +} + +bool MacOsJoystickInput::have_device(IOHIDDeviceRef p_device) const +{ + for (int i = 0; i < m_deviceList.size(); i++) + if (m_deviceList[i].deviceRef == p_device) + return true; + + return false; +} + +static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 usage, int *okay) +{ + CFDictionaryRef retval = nullptr; + CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); + CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + + if (pageNumRef && usageNumRef) { + const void *keys[2] = { (void *)CFSTR(kIOHIDDeviceUsagePageKey), (void *)CFSTR(kIOHIDDeviceUsageKey) }; + const void *vals[2] = { (void *)pageNumRef, (void *)usageNumRef }; + retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + + if (pageNumRef) { + CFRelease(pageNumRef); + } + if (usageNumRef) { + CFRelease(usageNumRef); + } + + if (!retval) { + *okay = 0; + } + + return retval; +} + +void MacOsJoystickInput::config_hid_manager(CFArrayRef p_matching_array) const +{ + CFRunLoopRef runloop = CFRunLoopGetCurrent(); + IOReturn ret = IOHIDManagerOpen(m_hidManager, kIOHIDOptionsTypeNone); + Q_ASSERT(ret == kIOReturnSuccess); + + IOHIDManagerSetDeviceMatchingMultiple(m_hidManager, p_matching_array); + IOHIDManagerRegisterDeviceMatchingCallback(m_hidManager, joypad_added_callback, nullptr); + IOHIDManagerRegisterDeviceRemovalCallback(m_hidManager, joypad_removed_callback, nullptr); + IOHIDManagerScheduleWithRunLoop(m_hidManager, runloop, JOYPAD_LOOP_RUN_MODE); + + while (CFRunLoopRunInMode(JOYPAD_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { + // No-op. Callback fires once per existing device. + } +} + +MacOsJoystickInput::MacOsJoystickInput() +{ + self = this; + + int okay = 1; + const void *vals[] = { + (void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay), + (void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay), + (void *)create_match_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay), + }; + const size_t n_elements = sizeof(vals) / sizeof(vals[0]); + CFArrayRef array = okay ? CFArrayCreate(kCFAllocatorDefault, vals, n_elements, &kCFTypeArrayCallBacks) : nullptr; + + for (size_t i = 0; i < n_elements; i++) + if (vals[i]) + CFRelease((CFTypeRef)vals[i]); + + if (array) { + m_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (m_hidManager) + config_hid_manager(array); + + CFRelease(array); + } + + startTimer(1); +} + +MacOsJoystickInput::~MacOsJoystickInput() +{ + for (auto &joy : m_deviceList) + joy.free(); + m_deviceList.clear(); + + IOHIDManagerUnscheduleFromRunLoop(m_hidManager, CFRunLoopGetCurrent(), JOYPAD_LOOP_RUN_MODE); + IOHIDManagerClose(m_hidManager, kIOHIDOptionsTypeNone); + CFRelease(m_hidManager); + m_hidManager = nullptr; +} + +void MacOsJoystickInput::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + processJoypads(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/macos/macosjoystickinputplugin.cpp b/src/plugins/joystickinputs/macos/macosjoystickinputplugin.cpp new file mode 100644 index 0000000..4128dc2 --- /dev/null +++ b/src/plugins/joystickinputs/macos/macosjoystickinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "macosjoystickinputplugin.h" +#include "macosjoystickinput.h" + +QT_BEGIN_NAMESPACE + +QJoystickInput *MacOsJoystickInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("macos")) + return new MacOsJoystickInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/macos/macosjoystickinputplugin.h b/src/plugins/joystickinputs/macos/macosjoystickinputplugin.h new file mode 100644 index 0000000..8c711ba --- /dev/null +++ b/src/plugins/joystickinputs/macos/macosjoystickinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef MACOSJOYSTICKINPUTPLUGIN_H +#define MACOSJOYSTICKINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class MacOsJoystickInputPlugin : public QJoystickInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QJoystickInputFactoryInterface_iid FILE "macos.json") + +public: + QJoystickInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // MACOSJOYSTICKINPUTPLUGIN_H diff --git a/src/plugins/joystickinputs/windows/CMakeLists.txt b/src/plugins/joystickinputs/windows/CMakeLists.txt new file mode 100644 index 0000000..30ab5b1 --- /dev/null +++ b/src/plugins/joystickinputs/windows/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(WindowsJoystickInputPlugin + OUTPUT_NAME windowsjoystickinput + PLUGIN_TYPE joystickinputs + SOURCES + windowsjoystickinput.cpp windowsjoystickinput.h + windowsjoystickinputplugin.cpp windowsjoystickinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + dinput8 +) diff --git a/src/plugins/joystickinputs/windows/windows.json b/src/plugins/joystickinputs/windows/windows.json new file mode 100644 index 0000000..05032c1 --- /dev/null +++ b/src/plugins/joystickinputs/windows/windows.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "windows" ] +} diff --git a/src/plugins/joystickinputs/windows/windowsjoystickinput.cpp b/src/plugins/joystickinputs/windows/windowsjoystickinput.cpp new file mode 100644 index 0000000..00a12b1 --- /dev/null +++ b/src/plugins/joystickinputs/windows/windowsjoystickinput.cpp @@ -0,0 +1,571 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/windows/joypad_windows.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "windowsjoystickinput.h" + +#include + +#include +#include + +#include + +#include + +DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE *pState) +{ + return ERROR_DEVICE_NOT_CONNECTED; +} + +DWORD WINAPI _xinput_set_state(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration) +{ + return ERROR_DEVICE_NOT_CONNECTED; +} + +QT_BEGIN_NAMESPACE + +// Function to convert HRESULT to QString +static QString convertHRESULTToQString(HRESULT hr) +{ + char *msgBuf = nullptr; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msgBuf, 0, nullptr); + QString msg = QString::fromLocal8Bit(msgBuf); + LocalFree(msgBuf); + return msg; +} + +WindowsJoystickInput::WindowsJoystickInput() +{ + auto qtApp = QGuiApplication::instance(); + if (qtApp && qApp->focusWindow()) + hWnd = (HWND)qApp->focusWindow()->winId(); + // ### Maybe we should delay the initialization until we know there is an available window? + + load_xinput(); + + for (int i = 0; i < JOYPADS_MAX; i++) + attached_joypads[i] = false; + + HRESULT result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr); + if (result == DI_OK) { + probeJoypads(); + } else { + qWarning() << "Couldn't initialize DirectInput. Error: " << convertHRESULTToQString(result); + if (result == DIERR_OUTOFMEMORY) { + qWarning("The Windows DirectInput subsystem could not allocate sufficient memory."); + qWarning("Rebooting your PC may solve this issue."); + } + // Ensure dinput is still a nullptr. + dinput = nullptr; + } + + // ### Replace with Thread later + startTimer(1); +} + +WindowsJoystickInput::~WindowsJoystickInput() +{ + close_joypad(); + if (dinput) + dinput->Release(); + unload_xinput(); +} + +void WindowsJoystickInput::probeJoypads() +{ + if (dinput == nullptr) { + qWarning("DirectInput not initialized. Rebooting your PC may solve this issue."); + return; + } + DWORD dwResult; + auto input = QUniversalInput::instance(); + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { + ZeroMemory(&x_joypads[i].state, sizeof(XINPUT_STATE)); + + dwResult = xinput_get_state(i, &x_joypads[i].state); + if (dwResult == ERROR_SUCCESS) { + int id = input->getUnusedJoyId(); + if (id != -1 && !x_joypads[i].attached) { + x_joypads[i].attached = true; + x_joypads[i].id = id; + x_joypads[i].ff_timestamp = 0; + x_joypads[i].ff_end_timestamp = 0; + x_joypads[i].vibrating = false; + attached_joypads[id] = true; + input->updateJoyConnection(id, true, "XInput Gamepad", "__XINPUT_DEVICE__"); + } + } else if (x_joypads[i].attached) { + x_joypads[i].attached = false; + attached_joypads[x_joypads[i].id] = false; + input->updateJoyConnection(x_joypads[i].id, false, ""); + } + } + + for (int i = 0; i < joypad_count; i++) { + d_joypads[i].confirmed = false; + } + + dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY); + + for (int i = 0; i < joypad_count; i++) { + if (!d_joypads[i].confirmed) { + close_joypad(i); + } + } +} + +void WindowsJoystickInput::processJoypads() +{ + HRESULT hr; + auto input = QUniversalInput::instance(); + for (int i = 0; i < XUSER_MAX_COUNT; i++) { + xinput_gamepad &joy = x_joypads[i]; + if (!joy.attached) { + continue; + } + ZeroMemory(&joy.state, sizeof(XINPUT_STATE)); + + xinput_get_state(i, &joy.state); + if (joy.state.dwPacketNumber != joy.last_packet) { + int button_mask = XINPUT_GAMEPAD_DPAD_UP; + for (int j = 0; j <= 16; j++) { + input->joyButton(joy.id, (JoyButton)j, joy.state.Gamepad.wButtons & button_mask); + button_mask = button_mask * 2; + } + + input->joyAxis(joy.id, JoyAxis::LeftX, axis_correct(joy.state.Gamepad.sThumbLX, true)); + input->joyAxis(joy.id, JoyAxis::LeftY, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true)); + input->joyAxis(joy.id, JoyAxis::RightX, axis_correct(joy.state.Gamepad.sThumbRX, true)); + input->joyAxis(joy.id, JoyAxis::RightY, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true)); + input->joyAxis(joy.id, JoyAxis::TriggerLeft, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true)); + input->joyAxis(joy.id, JoyAxis::TriggerRight, axis_correct(joy.state.Gamepad.bRightTrigger, true, true)); + joy.last_packet = joy.state.dwPacketNumber; + } + uint64_t timestamp = input->getJoyVibrationTimestamp(joy.id); + if (timestamp > joy.ff_timestamp) { + QVector2D strength = input->getJoyVibrationStrength(joy.id); + float duration = input->getJoyVibrationDuration(joy.id); + if (strength.x() == 0 && strength.y() == 0) { + joypad_vibration_stop_xinput(i, timestamp); + } else { + joypad_vibration_start_xinput(i, strength.x(), strength.y(), duration, timestamp); + } + } else if (joy.vibrating && joy.ff_end_timestamp != 0) { + uint64_t currentTime = QDateTime::currentMSecsSinceEpoch(); + if (currentTime >= joy.ff_end_timestamp) + joypad_vibration_stop_xinput(i, currentTime); + } + } + + for (int i = 0; i < JOYPADS_MAX; i++) { + dinput_gamepad *joy = &d_joypads[i]; + + if (!joy->attached) { + continue; + } + + DIJOYSTATE2 js; + hr = joy->di_joy->Poll(); + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) { + IDirectInputDevice8_Acquire(joy->di_joy); + joy->di_joy->Poll(); + } + + hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js); + if (FAILED(hr)) { + continue; + } + + post_hat(joy->id, js.rgdwPOV[0]); + + for (int j = 0; j < 128; j++) { + if (js.rgbButtons[j] & 0x80) { + if (!joy->last_buttons[j]) { + input->joyButton(joy->id, (JoyButton)j, true); + joy->last_buttons[j] = true; + } + } else { + if (joy->last_buttons[j]) { + input->joyButton(joy->id, (JoyButton)j, false); + joy->last_buttons[j] = false; + } + } + } + + // on mingw, these constants are not constants + int count = 8; + const LONG axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, (LONG)DIJOFS_SLIDER(0), (LONG)DIJOFS_SLIDER(1) }; + int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz, js.rglSlider[0], js.rglSlider[1] }; + + for (int j = 0; j < joy->joy_axis.size(); j++) { + for (int k = 0; k < count; k++) { + if (joy->joy_axis[j] == axes[k]) { + input->joyAxis(joy->id, (JoyAxis)j, axis_correct(values[k])); + break; + } + } + } + } +} + +void WindowsJoystickInput::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + processJoypads(); +} + +bool WindowsJoystickInput::have_device(const GUID &p_guid) +{ + for (int i = 0; i < JOYPADS_MAX; i++) { + if (d_joypads[i].guid == p_guid) { + d_joypads[i].confirmed = true; + return true; + } + } + return false; +} + +bool WindowsJoystickInput::is_xinput_device(const GUID *p_guid) +{ + static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + + if (::memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 || + ::memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 || + ::memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0) + return true; + + PRAWINPUTDEVICELIST dev_list = nullptr; + unsigned int dev_list_count = 0; + + if (GetRawInputDeviceList(nullptr, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) + return false; + + dev_list = (PRAWINPUTDEVICELIST)::malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count); + if (dev_list == nullptr) { + qWarning("Out of memory."); + return false; + } + + if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) { + ::free(dev_list); + return false; + } + for (unsigned int i = 0; i < dev_list_count; i++) { + RID_DEVICE_INFO rdi; + char dev_name[128]; + UINT rdiSize = sizeof(rdi); + UINT nameSize = sizeof(dev_name); + + rdi.cbSize = rdiSize; + if ((dev_list[i].dwType == RIM_TYPEHID) && + (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) && + (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) && + (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) && + (strstr(dev_name, "IG_") != nullptr)) { + ::free(dev_list); + return true; + } + } + ::free(dev_list); + return false; +} + +static inline uint16_t BSWAP16(uint16_t x) +{ + return (x >> 8) | (x << 8); +} + +bool WindowsJoystickInput::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) +{ + if (dinput == nullptr) { + qWarning("DirectInput not initialized. Rebooting your PC may solve this issue."); + return false; + } + + HRESULT hr; + auto input = QUniversalInput::instance(); + int num = input->getUnusedJoyId(); + + if (have_device(instance->guidInstance) || num == -1) + return false; + + d_joypads[num] = dinput_gamepad(); + dinput_gamepad *joy = &d_joypads[num]; + + const DWORD devtype = (instance->dwDevType & 0xFF); + + if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON) && (devtype != DI8DEVTYPE_DRIVING)) + return false; + + hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, nullptr); + + if (FAILED(hr)) + return false; + + const GUID &guid = instance->guidProduct; + char uid[128]; + + if (memcmp(&guid.Data4[2], "PIDVID", 6) != 0) { + qWarning("DirectInput device not recognized."); + return false; + } + + WORD type = BSWAP16(0x03); + WORD vendor = BSWAP16(LOWORD(guid.Data1)); + WORD product = BSWAP16(HIWORD(guid.Data1)); + WORD version = 0; + sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0); + + id_to_change = num; + slider_count = 0; + + joy->di_joy->SetDataFormat(&c_dfDIJoystick2); + joy->di_joy->SetCooperativeLevel(hWnd, DISCL_FOREGROUND); + joy->di_joy->EnumObjects(objectsCallback, this, 0); + std::sort(joy->joy_axis.begin(), joy->joy_axis.end()); + + joy->guid = instance->guidInstance; + input->updateJoyConnection(num, true, QString::fromWCharArray(instance->tszProductName), QString::fromLocal8Bit(uid)); + joy->attached = true; + joy->id = num; + attached_joypads[num] = true; + joy->confirmed = true; + joypad_count++; + return true; +} + +void WindowsJoystickInput::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) +{ + if (ob->dwType & DIDFT_AXIS) { + HRESULT res; + DIPROPRANGE prop_range; + DIPROPDWORD dilong; + LONG ofs; + if (ob->guidType == GUID_XAxis) { + ofs = DIJOFS_X; + } else if (ob->guidType == GUID_YAxis) { + ofs = DIJOFS_Y; + } else if (ob->guidType == GUID_ZAxis) { + ofs = DIJOFS_Z; + } else if (ob->guidType == GUID_RxAxis) { + ofs = DIJOFS_RX; + } else if (ob->guidType == GUID_RyAxis) { + ofs = DIJOFS_RY; + } else if (ob->guidType == GUID_RzAxis) { + ofs = DIJOFS_RZ; + } else if (ob->guidType == GUID_Slider) { + if (slider_count < 2) { + ofs = DIJOFS_SLIDER(slider_count); + slider_count++; + } else { + return; + } + } else { + return; + } + prop_range.diph.dwSize = sizeof(DIPROPRANGE); + prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + prop_range.diph.dwObj = ob->dwType; + prop_range.diph.dwHow = DIPH_BYID; + prop_range.lMin = -MAX_JOY_AXIS; + prop_range.lMax = +MAX_JOY_AXIS; + + dinput_gamepad &joy = d_joypads[p_joy_id]; + + res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_RANGE, &prop_range.diph); + if (FAILED(res)) { + return; + } + + dilong.diph.dwSize = sizeof(dilong); + dilong.diph.dwHeaderSize = sizeof(dilong.diph); + dilong.diph.dwObj = ob->dwType; + dilong.diph.dwHow = DIPH_BYID; + dilong.dwData = 0; + + res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_DEADZONE, &dilong.diph); + if (FAILED(res)) { + return; + } + + joy.joy_axis.push_back(ofs); + } +} + +BOOL CALLBACK WindowsJoystickInput::enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context) +{ + WindowsJoystickInput *self = static_cast(p_context); + if (self->is_xinput_device(&p_instance->guidProduct)) { + return DIENUM_CONTINUE; + } + self->setup_dinput_joypad(p_instance); + return DIENUM_CONTINUE; +} + +BOOL CALLBACK WindowsJoystickInput::objectsCallback(const DIDEVICEOBJECTINSTANCE *p_instance, void *p_context) +{ + WindowsJoystickInput *self = static_cast(p_context); + self->setup_joypad_object(p_instance, self->id_to_change); + + return DIENUM_CONTINUE; +} + +void WindowsJoystickInput::close_joypad(int id) +{ + if (id == -1) { + for (int i = 0; i < JOYPADS_MAX; i++) { + close_joypad(i); + } + return; + } + + if (!d_joypads[id].attached) { + return; + } + + d_joypads[id].di_joy->Unacquire(); + d_joypads[id].di_joy->Release(); + d_joypads[id].attached = false; + attached_joypads[d_joypads[id].id] = false; + d_joypads[id].guid.Data1 = d_joypads[id].guid.Data2 = d_joypads[id].guid.Data3 = 0; + QUniversalInput::instance()->updateJoyConnection(d_joypads[id].id, false, ""); + joypad_count--; +} + +void WindowsJoystickInput::post_hat(int p_device, DWORD p_dpad) +{ + HatMask dpad_val = (HatMask)0; + + // Should be -1 when centered, but according to docs: + // "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows: + // BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);" + // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks + if (LOWORD(p_dpad) == 0xFFFF) + dpad_val = (HatMask)HatMask::Center; + + if (p_dpad == 0) { + dpad_val = (HatMask)HatMask::Up; + + } else if (p_dpad == 4500) { + dpad_val = (HatMask)(HatMask::Up | HatMask::Right); + + } else if (p_dpad == 9000) { + dpad_val = (HatMask)HatMask::Right; + + } else if (p_dpad == 13500) { + dpad_val = (HatMask)(HatMask::Right | HatMask::Down); + + } else if (p_dpad == 18000) { + dpad_val = (HatMask)HatMask::Down; + + } else if (p_dpad == 22500) { + dpad_val = (HatMask)(HatMask::Down | HatMask::Left); + + } else if (p_dpad == 27000) { + dpad_val = (HatMask)HatMask::Left; + + } else if (p_dpad == 31500) { + dpad_val = (HatMask)(HatMask::Left | HatMask::Up); + } + QUniversalInput::instance()->joyHat(p_device, dpad_val); +} + +float WindowsJoystickInput::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const +{ + if (qFabs(p_val) < MIN_JOY_AXIS) + return p_trigger ? -1.0f : 0.0f; + + if (!p_xinput) + return (float)p_val / MAX_JOY_AXIS; + + // Convert to a value between -1.0f and 1.0f. + if (p_trigger) + return 2.0f * p_val / MAX_TRIGGER - 1.0f; + + float value; + if (p_val < 0) + value = (float)p_val / MAX_JOY_AXIS; + else + value = (float)p_val / (MAX_JOY_AXIS - 1); + + if (p_negate) + value = -value; + + return value; +} + +void WindowsJoystickInput::joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) +{ + xinput_gamepad &joy = x_joypads[p_device]; + if (joy.attached) { + XINPUT_VIBRATION effect; + effect.wLeftMotorSpeed = (65535 * p_strong_magnitude); + effect.wRightMotorSpeed = (65535 * p_weak_magnitude); + if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { + joy.ff_timestamp = p_timestamp; + joy.ff_end_timestamp = p_duration == 0 ? 0 : p_timestamp + (uint64_t)(p_duration * 1000); + joy.vibrating = true; + } + } +} + +void WindowsJoystickInput::joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp) +{ + xinput_gamepad &joy = x_joypads[p_device]; + if (joy.attached) { + XINPUT_VIBRATION effect; + effect.wLeftMotorSpeed = 0; + effect.wRightMotorSpeed = 0; + if (xinput_set_state(p_device, &effect) == ERROR_SUCCESS) { + joy.ff_timestamp = p_timestamp; + joy.vibrating = false; + } + } +} + +void WindowsJoystickInput::load_xinput() +{ + xinput_get_state = &_xinput_get_state; + xinput_set_state = &_xinput_set_state; + xinput_dll.setFileName("xinput1_4.dll"); + if (!xinput_dll.load()) { + xinput_dll.setFileName("xinput1_3.dll"); + if (!xinput_dll.load()) { + xinput_dll.setFileName("xinput9_1_0.dll"); + xinput_dll.load(); + } + } + + if (!xinput_dll.isLoaded()) { + qWarning("Could not find XInput, using DirectInput only"); + return; + } + + XInputGetState_t func = (XInputGetState_t)xinput_dll.resolve("XInputGetState"); + XInputSetState_t set_func = (XInputSetState_t)xinput_dll.resolve("XInputSetState"); + + if (!func || !set_func) { + unload_xinput(); + return; + } + xinput_get_state = func; + xinput_set_state = set_func; +} + +void WindowsJoystickInput::unload_xinput() +{ + if (xinput_dll.isLoaded()) + xinput_dll.unload(); +} + + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/windows/windowsjoystickinput.h b/src/plugins/joystickinputs/windows/windowsjoystickinput.h new file mode 100644 index 0000000..eaab459 --- /dev/null +++ b/src/plugins/joystickinputs/windows/windowsjoystickinput.h @@ -0,0 +1,123 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/windows/joypad_windows.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef WINDOWSJOYSTICKINPUT_H +#define WINDOWSJOYSTICKINPUT_H + +#include + +#include + + +#include + +#define DIRECTINPUT_VERSION 0x0800 +#include +#include + +QT_BEGIN_NAMESPACE + +class WindowsJoystickInput : public QJoystickInput +{ + Q_OBJECT +public: + WindowsJoystickInput(); + ~WindowsJoystickInput(); + + void probeJoypads(); + void processJoypads(); + +protected: + void timerEvent(QTimerEvent *event) override; + +private: + enum { + JOYPADS_MAX = 16, + JOY_AXIS_COUNT = 6, + MIN_JOY_AXIS = 10, + MAX_JOY_AXIS = 32768, + MAX_JOY_BUTTONS = 128, + KEY_EVENT_BUFFER_SIZE = 512, + MAX_TRIGGER = 255 + }; + + struct dinput_gamepad { + int id; + bool attached; + bool confirmed; + bool last_buttons[MAX_JOY_BUTTONS]; + DWORD last_pad; + + LPDIRECTINPUTDEVICE8 di_joy; + QList joy_axis; + GUID guid; + + dinput_gamepad() { + id = -1; + last_pad = -1; + attached = false; + confirmed = false; + di_joy = nullptr; + guid = {}; + + for (int i = 0; i < MAX_JOY_BUTTONS; i++) { + last_buttons[i] = false; + } + } + }; + + struct xinput_gamepad { + int id = 0; + bool attached = false; + bool vibrating = false; + DWORD last_packet = 0; + XINPUT_STATE state; + uint64_t ff_timestamp = 0; + uint64_t ff_end_timestamp = 0; + }; + + typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState); + typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration); + + HWND hWnd = nullptr; + LPDIRECTINPUT8 dinput = nullptr; + + int id_to_change; + int slider_count; + int joypad_count; + bool attached_joypads[JOYPADS_MAX]; + dinput_gamepad d_joypads[JOYPADS_MAX]; + xinput_gamepad x_joypads[XUSER_MAX_COUNT]; + + static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context); + static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context); + + void setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id); + void close_joypad(int id = -1); + void load_xinput(); + void unload_xinput(); + + void post_hat(int p_device, DWORD p_dpad); + + bool have_device(const GUID &p_guid); + bool is_xinput_device(const GUID *p_guid); + bool setup_dinput_joypad(const DIDEVICEINSTANCE *instance); + void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); + void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp); + + float axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const; + + QLibrary xinput_dll; + XInputGetState_t xinput_get_state = nullptr; + XInputSetState_t xinput_set_state = nullptr; +}; + +QT_END_NAMESPACE + +#endif // WINDOWSJOYSTICKINPUT_H diff --git a/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.cpp b/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.cpp new file mode 100644 index 0000000..da98281 --- /dev/null +++ b/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "windowsjoystickinputplugin.h" +#include "windowsjoystickinput.h" + +QT_BEGIN_NAMESPACE + +QJoystickInput *WindowsJoystickInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("windows")) + return new WindowsJoystickInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.h b/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.h new file mode 100644 index 0000000..a7fb726 --- /dev/null +++ b/src/plugins/joystickinputs/windows/windowsjoystickinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef WINDOWSJOYSTICKINPUTPLUGIN_H +#define WINDOWSJOYSTICKINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class WindowsJoystickInputPlugin : public QJoystickInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QJoystickInputFactoryInterface_iid FILE "windows.json") + +public: + QJoystickInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // WINDOWSJOYSTICKINPUTPLUGIN_H diff --git a/src/plugins/mouseinputs/CMakeLists.txt b/src/plugins/mouseinputs/CMakeLists.txt new file mode 100644 index 0000000..156e04e --- /dev/null +++ b/src/plugins/mouseinputs/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# for each platform, add a subdirectory with the platform name +#if(ANDROID) +# add_subdirectory(android) +#endif() +if(MACOS) + add_subdirectory(macos) +endif() +#if(IOS) +# add_subdirectory(ios) +#endif() +if(WIN32) + add_subdirectory(windows) +endif() +if(LINUX) + add_subdirectory(linux) +endif() + +#add_subdirectory(macos) +#add_subdirectory(ios) +#add_subdirectory(windows) diff --git a/src/plugins/mouseinputs/linux/CMakeLists.txt b/src/plugins/mouseinputs/linux/CMakeLists.txt new file mode 100644 index 0000000..7d1da23 --- /dev/null +++ b/src/plugins/mouseinputs/linux/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(LinuxMouseInputPlugin + OUTPUT_NAME linuxmouseinput + PLUGIN_TYPE mouseinputs + SOURCES + linuxmouseinput.cpp linuxmouseinput.h + linuxmouseinputplugin.cpp linuxmouseinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate +) diff --git a/src/plugins/mouseinputs/linux/linux.json b/src/plugins/mouseinputs/linux/linux.json new file mode 100644 index 0000000..8165d39 --- /dev/null +++ b/src/plugins/mouseinputs/linux/linux.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "linux" ] +} diff --git a/src/plugins/mouseinputs/linux/linuxmouseinput.cpp b/src/plugins/mouseinputs/linux/linuxmouseinput.cpp new file mode 100644 index 0000000..87cad43 --- /dev/null +++ b/src/plugins/mouseinputs/linux/linuxmouseinput.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "linuxmouseinput.h" +#include +#include + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static LinuxMouseInput *self = nullptr; + +LinuxMouseInput::LinuxMouseInput() +{ + self = this; + + m_timer = new QTimer(this); + m_timer->setInterval(1); + connect(m_timer, &QTimer::timeout, this, &LinuxMouseInput::onUpdate); + m_timer->start(); +} + +LinuxMouseInput::~LinuxMouseInput() +{ + self = nullptr; + m_timer->stop(); + delete m_timer; +} + +QVector2D LinuxMouseInput::getMouseDelta() +{ + static QPoint lastPos = QCursor::pos(); + QPoint newPos = QCursor::pos(); + QVector2D delta = QVector2D(newPos.toPointF() - lastPos.toPointF()); + lastPos = newPos; + return delta; +} + +void LinuxMouseInput::setCursorCenterOfWindow() +{ + QWindow* window = QGuiApplication::focusWindow(); + if (!window) + return; + QPoint center = window->geometry().center(); + QCursor::setPos(center); +} + +void LinuxMouseInput::onUpdate() +{ + if (!self) + return; + + auto input = QUniversalInput::instance(); + + QVector2D delta = getMouseDelta(); + if (delta.x() == 0 && delta.y() == 0) + return; + + input->mouseMove(delta); + + if (input->isMouseDisabled()) { + setCursorCenterOfWindow(); + // set cursor to blank + QGuiApplication::setOverrideCursor(Qt::BlankCursor); + m_wasDisabled = true; + } else if (m_wasDisabled) { + QGuiApplication::setOverrideCursor(Qt::ArrowCursor); + m_wasDisabled = false; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/linux/linuxmouseinput.h b/src/plugins/mouseinputs/linux/linuxmouseinput.h new file mode 100644 index 0000000..bc67ce4 --- /dev/null +++ b/src/plugins/mouseinputs/linux/linuxmouseinput.h @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef LINUXMOUSEINPUT_H +#define LINUXMOUSEINPUT_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class LinuxMouseInput : public QMouseInput +{ + Q_OBJECT +public: + LinuxMouseInput(); + ~LinuxMouseInput(); + + QVector2D getMouseDelta(); + void setCursorCenterOfWindow(); + + +public Q_SLOTS: + void onUpdate(); + +private: + QTimer* m_timer = nullptr; + bool m_wasDisabled = false; +}; + +QT_END_NAMESPACE + +#endif // LINUXMOUSEINPUT_H diff --git a/src/plugins/mouseinputs/linux/linuxmouseinputplugin.cpp b/src/plugins/mouseinputs/linux/linuxmouseinputplugin.cpp new file mode 100644 index 0000000..31a1bf1 --- /dev/null +++ b/src/plugins/mouseinputs/linux/linuxmouseinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "linuxmouseinputplugin.h" +#include "linuxmouseinput.h" + +QT_BEGIN_NAMESPACE + +QMouseInput *LinuxMouseInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("linux")) + return new LinuxMouseInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/linux/linuxmouseinputplugin.h b/src/plugins/mouseinputs/linux/linuxmouseinputplugin.h new file mode 100644 index 0000000..a577f49 --- /dev/null +++ b/src/plugins/mouseinputs/linux/linuxmouseinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef LINUXMOUSEINPUTPLUGIN_H +#define LINUXMOUSEINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class LinuxMouseInputPlugin : public QMouseInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMouseInputFactoryInterface_iid FILE "linux.json") + +public: + QMouseInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // LINUXMOUSEINPUTPLUGIN_H diff --git a/src/plugins/mouseinputs/macos/CMakeLists.txt b/src/plugins/mouseinputs/macos/CMakeLists.txt new file mode 100644 index 0000000..5d1005e --- /dev/null +++ b/src/plugins/mouseinputs/macos/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_find_apple_system_framework(FWAppKit AppKit) + +qt_internal_add_plugin(MacOSMouseInputPlugin + OUTPUT_NAME macosmouseinput + PLUGIN_TYPE mouseinputs + SOURCES + macosmouseinput.mm macosmouseinput.h + macosmouseinputplugin.cpp macosmouseinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate + ${FWAppKit} +) diff --git a/src/plugins/mouseinputs/macos/macos.json b/src/plugins/mouseinputs/macos/macos.json new file mode 100644 index 0000000..a3f3787 --- /dev/null +++ b/src/plugins/mouseinputs/macos/macos.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "macos" ] +} diff --git a/src/plugins/mouseinputs/macos/macosmouseinput.h b/src/plugins/mouseinputs/macos/macosmouseinput.h new file mode 100644 index 0000000..aefdc2e --- /dev/null +++ b/src/plugins/mouseinputs/macos/macosmouseinput.h @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef MACOSMOUSEINPUT_H +#define MACOSMOUSEINPUT_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class MacOsMouseInput : public QMouseInput +{ + Q_OBJECT +public: + MacOsMouseInput(); + ~MacOsMouseInput(); + + QVector2D getMouseDelta(); + void setCursorCenterOfWindow(); + + +public Q_SLOTS: + void onUpdate(); + +private: + QTimer* m_timer = nullptr; + bool m_wasDisabled = false; +}; + +QT_END_NAMESPACE + +#endif // MACOSMOUSEINPUT_H diff --git a/src/plugins/mouseinputs/macos/macosmouseinput.mm b/src/plugins/mouseinputs/macos/macosmouseinput.mm new file mode 100644 index 0000000..abd2a3d --- /dev/null +++ b/src/plugins/mouseinputs/macos/macosmouseinput.mm @@ -0,0 +1,82 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "macosmouseinput.h" +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +static MacOsMouseInput *self = nullptr; + +MacOsMouseInput::MacOsMouseInput() +{ + self = this; + + m_timer = new QTimer(this); + m_timer->setInterval(1); + connect(m_timer, &QTimer::timeout, this, &MacOsMouseInput::onUpdate); + m_timer->start(); +} + +MacOsMouseInput::~MacOsMouseInput() +{ + self = nullptr; + m_timer->stop(); + delete m_timer; +} + +QVector2D MacOsMouseInput::getMouseDelta() +{ + // kind of a hack, but it works for now + static NSPoint previousLocation; + NSPoint currentLocation = [NSEvent mouseLocation]; + CGPoint delta = CGPointMake(currentLocation.x - previousLocation.x, currentLocation.y - previousLocation.y); + previousLocation = currentLocation; + return QVector2D(float(delta.x), float(delta.y)); +} + +void MacOsMouseInput::setCursorCenterOfWindow() +{ + NSRect windowRect = [[NSApp mainWindow] frame]; + NSPoint windowCenter = NSMakePoint(NSMidX(windowRect), NSMidY(windowRect)); + CGWarpMouseCursorPosition(windowCenter); +} + +void MacOsMouseInput::onUpdate() +{ + if (!self) + return; + + auto input = QUniversalInput::instance(); + + QVector2D delta = getMouseDelta(); + if (delta.x() == 0 && delta.y() == 0) + return; + + input->mouseMove(delta); + + if (input->isMouseDisabled()) { + setCursorCenterOfWindow(); + // set cursor to blank + QGuiApplication::setOverrideCursor(Qt::BlankCursor); + m_wasDisabled = true; + } else if (m_wasDisabled) { + QGuiApplication::setOverrideCursor(Qt::ArrowCursor); + m_wasDisabled = false; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/macos/macosmouseinputplugin.cpp b/src/plugins/mouseinputs/macos/macosmouseinputplugin.cpp new file mode 100644 index 0000000..88411ac --- /dev/null +++ b/src/plugins/mouseinputs/macos/macosmouseinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "macosmouseinputplugin.h" +#include "macosmouseinput.h" + +QT_BEGIN_NAMESPACE + +QMouseInput *MacOsMouseInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("macos")) + return new MacOsMouseInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/macos/macosmouseinputplugin.h b/src/plugins/mouseinputs/macos/macosmouseinputplugin.h new file mode 100644 index 0000000..6245974 --- /dev/null +++ b/src/plugins/mouseinputs/macos/macosmouseinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef MACOSMOUSEINPUTPLUGIN_H +#define MACOSMOUSEINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class MacOsMouseInputPlugin : public QMouseInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMouseInputFactoryInterface_iid FILE "macos.json") + +public: + QMouseInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // MACOSMOUSEINPUTPLUGIN_H diff --git a/src/plugins/mouseinputs/windows/CMakeLists.txt b/src/plugins/mouseinputs/windows/CMakeLists.txt new file mode 100644 index 0000000..c981277 --- /dev/null +++ b/src/plugins/mouseinputs/windows/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_plugin(WindowsMouseInputPlugin + OUTPUT_NAME windowsmouseinput + PLUGIN_TYPE mouseinputs + SOURCES + windowsmouseinput.cpp windowsmouseinput.h + windowsmouseinputplugin.cpp windowsmouseinputplugin.h + LIBRARIES + Qt::Core + Qt::Gui + Qt::UniversalInput + Qt::UniversalInputPrivate +) diff --git a/src/plugins/mouseinputs/windows/windows.json b/src/plugins/mouseinputs/windows/windows.json new file mode 100644 index 0000000..05032c1 --- /dev/null +++ b/src/plugins/mouseinputs/windows/windows.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "windows" ] +} diff --git a/src/plugins/mouseinputs/windows/windowsmouseinput.cpp b/src/plugins/mouseinputs/windows/windowsmouseinput.cpp new file mode 100644 index 0000000..d6b86d9 --- /dev/null +++ b/src/plugins/mouseinputs/windows/windowsmouseinput.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "windowsmouseinput.h" +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static WindowsMouseInput *self = nullptr; + +WindowsMouseInput::WindowsMouseInput() +{ + self = this; + + m_timer = new QTimer(this); + m_timer->setInterval(1); + connect(m_timer, &QTimer::timeout, this, &WindowsMouseInput::onUpdate); + m_timer->start(); +} + +WindowsMouseInput::~WindowsMouseInput() +{ + self = nullptr; + m_timer->stop(); + delete m_timer; +} + +QVector2D WindowsMouseInput::getMouseDelta() +{ + // kind of a hack, but it works for now + static QVector2D previousLocation; + auto pos = QCursor::pos(); + QVector2D currentLocation = {float(pos.x()), float(pos.y())}; + QVector2D delta = currentLocation - previousLocation; + previousLocation = currentLocation; + return delta; +} + +void WindowsMouseInput::setCursorCenterOfWindow() +{ + QWindow* window = QGuiApplication::focusWindow(); + if (!window) + return; + QPoint center = window->geometry().center(); + QCursor::setPos(center); +} + +void WindowsMouseInput::onUpdate() +{ + if (!self) + return; + + auto input = QUniversalInput::instance(); + + QVector2D delta = getMouseDelta(); + if (delta.x() == 0 && delta.y() == 0) { + return; + } + + input->mouseMove(delta); + + if (input->isMouseDisabled()) { + setCursorCenterOfWindow(); + // set cursor to blank + QGuiApplication::setOverrideCursor(Qt::BlankCursor); + m_wasDisabled = true; + } else if (m_wasDisabled) { + QGuiApplication::setOverrideCursor(Qt::ArrowCursor); + m_wasDisabled = false; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/windows/windowsmouseinput.h b/src/plugins/mouseinputs/windows/windowsmouseinput.h new file mode 100644 index 0000000..01b5cfa --- /dev/null +++ b/src/plugins/mouseinputs/windows/windowsmouseinput.h @@ -0,0 +1,41 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "platform/macos/joypad_macos.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef WINDOWSMOUSEINPUT_H +#define WINDOWSMOUSEINPUT_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class WindowsMouseInput : public QMouseInput +{ + Q_OBJECT +public: + WindowsMouseInput(); + ~WindowsMouseInput(); + + QVector2D getMouseDelta(); + void setCursorCenterOfWindow(); + + +public Q_SLOTS: + void onUpdate(); + +private: + QTimer* m_timer = nullptr; + bool m_wasDisabled = false; +}; + +QT_END_NAMESPACE + +#endif // WINDOWSMOUSEINPUT_H diff --git a/src/plugins/mouseinputs/windows/windowsmouseinputplugin.cpp b/src/plugins/mouseinputs/windows/windowsmouseinputplugin.cpp new file mode 100644 index 0000000..516751b --- /dev/null +++ b/src/plugins/mouseinputs/windows/windowsmouseinputplugin.cpp @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "windowsmouseinputplugin.h" +#include "windowsmouseinput.h" + +QT_BEGIN_NAMESPACE + +QMouseInput *WindowsMouseInputPlugin::create(const QString &key, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + if (key == QLatin1String("windows")) + return new WindowsMouseInput(); + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/plugins/mouseinputs/windows/windowsmouseinputplugin.h b/src/plugins/mouseinputs/windows/windowsmouseinputplugin.h new file mode 100644 index 0000000..a527047 --- /dev/null +++ b/src/plugins/mouseinputs/windows/windowsmouseinputplugin.h @@ -0,0 +1,23 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef WINDOWSMOUSEINPUTPLUGIN_H +#define WINDOWSMOUSEINPUTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class WindowsMouseInputPlugin : public QMouseInputPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QMouseInputFactoryInterface_iid FILE "windows.json") + +public: + QMouseInput *create(const QString &key, const QStringList ¶mList) override; +}; + +QT_END_NAMESPACE + +#endif // WINDOWSMOUSEINPUTPLUGIN_H diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro deleted file mode 100644 index ac81e82..0000000 --- a/src/plugins/plugins.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += gamepads diff --git a/src/quickactionstore/CMakeLists.txt b/src/quickactionstore/CMakeLists.txt new file mode 100644 index 0000000..a8957f1 --- /dev/null +++ b/src/quickactionstore/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_qml_module(QuickActionStore + URI "QtActionStore" + VERSION "${PROJECT_VERSION}" + DEPENDENCIES QtQuick + SOURCES + qquickactionstore.cpp qquickactionstore_p.h + qquickeventlistener.cpp qquickeventlistener_p.h + qquickactionhandler.cpp qquickactionhandler_p.h + QML_FILES + ${qml_files} + PUBLIC_LIBRARIES + Qt::Core + Qt::Quick + Qt::QuickPrivate + Qt::UniversalInput + GENERATE_CPP_EXPORTS +) diff --git a/src/quickactionstore/qquickactionhandler.cpp b/src/quickactionstore/qquickactionhandler.cpp new file mode 100644 index 0000000..086749b --- /dev/null +++ b/src/quickactionstore/qquickactionhandler.cpp @@ -0,0 +1,177 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickactionhandler_p.h" + +QT_BEGIN_NAMESPACE + +// ActionHandler + +QQuickActionHandler::QQuickActionHandler(QObject *parent) + : QObject(parent), m_actionStore(nullptr) +{ +} + +void QQuickActionHandler::setActionStore(QQuickActionStore *actionStore) +{ + if (m_actionStore == actionStore) + return; + + if (m_actionStore) { + disconnect(m_actionStore, &QQuickActionStore::actionEvent, this, nullptr); + disconnect(m_actionStore, &QQuickActionStore::actionKeyEvent, this, nullptr); + } + m_actionStore = actionStore; + connect(m_actionStore, &QQuickActionStore::actionKeyEvent, this, [this](const QString &action, Qt::Key key, bool isPressed) + { + Q_UNUSED(key) + Q_UNUSED(isPressed) + if (action == m_actionTitle) { + setSource(Source::Key); + setValue(1.0f); + emit triggered(); + } }); + connect(m_actionStore, &QQuickActionStore::actionMouseButtonEvent, this, [this](const QString &action, Qt::MouseButton button, bool isPressed) + { + Q_UNUSED(button) + Q_UNUSED(isPressed) + if (action == m_actionTitle) { + setSource(Source::MouseButton); + setValue(1.0f); + emit triggered(); + } }); + connect(m_actionStore, &QQuickActionStore::actionJoyAxisEvent, this, [this](const QString &action, int device, JoyAxis axis, float value) + { + Q_UNUSED(device) + Q_UNUSED(axis) + if (action == m_actionTitle) + { + setSource(Source::JoyAxis); + setValue(value); + emit triggered(); + } + }); + connect(m_actionStore, &QQuickActionStore::actionJoyButtonEvent, this, [this](const QString &action, int device, JoyButton button, bool isPressed) + { + Q_UNUSED(device) + Q_UNUSED(button) + Q_UNUSED(isPressed) + if (action == m_actionTitle) { + setSource(Source::JoyButton); + setValue(1.0f); + emit triggered(); + } }); + + emit actionStoreChanged(); +} + +QQuickActionStore *QQuickActionHandler::actionStore() const +{ + return m_actionStore; +} + +void QQuickActionHandler::setActionTitle(const QString &actionTitle) +{ + if (m_actionTitle == actionTitle) + return; + + m_actionTitle = actionTitle; + emit actionTitleChanged(); +} + +QString QQuickActionHandler::actionTitle() const +{ + return m_actionTitle; +} + +void QQuickActionHandler::setSource(Source source) +{ + if (m_source == source) + return; + + m_source = source; + emit sourceChanged(); +} + +QQuickActionHandler::Source QQuickActionHandler::source() const +{ + return m_source; +} + +void QQuickActionHandler::setValue(float value) +{ + if (m_value == value) + return; + + m_value = value; + emit valueChanged(); +} + +float QQuickActionHandler::value() const +{ + return m_value; +} + +// ActionHandler +// ActionDispatch + +QQuickActionDispatch::QQuickActionDispatch(QObject *parent) + : QObject(parent), m_actionStore(nullptr) +{ +} + +void QQuickActionDispatch::setActionStore(QQuickActionStore *actionStore) +{ + if (m_actionStore == actionStore) + return; + + m_actionStore = actionStore; + for (QQuickActionHandler *handler : m_handlers) + handler->setActionStore(m_actionStore); + + emit actionStoreChanged(); +} + +QQuickActionStore *QQuickActionDispatch::actionStore() const +{ + return m_actionStore; +} + +QQmlListProperty QQuickActionDispatch::handlers() +{ + return QQmlListProperty(this, nullptr, &QQuickActionDispatch::appendActionHandler, + &QQuickActionDispatch::countActionHandler, + &QQuickActionDispatch::atActionHandler, + &QQuickActionDispatch::clearActionHandler); +} + +void QQuickActionDispatch::appendActionHandler(QQmlListProperty *list, QQuickActionHandler *action) +{ + auto *dispatch = static_cast(list->object); + dispatch->m_handlers.append(action); + action->setActionStore(dispatch->m_actionStore); + emit dispatch->handlersChanged(); +} + +qsizetype QQuickActionDispatch::countActionHandler(QQmlListProperty *list) +{ + auto *dispatch = static_cast(list->object); + return dispatch->m_handlers.count(); +} + +QQuickActionHandler *QQuickActionDispatch::atActionHandler(QQmlListProperty *list, qsizetype index) +{ + auto *dispatch = static_cast(list->object); + return dispatch->m_handlers.at(index); +} + +void QQuickActionDispatch::clearActionHandler(QQmlListProperty *list) +{ + auto *dispatch = static_cast(list->object); + for (QQuickActionHandler *handler : dispatch->m_handlers) + handler->setActionStore(nullptr); + dispatch->m_handlers.clear(); + emit dispatch->handlersChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quickactionstore/qquickactionhandler_p.h b/src/quickactionstore/qquickactionhandler_p.h new file mode 100644 index 0000000..9ced798 --- /dev/null +++ b/src/quickactionstore/qquickactionhandler_p.h @@ -0,0 +1,104 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTQUICKACTIONHANDLER_H +#define QTQUICKACTIONHANDLER_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickactionstore_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickActionHandler : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(ActionHandler) + Q_PROPERTY(QString actionTitle READ actionTitle WRITE setActionTitle NOTIFY actionTitleChanged) + Q_PROPERTY(QQuickActionStore* actionStore READ actionStore WRITE setActionStore NOTIFY actionStoreChanged) + Q_PROPERTY(Source source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(float value READ value WRITE setValue NOTIFY valueChanged) + Q_ENUMS(Source) + +public: + enum class Source { + Key, + MouseButton, + Touch, + JoyButton, + JoyAxis, + Other + }; + QQuickActionHandler(QObject *parent = nullptr); + ~QQuickActionHandler() override = default; + + void setActionStore(QQuickActionStore *actionStore); + QQuickActionStore* actionStore() const; + + void setActionTitle(const QString &actionName); + QString actionTitle() const; + + void setSource(Source source); + Source source() const; + + void setValue(float value); + float value() const; + +Q_SIGNALS: + void actionStoreChanged(); + void actionTitleChanged(); + void sourceChanged(); + void valueChanged(); + void triggered(); + + +private: + QQuickActionStore *m_actionStore; + QString m_actionTitle; + Source m_source; + float m_value; +}; + +class QQuickActionDispatch : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(ActionDispatch) + Q_PROPERTY(QQuickActionStore* actionStore READ actionStore WRITE setActionStore NOTIFY actionStoreChanged) + Q_PROPERTY(QQmlListProperty handlers READ handlers NOTIFY handlersChanged) + Q_CLASSINFO("DefaultProperty", "handlers") + +public: + QQuickActionDispatch(QObject *parent = nullptr); + ~QQuickActionDispatch() override = default; + + void setActionStore(QQuickActionStore *actionStore); + QQuickActionStore* actionStore() const; + + QQmlListProperty handlers(); + static void appendActionHandler(QQmlListProperty *list, QQuickActionHandler *action); + static qsizetype countActionHandler(QQmlListProperty *list); + static QQuickActionHandler *atActionHandler(QQmlListProperty *list, qsizetype index); + static void clearActionHandler(QQmlListProperty *list); + +Q_SIGNALS: + void actionStoreChanged(); + void handlersChanged(); + +private: + QQuickActionStore *m_actionStore; + QList m_handlers; +}; + +QT_END_NAMESPACE + +#endif // QTQUICKACTIONHANDLER_H diff --git a/src/quickactionstore/qquickactionstore.cpp b/src/quickactionstore/qquickactionstore.cpp new file mode 100644 index 0000000..df3dc46 --- /dev/null +++ b/src/quickactionstore/qquickactionstore.cpp @@ -0,0 +1,316 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickactionstore_p.h" + +QT_BEGIN_NAMESPACE + +// Events + +QQuickInputActionEvent::QQuickInputActionEvent(QObject *parent) + : QObject(parent) +{ +} + +QQuickInputJoyButtonEvent::QQuickInputJoyButtonEvent(QObject *parent) + : QQuickInputActionEvent(parent) +{ +} + +int QQuickInputJoyButtonEvent::device() const +{ + return m_device; +} + +void QQuickInputJoyButtonEvent::setDevice(int device) +{ + m_device = device; + emit deviceChanged(device); +} + +int QQuickInputJoyButtonEvent::button() const +{ + return m_button; +} + +void QQuickInputJoyButtonEvent::setButton(int button) +{ + m_button = button; + emit buttonChanged(button); +} + +bool QQuickInputJoyButtonEvent::isPressed() const +{ + return m_pressed; +} + +void QQuickInputJoyButtonEvent::setPressed(bool pressed) +{ + m_pressed = pressed; + emit isPressedChanged(pressed); +} + +QQuickInputKeyEvent::QQuickInputKeyEvent(QObject *parent) + : QQuickInputActionEvent(parent) +{ +} + +Qt::Key QQuickInputKeyEvent::key() const +{ + return m_key; +} + +void QQuickInputKeyEvent::setKey(Qt::Key key) +{ + m_key = key; + emit keyChanged(key); +} + +bool QQuickInputKeyEvent::isPressed() const +{ + return m_isPressed; +} + +void QQuickInputKeyEvent::setPressed(bool pressed) +{ + m_isPressed = pressed; + emit isPressedChanged(pressed); +} + +QQuickInputMouseButtonEvent::QQuickInputMouseButtonEvent(QObject *parent) + : QQuickInputActionEvent(parent) +{ +} + +int QQuickInputMouseButtonEvent::button() const +{ + return m_button; +} + +void QQuickInputMouseButtonEvent::setButton(int button) +{ + m_button = button; + emit buttonChanged(button); +} + +bool QQuickInputMouseButtonEvent::isPressed() const +{ + return m_isPressed; +} + +void QQuickInputMouseButtonEvent::setPressed(bool pressed) +{ + m_isPressed = pressed; + emit isPressedChanged(pressed); +} + +QQuickInputJoyAxisEvent::QQuickInputJoyAxisEvent(QObject *parent) + : QQuickInputActionEvent(parent) +{ +} + +int QQuickInputJoyAxisEvent::device() const +{ + return m_device; +} +void QQuickInputJoyAxisEvent::setDevice(int device) +{ + m_device = device; + emit deviceChanged(); +} + +int QQuickInputJoyAxisEvent::axis() const +{ + return m_axis; +} + +void QQuickInputJoyAxisEvent::setAxis(int axis) +{ + m_axis = axis; + emit axisChanged(); +} + +int QQuickInputJoyAxisEvent::direction() const +{ + return m_direction; +} + +void QQuickInputJoyAxisEvent::setDirection(int direction) +{ + m_direction = direction; + emit directionChanged(); +} + +float QQuickInputJoyAxisEvent::deadzone() const { + return m_deadzone; +} + +void QQuickInputJoyAxisEvent::setDeadzone(float deadzone) +{ + m_deadzone = deadzone; + emit deadzoneChanged(); +} + +// Actions + +QQuickInputAction::QQuickInputAction(QObject *parent) : QObject(parent) +{ +} + +QString QQuickInputAction::title() const +{ + return m_title; +} + +void QQuickInputAction::setTitle(const QString &title) +{ + m_title = title; + emit titleChanged(title); +} + +QQmlListProperty QQuickInputAction::events() +{ + return QQmlListProperty(this, nullptr, &QQuickInputAction::appendEvent, &QQuickInputAction::countEvent, &QQuickInputAction::atEvent, &QQuickInputAction::clearEvent); +} + +void QQuickInputAction::appendEvent(QQmlListProperty *list, QQuickInputActionEvent *event) +{ + if (event == nullptr) + return; + auto *self = static_cast(list->object); + self->m_events.push_back(event); + emit self->eventsChanged(); + + if (auto *joyButtonEvent = qobject_cast(event)) { + connect(joyButtonEvent, &QQuickInputJoyButtonEvent::deviceChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(joyButtonEvent, &QQuickInputJoyButtonEvent::buttonChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(joyButtonEvent, &QQuickInputJoyButtonEvent::isPressedChanged, self, [self]() + { emit self->eventsChanged(); }); + } + + if (auto *keyEvent = qobject_cast(event)) { + connect(keyEvent, &QQuickInputKeyEvent::keyChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(keyEvent, &QQuickInputKeyEvent::isPressedChanged, self, [self]() + { emit self->eventsChanged(); }); + } + + if (auto *joyAxisEvent = qobject_cast(event)) { + connect(joyAxisEvent, &QQuickInputJoyAxisEvent::deviceChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(joyAxisEvent, &QQuickInputJoyAxisEvent::axisChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(joyAxisEvent, &QQuickInputJoyAxisEvent::directionChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(joyAxisEvent, &QQuickInputJoyAxisEvent::deadzoneChanged, self, [self]() + { emit self->eventsChanged(); }); + } + + if (auto *mouseButtonEvent = qobject_cast(event)) { + connect(mouseButtonEvent, &QQuickInputMouseButtonEvent::buttonChanged, self, [self]() + { emit self->eventsChanged(); }); + connect(mouseButtonEvent, &QQuickInputMouseButtonEvent::isPressedChanged, self, [self]() + { emit self->eventsChanged(); }); + } +} +qsizetype QQuickInputAction::countEvent(QQmlListProperty *list) +{ + auto *self = static_cast(list->object); + return self->m_events.size(); +} +QQuickInputActionEvent *QQuickInputAction::atEvent(QQmlListProperty *list, qsizetype index) +{ + auto *self = static_cast(list->object); + return self->m_events.at(index); +} +void QQuickInputAction::clearEvent(QQmlListProperty *list) +{ + auto *self = static_cast(list->object); + self->m_events.clear(); + emit self->eventsChanged(); +} + +QActionStore::Action QQuickInputAction::action() const +{ + QActionStore::ActionBuilder builder(m_title); + + for (auto *event : m_events) { + if (auto *joyButtonEvent = qobject_cast(event)) + builder.addButton(QActionStore::Controller(joyButtonEvent->device()), JoyButton(joyButtonEvent->button()), joyButtonEvent->isPressed()); + if (auto *keyEvent = qobject_cast(event)) + builder.addKey(keyEvent->key(), keyEvent->isPressed()); + if (auto *joyAxisEvent = qobject_cast(event)) + builder.addAxis(QActionStore::Controller(joyAxisEvent->device()), JoyAxis(joyAxisEvent->axis()), QActionStore::AxisDirection(joyAxisEvent->direction()), joyAxisEvent->deadzone()); + if (auto *mouseButtonEvent = qobject_cast(event)) + builder.addMouseButton(Qt::MouseButton(mouseButtonEvent->button()), mouseButtonEvent->isPressed()); + } + + return builder.build(); +} + +QQuickActionStore::QQuickActionStore(QObject *parent) + : QActionStore(parent) +{ +} + +QQmlListProperty QQuickActionStore::actions() +{ + return QQmlListProperty(this, + nullptr, + QQuickActionStore::appendAction, + QQuickActionStore::countAction, + QQuickActionStore::atAction, + QQuickActionStore::clearAction); +} + +void QQuickActionStore::appendAction(QQmlListProperty *list, QQuickInputAction *action) +{ + if (action == nullptr) + return; + + auto *self = static_cast(list->object); + self->m_actions.push_back(action); + + auto actionItem = action->action(); + self->registerAction(actionItem); + + connect(action, &QQuickInputAction::titleChanged, self, [self, actionItem](){ + self->clearActions(); + for (auto *action : self->m_actions){ + self->registerAction(action->action()); + } + }); + connect(action, &QQuickInputAction::eventsChanged, self, [self, actionItem](){ + self->clearActions(); + for (auto *action : self->m_actions){ + self->registerAction(action->action()); + } + }); + + emit self->actionsChanged(); +} + +qsizetype QQuickActionStore::countAction(QQmlListProperty *list) +{ + auto *self = static_cast(list->object); + return self->m_actions.size(); +} + +QQuickInputAction *QQuickActionStore::atAction(QQmlListProperty *list, qsizetype index) +{ + auto *self = static_cast(list->object); + return self->m_actions.at(index); +} + +void QQuickActionStore::clearAction(QQmlListProperty *list) +{ + auto *self = static_cast(list->object); + self->clearActions(); + self->m_actions.clear(); + + emit self->actionsChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quickactionstore/qquickactionstore_p.h b/src/quickactionstore/qquickactionstore_p.h new file mode 100644 index 0000000..d59ae3e --- /dev/null +++ b/src/quickactionstore/qquickactionstore_p.h @@ -0,0 +1,315 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTQUICKACTIONSTORE_H +#define QTQUICKACTIONSTORE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQuickInputActionEvent : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(ActionEvent) +public: + QQuickInputActionEvent(QObject *parent = nullptr); + virtual ~QQuickInputActionEvent() = default; +}; + +class QQuickInputJoyButtonEvent : public QQuickInputActionEvent +{ + Q_OBJECT + QML_NAMED_ELEMENT(JoyButtonEvent) + Q_PROPERTY(int device READ device WRITE setDevice NOTIFY deviceChanged) + Q_PROPERTY(int button READ button WRITE setButton NOTIFY buttonChanged) + Q_PROPERTY(bool isPressed READ isPressed WRITE setPressed NOTIFY isPressedChanged) + Q_ENUMS(JoyButton) + Q_ENUMS(Controller) + +public: + // Taken from quniversalinput.h + enum class JoyButton + { + Invalid = -1, + A = 0, + B = 1, + X = 2, + Y = 3, + Back = 4, + Guide = 5, + Start = 6, + LeftStick = 7, + RightStick = 8, + LeftShoulder = 9, + RightShoulder = 10, + DpadUp = 11, + DpadDown = 12, + DpadLeft = 13, + DpadRight = 14, + Misc1 = 15, + Paddle1 = 16, + Paddle2 = 17, + Paddle3 = 18, + Paddle4 = 19, + Touchpad = 20, + MAX = 128 + }; + + // Taken from qactionstore.h + enum class Controller + { + All = -1, + Device0 = 0, + Device1 = 1, + Device2 = 2, + Device3 = 3, + Device4 = 4, + Device5 = 5, + Device6 = 6, + Device7 = 7, + Device8 = 8, + Device9 = 9, + Device10 = 10, + Device11 = 11, + Device12 = 12, + Device13 = 13, + Device14 = 14, + Device15 = 15, + Device16 = 16, + }; + + QQuickInputJoyButtonEvent(QObject *parent = nullptr); + ~QQuickInputJoyButtonEvent() override = default; + + int device() const; + void setDevice(int device); + + int button() const; + void setButton(int button); + + bool isPressed() const; + void setPressed(bool pressed); + +Q_SIGNALS: + void deviceChanged(int device); + void buttonChanged(int button); + void isPressedChanged(bool isPressed); + +private: + int m_device; + int m_button; + bool m_pressed; +}; + +class QQuickInputKeyEvent : public QQuickInputActionEvent +{ + Q_OBJECT + QML_NAMED_ELEMENT(KeyboardEvent) + Q_PROPERTY(Qt::Key key READ key WRITE setKey NOTIFY keyChanged) + Q_PROPERTY(bool isPressed READ isPressed WRITE setPressed NOTIFY isPressedChanged) + +public: + QQuickInputKeyEvent(QObject *parent = nullptr); + ~QQuickInputKeyEvent() override = default; + + Qt::Key key() const; + void setKey(Qt::Key key); + + bool isPressed() const; + void setPressed(bool pressed); + +Q_SIGNALS: + void keyChanged(Qt::Key key); + void isPressedChanged(bool isPressed); + +private: + Qt::Key m_key = Qt::Key_unknown; + bool m_isPressed = false; +}; + +class QQuickInputMouseButtonEvent : public QQuickInputActionEvent +{ + Q_OBJECT + QML_NAMED_ELEMENT(MouseButtonEvent) + Q_PROPERTY(int button READ button WRITE setButton NOTIFY buttonChanged) + Q_PROPERTY(bool isPressed READ isPressed WRITE setPressed NOTIFY isPressedChanged) +public: + QQuickInputMouseButtonEvent(QObject *parent = nullptr); + ~QQuickInputMouseButtonEvent() override = default; + + int button() const; + void setButton(int button); + + bool isPressed() const; + void setPressed(bool pressed); + +Q_SIGNALS: + void buttonChanged(int button); + void isPressedChanged(bool isPressed); + +private: + int m_button = 0; + bool m_isPressed = false; +}; + +class QQuickInputJoyAxisEvent : public QQuickInputActionEvent +{ + Q_OBJECT + QML_NAMED_ELEMENT(JoyAxisEvent) + Q_PROPERTY(int device READ device WRITE setDevice NOTIFY deviceChanged) + Q_PROPERTY(int axis READ axis WRITE setAxis NOTIFY axisChanged) + Q_PROPERTY(int direction READ direction WRITE setDirection NOTIFY directionChanged) + Q_PROPERTY(float deadzone READ deadzone WRITE setDeadzone NOTIFY deadzoneChanged) + Q_ENUMS(JoyAxis) + Q_ENUMS(AxisDirection) + Q_ENUMS(Controller) + +public: + // Taken from quniversalinput.h + enum class JoyAxis + { + Invalid = -1, + LeftX = 0, + LeftY = 1, + RightX = 2, + RightY = 3, + TriggerLeft = 4, + TriggerRight = 5, + MAX = 10, + }; + + // Taken from qactionstore.h + enum class Controller + { + All = -1, + Device0 = 0, + Device1 = 1, + Device2 = 2, + Device3 = 3, + Device4 = 4, + Device5 = 5, + Device6 = 6, + Device7 = 7, + Device8 = 8, + Device9 = 9, + Device10 = 10, + Device11 = 11, + Device12 = 12, + Device13 = 13, + Device14 = 14, + Device15 = 15, + Device16 = 16, + }; + + // Taken from qactionstore.h + enum class AxisDirection + { + All = -1, + Up = 0, + Right = 1, + Down = 2, + Left = 3, + Max = 4, + }; + + QQuickInputJoyAxisEvent(QObject *parent = nullptr); + ~QQuickInputJoyAxisEvent() override = default; + + int device() const; + void setDevice(int device); + + int axis() const; + void setAxis(int axis); + + int direction() const; + void setDirection(int direction); + + float deadzone() const; + void setDeadzone(float deadzone); + +Q_SIGNALS: + void deviceChanged(); + void axisChanged(); + void directionChanged(); + void deadzoneChanged(); + +private: + int m_device = 0; + int m_axis = 0; + int m_direction = 0; + float m_deadzone = 0.5f; +}; + +class QQuickInputAction : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_PROPERTY(QQmlListProperty events READ events NOTIFY eventsChanged) + Q_CLASSINFO("DefaultProperty", "events") + QML_NAMED_ELEMENT(InputAction) +public: + QQuickInputAction(QObject *parent = nullptr); + ~QQuickInputAction() override = default; + + QQmlListProperty events(); + static void appendEvent(QQmlListProperty *list, QQuickInputActionEvent *event); + static qsizetype countEvent(QQmlListProperty *list); + static QQuickInputActionEvent *atEvent(QQmlListProperty *list, qsizetype index); + static void clearEvent(QQmlListProperty *list); + + QString title() const; + void setTitle(const QString &title); + + QActionStore::Action action() const; + +Q_SIGNALS: + void titleChanged(const QString &title); + void eventsChanged(); + +private: + QString m_title; + QList m_events; +}; + +class QQuickActionStore : public QActionStore +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty actions READ actions) + Q_CLASSINFO("DefaultProperty", "actions") + QML_NAMED_ELEMENT(ActionStore) + +public: + QQuickActionStore(QObject *parent = nullptr); + ~QQuickActionStore() override = default; + + QQmlListProperty actions(); + static void appendAction(QQmlListProperty *list, QQuickInputAction *action); + static qsizetype countAction(QQmlListProperty *list); + static QQuickInputAction *atAction(QQmlListProperty *list, qsizetype index); + static void clearAction(QQmlListProperty *list); + +Q_SIGNALS: + void actionsChanged(); + +private: + QList m_actions; +}; + +QT_END_NAMESPACE + +#endif // QTQUICKACTIONSTORE_H diff --git a/src/quickactionstore/qquickeventlistener.cpp b/src/quickactionstore/qquickeventlistener.cpp new file mode 100644 index 0000000..52a3de3 --- /dev/null +++ b/src/quickactionstore/qquickeventlistener.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickeventlistener_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +ActionStoreEventListener::ActionStoreEventListener(QQuickItem *parent) + : QQuickItem(parent) +{ + setAcceptedMouseButtons(Qt::AllButtons); + setOpacity(0.0); +} + +QQmlListProperty ActionStoreEventListener::actionStores() +{ + return QQmlListProperty(this, nullptr, + &ActionStoreEventListener::appendActionHandler, + &ActionStoreEventListener::countActionHandler, + &ActionStoreEventListener::atActionHandler, + &ActionStoreEventListener::clearActionHandler); +} + +void ActionStoreEventListener::appendActionHandler(QQmlListProperty *list, QQuickActionStore *action) +{ + auto *Listener = static_cast(list->object); + Listener->m_actionStores.append(action); +} + +qsizetype ActionStoreEventListener::countActionHandler(QQmlListProperty *list) +{ + auto *Listener = static_cast(list->object); + return Listener->m_actionStores.count(); +} + +QQuickActionStore *ActionStoreEventListener::atActionHandler(QQmlListProperty *list, qsizetype index) +{ + auto *Listener = static_cast(list->object); + return Listener->m_actionStores.at(index); +} + +void ActionStoreEventListener::clearActionHandler(QQmlListProperty *list) +{ + auto *Listener = static_cast(list->object); + Listener->m_actionStores.clear(); +} + +void ActionStoreEventListener::sendKeyEvent(Qt::Key key, bool isPressed) +{ + for (auto *store : m_actionStores) + store->sendKeyEvent(key, isPressed); +} + +void ActionStoreEventListener::sendMouseButtonEvent(Qt::MouseButton button, bool isPressed) +{ + for (auto *store : m_actionStores) + store->sendMouseButtonEvent(button, isPressed); +} + +void ActionStoreEventListener::keyPressEvent(QKeyEvent *event) +{ + for (auto *store : m_actionStores) + store->sendKeyEvent(Qt::Key(event->key()), true); + + QQuickItem::keyPressEvent(event); +} + +void ActionStoreEventListener::keyReleaseEvent(QKeyEvent *event) +{ + for (auto *store : m_actionStores) + store->sendKeyEvent(Qt::Key(event->key()), false); + + QQuickItem::keyReleaseEvent(event); +} + +void ActionStoreEventListener::mousePressEvent(QMouseEvent *event) +{ + for (auto *store : m_actionStores) + store->sendMouseButtonEvent(event->button(), true); + + QQuickItem::mousePressEvent(event); +} + +void ActionStoreEventListener::mouseReleaseEvent(QMouseEvent *event) +{ + for (auto *store : m_actionStores) + store->sendMouseButtonEvent(event->button(), false); + + QQuickItem::mouseReleaseEvent(event); +} + +QT_END_NAMESPACE diff --git a/src/quickactionstore/qquickeventlistener_p.h b/src/quickactionstore/qquickeventlistener_p.h new file mode 100644 index 0000000..f327715 --- /dev/null +++ b/src/quickactionstore/qquickeventlistener_p.h @@ -0,0 +1,58 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTQUICKEVENTLISTENER_H +#define QTQUICKEVENTLISTENER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +#include "qquickactionstore_p.h" + +QT_BEGIN_NAMESPACE + +class ActionStoreEventListener : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty actionStores READ actionStores) + QML_ELEMENT + +public: + ActionStoreEventListener(QQuickItem *parent = nullptr); + + QQmlListProperty actionStores(); + static void appendActionHandler(QQmlListProperty *list, QQuickActionStore *action); + static qsizetype countActionHandler(QQmlListProperty *list); + static QQuickActionStore *atActionHandler(QQmlListProperty *list, qsizetype index); + static void clearActionHandler(QQmlListProperty *list); + +public Q_SLOTS: + void sendKeyEvent(Qt::Key key, bool isPressed = true); + void sendMouseButtonEvent(Qt::MouseButton button, bool isPressed = true); + +protected: + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + QList m_actionStores; +}; + +QT_END_NAMESPACE + +#endif // QTQUICKEVENTLISTENER_H diff --git a/src/quickgamepad/CMakeLists.txt b/src/quickgamepad/CMakeLists.txt new file mode 100644 index 0000000..35cc271 --- /dev/null +++ b/src/quickgamepad/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_qml_module(QuickGamepad + URI "QtGamepad" + VERSION "${PROJECT_VERSION}" + DEPENDENCIES QtQuick + SOURCES + qquickgamepad.cpp qquickgamepad_p.h + QML_FILES + ${qml_files} + PUBLIC_LIBRARIES + Qt::Core + Qt::GamepadPrivate + Qt::Quick + Qt::QuickPrivate + GENERATE_CPP_EXPORTS +) diff --git a/src/quickgamepad/qquickgamepad.cpp b/src/quickgamepad/qquickgamepad.cpp new file mode 100644 index 0000000..560110c --- /dev/null +++ b/src/quickgamepad/qquickgamepad.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickgamepad_p.h" + +QT_BEGIN_NAMESPACE + +QQuickGamepad::QQuickGamepad(QObject *parent) + : QGamepad(-1, parent) +{ + +} + +QQuickGamepad::~QQuickGamepad() +{ + +} + +QT_END_NAMESPACE diff --git a/src/quickgamepad/qquickgamepad_p.h b/src/quickgamepad/qquickgamepad_p.h new file mode 100644 index 0000000..d0034f1 --- /dev/null +++ b/src/quickgamepad/qquickgamepad_p.h @@ -0,0 +1,36 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTQUICKGAMEPAD_H +#define QTQUICKGAMEPAD_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickGamepad : public QGamepad { + Q_OBJECT + QML_NAMED_ELEMENT(Gamepad) +public: + QQuickGamepad(QObject *parent = nullptr); + ~QQuickGamepad(); + +}; + + +QT_END_NAMESPACE + +#endif // QTQUICKGAMEPAD_H diff --git a/src/quickuniversalinput/CMakeLists.txt b/src/quickuniversalinput/CMakeLists.txt new file mode 100644 index 0000000..0fc835a --- /dev/null +++ b/src/quickuniversalinput/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_qml_module(QuickUniversalInput + URI "QtUniversalInput" + VERSION "${PROJECT_VERSION}" + DEPENDENCIES QtQuick + SOURCES + qquickuniversalinput.cpp qquickuniversalinput_p.h + QML_FILES + ${qml_files} + PUBLIC_LIBRARIES + Qt::Core + Qt::Quick + Qt::QuickPrivate + Qt::UniversalInput + GENERATE_CPP_EXPORTS +) diff --git a/src/quickuniversalinput/qquickuniversalinput.cpp b/src/quickuniversalinput/qquickuniversalinput.cpp new file mode 100644 index 0000000..d0031fc --- /dev/null +++ b/src/quickuniversalinput/qquickuniversalinput.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickuniversalinput_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQuickUniversalInputPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QQuickUniversalInput) +public: + QQuickUniversalInputPrivate(); +}; + +QQuickUniversalInputPrivate::QQuickUniversalInputPrivate() +{ + +} + +QQuickUniversalInput::QQuickUniversalInput(QObject *parent) + : QObject(*new QQuickUniversalInputPrivate, parent) +{ + connect(QUniversalInput::instance(), &QUniversalInput::joyConnectionChanged, this, &QQuickUniversalInput::joyConnectionChanged); + connect(QUniversalInput::instance(), &QUniversalInput::joyButtonEvent, this, &QQuickUniversalInput::joyButtonEvent); + connect(QUniversalInput::instance(), &QUniversalInput::joyAxisEvent, this, &QQuickUniversalInput::joyAxisEvent); + connect(QUniversalInput::instance(), &QUniversalInput::mouseMovedWithDeltas, this, &QQuickUniversalInput::mouseDeltaChanged); +} + +bool QQuickUniversalInput::isMouseDisabled() const +{ + auto input = QUniversalInput::instance(); + return input->isMouseDisabled(); +} + +void QQuickUniversalInput::setMouseDisabled(bool disabled) +{ + auto input = QUniversalInput::instance(); + if (input->isMouseDisabled() == disabled) + return; + input->setMouseDisabled(disabled); + emit mouseDisabledChanged(); +} + +void QQuickUniversalInput::addForce(int device, const QVector2D &force, float duration) +{ + QUniversalInput::instance()->addForce(device, force, duration); +} + +void QQuickUniversalInput::joyButton(int device, JoyButton button, bool isPressed) +{ + auto input = QUniversalInput::instance(); + input->joyButton(device,button, isPressed); +} + +void QQuickUniversalInput::joyAxis(int device, JoyAxis axis, float value) +{ + auto input = QUniversalInput::instance(); + input->joyAxis(device, axis, value); +} + +void QQuickUniversalInput::joyHat(int device, HatMask value) +{ + auto input = QUniversalInput::instance(); + input->joyHat(device, value); +} + +QT_END_NAMESPACE diff --git a/src/quickuniversalinput/qquickuniversalinput_p.h b/src/quickuniversalinput/qquickuniversalinput_p.h new file mode 100644 index 0000000..8d5f1dc --- /dev/null +++ b/src/quickuniversalinput/qquickuniversalinput_p.h @@ -0,0 +1,64 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTQUICKUNIVERSALINPUT_H +#define QTQUICKUNIVERSALINPUT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickUniversalInputPrivate; + +class QQuickUniversalInput : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(UniversalInput) + Q_PROPERTY(bool mouseDisabled READ isMouseDisabled WRITE setMouseDisabled NOTIFY mouseDisabledChanged) + +public: + QQuickUniversalInput(QObject *parent = nullptr); + ~QQuickUniversalInput() override = default; + + bool isMouseDisabled() const; + void setMouseDisabled(bool disabled); + +Q_SIGNALS: + void joyConnectionChanged(int index, bool isConnected); + void joyButtonEvent(int device, JoyButton button, bool isPressed); + void joyAxisEvent(int device, JoyAxis axis, float value); + + void mouseDisabledChanged(); + void mouseDeltaChanged(const QVector2D& delta); + +public Q_SLOTS: + void addForce(int device, const QVector2D& force, float duration); + + void joyButton(int device, JoyButton button, bool isPressed); + void joyAxis(int device, JoyAxis axis, float value); + void joyHat(int device, HatMask value); + + +private: + Q_DISABLE_COPY(QQuickUniversalInput) + Q_DECLARE_PRIVATE(QQuickUniversalInput) +}; + +QT_END_NAMESPACE + +#endif // QTQUICKUNIVERSALINPUT_H diff --git a/src/src.pro b/src/src.pro deleted file mode 100644 index ed7c34c..0000000 --- a/src/src.pro +++ /dev/null @@ -1,11 +0,0 @@ -TEMPLATE = subdirs -CONFIG += ordered -SUBDIRS += \ - gamepad \ - plugins - -qtHaveModule(quick) { - src_imports.subdir = imports - src_imports.depends = gamepad - SUBDIRS += src_imports -} diff --git a/src/universalinput/CMakeLists.txt b/src/universalinput/CMakeLists.txt new file mode 100644 index 0000000..7f8a893 --- /dev/null +++ b/src/universalinput/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_module(UniversalInput + PLUGIN_TYPES joystickinputs mouseinputs + SOURCES + qjoystickinput_p.h + qjoystickinputplugin_p.h + qjoystickinputfactory.cpp qjoystickinputfactory_p.h + quniversalinput.cpp quniversalinput.h quniversalinput_p.h + qtuniversalinputglobal_p.h + qtuniversalinputglobal.h + qjoydevicemappingparser.cpp qjoydevicemappingparser_p.h + qactionstore.cpp qactionstore.h + qmouseinput_p.h + qmouseinputfactory.cpp qmouseinputfactory_p.h + qmouseinputplugin_p.h + DEFINES + QT_BUILD_UNIVERSALINPUT_LIB + LIBRARIES + Qt::CorePrivate + Qt::GuiPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + Qt::GuiPrivate + GENERATE_CPP_EXPORTS +) + +set_source_files_properties(../3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt PROPERTIES + QT_RESOURCE_ALIAS gamecontrollerdb.txt +) + +qt_internal_add_resource(UniversalInput "qtuniversalinputresources" + PREFIX + "/qt-project.org/qtuniversalinput/" + FILES + "../3rdparty/sdlgamecontrollerdb/gamecontrollerdb.txt" +) + + + +# file *should* be :/qt-project.org/qtuniversalinput/gamecontrollerdb.txt diff --git a/src/universalinput/GODOT_LICENSE.txt b/src/universalinput/GODOT_LICENSE.txt new file mode 100644 index 0000000..0e3ba08 --- /dev/null +++ b/src/universalinput/GODOT_LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). +Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/universalinput/doc/images/gamecontrollers.jpg b/src/universalinput/doc/images/gamecontrollers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5dae209a05f0bbb3d1777916f038ed9062adfeab GIT binary patch literal 45722 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 + +#include + +QT_BEGIN_NAMESPACE + +class QActionStorePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QActionStore) + +public: + QActionStorePrivate() + { + } + + QHash actions; + + void _q_handleJoyAxisEvent(int device, JoyAxis axis, float value); + void _q_handleJoyButtonEvent(int device, JoyButton button, bool isPressed); +}; + +QActionStore::QActionStore(QObject *parent) + : QObject(*new QActionStorePrivate, parent) +{ + Q_D(QActionStore); + d->q_ptr = this; + + auto input = QUniversalInput::instance(); + connect(input, SIGNAL(joyAxisEvent(int, JoyAxis, float)), this, SLOT(_q_handleJoyAxisEvent(int, JoyAxis, float))); + connect(input, SIGNAL(joyButtonEvent(int, JoyButton, bool)), this, SLOT(_q_handleJoyButtonEvent(int, JoyButton, bool))); + + if (parent) + parent->installEventFilter(this); +} + +QActionStore::~QActionStore() +{ + if (parent()) + parent()->removeEventFilter(this); +} + +void QActionStore::registerAction(const Action &action) +{ + Q_D(QActionStore); + d->actions.insert(action.name, action); +} + +void QActionStore::clearActions() +{ + Q_D(QActionStore); + d->actions.clear(); +} + +void QActionStorePrivate::_q_handleJoyAxisEvent(int device, JoyAxis axis, float value) +{ + for (int j = 0; j < actions.size(); j++) { + auto key = actions.keys()[j]; + auto action = actions[key]; + for (auto axisAction : action.axes) { + const auto absValue = abs(value); + if (axisAction.axis == axis && ((int)axisAction.device == device || axisAction.device == QActionStore::Controller::All) && absValue >= axisAction.deadzone) { + switch (axisAction.direction) { + case QActionStore::AxisDirection::Left: + case QActionStore::AxisDirection::Up: + if (value < 0) { + Q_EMIT q_func()->actionEvent(action.name); + Q_EMIT q_func()->actionJoyAxisEvent(action.name, device, axis, absValue); + } + break; + case QActionStore::AxisDirection::Right: + case QActionStore::AxisDirection::Down: + if (value > 0) { + Q_EMIT q_func()->actionEvent(action.name); + Q_EMIT q_func()->actionJoyAxisEvent(action.name, device, axis, absValue); + } + break; + case QActionStore::AxisDirection::All: + Q_EMIT q_func()->actionEvent(action.name); + Q_EMIT q_func()->actionJoyAxisEvent(action.name, device, axis, absValue); + break; + default: + break; + }; + } + + if (actions.size() == 0) + break; + } + if (actions.size() == 0) + break; + } +} + +void QActionStorePrivate::_q_handleJoyButtonEvent(int device, JoyButton button, bool isPressed) +{ + for (auto j = 0; j < actions.size(); j++) { + auto key = actions.keys()[j]; + auto action = actions[key]; + + for (auto buttonAction : action.buttons) { + if (buttonAction.button == button && buttonAction.isPressed == isPressed && ((int)buttonAction.device == device || buttonAction.device == QActionStore::Controller::All)) { + Q_EMIT q_func()->actionEvent(action.name); + Q_EMIT q_func()->actionJoyButtonEvent(action.name, device, button, isPressed); + } + if (actions.size() == 0) + break; + } + if (actions.size() == 0) + break; + } +} + + +void QActionStore::sendKeyEvent(Qt::Key key, bool isPressed) +{ + Q_D(QActionStore); + for (auto j = 0; j < d->actions.size(); j++) { + auto aKey = d->actions.keys()[j]; + auto action = d->actions[aKey]; + for (auto keyAction : action.keys) { + if (keyAction.key == key && keyAction.isPressed == isPressed) + { + Q_EMIT actionEvent(action.name); + Q_EMIT actionKeyEvent(action.name, key, isPressed); + } + if (d->actions.size() == 0) + break; + } + if (d->actions.size() == 0) + break; + } +} + +void QActionStore::sendMouseButtonEvent(Qt::MouseButton button, bool isPressed) +{ + Q_D(QActionStore); + for (int j = 0; j < d->actions.size(); j++) { + auto aKey = d->actions.keys()[j]; + auto action = d->actions[aKey]; + for (auto mouseButtonAction : action.mouseButtons) { + if (mouseButtonAction.button == button && mouseButtonAction.isPressed == isPressed) { + Q_EMIT actionEvent(action.name); + Q_EMIT actionMouseButtonEvent(action.name, button, isPressed); + } + if (d->actions.size() == 0) + break; + } + if (d->actions.size() == 0) + break; + } +} + +// ActionBuilder +QActionStore::ActionBuilder::ActionBuilder(const QString &name) + : m_action({name, {}, {}, {}, {}}) +{ +} + +QActionStore::ActionBuilder &QActionStore::ActionBuilder::addAxis(Controller device, JoyAxis axis, AxisDirection direction, float deadzone) +{ + m_action.axes.push_back({device, axis, direction, deadzone}); + return *this; +} + +QActionStore::ActionBuilder &QActionStore::ActionBuilder::addButton(Controller device, JoyButton button, bool isPressed) +{ + m_action.buttons.push_back({device, button, isPressed}); + return *this; +} + +QActionStore::ActionBuilder &QActionStore::ActionBuilder::addKey(Qt::Key key, bool isPressed) +{ + m_action.keys.push_back({key, isPressed}); + return *this; +} + +QActionStore::ActionBuilder &QActionStore::ActionBuilder::addMouseButton(Qt::MouseButton button, bool isPressed) +{ + m_action.mouseButtons.push_back({button, isPressed}); + return *this; +} + +QActionStore::Action QActionStore::ActionBuilder::build() const +{ + return m_action; +} + + +QT_END_NAMESPACE + +#include "moc_qactionstore.cpp" diff --git a/src/universalinput/qactionstore.h b/src/universalinput/qactionstore.h new file mode 100644 index 0000000..f16f07b --- /dev/null +++ b/src/universalinput/qactionstore.h @@ -0,0 +1,141 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QACTIONSTORE_H +#define QACTIONSTORE_H + +#include + +using namespace Qt::Literals::StringLiterals; + +QT_BEGIN_NAMESPACE + +class QActionStorePrivate; + +class Q_UNIVERSALINPUT_EXPORT QActionStore : public QObject +{ + Q_OBJECT + Q_ENUMS(Controller) + Q_ENUMS(AxisDirection) +public: + enum class Controller + { + All = -1, + Device0 = 0, + Device1 = 1, + Device2 = 2, + Device3 = 3, + Device4 = 4, + Device5 = 5, + Device6 = 6, + Device7 = 7, + Device8 = 8, + Device9 = 9, + Device10 = 10, + Device11 = 11, + Device12 = 12, + Device13 = 13, + Device14 = 14, + Device15 = 15, + Device16 = 16, + DeviceMAX = 17, + }; + + enum class AxisDirection + { + All = -1, + Up = 0, + Right = 1, + Down = 2, + Left = 3, + Max = 4, + }; + + struct JoyButtonAction + { + Controller device = Controller::All; + JoyButton button = JoyButton::Invalid; + bool isPressed = false; + }; + + struct JoyAxisAction + { + Controller device = Controller::All; + JoyAxis axis = JoyAxis::Invalid; + AxisDirection direction = AxisDirection::Max; + float deadzone = 0.5f; + }; + + struct KeyEventAction + { + Qt::Key key = Qt::Key_unknown; + bool isPressed = false; + }; + + struct MouseButtonAction + { + Qt::MouseButton button = Qt::NoButton; + bool isPressed = false; + }; + + struct Action + { + QString name = u""_s; + QList buttons; + QList axes; + QList keys; + QList mouseButtons; + }; + + struct Q_UNIVERSALINPUT_EXPORT ActionBuilder + { + ActionBuilder(const QString &name); + ActionBuilder &addAxis(Controller device, JoyAxis axis, AxisDirection direction, float deadzone); + ActionBuilder &addButton(Controller device, JoyButton button, bool isPressed = true); + ActionBuilder &addKey(Qt::Key key, bool isPressed = true); + ActionBuilder &addMouseButton(Qt::MouseButton button, bool isPressed = true); + + Action build() const; + + private: + Action m_action; + }; + + explicit QActionStore(QObject *parent = nullptr); + ~QActionStore(); + + void registerAction(const Action &action); + void clearActions(); + +Q_SIGNALS: + void actionEvent(const QString &action); + void actionKeyEvent(const QString &action, Qt::Key key, bool isPressed); + void actionMouseButtonEvent(const QString &action, Qt::MouseButton button, bool isPressed); + void actionJoyButtonEvent(const QString &action, int device, JoyButton button, bool isPressed); + void actionJoyAxisEvent(const QString &action, int device, JoyAxis axis, float value); + +public Q_SLOTS: + void sendKeyEvent(Qt::Key key, bool isPressed = true); + void sendMouseButtonEvent(Qt::MouseButton button, bool isPressed = true); + +private: + Q_DECLARE_PRIVATE(QActionStore) + Q_DISABLE_COPY(QActionStore) + +private: + Q_PRIVATE_SLOT(d_func(), void _q_handleJoyAxisEvent(int, JoyAxis, float)) + Q_PRIVATE_SLOT(d_func(), void _q_handleJoyButtonEvent(int, JoyButton, bool)) +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QActionStore *) +Q_DECLARE_METATYPE(QActionStore::Controller) +Q_DECLARE_METATYPE(QActionStore::AxisDirection) +Q_DECLARE_METATYPE(QActionStore::JoyButtonAction) +Q_DECLARE_METATYPE(QActionStore::JoyAxisAction) +Q_DECLARE_METATYPE(QActionStore::KeyEventAction) +Q_DECLARE_METATYPE(QActionStore::MouseButtonAction) +Q_DECLARE_METATYPE(QActionStore::Action) + +#endif // QACTIONSTORE_H diff --git a/src/universalinput/qjoydevicemappingparser.cpp b/src/universalinput/qjoydevicemappingparser.cpp new file mode 100644 index 0000000..26247f8 --- /dev/null +++ b/src/universalinput/qjoydevicemappingparser.cpp @@ -0,0 +1,248 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qjoydevicemappingparser_p.h" + +#include + +QT_BEGIN_NAMESPACE + +QJoyDeviceMappingParser::QJoyDeviceMappingParser(const QString &filepath) + : m_filepath(filepath), m_file(filepath), m_stream(&m_file) +{ + if (!m_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "QJoyDeviceMappingParser could not open file" << m_filepath; + return; + } +} + +struct Axis +{ + JoyAxis axis; + QUniversalInput::JoyAxisRange range; + bool invert; +}; + +static Axis axisFromString(const QString &axisStr) +{ + auto axis = axisStr; + + auto joyAxis = JoyAxis::Invalid; + auto axisRange = QUniversalInput::JoyAxisRange::FullAxis; + + // if first character is a minus, it's a negative axis + if (axis[0] == u"-"_s) { + axisRange = QUniversalInput::JoyAxisRange::NegativeHalfAxis; + // remove the minus sign + // qstring + axis = axis.remove(0, 1); + } else if (axis[0] == u"+"_s) { + // if first character is a plus, it's a positive axis + axisRange = QUniversalInput::JoyAxisRange::PositiveHalfAxis; + // remove the plus sign + axis = axis.remove(0, 1); + } + + if (axis[0] == u"a"_s) { + // remove the a + axis = axis.remove(0, 1); + int axisNumber = axis.toInt(); + joyAxis = static_cast(axisNumber); + } else if (axis == u"rightx"_s) { + joyAxis = JoyAxis::RightX; + } else if (axis == u"righty"_s) { + joyAxis = JoyAxis::RightY; + } else if (axis == u"leftx"_s) { + joyAxis = JoyAxis::LeftX; + } else if (axis == u"lefty"_s) { + joyAxis = JoyAxis::LeftY; + } else if (axis == u"lefttrigger"_s) { + joyAxis = JoyAxis::TriggerLeft; + } else if (axis == u"righttrigger"_s) { + joyAxis = JoyAxis::TriggerRight; + } else { + qDebug() << "QJoyDeviceMappingParser::axisFromString:" << axis; + } + + return {joyAxis, axisRange, false}; +} + +static JoyButton buttonFromString(const QString &button) +{ + if (button == u"a"_s) + return JoyButton::A; + if (button == u"b"_s) + return JoyButton::B; + if (button == u"x"_s) + return JoyButton::X; + if (button == u"y"_s) + return JoyButton::Y; + if (button == u"back"_s) + return JoyButton::Back; + if (button == u"guide"_s) + return JoyButton::Guide; + if (button == u"start"_s) + return JoyButton::Start; + if (button == u"leftstick"_s) + return JoyButton::LeftStick; + if (button == u"rightstick"_s) + return JoyButton::RightStick; + if (button == u"leftshoulder"_s) + return JoyButton::LeftShoulder; + if (button == u"rightshoulder"_s) + return JoyButton::RightShoulder; + if (button == u"dpadup"_s || button == u"dpup"_s) + return JoyButton::DpadUp; + if (button == u"dpaddown"_s || button == u"dpdown"_s) + return JoyButton::DpadDown; + if (button == u"dpadleft"_s || button == u"dpleft"_s) + return JoyButton::DpadLeft; + if (button == u"dpadright"_s || button == u"dpright"_s) + return JoyButton::DpadRight; + if (button == u"misc1"_s) + return JoyButton::Misc1; + if (button == u"paddle1"_s) + return JoyButton::Paddle1; + if (button == u"paddle2"_s) + return JoyButton::Paddle2; + if (button == u"paddle3"_s) + return JoyButton::Paddle3; + if (button == u"paddle4"_s) + return JoyButton::Paddle4; + if (button == u"touchpad"_s) + return JoyButton::Touchpad; + if (button.startsWith(u"b"_s)) { + bool ok; + int index = button.mid(1).toInt(&ok); + if (ok) + return static_cast(index); + } + qWarning() << "QJoyDeviceMappingParser::buttonFromString: Unknown button" << button; + return JoyButton::Invalid; +} + +struct Hat +{ + HatDirection direction; + HatMask mask; +}; + +static Hat hatFromString(const QString &hat) +{ + int hatMask = hat[hat.length() - 1].digitValue(); + int log2hatMask = qFloor(qLn(hatMask) / qLn(2)); + return {HatDirection(log2hatMask), HatMask(hatMask)}; +} + +QUniversalInput::JoyType QJoyDeviceMappingParser::toJoyType(const QString &type) const +{ + if (type == u"a"_s || type == u"b"_s) // these messes with the rest of the capturing + return QUniversalInput::JoyType::TypeButton; + if (auto match = m_buttonRegex.match(type); match.hasMatch() && match.capturedLength() == type.length()) + return QUniversalInput::JoyType::TypeButton; + if (m_axisRegex.match(type).hasMatch()) + return QUniversalInput::JoyType::TypeAxis; + if (m_hatRegex.match(type).hasMatch()) + return QUniversalInput::JoyType::TypeHat; + + qWarning() << "QJoyDeviceMappingParser::toJoyType: Unknown type" << type; + return QUniversalInput::JoyType::TypeMax; +} + +QUniversalInput::JoyBinding QJoyDeviceMappingParser::parseBinding(const QString &token) const +{ + auto actions = token.split(u':'); + auto output = actions[0]; + auto input = actions[0]; + if (actions.size() == 2) + input = actions[1]; + + QUniversalInput::JoyBinding binding = {}; + binding.inputType = toJoyType(input); + binding.outputType = toJoyType(output); + + // input + switch (binding.inputType) { + case QUniversalInput::JoyType::TypeButton: + binding.input.button = buttonFromString(input); + break; + case QUniversalInput::JoyType::TypeAxis: + { + auto axis = axisFromString(input); + binding.input.axis.axis = axis.axis; + binding.input.axis.range = axis.range; + binding.input.axis.invert = axis.invert; + break; + } + case QUniversalInput::JoyType::TypeHat: + { + auto hat = hatFromString(input); + binding.input.hat.hat = hat.direction; + binding.input.hat.hat_mask = hat.mask; + break; + } + default: + qWarning() << "QJoyDeviceMappingParser::parseBinding: Unknown input type" << input; + break; + } + + // output + switch (binding.outputType) { + case QUniversalInput::JoyType::TypeHat: + binding.outputType = QUniversalInput::JoyType::TypeButton; + break; + case QUniversalInput::JoyType::TypeButton: + binding.output.button = buttonFromString(output); + break; + case QUniversalInput::JoyType::TypeAxis: + { + auto axis = axisFromString(output); + binding.output.axis.axis = axis.axis; + binding.output.axis.range = axis.range; + break; + } + default: + qWarning() << "QJoyDeviceMappingParser::parseBinding: Unknown output type" << output; + break; + } + + return binding; +} + +std::optional QJoyDeviceMappingParser::next() +{ + if (m_stream.atEnd()) + return {}; + + auto line = m_stream.readLine().trimmed(); + + // skip comments and empty lines + while (line.startsWith(u"#"_s) || line.isEmpty()) { + line = m_stream.readLine().trimmed(); + if (m_stream.atEnd()) + return {}; + } + + auto tokens = line.split(u','); + + // last , makes an empty token + if (tokens.back().isEmpty()) + tokens.pop_back(); + + auto uid = tokens.takeFirst(); + auto name = tokens.takeFirst(); + auto platform = tokens.takeLast(); + Q_UNUSED(platform); // just had to remove platform from the tokens + + QVector bindings; + for (const auto &token : tokens) { + auto bindingToken = token.trimmed(); + auto binding = parseBinding(bindingToken); + bindings.push_back(binding); + } + + QUniversalInput::JoyDeviceMapping mapping = {uid, name, bindings}; + return mapping; +} + +QT_END_NAMESPACE diff --git a/src/universalinput/qjoydevicemappingparser_p.h b/src/universalinput/qjoydevicemappingparser_p.h new file mode 100644 index 0000000..c447923 --- /dev/null +++ b/src/universalinput/qjoydevicemappingparser_p.h @@ -0,0 +1,54 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QJOYDEVICEMAPPINGPARSER_P_H +#define QJOYDEVICEMAPPINGPARSER_P_H + +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace Qt::Literals::StringLiterals; + +class QJoyDeviceMappingParser +{ +public: + QJoyDeviceMappingParser(const QString &filepath); + + std::optional next(); + +private: + QUniversalInput::JoyBinding parseBinding(const QString &token) const; + QUniversalInput::JoyType toJoyType(const QString &type) const; + +private: + QString m_filepath; + QFile m_file; + QTextStream m_stream; + QString m_currentLine; + + QRegularExpression m_buttonRegex{u"b([0-9]+)|(x)|(y)|(back)|(guide)|(start)|(leftstick)|(rightstick)|(leftshoulder)|(rightshoulder)|(misc1)|(paddle1)|(paddle2)|(paddle3)|(paddle4)|(touchpad)"_s}; + QRegularExpression m_axisRegex{u"a[0-9]+|rightx|righty|leftx|lefty|lefttrigger|righttrigger"_s}; + QRegularExpression m_hatRegex{u"h[0-9]+|dpup|dpdown|dpleft|dpright|dpadup|dpaddown|dpadleft|dpadright"_s}; +}; + +QT_END_NAMESPACE + +#endif // QJOYDEVICEMAPPINGPARSER_P_H diff --git a/src/universalinput/qjoystickinput_p.h b/src/universalinput/qjoystickinput_p.h new file mode 100644 index 0000000..7c7a7c5 --- /dev/null +++ b/src/universalinput/qjoystickinput_p.h @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QJOYSTICKINPUT_P_H +#define QJOYSTICKINPUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_UNIVERSALINPUT_EXPORT QJoystickInput : public QObject +{ + Q_OBJECT +}; + +QT_END_NAMESPACE + +#endif // QJOYSTICKINPUT_P_H diff --git a/src/universalinput/qjoystickinputfactory.cpp b/src/universalinput/qjoystickinputfactory.cpp new file mode 100644 index 0000000..99e7754 --- /dev/null +++ b/src/universalinput/qjoystickinputfactory.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qjoystickinputfactory_p.h" +#include "qjoystickinputplugin_p.h" +#include "qjoystickinput_p.h" + +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QJoystickInputFactoryInterface_iid, QLatin1String("/joystickinputs"), Qt::CaseInsensitive)) + +QStringList QJoystickInputFactory::keys() +{ + return loader->keyMap().values(); +} + +QJoystickInput *QJoystickInputFactory::create(const QString &key, const QStringList ¶mList) +{ + return qLoadPlugin(loader(), key, paramList); +} + +QT_END_NAMESPACE diff --git a/src/universalinput/qjoystickinputfactory_p.h b/src/universalinput/qjoystickinputfactory_p.h new file mode 100644 index 0000000..359350f --- /dev/null +++ b/src/universalinput/qjoystickinputfactory_p.h @@ -0,0 +1,34 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QJOYSTICKINPUTFACTORY_P_H +#define QJOYSTICKINPUTFACTORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QJoystickInput; + +class Q_UNIVERSALINPUT_EXPORT QJoystickInputFactory +{ +public: + static QStringList keys(); + static QJoystickInput *create(const QString &key, const QStringList ¶mList); +}; + +QT_END_NAMESPACE + +#endif // QJOYSTICKINPUTFACTORY_P_H diff --git a/src/universalinput/qjoystickinputplugin_p.h b/src/universalinput/qjoystickinputplugin_p.h new file mode 100644 index 0000000..4bf003a --- /dev/null +++ b/src/universalinput/qjoystickinputplugin_p.h @@ -0,0 +1,40 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QJOYSTICKINPUTPLUGIN_P_H +#define QJOYSTICKINPUTPLUGIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QJoystickInput; + +#define QJoystickInputFactoryInterface_iid "org.qt-project.QtUniversalInput.JoystickInput.6.5" + +class Q_UNIVERSALINPUT_EXPORT QJoystickInputPlugin : public QObject +{ + Q_OBJECT +public: + virtual QJoystickInput *create(const QString &key, const QStringList ¶mList) = 0; +}; + +QT_END_NAMESPACE + +#endif // QJOYSTICKINPUTPLUGIN_P_H diff --git a/src/universalinput/qmouseinput_p.h b/src/universalinput/qmouseinput_p.h new file mode 100644 index 0000000..05cbbff --- /dev/null +++ b/src/universalinput/qmouseinput_p.h @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QMOUSEINPUT_P_H +#define QMOUSEINPUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_UNIVERSALINPUT_EXPORT QMouseInput : public QObject +{ + Q_OBJECT +}; + +QT_END_NAMESPACE + +#endif // QMOUSEINPUT_P_H diff --git a/src/universalinput/qmouseinputfactory.cpp b/src/universalinput/qmouseinputfactory.cpp new file mode 100644 index 0000000..b16de6c --- /dev/null +++ b/src/universalinput/qmouseinputfactory.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qmouseinputfactory_p.h" +#include "qmouseinputplugin_p.h" +#include "qmouseinput_p.h" + +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QMouseInputFactoryInterface_iid, QLatin1String("/mouseinputs"), Qt::CaseInsensitive)) + +QStringList QMouseInputFactory::keys() +{ + return loader->keyMap().values(); +} + +QMouseInput *QMouseInputFactory::create(const QString &key, const QStringList ¶mList) +{ + return qLoadPlugin(loader(), key, paramList); +} + +QT_END_NAMESPACE diff --git a/src/universalinput/qmouseinputfactory_p.h b/src/universalinput/qmouseinputfactory_p.h new file mode 100644 index 0000000..b0cd9ad --- /dev/null +++ b/src/universalinput/qmouseinputfactory_p.h @@ -0,0 +1,34 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QMOUSEINPUTFACTORY_P_H +#define QMOUSEINPUTFACTORY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMouseInput; + +class Q_UNIVERSALINPUT_EXPORT QMouseInputFactory +{ +public: + static QStringList keys(); + static QMouseInput *create(const QString &key, const QStringList ¶mList); +}; + +QT_END_NAMESPACE + +#endif // QMOUSEINPUTFACTORY_P_H diff --git a/src/universalinput/qmouseinputplugin_p.h b/src/universalinput/qmouseinputplugin_p.h new file mode 100644 index 0000000..1e268c3 --- /dev/null +++ b/src/universalinput/qmouseinputplugin_p.h @@ -0,0 +1,40 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QMOUSEINPUTPLUGIN_P_H +#define QMOUSEINPUTPLUGIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMouseInput; + +#define QMouseInputFactoryInterface_iid "org.qt-project.QtUniversalInput.MouseInput.6.5" + +class Q_UNIVERSALINPUT_EXPORT QMouseInputPlugin : public QObject +{ + Q_OBJECT +public: + virtual QMouseInput *create(const QString &key, const QStringList ¶mList) = 0; +}; + +QT_END_NAMESPACE + +#endif // QMOUSEINPUTPLUGIN_P_H diff --git a/src/universalinput/qt_attribution.json b/src/universalinput/qt_attribution.json new file mode 100644 index 0000000..b47df25 --- /dev/null +++ b/src/universalinput/qt_attribution.json @@ -0,0 +1,16 @@ +[ + { + "Id": "godotinput", + "Name": "GodotInput", + "QDocModule": "qtuniveralinput", + "QtUsage": "UniversalInput backends and API are based on the Godot Engine Input API.", + "Files": "quniversalinput.h quniveralinput.cpp ../../plugins/joystickinputs/android/androidjoystickinput.cpp ../../plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystick.java ../../plugins/joystickinputs/android/jar/src/org/qtproject/qt/android/universalinput/QtJoystickInputHandler.java ../../plugins/joystickinputs/ios/iosjoystickinput.mm ../../plugins/joystickinputs/linux/linuxjoystickinput.cpp ../../plugins/joystickinputs/linux/linuxjoystickinput.h ../../plugins/joystickinputs/macos/macosjoystickinput.mm ../../plugins/joystickinputs/macos/macosjoystickinput.h ../../plugins/joystickinputs/windows/windowsjoystickinput.cpp ../../plugins/joystickinputs/windows/windowsjoystickinput.h ../../plugins/mouseinputs/linux/linuxmouseinput.cpp ../../plugins/mouseinputs/linux/linuxmouseinput.h ../../plugins/mouseinputs/macos/macosmouseinput.cpp ../../plugins/mouseinputs/macos/macosmouseinput.h ../../plugins/mouseinputs/windows/windowsmouseinput.cpp ../../plugins/mouseinputs/windows/windowsmouseinput.h", + "Description": "2D and 3D cross-platform game engine", + "Homepage": "https://godotengine.org/", + "Version": "4.0.3", + "License": "MIT License", + "LicenseId": "MIT", + "LicenseFile": "GODOT_LICENSE.txt", + "Copyright": "Copyright (c) 2014-present Godot Engine contributors\nCopyright (c) 2007-2014 Juan Linietsky, Ariel Manzur." + } +] diff --git a/src/universalinput/qtuniversalinputglobal.h b/src/universalinput/qtuniversalinputglobal.h new file mode 100644 index 0000000..0f8db2a --- /dev/null +++ b/src/universalinput/qtuniversalinputglobal.h @@ -0,0 +1,10 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTUNIVERSALINPUTGLOBAL_H +#define QTUNIVERSALINPUTGLOBAL_H + +#include +#include + +#endif // QTUNIVERSALINPUTGLOBAL_H diff --git a/src/universalinput/qtuniversalinputglobal_p.h b/src/universalinput/qtuniversalinputglobal_p.h new file mode 100644 index 0000000..2f92d20 --- /dev/null +++ b/src/universalinput/qtuniversalinputglobal_p.h @@ -0,0 +1,21 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QTUNIVERSALINPUTGLOBAL_P_H +#define QTUNIVERSALINPUTGLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#include + +#endif // QTUNIVERSALINPUTGLOBAL_P_H diff --git a/src/universalinput/quniversalinput.cpp b/src/universalinput/quniversalinput.cpp new file mode 100644 index 0000000..b374308 --- /dev/null +++ b/src/universalinput/quniversalinput.cpp @@ -0,0 +1,742 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "core/input/input.cpp" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#include "quniversalinput.h" +#include "quniversalinput_p.h" +#include "qjoystickinput_p.h" +#include "qjoystickinputfactory_p.h" +#include "qjoydevicemappingparser_p.h" +#include "qmouseinput_p.h" +#include "qmouseinputfactory_p.h" + +#include + +QT_BEGIN_NAMESPACE + +static JoyAxis _combine_device(JoyAxis p_value, int p_device) { + return JoyAxis((int)p_value | (p_device << 20)); +} + +static JoyButton _combine_device(JoyButton p_value, int p_device) { + return JoyButton((int)p_value | (p_device << 20)); +} + +static QByteArray _hex_str(quint8 p_byte) { + static const char *dict = "0123456789abcdef"; + char ret[3]; + ret[2] = 0; + + ret[0] = dict[p_byte >> 4]; + ret[1] = dict[p_byte & 0xf]; + + return QByteArray(ret); +} + +QUniversalInputPrivate::QUniversalInputPrivate() { + +} + +QUniversalInputPrivate::~QUniversalInputPrivate() +{ + delete joystickInput; +} + +void QUniversalInputPrivate::_q_init() +{ + loadMappingDatabase(); + + QStringList keys = QJoystickInputFactory::keys(); + if (!keys.isEmpty()) + joystickInput = QJoystickInputFactory::create(keys.first(), QStringList()); + + // If we fail to load a plugin, create a dummy joystick input + if (!joystickInput) + joystickInput = new QJoystickInput(); + + keys = QMouseInputFactory::keys(); + if (!keys.isEmpty()) + mouseInput = QMouseInputFactory::create(keys.first(), QStringList()); + + // If we fail to load a plugin, create a dummy mouse input + if (!mouseInput) + mouseInput = new QMouseInput(); +} + +void QUniversalInputPrivate::loadMappingDatabase() +{ + QJoyDeviceMappingParser parser(QString::fromUtf8(":/qt-project.org/qtuniversalinput/gamecontrollerdb.txt")); + auto mapping = parser.next(); + for (; mapping.has_value(); mapping = parser.next()) + mappingDatabase.push_back(mapping.value()); +} + +void QUniversalInput::VelocityTrack::update(const QVector2D &valueDelta) { + float delta_t = frameTimer.restart() / 1000.0f; + + if (delta_t > maxRefFrame) { + // First movement in a long time, reset and start again. + velocity = QVector2D(); + accum = valueDelta; + accumTime = 0.0f; + return; + } + + accum += valueDelta; + accumTime += delta_t; + + if (accumTime < minRefFrame) { + // Not enough time has passed to calculate speed precisely. + return; + } + + velocity = accum / accumTime; + accum = QVector2D(); + accumTime = 0.0f; +} + +void QUniversalInput::VelocityTrack::reset() +{ + frameTimer.restart(); + velocity = QVector2D(); + accum = QVector2D(); + accumTime = 0.0f; +} + +QUniversalInput::VelocityTrack::VelocityTrack() { + minRefFrame = 0.1f; + maxRefFrame = 3.0f; + frameTimer.start(); + reset(); +} + +void QUniversalInput::loadPlugins(){ + Q_D(QUniversalInput); + d->_q_init(); +} + +QUniversalInput::QUniversalInput() + : QObject(*new QUniversalInputPrivate(), nullptr) +{ + // We need to delay the plugin loading until the event loop is running + QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection); +} + +QUniversalInput::~QUniversalInput() +{ +} + +QUniversalInput *QUniversalInput::instance() +{ + static QUniversalInput instance; + return &instance; +} + +QString QUniversalInput::getJoyName(int device) const +{ + Q_D(const QUniversalInput); + // If the device does not exist, an empty Joypad + // Struct should be returned, so name will be empty + const auto joypad = d->joypadNames[device]; + return joypad.name; +} + +bool QUniversalInput::isJoyConnected(int device) const +{ + Q_D(const QUniversalInput); + // If the device does not exist, an empty Joypad + // Struct should be returned + const auto joypad = d->joypadNames[device]; + return joypad.isConnected; +} + +bool QUniversalInput::isGamepad(int device) const +{ + Q_D(const QUniversalInput); + // If the device does not exist, an empty Joypad + // Struct should be returned + const auto joypad = d->joypadNames[device]; + // If a device has a mapping, it is a gamepad + return joypad.mapping != -1; +} + +int QUniversalInput::getUnusedJoyId() { + Q_D(QUniversalInput); + for (int i = 0; i < JoypadsMax; i++) + if (!d->joypadNames.contains(i) || !d->joypadNames[i].isConnected) + return i; + return -1; +} + +void QUniversalInput::updateJoyConnection(int index, bool isConnected, const QString &name, const QString &guid) { + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + + Joypad js; + js.name = isConnected ? name : QString(); + js.uid = isConnected ? guid : QString(); + + if (isConnected) { + QByteArray uidname = guid.toLocal8Bit(); + if (guid.isEmpty()) { + int uidlen = int(qMin(name.length(), 16LL)); + QByteArray localName = name.toLocal8Bit(); + for (int i = 0; i < uidlen; i++) + uidname = uidname + _hex_str(localName[i]); + } + js.uid = QString::fromLocal8Bit(uidname); + js.isConnected = true; + int mapping = d->fallbackMapping; + for (int i = 0; i < d->mappingDatabase.size(); i++) { + if (js.uid == d->mappingDatabase[i].uid) { + mapping = i; + js.name = d->mappingDatabase[i].name; + } + } + js.mapping = mapping; + } else { + js.isConnected = false; + for (int i = 0; i < (int)JoyButton::MAX; i++) { + JoyButton c = _combine_device((JoyButton)i, index); + d->joystickButtonsPressed.remove(c); + } + for (int i = 0; i < (int)JoyAxis::MAX; i++) + setJoyAxis(index, (JoyAxis)i, 0.0f); + + } + d->joypadNames[index] = js; + + Q_EMIT joyConnectionChanged(index, isConnected); +} + +void QUniversalInput::joyButton(int device, JoyButton button, bool isPressed) { + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + + Joypad &joy = d->joypadNames[device]; + Q_ASSERT(int(button) < int(JoyButton::MAX)); + + if (joy.lastButtons[size_t(button)] == isPressed) + return; + + joy.lastButtons[size_t(button)] = isPressed; + if (joy.mapping == -1) { + sendButtonEvent(device, button, isPressed); + return; + } + + JoyEvent map = mappedButtonEvent(d->mappingDatabase[joy.mapping], button); + + if (map.type == TypeButton) { + sendButtonEvent(device, JoyButton(map.index), isPressed); + return; + } + + if (map.type == TypeAxis) + sendAxisEvent(device, JoyAxis(map.index), isPressed ? map.value : 0.0f); +} + +void QUniversalInput::joyAxis(int device, JoyAxis axis, float value) +{ + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + + Q_ASSERT(int(axis) < int(JoyAxis::MAX)); + + Joypad &joy = d->joypadNames[device]; + + if (joy.lastAxis[size_t(axis)] == value) + return; + + joy.lastAxis[size_t(axis)] = value; + + if (joy.mapping == -1) { + sendAxisEvent(device, axis, value); + return; + } + + JoyEvent map = mappedAxisEvent(d->mappingDatabase[joy.mapping], axis, value); + + if (map.type == TypeButton) { + bool pressed = map.value > 0.5; + if (pressed != d->joystickButtonsPressed.contains(_combine_device(JoyButton(map.index), device))) + sendButtonEvent(device, JoyButton(map.index), pressed); + + // Ensure opposite D-Pad button is also released. + switch (JoyButton(map.index)) { + case JoyButton::DpadUp: + if (d->joystickButtonsPressed.contains(_combine_device(JoyButton::DpadDown, device))) + sendButtonEvent(device, JoyButton::DpadDown, false); + break; + case JoyButton::DpadDown: + if (d->joystickButtonsPressed.contains(_combine_device(JoyButton::DpadUp, device))) + sendButtonEvent(device, JoyButton::DpadUp, false); + break; + case JoyButton::DpadLeft: + if (d->joystickButtonsPressed.contains(_combine_device(JoyButton::DpadRight, device))) + sendButtonEvent(device, JoyButton::DpadRight, false); + break; + case JoyButton::DpadRight: + if (d->joystickButtonsPressed.contains(_combine_device(JoyButton::DpadLeft, device))) + sendButtonEvent(device, JoyButton::DpadLeft, false); + break; + default: + // Nothing to do. + break; + } + return; + } + + if (map.type == TypeAxis) { + JoyAxis axis = JoyAxis(map.index); + float value = map.value; + if (axis == JoyAxis::TriggerLeft || axis == JoyAxis::TriggerRight) + value = 0.5f + value / 2.0f; // Convert to a value between 0.0f and 1.0f. + sendAxisEvent(device, axis, value); + return; + } +} + +void QUniversalInput::joyHat(int device, HatMask value) +{ + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + + const Joypad &joy = d->joypadNames[device]; + + JoyEvent map[size_t(HatDirection::Max)]; + map[size_t(HatDirection::Up)].type = TypeButton; + map[size_t(HatDirection::Up)].index = int(JoyButton::DpadUp); + map[size_t(HatDirection::Up)].value = 0; + + map[size_t(HatDirection::Right)].type = TypeButton; + map[size_t(HatDirection::Right)].index = int(JoyButton::DpadRight); + map[size_t(HatDirection::Right)].value = 0; + + map[size_t(HatDirection::Down)].type = TypeButton; + map[size_t(HatDirection::Down)].index = int(JoyButton::DpadDown); + map[size_t(HatDirection::Down)].value = 0; + + map[size_t(HatDirection::Left)].type = TypeButton; + map[size_t(HatDirection::Left)].index = int(JoyButton::DpadLeft); + map[size_t(HatDirection::Left)].value = 0; + + // This is a bit weird... as it overwrites index [0] DirectionUp + if (joy.mapping != -1) + mappedHatEvents(d->mappingDatabase[joy.mapping], HatDirection(0), map); + + int cur_val = d->joypadNames[device].hatCurrent; + + for (int hat_direction = 0, hat_mask = 1; hat_direction < (int)HatDirection::Max; hat_direction++, hat_mask <<= 1) { + if ((int(value) & hat_mask) != (cur_val & hat_mask)) { + if (map[hat_direction].type == TypeButton) + sendButtonEvent(device, JoyButton(map[hat_direction].index), int(value) & hat_mask); + if (map[hat_direction].type == TypeAxis) + sendAxisEvent(device, JoyAxis(map[hat_direction].index), (int(value) & hat_mask) ? map[hat_direction].value : 0.0f); + } + } + + d->joypadNames[device].hatCurrent = int(value); +} + +QVector2D QUniversalInput::getJoyVibrationStrength(int device) +{ + Q_D(QUniversalInput); + if (d->joystickVibrations.contains(device)) + return QVector2D(d->joystickVibrations[device].weakMagnitude, d->joystickVibrations[device].strongMagnitude); + else + return QVector2D(0.0f, 0.0f); +} + +float QUniversalInput::getJoyVibrationDuration(int device) +{ + Q_D(QUniversalInput); + if (d->joystickVibrations.contains(device)) + return d->joystickVibrations[device].duration; + else + return 0.0f; +} + +quint64 QUniversalInput::getJoyVibrationTimestamp(int device) +{ + Q_D(QUniversalInput); + if (d->joystickVibrations.contains(device)) + return d->joystickVibrations[device].timestamp; + else + return 0; +} + +void QUniversalInput::addForce(int deivce, QVector2D strength, float duration) { + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + d->joystickVibrations[deivce].weakMagnitude = strength.x(); + d->joystickVibrations[deivce].strongMagnitude = strength.y(); + d->joystickVibrations[deivce].duration = duration; // sec + d->joystickVibrations[deivce].timestamp = QDateTime::currentMSecsSinceEpoch(); +} + +void QUniversalInput::setJoyAxis(int device, JoyAxis axis, float value) +{ + Q_D(QUniversalInput); + QMutexLocker locker(&d->mutex); + + JoyAxis c = _combine_device(axis, device); + d->joystickAxes[c] = value; +} + +void QUniversalInput::sendButtonEvent(int device, JoyButton index, bool pressed) +{ + Q_UNUSED(device); + Q_UNUSED(index); + Q_UNUSED(pressed); + Q_EMIT joyButtonEvent(device, index, pressed); + // qDebug() << "Button event" << device << int(index) << pressed; +} + +void QUniversalInput::sendAxisEvent(int device, JoyAxis axis, float value) +{ + Q_UNUSED(device); + Q_UNUSED(axis); + Q_UNUSED(value); + // qDebug() << "Axis event" << device << int(axis) << value; + Q_EMIT joyAxisEvent(device, axis, value); +} + +// mouse disable +void QUniversalInput::setMouseDisabled(bool disabled) { + Q_D(QUniversalInput); + if (d->mouseDisabled == disabled) + return; + + d->mouseDisabled = disabled; + Q_EMIT mouseDisabledChanged(); +} + +bool QUniversalInput::isMouseDisabled() const { + Q_D(const QUniversalInput); + return d->mouseDisabled; +} + +void QUniversalInput::mouseMove(const QVector2D &deltas) +{ + Q_EMIT mouseMovedWithDeltas(deltas); +} + +// mouse disable + +QUniversalInput::JoyEvent QUniversalInput::mappedButtonEvent(const JoyDeviceMapping &mapping, JoyButton button) +{ + JoyEvent event; + + for (int i = 0; i < mapping.bindings.size(); i++) { + const JoyBinding binding = mapping.bindings[i]; + if (binding.inputType == TypeButton && binding.input.button == button) { + event.type = binding.outputType; + switch (binding.outputType) { + case TypeButton: + event.index = (int)binding.output.button; + return event; + case TypeAxis: + event.index = (int)binding.output.axis.axis; + switch (binding.output.axis.range) { + case PositiveHalfAxis: + event.value = 1; + break; + case NegativeHalfAxis: + event.value = -1; + break; + case FullAxis: + // It doesn't make sense for a button to map to a full axis, + // but keeping as a default for a trigger with a positive half-axis. + event.value = 1; + break; + } + return event; + default: + qWarning("Joypad button mapping error."); + } + } + } + return event; +} + +QUniversalInput::JoyEvent QUniversalInput::mappedAxisEvent(const JoyDeviceMapping &mapping, JoyAxis axis, float inValue) +{ + JoyEvent event; + + for (int i = 0; i < mapping.bindings.size(); i++) { + const JoyBinding binding = mapping.bindings[i]; + if (binding.inputType == TypeAxis && binding.input.axis.axis == axis) { + float value = inValue; + if (binding.input.axis.invert) + value = -value; + if (binding.input.axis.range == FullAxis || + (binding.input.axis.range == PositiveHalfAxis && value >= 0) || + (binding.input.axis.range == NegativeHalfAxis && value < 0)) { + event.type = binding.outputType; + float shifted_positive_value = 0; + switch (binding.input.axis.range) { + case PositiveHalfAxis: + shifted_positive_value = value; + break; + case NegativeHalfAxis: + shifted_positive_value = value + 1; + break; + case FullAxis: + shifted_positive_value = (value + 1) / 2; + break; + } + switch (binding.outputType) { + case TypeButton: + event.index = (int)binding.output.button; + switch (binding.input.axis.range) { + case PositiveHalfAxis: + event.value = shifted_positive_value; + break; + case NegativeHalfAxis: + event.value = 1 - shifted_positive_value; + break; + case FullAxis: + // It doesn't make sense for a full axis to map to a button, + // but keeping as a default for a trigger with a positive half-axis. + event.value = (shifted_positive_value * 2) - 1; + break; + } + return event; + case TypeAxis: + event.index = (int)binding.output.axis.axis; + event.value = value; + if (binding.output.axis.range != binding.input.axis.range) { + switch (binding.output.axis.range) { + case PositiveHalfAxis: + event.value = shifted_positive_value; + break; + case NegativeHalfAxis: + event.value = shifted_positive_value - 1; + break; + case FullAxis: + event.value = (shifted_positive_value * 2) - 1; + break; + } + } + return event; + default: + qWarning("Joypad axis mapping error."); + } + } + } + } + return event; +} + +void QUniversalInput::mappedHatEvents(const JoyDeviceMapping &mapping, HatDirection hat, JoyEvent events[size_t(HatDirection::Max)]) +{ + for (int i = 0; i < mapping.bindings.size(); i++) { + const JoyBinding binding = mapping.bindings[i]; + if (binding.inputType == TypeHat && binding.input.hat.hat == hat) { + HatDirection hat_direction; + switch (binding.input.hat.hat_mask) { + case HatMask::Up: + hat_direction = HatDirection::Up; + break; + case HatMask::Right: + hat_direction = HatDirection::Right; + break; + case HatMask::Down: + hat_direction = HatDirection::Down; + break; + case HatMask::Left: + hat_direction = HatDirection::Left; + break; + default: + qWarning("Joypad button mapping error."); + continue; + } + + events[size_t(hat_direction)].type = binding.outputType; + switch (binding.outputType) { + case TypeButton: + events[size_t(hat_direction)].index = int(binding.output.button); + break; + case TypeAxis: + events[size_t(hat_direction)].index = int(binding.output.axis.axis); + switch (binding.output.axis.range) { + case PositiveHalfAxis: + events[size_t(hat_direction)].value = 1; + break; + case NegativeHalfAxis: + events[size_t(hat_direction)].value = -1; + break; + case FullAxis: + // It doesn't make sense for a hat direction to map to a full axis, + // but keeping as a default for a trigger with a positive half-axis. + events[size_t(hat_direction)].value = 1; + break; + } + break; + default: + qWarning("Joypad button mapping error."); + } + } + } +} + +QDebug operator<<(QDebug debug, const JoyButton &joyButton) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "JoyButton::"; + + switch (joyButton) { + case JoyButton::Invalid: debug.nospace() << "Invalid"; break; + case JoyButton::A: debug.nospace() << "A"; break; + case JoyButton::B: debug.nospace() << "B"; break; + case JoyButton::X: debug.nospace() << "X"; break; + case JoyButton::Y: debug.nospace() << "Y"; break; + case JoyButton::Back: debug.nospace() << "Back"; break; + case JoyButton::Guide: debug.nospace() << "Guide"; break; + case JoyButton::Start: debug.nospace() << "Start"; break; + case JoyButton::LeftStick: debug.nospace() << "LeftStick"; break; + case JoyButton::RightStick: debug.nospace() << "RightStick"; break; + case JoyButton::LeftShoulder: debug.nospace() << "LeftShoulder"; break; + case JoyButton::RightShoulder: debug.nospace() << "RightShoulder"; break; + case JoyButton::DpadUp: debug.nospace() << "DpadUp"; break; + case JoyButton::DpadDown: debug.nospace() << "DpadDown"; break; + case JoyButton::DpadLeft: debug.nospace() << "DpadLeft"; break; + case JoyButton::DpadRight: debug.nospace() << "DpadRight"; break; + case JoyButton::Misc1: debug.nospace() << "Misc1"; break; + case JoyButton::Paddle1: debug.nospace() << "Paddle1"; break; + case JoyButton::Paddle2: debug.nospace() << "Paddle2"; break; + case JoyButton::Paddle3: debug.nospace() << "Paddle3"; break; + case JoyButton::Paddle4: debug.nospace() << "Paddle4"; break; + case JoyButton::Touchpad: debug.nospace() << "Touchpad"; break; + default: + debug.nospace() << "Button(" << static_cast(joyButton) << ")"; + break; + } + return debug; +} + +QDebug operator<<(QDebug debug, const JoyAxis &axis) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "JoyAxis::"; + + switch (axis) { + case JoyAxis::Invalid: debug.nospace() << "Invalid"; break; + case JoyAxis::LeftX: debug.nospace() << "LeftX"; break; + case JoyAxis::LeftY: debug.nospace() << "LeftY"; break; + case JoyAxis::RightX: debug.nospace() << "RightX"; break; + case JoyAxis::RightY: debug.nospace() << "RightY"; break; + case JoyAxis::TriggerLeft: debug.nospace() << "TriggerLeft"; break; + case JoyAxis::TriggerRight: debug.nospace() << "TriggerRight"; break; + default: + debug.nospace() << "(" << static_cast(axis) << ")"; + break; + } + return debug; +} + +QDebug operator<<(QDebug debug, const QUniversalInput::JoyAxisRange &range) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "JoyAxisRange::"; + switch (range) { + case QUniversalInput::NegativeHalfAxis: debug.nospace() << "NegativeHalfAxis"; break; + case QUniversalInput::FullAxis: debug.nospace() << "FullAxis"; break; + case QUniversalInput::PositiveHalfAxis: debug.nospace() << "PositiveHalfAxis"; break; + default: + debug.nospace() << "(" << static_cast(range) << ")"; + break; + } + + return debug; +} + +QDebug operator<<(QDebug debug, const HatDirection &hatDirection) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "HatDirection::"; + switch (hatDirection) { + case HatDirection::Up: debug.nospace() << "Up"; break; + case HatDirection::Right: debug.nospace() << "Right"; break; + case HatDirection::Down: debug.nospace() << "Down"; break; + case HatDirection::Left: debug.nospace() << "Left"; break; + default: + debug.nospace() << "(" << static_cast(hatDirection) << ")"; + break; + } + return debug; +} + +QDebug operator<<(QDebug debug, const HatMask &hatMask) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "HatMask::"; + + switch (hatMask) { + case HatMask::Center: debug.nospace() << "Center"; break; + case HatMask::Up: debug.nospace() << "Up"; break; + case HatMask::Right: debug.nospace() << "Right"; break; + case HatMask::Down: debug.nospace() << "Down"; break; + case HatMask::Left: debug.nospace() << "Left"; break; + default: + debug.nospace() << "(" << static_cast(hatMask) << ")"; + break; + } + return debug; +} + +QDebug operator<<(QDebug debug, const QUniversalInput::JoyBinding &binding) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "JoyBinding( inputType: "; + switch (binding.inputType) { + + case QUniversalInput::TypeButton: + debug.nospace() << "TypeButton, input: " << binding.input.button; + break; + case QUniversalInput::TypeAxis: + debug.nospace() << "TypeAxis, input: " << binding.input.axis.axis << ", range: " << binding.input.axis.range; + break; + case QUniversalInput::TypeHat: + debug.nospace() << "TypeHat, input: " << binding.input.hat.hat << ", mask: " << binding.input.hat.hat_mask; + break; + case QUniversalInput::TypeMax: + break; + } + + debug.nospace() << ", outputType: "; + switch (binding.outputType) { + case QUniversalInput::TypeButton: + debug.nospace() << "TypeButton, output: " << binding.output.button; + break; + case QUniversalInput::TypeAxis: + debug.nospace() << "TypeAxis, output: " << binding.output.axis.axis << ", range: " << binding.output.axis.range; + break; + case QUniversalInput::TypeHat: + case QUniversalInput::TypeMax: + break; + } + + debug.nospace() << ")"; + + return debug; +} + +QDebug operator<<(QDebug debug, const QUniversalInput::JoyDeviceMapping &mapping) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "JoyDeviceMapping(" << mapping.uid << ", " << mapping.name << ", bindings: ["; + for (const QUniversalInput::JoyBinding &binding : mapping.bindings) { + debug.nospace() << binding << ", "; + } + debug.nospace() << "])"; + return debug; +} + +QT_END_NAMESPACE diff --git a/src/universalinput/quniversalinput.h b/src/universalinput/quniversalinput.h new file mode 100644 index 0000000..8c68cf5 --- /dev/null +++ b/src/universalinput/quniversalinput.h @@ -0,0 +1,263 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +/* + Originally based on code from "core/input/input.h" from Godot Engine v4.0 + Copyright (c) 2014-present Godot Engine contributors + Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. +*/ + +#ifndef QUNIVERSALINPUT_H +#define QUNIVERSALINPUT_H + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum class HatDirection { + Up = 0, + Right = 1, + Down = 2, + Left = 3, + Max = 4, +}; + +enum class HatMask { + Center = 0, + Up = 1, + Right = 2, + Down = 4, + Left = 8, +}; + +enum class JoyAxis { + Invalid = -1, + LeftX = 0, + LeftY = 1, + RightX = 2, + RightY = 3, + TriggerLeft = 4, + TriggerRight = 5, + MAX = 10, +}; + +enum class JoyButton { + Invalid = -1, + A = 0, + B = 1, + X = 2, + Y = 3, + Back = 4, + Guide = 5, + Start = 6, + LeftStick = 7, + RightStick = 8, + LeftShoulder = 9, + RightShoulder = 10, + DpadUp = 11, + DpadDown = 12, + DpadLeft = 13, + DpadRight = 14, + Misc1 = 15, + Paddle1 = 16, + Paddle2 = 17, + Paddle3 = 18, + Paddle4 = 19, + Touchpad = 20, + MAX = 128 +}; + +inline HatMask operator|(HatMask a, HatMask b) { + return (HatMask)((int)a | (int)b); +} + +inline HatMask operator&(HatMask a, HatMask b) { + return (HatMask)((int)a & (int)b); +} + +inline HatMask &operator&=(HatMask &a, HatMask b) { + return (HatMask &)((int &)a &= (int)b); +} + +inline HatMask &operator|=(HatMask &a, HatMask b) { + return (HatMask &)((int &)a |= (int)b); +} + +inline HatMask operator~(HatMask a) { + return (HatMask)(~(int)a); +} + +class QUniversalInputPrivate; +class Q_UNIVERSALINPUT_EXPORT QUniversalInput : public QObject +{ + Q_OBJECT +public: + enum { + JoypadsMax = 16, + }; + + struct Action { + quint64 frame; + bool isPressed; + bool isExact; + float strength; + float rawStrength; + }; + struct VibrationInfo { + float weakMagnitude; + float strongMagnitude; + float duration; + quint64 timestamp; + }; + struct VelocityTrack { + QElapsedTimer frameTimer; + QVector2D velocity; + QVector2D accum; + float accumTime = 0.0; + float minRefFrame; + float maxRefFrame; + + void update(const QVector2D &delta); + void reset(); + VelocityTrack(); + }; + + struct Joypad { + QString name; + QString uid; + bool isConnected = false; + bool lastButtons[size_t(JoyButton::MAX)] = { false }; + float lastAxis[size_t(JoyAxis::MAX)] = { 0.0f }; + HatMask lastHat = HatMask::Center; + int mapping = -1; + int hatCurrent = 0; + }; + + enum JoyType { + TypeButton, + TypeAxis, + TypeHat, + TypeMax, + }; + + enum JoyAxisRange { + NegativeHalfAxis = -1, + FullAxis = 0, + PositiveHalfAxis = 1 + }; + + struct JoyEvent { + int type = TypeMax; + int index = -1; + float value = 0.0f; + }; + + struct JoyBinding { + JoyType inputType; + union { + JoyButton button; + + struct { + JoyAxis axis; + JoyAxisRange range; + bool invert; + } axis; + + struct { + HatDirection hat; + HatMask hat_mask; + } hat; + + } input; + + JoyType outputType; + union { + JoyButton button; + + struct { + JoyAxis axis; + JoyAxisRange range; + } axis; + + } output; + }; + + struct JoyDeviceMapping { + QString uid; + QString name; + QVector bindings; + }; + + static QUniversalInput *instance(); + + QString getJoyName(int device) const; + bool isJoyConnected(int device) const; + bool isGamepad(int device) const; + + // API used by platform specific plugins + // Joypad/Joystick/Gamepads + int getUnusedJoyId(); + void updateJoyConnection(int index, bool isConnected, const QString &name, const QString &guid = QString()); + + void joyButton(int device, JoyButton button, bool isPressed); + void joyAxis(int device, JoyAxis axis, float value); + void joyHat(int device, HatMask value); + + // Force Feedback + QVector2D getJoyVibrationStrength(int device); + float getJoyVibrationDuration(int device); + quint64 getJoyVibrationTimestamp(int device); + void addForce(int deivce, QVector2D strength, float duration); + + void setJoyAxis(int device, JoyAxis axis, float value); + + void setMouseDisabled(bool disabled); // looking for better name. Is "make invisible and center" + bool isMouseDisabled() const; + void mouseMove(const QVector2D& deltas); + +Q_SIGNALS: + void joyConnectionChanged(int index, bool isConnected); + void joyButtonEvent(int device, JoyButton button, bool isPressed); + void joyAxisEvent(int device, JoyAxis axis, float value); + + void mouseDisabledChanged(); + void mouseMovedWithDeltas(const QVector2D& deltas); + +private Q_SLOTS: + void loadPlugins(); + +private: + QUniversalInput(); + ~QUniversalInput(); + + void sendButtonEvent(int device, JoyButton index, bool pressed); + void sendAxisEvent(int device, JoyAxis axis, float value); + JoyEvent mappedButtonEvent(const JoyDeviceMapping &mapping, JoyButton button); + JoyEvent mappedAxisEvent(const JoyDeviceMapping &mapping, JoyAxis axis, float inValue); + void mappedHatEvents(const JoyDeviceMapping &mapping, HatDirection hat, JoyEvent events[size_t(HatDirection::Max)]); + + Q_DECLARE_PRIVATE(QUniversalInput) + Q_DISABLE_COPY(QUniversalInput) +}; + +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const JoyButton &joyButton); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const JoyAxis &axis); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const QUniversalInput::JoyAxisRange &range); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const HatDirection &hatDirection); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const HatMask &hatMask); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const QUniversalInput::JoyBinding &binding); +Q_UNIVERSALINPUT_EXPORT QDebug operator<<(QDebug debug, const QUniversalInput::JoyDeviceMapping &mapping); + + + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(JoyButton) +Q_DECLARE_METATYPE(JoyAxis) + +#endif // QUNIVERSALINPUT_H diff --git a/src/universalinput/quniversalinput_p.h b/src/universalinput/quniversalinput_p.h new file mode 100644 index 0000000..f90b7ce --- /dev/null +++ b/src/universalinput/quniversalinput_p.h @@ -0,0 +1,85 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QUNIVERSALINPUT_P_H +#define QUNIVERSALINPUT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include + + +#include +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE +class QJoystickInput; +class QMouseInput; +class QUniversalInputPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QUniversalInput) + +public: + QUniversalInputPrivate(); + ~QUniversalInputPrivate(); + + // private slots + void _q_init(); + + QJoystickInput *joystickInput = nullptr; + QMouseInput *mouseInput = nullptr; + + + QSet keysPressed; + QSet joystickButtonsPressed; + QMap joystickAxes; + + QVector3D gravity; + QVector3D acceleration; + QVector3D magnetometer; + QVector3D gyroscope; + + QHash actionState; + + bool useInputBuffering = false; + bool useAccumulatedInput = true; + + QHash joystickVibrations; + + QUniversalInput::VelocityTrack mouseVelocityTrack; + QHash touchVelocityTrack; + QHash joypadNames; + int fallbackMapping = -1; + + QVector mappingDatabase; + + QRecursiveMutex mutex; + + // mouse disable + bool mouseDisabled = false; + // mouse disable + +private: + void loadMappingDatabase(); +}; + +QT_END_NAMESPACE + +#endif // QUNIVERSALINPUT_P_H diff --git a/sync.profile b/sync.profile deleted file mode 100644 index 7aa408e..0000000 --- a/sync.profile +++ /dev/null @@ -1,16 +0,0 @@ -%modules = ( # path to module name map - "QtGamepad" => "$basedir/src/gamepad", -); -%moduleheaders = ( # restrict the module headers to those found in relative path -); -# Module dependencies. -# Every module that is required to build this module should have one entry. -# Each of the module version specifiers can take one of the following values: -# - A specific Git revision. -# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) -# -%dependencies = ( - "qtbase" => "", - "qtdeclarative" => "", - "qtxmlpatterns" => "", -); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..d75e34f --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_build_tests() + diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt new file mode 100644 index 0000000..e98ca9f --- /dev/null +++ b/tests/auto/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(QT_BUILD_MINIMAL_STATIC_TESTS) + return() +endif() + diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro deleted file mode 100644 index fce98ce..0000000 --- a/tests/auto/auto.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt deleted file mode 100644 index 3d77b9e..0000000 --- a/tests/auto/cmake/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(qmake_cmake_files) - -enable_testing() - -find_package(Qt5Core REQUIRED) - -include("${_Qt5CTestMacros}") - -test_module_includes( -) diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro deleted file mode 100644 index 929589a..0000000 --- a/tests/auto/cmake/cmake.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs - -CMAKE_QT_MODULES_UNDER_TEST = gamepad - -CONFIG += ctest_testcase diff --git a/tests/tests.pro b/tests/tests.pro deleted file mode 100644 index f887d53..0000000 --- a/tests/tests.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs - -!package: SUBDIRS += auto