From 85231dfca686d13ba253d6a5436f73f00aee6c5b Mon Sep 17 00:00:00 2001 From: Gauvain 'GovanifY' Roussel-Tarbouriech Date: Wed, 9 Dec 2020 05:00:59 +0100 Subject: [PATCH] PAD: add back some initial references --- pcsx2/CMakeLists.txt | 83 +++ pcsx2/PAD/Linux/CMakeLists.txt | 141 ++++ pcsx2/PAD/Linux/GamePad.cpp | 76 +++ pcsx2/PAD/Linux/GamePad.h | 94 +++ pcsx2/PAD/Linux/Img/analog-2.png | Bin 0 -> 170 bytes pcsx2/PAD/Linux/Img/analog.png | Bin 0 -> 137 bytes pcsx2/PAD/Linux/Img/arrow_bottom.png | Bin 0 -> 283 bytes pcsx2/PAD/Linux/Img/arrow_left.png | Bin 0 -> 240 bytes pcsx2/PAD/Linux/Img/arrow_right.png | Bin 0 -> 252 bytes pcsx2/PAD/Linux/Img/arrow_up.png | Bin 0 -> 269 bytes pcsx2/PAD/Linux/Img/circle.png | Bin 0 -> 916 bytes pcsx2/PAD/Linux/Img/cross.png | Bin 0 -> 923 bytes pcsx2/PAD/Linux/Img/dp_bottom.png | Bin 0 -> 278 bytes pcsx2/PAD/Linux/Img/dp_left.png | Bin 0 -> 316 bytes pcsx2/PAD/Linux/Img/dp_right.png | Bin 0 -> 307 bytes pcsx2/PAD/Linux/Img/dp_up.png | Bin 0 -> 338 bytes pcsx2/PAD/Linux/Img/dualshock2.png | Bin 0 -> 110432 bytes pcsx2/PAD/Linux/Img/joystick_cursor.png | Bin 0 -> 171 bytes pcsx2/PAD/Linux/Img/l1.png | Bin 0 -> 947 bytes pcsx2/PAD/Linux/Img/l2.png | Bin 0 -> 1096 bytes pcsx2/PAD/Linux/Img/l3.png | Bin 0 -> 884 bytes pcsx2/PAD/Linux/Img/r1.png | Bin 0 -> 949 bytes pcsx2/PAD/Linux/Img/r2.png | Bin 0 -> 1166 bytes pcsx2/PAD/Linux/Img/r3.png | Bin 0 -> 889 bytes pcsx2/PAD/Linux/Img/select.png | Bin 0 -> 173 bytes pcsx2/PAD/Linux/Img/square.png | Bin 0 -> 538 bytes pcsx2/PAD/Linux/Img/start.png | Bin 0 -> 240 bytes pcsx2/PAD/Linux/Img/triangle.png | Bin 0 -> 906 bytes pcsx2/PAD/Linux/KeyStatus.cpp | 198 ++++++ pcsx2/PAD/Linux/KeyStatus.h | 80 +++ pcsx2/PAD/Linux/SDL/joystick.cpp | 290 ++++++++ pcsx2/PAD/Linux/SDL/joystick.h | 63 ++ pcsx2/PAD/Linux/bitwise.h | 44 ++ pcsx2/PAD/Linux/controller.cpp | 44 ++ pcsx2/PAD/Linux/controller.h | 129 ++++ pcsx2/PAD/Linux/ini.cpp | 132 ++++ pcsx2/PAD/Linux/keyboard.cpp | 359 ++++++++++ pcsx2/PAD/Linux/keyboard.h | 45 ++ pcsx2/PAD/Linux/linux.cpp | 141 ++++ pcsx2/PAD/Linux/onepad.cpp | 358 ++++++++++ pcsx2/PAD/Linux/onepad.h | 138 ++++ pcsx2/PAD/Linux/res/game_controller_db.txt | 499 ++++++++++++++ pcsx2/PAD/Linux/res/onepad-res.xml | 6 + pcsx2/PAD/Linux/state_management.cpp | 468 +++++++++++++ pcsx2/PAD/Linux/state_management.h | 119 ++++ .../Linux/wx_dialog/GamepadConfiguration.cpp | 185 +++++ .../Linux/wx_dialog/GamepadConfiguration.h | 57 ++ .../Linux/wx_dialog/JoystickConfiguration.cpp | 211 ++++++ .../Linux/wx_dialog/JoystickConfiguration.h | 64 ++ pcsx2/PAD/Linux/wx_dialog/dialog.cpp | 640 ++++++++++++++++++ pcsx2/PAD/Linux/wx_dialog/dialog.h | 98 +++ pcsx2/PAD/Linux/wx_dialog/opPanel.cpp | 237 +++++++ pcsx2/PAD/Linux/wx_dialog/opPanel.h | 77 +++ 53 files changed, 5076 insertions(+) create mode 100644 pcsx2/PAD/Linux/CMakeLists.txt create mode 100644 pcsx2/PAD/Linux/GamePad.cpp create mode 100644 pcsx2/PAD/Linux/GamePad.h create mode 100644 pcsx2/PAD/Linux/Img/analog-2.png create mode 100644 pcsx2/PAD/Linux/Img/analog.png create mode 100644 pcsx2/PAD/Linux/Img/arrow_bottom.png create mode 100644 pcsx2/PAD/Linux/Img/arrow_left.png create mode 100644 pcsx2/PAD/Linux/Img/arrow_right.png create mode 100644 pcsx2/PAD/Linux/Img/arrow_up.png create mode 100644 pcsx2/PAD/Linux/Img/circle.png create mode 100644 pcsx2/PAD/Linux/Img/cross.png create mode 100644 pcsx2/PAD/Linux/Img/dp_bottom.png create mode 100644 pcsx2/PAD/Linux/Img/dp_left.png create mode 100644 pcsx2/PAD/Linux/Img/dp_right.png create mode 100644 pcsx2/PAD/Linux/Img/dp_up.png create mode 100644 pcsx2/PAD/Linux/Img/dualshock2.png create mode 100644 pcsx2/PAD/Linux/Img/joystick_cursor.png create mode 100644 pcsx2/PAD/Linux/Img/l1.png create mode 100644 pcsx2/PAD/Linux/Img/l2.png create mode 100644 pcsx2/PAD/Linux/Img/l3.png create mode 100644 pcsx2/PAD/Linux/Img/r1.png create mode 100644 pcsx2/PAD/Linux/Img/r2.png create mode 100644 pcsx2/PAD/Linux/Img/r3.png create mode 100644 pcsx2/PAD/Linux/Img/select.png create mode 100644 pcsx2/PAD/Linux/Img/square.png create mode 100644 pcsx2/PAD/Linux/Img/start.png create mode 100644 pcsx2/PAD/Linux/Img/triangle.png create mode 100644 pcsx2/PAD/Linux/KeyStatus.cpp create mode 100644 pcsx2/PAD/Linux/KeyStatus.h create mode 100644 pcsx2/PAD/Linux/SDL/joystick.cpp create mode 100644 pcsx2/PAD/Linux/SDL/joystick.h create mode 100644 pcsx2/PAD/Linux/bitwise.h create mode 100644 pcsx2/PAD/Linux/controller.cpp create mode 100644 pcsx2/PAD/Linux/controller.h create mode 100644 pcsx2/PAD/Linux/ini.cpp create mode 100644 pcsx2/PAD/Linux/keyboard.cpp create mode 100644 pcsx2/PAD/Linux/keyboard.h create mode 100644 pcsx2/PAD/Linux/linux.cpp create mode 100644 pcsx2/PAD/Linux/onepad.cpp create mode 100644 pcsx2/PAD/Linux/onepad.h create mode 100644 pcsx2/PAD/Linux/res/game_controller_db.txt create mode 100644 pcsx2/PAD/Linux/res/onepad-res.xml create mode 100644 pcsx2/PAD/Linux/state_management.cpp create mode 100644 pcsx2/PAD/Linux/state_management.h create mode 100644 pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.cpp create mode 100644 pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.h create mode 100644 pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.cpp create mode 100644 pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.h create mode 100644 pcsx2/PAD/Linux/wx_dialog/dialog.cpp create mode 100644 pcsx2/PAD/Linux/wx_dialog/dialog.h create mode 100644 pcsx2/PAD/Linux/wx_dialog/opPanel.cpp create mode 100644 pcsx2/PAD/Linux/wx_dialog/opPanel.h diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 25b279ba40..88a717aa53 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -56,6 +56,11 @@ if(XDG_STD) set(pcsx2FinalFlags ${pcsx2FinalFlags} -DXDG_STD) endif() +if(SDL_FOUND) + set(pcsx2FinalFlags ${pcsx2FinalFlags} -DSDL_BUILD) +endif() + + set(Output PCSX2) # Main pcsx2 source @@ -446,6 +451,82 @@ if(PULSEAUDIO_FOUND) set(pcsx2USBHeaders ${pcsx2USBHeaders} USB/usb-mic/audiodev-pulse.h) endif() + + +# PAD resources pre-compilation +set(PADImgHeader "${CMAKE_BINARY_DIR}/pcsx2/PAD/ImgHeader") +set(PADImg "${CMAKE_SOURCE_DIR}/pcsx2/PAD/Img") + +file(MAKE_DIRECTORY ${compiled_images}) + +foreach(result_file IN ITEMS + analog circle cross dp_bottom dp_left dp_right dp_up dualshock2 + joystick_cursor l1 r1 l2 r2 l3 r3 select square start triangle arrow_up + arrow_bottom arrow_left arrow_right) + add_custom_command( + OUTPUT "${PADImgHeader}/${result_file}.h" + COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl "${PADImg}/${result_file}.png" "${PADImgHeader}/${result_file}" ) +endforeach() + + +# PAD sources +set(pcsx2PADSources + PAD/controller.cpp + PAD/GamePad.cpp + PAD/SDL/joystick.cpp + PAD/keyboard.cpp + PAD/KeyStatus.cpp + PAD/onepad.cpp + PAD/resources.cpp + PAD/state_management.cpp + PAD/wx_dialog/dialog.cpp + PAD/wx_dialog/opPanel.cpp + PAD/wx_dialog/GamepadConfiguration.cpp + PAD/wx_dialog/JoystickConfiguration.cpp + PAD/ini.cpp + PAD/linux.cpp + ) + +# PAD headers +set(pcsx2PADHeaders + PAD/bitwise.h + PAD/controller.h + PAD/GamePad.h + PAD/SDL/joystick.h + PAD/keyboard.h + PAD/KeyStatus.h + PAD/onepad.h + PAD/resources.h + PAD/state_management.h + PAD/wx_dialog/opPanel.h + PAD/wx_dialog/GamepadConfiguration.h + PAD/wx_dialog/JoystickConfiguration.h + # images + ${PADImgHeader}/analog.h + ${PADImgHeader}/circle.h + ${PADImgHeader}/cross.h + ${PADImgHeader}/dp_bottom.h + ${PADImgHeader}/dp_left.h + ${PADImgHeader}/dp_right.h + ${PADImgHeader}/dp_up.h + ${PADImgHeader}/dualshock2.h + ${PADImgHeader}/joystick_cursor.h + ${PADImgHeader}/l1.h + ${PADImgHeader}/r1.h + ${PADImgHeader}/l2.h + ${PADImgHeader}/r2.h + ${PADImgHeader}/l3.h + ${PADImgHeader}/r3.h + ${PADImgHeader}/select.h + ${PADImgHeader}/square.h + ${PADImgHeader}/start.h + ${PADImgHeader}/triangle.h + ${PADImgHeader}/arrow_up.h + ${PADImgHeader}/arrow_bottom.h + ${PADImgHeader}/arrow_left.h + ${PADImgHeader}/arrow_right.h + ) + # DebugTools sources set(pcsx2DebugToolsSources DebugTools/DebugInterface.cpp @@ -908,6 +989,8 @@ if(Linux) ${pcsx2LinuxHeaders} ${pcsx2USBSources} ${pcsx2USBHeaders} + ${pcsx2PADHeaders} + ${pcsx2PADSources} ) set(Platform_Libs diff --git a/pcsx2/PAD/Linux/CMakeLists.txt b/pcsx2/PAD/Linux/CMakeLists.txt new file mode 100644 index 0000000000..df1de75926 --- /dev/null +++ b/pcsx2/PAD/Linux/CMakeLists.txt @@ -0,0 +1,141 @@ +# Check that people use the good file +if(NOT TOP_CMAKE_WAS_SOURCED) + message(FATAL_ERROR " + You did not 'cmake' the good CMakeLists.txt file. Use the one in the top dir. + It is advice to delete all wrongly generated cmake stuff => CMakeFiles & CMakeCache.txt") +endif() + +set(compiled_images "${CMAKE_BINARY_DIR}/plugins/onepad/ImgHeader") +set(image_sources "${CMAKE_SOURCE_DIR}/plugins/onepad/Img") +set(linux_sources "Linux") +set(linux_headers "Linux") +set(wx_sources "wx_dialog") +set(wx_headers "wx_dialog") + +set(onepadGuiResources + ${compiled_images}/analog.h + ${compiled_images}/circle.h + ${compiled_images}/cross.h + ${compiled_images}/dp_bottom.h + ${compiled_images}/dp_left.h + ${compiled_images}/dp_right.h + ${compiled_images}/dp_up.h + ${compiled_images}/dualshock2.h + ${compiled_images}/joystick_cursor.h + ${compiled_images}/l1.h + ${compiled_images}/r1.h + ${compiled_images}/l2.h + ${compiled_images}/r2.h + ${compiled_images}/l3.h + ${compiled_images}/r3.h + ${compiled_images}/select.h + ${compiled_images}/square.h + ${compiled_images}/start.h + ${compiled_images}/triangle.h + ${compiled_images}/arrow_up.h + ${compiled_images}/arrow_bottom.h + ${compiled_images}/arrow_left.h + ${compiled_images}/arrow_right.h + ) + +# plugin name +set(Output onepad) + +set(onepadFinalFlags + -fvisibility=hidden + -Wall + -Wno-parentheses + ) + +# onepad sources +set(onepadSources + controller.cpp + GamePad.cpp + SDL/joystick.cpp + keyboard.cpp + KeyStatus.cpp + onepad.cpp + resources.cpp + state_management.cpp) + +# onepad headers +set(onepadHeaders + bitwise.h + controller.h + GamePad.h + SDL/joystick.h + keyboard.h + KeyStatus.h + onepad.h + resources.h + state_management.h) + +# onepad wx sources +set(onepadwxSources + ${wx_sources}/dialog.cpp + ${wx_sources}/opPanel.cpp + ${wx_sources}/GamepadConfiguration.cpp + ${wx_headers}/JoystickConfiguration.cpp) + +# onepad wx headers +set(onepadwxHeaders + ${wx_headers}/opPanel.h + ${wx_headers}/GamepadConfiguration.h + ${wx_headers}/JoystickConfiguration.h) + +# onepad Linux sources +set(onepadLinuxSources + ${linux_sources}/ini.cpp + ${linux_sources}/linux.cpp) + +# onepad Linux headers +set(onepadLinuxHeaders) + +set(onepadFinalLibs ${SDL2_LIBRARIES}) +add_definitions(-DSDL_BUILD) + +set(onepadFinalLibs + ${onepadFinalLibs} + ${wxWidgets_LIBRARIES} + ${GTK2_LIBRARIES} + ${X11_LIBRARIES} +) + +set(onepadFinalSources + ${onepadSources} + ${onepadHeaders} + ${onepadwxSources} + ${onepadwxHeaders} + ${onepadLinuxSources} + ${onepadLinuxHeaders} + ${onepadGuiResources} +) + +include_directories( + ${CMAKE_BINARY_DIR}/plugins/onepad/ +) + +### Generate the resources files +file(MAKE_DIRECTORY ${compiled_images}) + +foreach(result_file IN ITEMS + analog circle cross dp_bottom dp_left dp_right dp_up dualshock2 + joystick_cursor l1 r1 l2 r2 l3 r3 select square start triangle arrow_up + arrow_bottom arrow_left arrow_right) + add_custom_command( + OUTPUT "${compiled_images}/${result_file}.h" + COMMAND perl ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl "${image_sources}/${result_file}.png" "${compiled_images}/${result_file}" ) +endforeach() + +set(RESOURCE_FILES res/game_controller_db.txt) + +add_custom_glib_res("resources" "onepad-res.xml" "onepad_res" ${RESOURCE_FILES}) + + +if(BUILTIN_PAD) + add_pcsx2_lib(${Output} "${onepadFinalSources}" "${onepadFinalLibs}" "${onepadFinalFlags}") +else() + add_pcsx2_plugin(${Output} "${onepadFinalSources}" "${onepadFinalLibs}" "${onepadFinalFlags}") +endif() + +target_compile_features(${Output} PRIVATE cxx_std_17) diff --git a/pcsx2/PAD/Linux/GamePad.cpp b/pcsx2/PAD/Linux/GamePad.cpp new file mode 100644 index 0000000000..1227072566 --- /dev/null +++ b/pcsx2/PAD/Linux/GamePad.cpp @@ -0,0 +1,76 @@ +/* + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#include "GamePad.h" +#ifdef SDL_BUILD +#include "SDL/joystick.h" +#endif + +std::vector> s_vgamePad; + +/** + * Following static methods are just forwarders to their backend + * This is where link between agnostic and specific code is done + **/ + +/** + * Find every interesting devices and create right structure for them(depend on backend) + **/ +void GamePad::EnumerateGamePads(std::vector> &vgamePad) +{ +#ifdef SDL_BUILD + JoystickInfo::EnumerateJoysticks(vgamePad); +#endif +} + +/** + * Safely dispatch to the Rumble method above + **/ +void GamePad::DoRumble(unsigned type, unsigned pad) +{ + int index = uid_to_index(pad); + if (index >= 0) + s_vgamePad[index]->Rumble(type, pad); +} + +size_t GamePad::index_to_uid(int index) +{ + if ((index >= 0) && (index < (int)s_vgamePad.size())) + return s_vgamePad[index]->GetUniqueIdentifier(); + else + return 0; +} + +int GamePad::uid_to_index(int pad) +{ + size_t uid = g_conf.get_joy_uid(pad); + + for (int i = 0; i < (int)s_vgamePad.size(); ++i) { + if (s_vgamePad[i]->GetUniqueIdentifier() == uid) + return i; + } + + // Current uid wasn't found maybe the pad was unplugged. Or + // user didn't select it. Fallback to 1st pad for + // 1st player. And 2nd pad for 2nd player. + if ((int)s_vgamePad.size() > pad) + return pad; + + return -1; +} diff --git a/pcsx2/PAD/Linux/GamePad.h b/pcsx2/PAD/Linux/GamePad.h new file mode 100644 index 0000000000..5a0a2c81b0 --- /dev/null +++ b/pcsx2/PAD/Linux/GamePad.h @@ -0,0 +1,94 @@ +/* + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#pragma once + +#include "onepad.h" +#include "controller.h" + +#ifdef SDL_BUILD +#include +#endif + +class GamePad +{ +public: + GamePad() + : m_deadzone(1500) + , m_no_error(false) + { + } + + virtual ~GamePad() + { + } + + GamePad(const GamePad &); // copy constructor + GamePad &operator=(const GamePad &); // assignment + + /* + * Find every interesting devices and create right structure for them(depend on backend) + */ + static void EnumerateGamePads(std::vector> &vgamePad); + + /* + * Update state of every attached devices + */ + virtual void UpdateGamePadState() = 0; + + /* + * Causes devices to rumble + * Rumble will differ according to type which is either 0(small motor) or 1(big motor) + */ + virtual void Rumble(unsigned type, unsigned pad) {} + /* + * Safely dispatch to the Rumble method above + */ + static void DoRumble(unsigned type, unsigned pad); + + /* + * Used for GUI checkbox to give feedback to the user + */ + virtual bool TestForce(float strength = 0.6) { return false; } + + virtual const char *GetName() = 0; + + virtual int GetInput(gamePadValues input) = 0; + + int GetDeadzone() + { + return m_deadzone; + } + + virtual size_t GetUniqueIdentifier() = 0; + + static size_t index_to_uid(int index); + static int uid_to_index(int pad); + + bool IsProperlyInitialized() + { + return m_no_error; + } + +protected: + int m_deadzone; + bool m_no_error; +}; + +extern std::vector> s_vgamePad; diff --git a/pcsx2/PAD/Linux/Img/analog-2.png b/pcsx2/PAD/Linux/Img/analog-2.png new file mode 100644 index 0000000000000000000000000000000000000000..0263c1ce1666756234301c77d8f0e1b20c758dfe GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^LO{&T!3HFY#P6~IDYhhUcNd2LAh=-f^2tCE&H|6f zVxTHv5N2eUHAey{$X?><>&kwgTSh>LF|f=o5-4Qu>EaloaXvX>)si3o?U|WfXEXwV z;IRcF28IEgJyIr%c#~$HIDcG0QO|K3wOm&K6{tV5@m|`IFUqfkrTRy85}S Ib4q9e0Btfc&Hw-a literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/analog.png b/pcsx2/PAD/Linux/Img/analog.png new file mode 100644 index 0000000000000000000000000000000000000000..dbd8c193139aa09cfa08ff7e476446d645015803 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~n!3HE}ZR`&LQfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#KDUejr&5%9%SND(n5Ts0Kj#m8nBT~B;E03b cf*TABO|zI-cCM7z1ysS{>FVdQ&MBb@06||QCjbBd literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/arrow_bottom.png b/pcsx2/PAD/Linux/Img/arrow_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebc6d553540f1a077af019d88f958506a8a3e13 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^d_b(k!3HGr)n3d2Qk(@Ik;OpqBOuH;Rhv&5D0tS> z#WBR9_wD7~yv+t8tq<=jvT7SRm?iMe;+dc&$)V{R6_&tyt0chCA#8!8x@*o!rDJNb zTL;mp%oeUpTU) z`I?HE_`XFeYp?_}{jlZa+Wzbr`;8y=)k0^aFX&k4man?YaQlMTbm@ehWp=SFr5l^q zDsAw(+m+5>yZFQ*Z-%&S2Yd{wGD@yrT)+N$VglQ{xRULWyI6KUNVWb^)wl3M&AZ2k cd!38#S$%zDm2AM}0rVJyr>mdKI;Vst0QOL6MgRZ+ literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/arrow_left.png b/pcsx2/PAD/Linux/Img/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..4000cb476f280b9eb26d20b58b7f2e0d824f3d34 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^NAn8f#cW>zV^xTS}HBF@!B}oZqIPt>huL zY3}58Ti%^4w{uS6@P4Qf(`xnY&wa%;Eq)aoT)XcyxLI(XH+NVlzAC0+YXM(Z`%cf; zJwj0rjTk+qF)tANc1YL!0ka_Ap}isrCtNSZ9Y3ZMWy~~H_F8B3udg+q9hm}dwtizZ kiTik4X#&HPCzq=k)l@c1274Aq0A0)A>FVdQ&MBb@0NANkvH$=8 literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/arrow_right.png b/pcsx2/PAD/Linux/Img/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..c391d0025b28a7b4ba2b32dc836a68a663a9a2e6 GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^NFdh=fQe5)P(bK7Ybj8u)6>N<#NzbXt9u0*6Gd7dw)<{t z)pcOMH9^C{WsTUv5bmf6r#eg)uyk6^zHw(m&Hb5{59d}s|2OBf2UqTnme?0lLL%B* z+$~xnH7BUW#2av)FW~uH-t}31{-H%|6AnJ#z~!4c;o$ZSyt+P4Q?APXUKtf~I^$L3 tHTjZ?pBI0I31=ub=XAOM+3vrdeM@R_N%(<^B|t|pc)I$ztaD0e0sz`+TnGRF literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/arrow_up.png b/pcsx2/PAD/Linux/Img/arrow_up.png new file mode 100644 index 0000000000000000000000000000000000000000..dc8de6ccde5abf63c3adf61d47ae9799dac10a6d GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^d_b(k!3HGr)n3d2Qk(@Ik;OpqBOuH;Rhv&5D7fF# z#WBR9_wA*Pyv+sztq<=n{K&;~fNhQAWX2VfW{GZM(%!(Nec{r?F2+qvyj7VwC%X)0 z=&`ErJyt$HWiIbTp*<|?BkbGOJb0XR{(zgpbT!e`Cd-D+3f_&S4K=SsEbq)KsK8nOW^dr)i?GDAS#!X7|#A+;Jc3ABb;w|0!g*$?fGp PuP}JJ`njxgN@xNAnVn_J literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/circle.png b/pcsx2/PAD/Linux/Img/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..cabc2681f576b9cce4a5f2aa45e75af973b97ea8 GIT binary patch literal 916 zcmV;F18e+=P)3#uwS~@1XM7ks(#}x3A)MqUckVLZx#yhwopT8kA&=|p zM1#=?N~?t^2;evlY%+;EE8htmmb`9j6Gb4e_SEGP%Lbe;s9JkT)5R+?e9kGB0=~cH z!cq0vh}SFnW@ZlDv|@K)`(zz7g7j~WBGEeiA?JaH>g!ZvL^1G&VZ`fxzv@qx>28pf zt)O^8bv|a&LfrZa*UUuTN@RSzXlfMugNurd-&%TL(9?OlFR9ZY#s|^j|EOm2gB4Ko zSK#U(syCAI_qtUNDmsgVk%D(}8~`xa*#~o+17T@}A(@ib?j{2`J3pCI2_hHx;^n)j z+G1t%CfFc6pT={ZKJ4vF@1~yYoiuq@5 ziL6Mq&BBQbP5=-{0`%B}qPZl-2LS*&HifXaH)HN*C=37~hn>z0-!I!8ux?60$0g=V zVo~>(3G5mu38=C~bq!^;*?>qy9$>3ZLzgz=!c@srE^N&KIvS<~FOS{u`2YYuK%}xs zXWh=gycz>fk!8sxF_R7zoYbFZF5=!9TgJQs#kj-E*RCA0|JrI*7_>acEI||s>=>n> zF~_;G0L*q>lKY&BTgkT!lQB@cF!mY1feEKjF~?cCua+Cgjc7DuAjQW!WHxK=F5SeI zHUL1pLbB}0=%_LsXXk<7l|fiHlMqM(wf;v%gNNFCVIdm<0NbfWMVcl6LNy4<-_sEQ zAO#U?4yJhX?@=(T(F&Qwfd!Bn*eKhAd+48GJeAZNrhCGVG8 zp)m2!bo}cq1K#F2{B)d4i8Tj_Xtpm-o9SS-@X$JXKC)7LZJI|78CVyZs5bb#=?ghOaf136_~1IM%dJ~4 z3gYE?jhg3vL4%aG6RmkX4x8>@TL2bbz6*9V1M3y;< za1Dn4EvQab0dP+4;f^fP_M!X1LQV(v^~Z~-jlrdP_AHAfoCE-@G9K}Z3;?!u9AjB~ zb5eM1V88X<8eWjFpNO(uPH=!oco8ms18^o#&Aniuqkw^#15}xZZTmI)e9Bq@owHhG zJV8Yl%x+f2#$$d*ceS$PC`;R09Bm2^F5UB4`QTuTm_%DO0N>hiJSp6A!t9BYv^p;7 zY@@Q{NYq~h#l~Z+ZMD&9`Nn^&MHlS-Cgn-zM`EA+tW^ui7%Wy zQqIEeb~5?SGtWF;c;@1!7yp~*TJ~mt{3x^oQL9|XCAkxTQGBC59E@o%KXjK*Y777y z&01EOSCa}5AhfpNmRxJWGx-q*2dJxA&S>%3N{XE)7O>#KDUejKa;sI^M9bwVow*x5Rc<;r&{wd8S=0mKWW&| z%4%gH)E<3g`D32~Hi4~~41p|bH(T&_sfueF)m8cB92DUCRVgNL+V&*ta}iGGgABXN zmho`1Zhca?^MX$FFOg_nA^s2BnI5tFiE=Q+8VB+h1TENFdF_sU{KN`Pznj7u5=W=V zKg+eOc>jI<2d?!W>RZbn3+62Etvdht`kt!wODFdgVpIb(NUyEtkYF41oNlzEY5Rc<;uUc~*au7K7v3}ZF z-YwoWEL+ayvK&0VR;PAB!rMZTCPT|sr(?%j6ap8eZU5AqIjvECb1)A>cbPZKKD}4Z z#8uXp9wQP2l*P_E^+aa#m%Uy-7Ym+wdR@II)qbjaI}_uZcIJ&t zy?yFsjtUG?hb7$w&F>4hww{?JqCMfG?B9j+A2%${Q8=c4N^o(2q#>KFGK1HqGZvpJ z+WX)A6ZiO7+HPRdB_jOvCR^>rUH3A@Pwt3a@AJ4jc=><6Hob{!Uz}cd6X+=hPgg&e IbxsLQ01#h#UjP6A literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/dp_right.png b/pcsx2/PAD/Linux/Img/dp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..23fa90cbc06b468c1e3d72bf8dca68f027d9b769 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)u!3HEnufz)gDYhhUcNd2LAh=-f^2tCE&H|6f zVg?3oVGw3ym^DWND9B#o>FdgVpIb(NPt4@fv%^541D-C9As)xyUUB3)WFWwL!T#VE zmR;FVrOUr~blp3(G^#*d?&PYkV$=F|M;V$d_1RREP?jj?Q^)jWh4(Z==H@DM$<4wR zYH0=+-ubD_U#7&tTw`FUExpOyaD9Hc$5oH)h=sX7TT1>qoSW{XE)7O>#KDUejuXLi{$-O|K`<^b2As)xyUfIugFhJz^$N6Qd zFT2_nF7&$0_jUdIM^~3@>~QIDY+AZ`Ycl&oR-F}jeT~NyoL)+*{8cO8d073s+V?v= z?|i?obuQ|NS7K^<%((Zh9y5c)6mOU9e~(PNoh8U{Ao%K$LZ%ZFyHzCi@%L@oDZ^r* z%Aq9Br*Jg*&*4KK{w!Bte!7+4o|VxcKT1db`eQE6!`X)`9^}Q|-Y~~1D=*Tf;L4)Q z&l(q}Ej!8V?pyjdxkTSnzopr0DWAF761SM literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/dualshock2.png b/pcsx2/PAD/Linux/Img/dualshock2.png new file mode 100644 index 0000000000000000000000000000000000000000..a64cf8edc27017a48c5857f4a4d7af0480ec494b GIT binary patch literal 110432 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 literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/joystick_cursor.png b/pcsx2/PAD/Linux/Img/joystick_cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..84733981029966f47f3f1d34fbd51e1d393bcc72 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=wj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&kwgOOj7tC&|4w3n*ma>Eal|aXs~nA=d!|0p^1T-|yjH z_U%3spTy1+qKzTlN4yk5W-P4fvR;#xncTYEl3njjc}n@edbu4I^2`Oni#UL0FnGH9 KxvX+}I00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-wPZNFFXB`uT=m513*bc zK~z}7-I&c!6G0fppP8M0VWEXm#6qg&OOUE)j4{!8F!A6;#CY&z^gr-F0B@f3=uJ&b z^rEN-3fV3;{9CvqS=eP5|&%W<4tWw`2 zE=qd5R@$S1iR{#JkFes^@lmwH~Bx%VRsXTi> z{bDGwRy^UueNA7QWjfMojKVIBd;Lf_JrFa~6Hi2C^;vy{l?9f<=p71#`r3@|SZn$i zXuxO9HGJ&lm!?(0_8*E;PfW*p(oi6T7gFHNn;2UbYg-2 zI-pc0_4-H;>Mvfw=Kb~drcMkj2W#x`Q%x$ls2P>ojsJ&k1)K9bJKwq1yWaci;1&Xr z*<$E+s2u_uR7y%jCgXWmCdwMror9gU(O`)Rkuqi`3%hG(5*u9v%I55H^L027f~g2n zT2M;O&9b2AWB?fFMZb9Ns}mvTk+bv6wTZ2(XgmzBA93zP$5gz)jhD<>-5UUiz&VGe z6f_~Qed0&icEHpGzWVF%t||y6Wp<&Q!|8Nkxou@!bD}vlzTmpJ(Y1{*{+FV(sKmO$fR-03w1A0v&&u&wN>#44l%+w}Q0|Ky0*hZftDw0i=*{dqIjoq;lb^ zl)_x1FqRK-&N&$4V4T6hfJmZv=(dgL?@hWl;caCtl$3CLJOv>?SX~bX5ip$}J18pR zxe98joHZ({kZ@JNvMgAc47!FUnO!^Ge<(^jr;}(&j4XP8ux1O)bQ+8?fC$3jKzs7% zg6b&;`?#y|dDKiDs7WO;;i<$AhZ~*x7+Z_3`l>T{ztZhG-ZD0_qEhjn&Y;%R?<9;~ z0DVgx-Lwsi+TY@pp}4=mVqh!=_9@u7=rhl(b&XhD*LOCOvBOUk22mLFHX1DOqCb}< VKGl8vMl$QV!0`U+K2n3=}Jn<_qzkt7h zR3s|F1Cc-=gu)Xb3N0$F?KF0UoF<`3W2b2x+qvux4~`vLU*g(XCuv5qyuQuMerLY( zof#7>u+h;`E?6sa(X;vPmZ`>tx$jC|{ z%J$7)W0oYJ==Ndo+Wd~)gJ{>mT*$%6XM)T+xE2rq@aEH_mVhy^G!NFntb@m29K6Xo zKIu3Z@l!r7C*fPmBeXD$-L{u*#g7Asmh<}M`Ou%1fpPK7i3$J%OY_+4c5XH`T+X-I ziV@pafuC6izc-h(EOGN61G(5TW`CQ({2y~xgov^Z{`TczZV8M;#J^bubC$2-jgLPl zDamJ1_|Et(i}Ob6GFS(H_sX-}w3@IEZZ%-7&9YfFN&Ykmr_+hR+1`#&>8sw8c=z`S zstZOtK(s@X@$qrE-EM?JAvnWY$726*@;SWz<0Y!1$!-7v0M|Zx2b!j#P$+=T^{sa@ z_G=TD@cpZ2`M%1S7z*%{i??x5?Mu%STa|H8fXJ(MOt=D7?>}`&*{Y1)qDZIhZ$}Rz z`NjIunuz!h1Q2n}3!hT^G?6{*f&u`?moo=~B8Figu#&CaV@b6HhH7lI9AHfG2qmx}NIuW9qT+|rW}5JJGevV`v9%8mk&bRUJv46M{``l7@-eg-hI zowJlDi1qa~7={6GNrwo4R1^p);V=yZ7u!3n-qze$?y|u!3>bz1W(LY2N(rT_3;mhd zmV947>_#|Op8+%lQsSC-WboddCQ57rRySyYdl>|_S>2e^1Jg7?0J>DQX%%GVh6)1| zp{O=nQ_l8+^qzR2DpHPM1so|Q8ZD}nvhHW;Ls|)p(4FahyCFW9d)(=PVHmL4?dZ?` zyVVHx1fWW#(U2$#0JKx*i;P3Vg3VFkySd4E(=;)BGgs9ET?siEL?9waAt0oLf1?Ob zA=h>;lkTHfEfgT6gw1Y8K9@tJaJS)p@z7vQ9_hvE>MA0MY{!PQpNE62b-VD^t?R9g z2YLbxDW3EkL;sbT`d~~S@gtKj;`HPa?L~Tg{lWmhJ(JiGUooc#;n+eo7+>`C;r!J! z?WcX?!cZTNP!Yjw%d#G&DSTRYxU*mF!cZT7xR`#Z-<0=@s(HqKxARxiL{lJ|0$ucm znmCmnt8UaDMSK5pssc>P8?5=AUpF4v+uuf&P6atL=&JnP5es{(gyTOBa+`FYB(`e+ O0000? zjU*rm#^=Tjm4yqK$#qv+I?&E^3Ulv0$ys#LHuJmZ|3CLJL%70N?dv`K=ktX$O@pdx zFiiu7VL&}OIhyoISD_%=NR2ZF*v`#~6w8Ifj1SOYfE9Gz5$I)^i+FGV787yT zL9KFmc1Jk}IEIsG96u6@+W;r%O4tLp_@xl#4Hu`xb&Epo1x+nIE0 zz;`Ayo&>H;S3T_&IlJZax}M(7WViu#r9kUrqn?+vrN`3_J)R8)xCAcG<*_KU?P;ET zY}enGo-XJ*_rSIamkkVXE$j37COXLK%3B0k*OPgbycfbD;eY{PX(+)ith9(#wyJiy z($9N)garnGg;0>yK>K@oMP^2q-(M?lk)?fJ;tBvfyWvUr^v6%GG%Ht6LmwU-5CKF0EykP; zz}7?xMO`n05u9otyNN-`*J{Y6`$t=1FWGr_Wg&J+vGnq=Zu9gWRTJT0000< KMNUMnLSTX*rIb1V literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/r1.png b/pcsx2/PAD/Linux/Img/r1.png new file mode 100644 index 0000000000000000000000000000000000000000..7f162ba21a4278f079731a362b861eedd68773b1 GIT binary patch literal 949 zcmV;m14{gfP)+}I00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-wPZNC>Hk&W#<3@142ne zK~z}7-IvdA8$}$&KQlYK4$j6lb!?+xOjBq|OG~McDnJ~1DWZUADndgREBBT~b^ zz!f322q95brS7E%B#<~DR8bN^l^;#5P^)sXDt7wA^^e{44u@3EZ_+r90~<1+t+?$tK-;#qbuI!^Leo@+4FDg)yIoh z!&Bj%kI2})PW-zsGhq>3i?CRBx#+M}D7<%)9bcS5Y?p*hb~$7xi2}H;ix6T{>@EQ= z9(q}KYC+d^0hl;)f~$w$? zShG>DBMpPN6lCvL9%_;4{sBA1VfKP5o&smOAu=X);(YQLz*JY^UxVzdV&_ ze{|{aL9KKA>+{QtnIHboC8&KHJF_!us<`vY%?A!}x~KS_dwow^#qyqnKD{s7Rf*#t X)!aa{0L0(@00000NkvXXu0mjfk08Oq literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/r2.png b/pcsx2/PAD/Linux/Img/r2.png new file mode 100644 index 0000000000000000000000000000000000000000..62ff3b217b8c855f772307e36a3d5fa848c80114 GIT binary patch literal 1166 zcmV;91abR`P)n3`qp_QJR!E@P}RC@`gRS%K0~YAJ2c@9{+`<+S0kvd1Gu0o6SbC?*jt^ES>SEWw6+!ue{Mt-BY)bNqeu|h9e2%(yJEA)9H|D z0Es}v?DFjaTx)s>zLkgg_~sbPDvT?q+o}70b|#++#8x0%&2D-g@Beo9z;omKak}_& zGm!~ICOi@l2els8UBu$O&}pW$!1(3O7l=%t4`xTx9`M4D8*?{i;s0wD+TSW;U_NnA zfJ`9!YgRfGj9=e6MPvfKJ9#T(K~{BEgTDR>05Ja9rRzu%9kv%Szh z|1zcjPLWL2pUTJtO1PR_J<~<+j16X0_;Rug zFjQf*)R+@6V#_Ue3td77>%ZerO63HMx96PEeTMJ9fE_?jBBxp{gbBkjm_2i8z4=Ue zH3D2f(=?E#ML#K8twaRQq5`jN^lfc(#y~*y(Vz3ptKs1SbSiSFc#1;7_|lq8Hvqt) zH=xDuIn+&@hGU3?!_Z`A5+H}@QcWhm0?u^tRUQwsTog*cH0 zQFT_-BD|p~O4A@Tway93688VG(|1Y~oLm#KTyc@lH#A2G0U;$C7iZE7!`V?s=B3%B zj`yCb+Lj#$G5gak@UM8+`y8_c+4`4%IAx}eh#x1G=MN6UVW}ibno|B!T@yaMagQCv zQs{4Opwldf`ek==7<=hP%H^%18rP`+y?3VB%0Z(%o g^|#aob7k)T1Chn4HQn|roW&$)N*ogpw#3+^$>3jzc| z0M8337G=otSv>jmo51W!i6Y&Yj!_D99PeUxXwvJU<^c7H^oQH62(($`5(%30xO;B^ zmM6lRf;NjxDA;}YbTD8DY;B}`qAGaB&4U76A9bSe`8lQ8?S-<^BI|9nITP=So!iBS znHhb+weHHAgU@OV-pjDn@i7|J27EgjrDlPq0Nqq;_04$PRKVp}zdfZ4JRR_x61W@- zEmm=)m*-)<=5fxdzyOd-BreDC#y@UqTi4m#Jx1Hw+bUUZW%CR6&W1yl0|tOa(My|V z+KO3jlZU$AY!XdU4%J&!Gn#4i=a( zbZxj|Zx*awZE@zHlOA{Hdt_#p&29&`Iy!R15_Df*Ke$4Fzn3Lwp69^{g20r$@9yk? zv)S#el{L7(g#vrfvMe(N{L|$ES1cBpf-aRx?5)TShKJc(oP4=rV{`4z0l@oMjIHhs z0H^sp6R^42*$VXIqa(rs^lAQ2<$ao!y1uYo1OQ7u(bB-LZ@Q}CD`IZn8vs@!6P5%{ z`^Res;G&p2%L0JqaL7`?Dbd?#5b9;6Y&SZXZ@Bh;?ijQza7!8Wk*i*@H11R8)?6ZC zO5ly@n7Z;b8}Qa#`|nK1Wx=gf$DA$=p$poMM)i5lt+~10{4_Ei*Vl<}CnG%toDK%4 zf)eOluUt3i)8i9GgLYq%>aMM>tr;^9cT&@}dUkw52tZaM5!Jx0t~XOQ6jW8es&+%? z_xA|_$okYRLz>mfWCR2t4-dYnYFL_V0ZY4kga9NP3hMM~=m!DF{MUU=y0fN7mem=^ zgo1S7>L6tKAMSnn-0{6K0Y4snKRmnN;i1-Zxp9&tscENuu(xa2|Cav&_=JI<>&kwgTSh=cRQ8+iBA}3!r;B5V#`(9G3`H3fc#d3BG42D MPgg&ebxsLQ004q8?f?J) literal 0 HcmV?d00001 diff --git a/pcsx2/PAD/Linux/Img/square.png b/pcsx2/PAD/Linux/Img/square.png new file mode 100644 index 0000000000000000000000000000000000000000..bcbed6d51b24a07e25a439541534e3f93450c7d2 GIT binary patch literal 538 zcmV+#0_FXQP)4s$;M_0`U3#q=HLj! z@WBmxV_#U>-N8z}fX`5nQWb->C6N3D2LOpiFxogQYzC^e=go?NRJ$N_Bj7{=v#W~+ zt72hqLkQ@3KihQ|dB44H-USYijUP^olcxl>UtT=}*Wwa+dIYP5;sC_JKLIbn^WiYK zCdE7>a0>!Y7Io$o0ku?SgAoIlirjbLY&6nXlr|?MGn2jJ8#?QL70(Y)*K0-AbW|YuPgg~ZW#e#OD=p&Q(pXEWO?u;qr*X|s%zTLOcGeG6Y3)_ ex-e@K6N6H3rMOzb@=ZX8FnGH9xvX`VMV>r zSz|5vr@PHt5F{ zP(nw)(dbg6OCu_%fRdzQA>ES5!Lbf+xOP+3J|O_ZM#ES<1x;6P;3zP0-e#xi>W#QS zoTa9i?$O3H_m`=-$OrTEC_sO{5jlY&YbRYB6;PtNMN;GI1NJW5+AIL3wK=%8Ssbu; zsd`6Y0A7}rjf*^-XSu~fYf)XhwR|>a6o}lu^7?&VuU-#;-n+=OHYdp2^~=r3xyGa- zL`pWy-mG2+fX=tX)Tw$lcz>hwErs!tafJlXzoAIT^yQrnd@JDhdS(EqU-%N7`_NF{ z=@0_ZtuOf+bb-k2&s=Herfw4erSeZEnh%EY&A0lP%*X}c^xP*pFIk0LAql77HTvMZ zW??#lAG#JQn-GMvq-4ByX2udv=y2;T9_DWZV8`z{-kxoUDz~$vn|Ikd01o~5%!8KZ z$Plip3kM)#{x!D;@km-S6hBKR_QjRWyfcKXk;wCVS!miH_i&-VpsM{I9%(sYR{nA) zG-*J_BWbB>znA)FG_n%&`F@$_)?*13KDQnt-!F&lRSlq`qX(~MIqa%Ev%(K6AnVm= zsOacX2f%7;V=TK60E4_pZ5 zkzqJgY8u}=>9YJ=X!I1A0ND2DJMYgNQB!TPz0<*mtO5Xzes|G*@pKsfNvY{$)J&-B zdd&Q)3;-JECs@0Z>yxE#t1`J?Xa=CrCo^}lCL$9?0H|)e%hSAK(m{JXvkad<9+`?? zSS%j{i?4EvNEe0b9^SI~b67o~fYM^KGqLiaq>Ie*Pg*Zuh+Z}STkEH5^qI|HRaZp+ zgFpwS@g!sz4I;h(ZmdS`Z=)swAo?Fb1l2kH(T4 gsM MAX_ANALOG_VALUE) + value = MAX_ANALOG_VALUE; + else if (value < -MAX_ANALOG_VALUE) + value = -MAX_ANALOG_VALUE; + + // Left -> -- -> Right + // Value range : FFFF8002 -> 0 -> 7FFE + // Force range : 80 -> 0 -> 7F + // Normal mode : expect value 0 -> 80 -> FF + // Reverse mode: expect value FF -> 7F -> 0 + u8 force = (value / 256); + if (analog_is_reversed(pad, index)) + analog_set(pad, index, m_analog_released_val - force); + else + analog_set(pad, index, m_analog_released_val + force); + } +} + +void KeyStatus::release(u32 pad, u32 index) +{ + if (!IsAnalogKey(index)) { + if (m_state_acces[pad]) + set_bit(m_internal_button_kbd[pad], index); + else + set_bit(m_internal_button_joy[pad], index); + } else { + analog_set(pad, index, m_analog_released_val); + } +} + +u16 KeyStatus::get(u32 pad) +{ + return m_button[pad]; +} + +void KeyStatus::analog_set(u32 pad, u32 index, u8 value) +{ + PADAnalog *m_internal_analog_ref; + if (m_state_acces[pad]) + m_internal_analog_ref = &m_internal_analog_kbd[pad]; + else + m_internal_analog_ref = &m_internal_analog_joy[pad]; + + switch (index) { + case PAD_R_LEFT: + case PAD_R_RIGHT: + m_internal_analog_ref->rx = value; + break; + + case PAD_R_DOWN: + case PAD_R_UP: + m_internal_analog_ref->ry = value; + break; + + case PAD_L_LEFT: + case PAD_L_RIGHT: + m_internal_analog_ref->lx = value; + break; + + case PAD_L_DOWN: + case PAD_L_UP: + m_internal_analog_ref->ly = value; + break; + + default: + break; + } +} + +bool KeyStatus::analog_is_reversed(u32 pad, u32 index) +{ + switch (index) { + case PAD_L_RIGHT: + case PAD_L_LEFT: + return (g_conf.pad_options[pad].reverse_lx); + + case PAD_R_LEFT: + case PAD_R_RIGHT: + return (g_conf.pad_options[pad].reverse_rx); + + case PAD_L_UP: + case PAD_L_DOWN: + return (g_conf.pad_options[pad].reverse_ly); + + case PAD_R_DOWN: + case PAD_R_UP: + return (g_conf.pad_options[pad].reverse_ry); + + default: + return false; + } +} + +u8 KeyStatus::get(u32 pad, u32 index) +{ + switch (index) { + case PAD_R_LEFT: + case PAD_R_RIGHT: + return m_analog[pad].rx; + + case PAD_R_DOWN: + case PAD_R_UP: + return m_analog[pad].ry; + + case PAD_L_LEFT: + case PAD_L_RIGHT: + return m_analog[pad].lx; + + case PAD_L_DOWN: + case PAD_L_UP: + return m_analog[pad].ly; + + default: + return m_button_pressure[pad][index]; + } +} + +u8 KeyStatus::analog_merge(u8 kbd, u8 joy) +{ + if (kbd != m_analog_released_val) + return kbd; + else + return joy; +} + +void KeyStatus::commit_status(u32 pad) +{ + m_button[pad] = m_internal_button_kbd[pad] & m_internal_button_joy[pad]; + + for (int index = 0; index < MAX_KEYS; index++) + m_button_pressure[pad][index] = m_internal_button_pressure[pad][index]; + + m_analog[pad].lx = analog_merge(m_internal_analog_kbd[pad].lx, m_internal_analog_joy[pad].lx); + m_analog[pad].ly = analog_merge(m_internal_analog_kbd[pad].ly, m_internal_analog_joy[pad].ly); + m_analog[pad].rx = analog_merge(m_internal_analog_kbd[pad].rx, m_internal_analog_joy[pad].rx); + m_analog[pad].ry = analog_merge(m_internal_analog_kbd[pad].ry, m_internal_analog_joy[pad].ry); +} diff --git a/pcsx2/PAD/Linux/KeyStatus.h b/pcsx2/PAD/Linux/KeyStatus.h new file mode 100644 index 0000000000..ae402e091a --- /dev/null +++ b/pcsx2/PAD/Linux/KeyStatus.h @@ -0,0 +1,80 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2011 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#ifndef __KEYSTATUS_H__ +#define __KEYSTATUS_H__ + +#include "onepad.h" + +typedef struct +{ + u8 lx, ly; + u8 rx, ry; +} PADAnalog; + +#define MAX_ANALOG_VALUE 32766 + +class KeyStatus +{ +private: + const u8 m_analog_released_val; + + u16 m_button[GAMEPAD_NUMBER]; + u16 m_internal_button_kbd[GAMEPAD_NUMBER]; + u16 m_internal_button_joy[GAMEPAD_NUMBER]; + + u8 m_button_pressure[GAMEPAD_NUMBER][MAX_KEYS]; + u8 m_internal_button_pressure[GAMEPAD_NUMBER][MAX_KEYS]; + + bool m_state_acces[GAMEPAD_NUMBER]; + + PADAnalog m_analog[GAMEPAD_NUMBER]; + PADAnalog m_internal_analog_kbd[GAMEPAD_NUMBER]; + PADAnalog m_internal_analog_joy[GAMEPAD_NUMBER]; + + void analog_set(u32 pad, u32 index, u8 value); + bool analog_is_reversed(u32 pad, u32 index); + u8 analog_merge(u8 kbd, u8 joy); + +public: + KeyStatus() + : m_analog_released_val(0x7F) + { + Init(); + } + void Init(); + + void keyboard_state_acces(u32 pad) { m_state_acces[pad] = true; } + void joystick_state_acces(u32 pad) { m_state_acces[pad] = false; } + + void press(u32 pad, u32 index, s32 value = 0xFF); + void release(u32 pad, u32 index); + + u16 get(u32 pad); + u8 get(u32 pad, u32 index); + + + void commit_status(u32 pad); +}; + +extern KeyStatus g_key_status; + +#endif diff --git a/pcsx2/PAD/Linux/SDL/joystick.cpp b/pcsx2/PAD/Linux/SDL/joystick.cpp new file mode 100644 index 0000000000..0204e9ac1b --- /dev/null +++ b/pcsx2/PAD/Linux/SDL/joystick.cpp @@ -0,0 +1,290 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#include "joystick.h" +#include "resources.h" +#include // sigaction + +////////////////////////// +// Joystick definitions // +////////////////////////// + +// opens handles to all possible joysticks +void JoystickInfo::EnumerateJoysticks(std::vector> &vjoysticks) +{ + uint32_t flag = SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER; + + if ((SDL_WasInit(0) & flag) != flag) { + // Tell SDL to catch event even if the windows isn't focussed + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + + if (SDL_Init(flag) < 0) + return; + + // WTF! Give me back the control of my system + struct sigaction action = {}; + action.sa_handler = SIG_DFL; + sigaction(SIGINT, &action, nullptr); + sigaction(SIGTERM, &action, nullptr); + + SDL_JoystickEventState(SDL_QUERY); + SDL_GameControllerEventState(SDL_QUERY); + SDL_EventState(SDL_CONTROLLERDEVICEADDED, SDL_ENABLE); + SDL_EventState(SDL_CONTROLLERDEVICEREMOVED, SDL_ENABLE); + + { // Support as much Joystick as possible + GBytes *bytes = g_resource_lookup_data(onepad_res_get_resource(), "/onepad/res/game_controller_db.txt", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr); + + size_t size = 0; + // SDL forget to add const for SDL_RWFromMem API... + void *data = const_cast(g_bytes_get_data(bytes, &size)); + + SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(data, size), 1); + + g_bytes_unref(bytes); + + // Add user mapping too + for (auto const &map : g_conf.sdl2_mapping) + SDL_GameControllerAddMapping(map.c_str()); + } + } + + vjoysticks.clear(); + + for (int i = 0; i < SDL_NumJoysticks(); ++i) { + vjoysticks.push_back(std::unique_ptr(new JoystickInfo(i))); + // Something goes wrong in the init, let's drop it + if (!vjoysticks.back()->IsProperlyInitialized()) + vjoysticks.pop_back(); + } +} + +void JoystickInfo::Rumble(unsigned type, unsigned pad) +{ + if (type >= m_effects_id.size()) + return; + + if (!(g_conf.pad_options[pad].forcefeedback)) + return; + + if (m_haptic == nullptr) + return; + + int id = m_effects_id[type]; + if (SDL_HapticRunEffect(m_haptic, id, 1) != 0) { + fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id); + } +} + +JoystickInfo::~JoystickInfo() +{ + // Haptic must be closed before the joystick + if (m_haptic != nullptr) { + for (const auto &eid : m_effects_id) { + if (eid >= 0) + SDL_HapticDestroyEffect(m_haptic, eid); + } + + SDL_HapticClose(m_haptic); + } + + if (m_controller != nullptr) { +#if SDL_MINOR_VERSION >= 4 + // Version before 2.0.4 are bugged, JoystickClose crashes randomly + // Note: GameControllerClose calls JoystickClose) + SDL_GameControllerClose(m_controller); +#endif + } +} + +JoystickInfo::JoystickInfo(int id) + : GamePad() + , m_controller(nullptr) + , m_haptic(nullptr) + , m_unique_id(0) +{ + SDL_Joystick *joy = nullptr; + m_effects_id.fill(-1); + // Values are hardcoded currently but it could be later extended to allow remapping of the buttons + m_pad_to_sdl[PAD_L2] = SDL_CONTROLLER_AXIS_TRIGGERLEFT; + m_pad_to_sdl[PAD_R2] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + m_pad_to_sdl[PAD_L1] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + m_pad_to_sdl[PAD_R1] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + m_pad_to_sdl[PAD_TRIANGLE] = SDL_CONTROLLER_BUTTON_Y; + m_pad_to_sdl[PAD_CIRCLE] = SDL_CONTROLLER_BUTTON_B; + m_pad_to_sdl[PAD_CROSS] = SDL_CONTROLLER_BUTTON_A; + m_pad_to_sdl[PAD_SQUARE] = SDL_CONTROLLER_BUTTON_X; + m_pad_to_sdl[PAD_SELECT] = SDL_CONTROLLER_BUTTON_BACK; + m_pad_to_sdl[PAD_L3] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + m_pad_to_sdl[PAD_R3] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + m_pad_to_sdl[PAD_START] = SDL_CONTROLLER_BUTTON_START; + m_pad_to_sdl[PAD_UP] = SDL_CONTROLLER_BUTTON_DPAD_UP; + m_pad_to_sdl[PAD_RIGHT] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + m_pad_to_sdl[PAD_DOWN] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + m_pad_to_sdl[PAD_LEFT] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + m_pad_to_sdl[PAD_L_UP] = SDL_CONTROLLER_AXIS_LEFTY; + m_pad_to_sdl[PAD_L_RIGHT] = SDL_CONTROLLER_AXIS_LEFTX; + m_pad_to_sdl[PAD_L_DOWN] = SDL_CONTROLLER_AXIS_LEFTY; + m_pad_to_sdl[PAD_L_LEFT] = SDL_CONTROLLER_AXIS_LEFTX; + m_pad_to_sdl[PAD_R_UP] = SDL_CONTROLLER_AXIS_RIGHTY; + m_pad_to_sdl[PAD_R_RIGHT] = SDL_CONTROLLER_AXIS_RIGHTX; + m_pad_to_sdl[PAD_R_DOWN] = SDL_CONTROLLER_AXIS_RIGHTY; + m_pad_to_sdl[PAD_R_LEFT] = SDL_CONTROLLER_AXIS_RIGHTX; + + if (SDL_IsGameController(id)) { + m_controller = SDL_GameControllerOpen(id); + joy = SDL_GameControllerGetJoystick(m_controller); + } else { + joy = SDL_JoystickOpen(id); + } + + if (joy == nullptr) { + fprintf(stderr, "onepad:failed to open joystick %d\n", id); + return; + } + + // Collect Device Information + char guid[64]; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joy), guid, 64); + const char *devname = SDL_JoystickNameForIndex(id); + + if (m_controller == nullptr) { + fprintf(stderr, "onepad: Joystick (%s,GUID:%s) isn't yet supported by the SDL2 game controller API\n" + "Fortunately you can use AntiMicro (https://github.com/AntiMicro/antimicro) or Steam to configure your joystick\n" + "The mapping can be stored in OnePAD2.ini as 'SDL2 = <...mapping description...>'\n" + "Please report it to us (https://github.com/PCSX2/pcsx2/issues) so we can add your joystick to our internal database.", + devname, guid); + +#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly + SDL_JoystickClose(joy); +#endif + + return; + } + + std::hash hash_me; + m_unique_id = hash_me(std::string(guid)); + + // Default haptic effect + SDL_HapticEffect effects[NB_EFFECT]; + for (int i = 0; i < NB_EFFECT; i++) { + SDL_HapticEffect effect; + memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default + SDL_HapticDirection direction; + direction.type = SDL_HAPTIC_POLAR; // We'll be using polar direction encoding. + direction.dir[0] = 18000; + effect.periodic.direction = direction; + effect.periodic.period = 10; + effect.periodic.magnitude = (Sint16)(g_conf.get_ff_intensity()); // Effect at maximum instensity + effect.periodic.offset = 0; + effect.periodic.phase = 18000; + effect.periodic.length = 125; // 125ms feels quite near to original + effect.periodic.delay = 0; + effect.periodic.attack_length = 0; + /* Sine and triangle are quite probably the best, don't change that lightly and if you do + * keep effects ordered by type + */ + if (i == 0) { + /* Effect for small motor */ + /* Sine seems to be the only effect making little motor from DS3/4 react + * Intensity has pretty much no effect either(which is coherent with what is explain in hid_sony driver + */ + effect.type = SDL_HAPTIC_SINE; + } else { + /** Effect for big motor **/ + effect.type = SDL_HAPTIC_TRIANGLE; + } + + effects[i] = effect; + } + + if (SDL_JoystickIsHaptic(joy)) { + m_haptic = SDL_HapticOpenFromJoystick(joy); + + for (auto &eid : m_effects_id) { + eid = SDL_HapticNewEffect(m_haptic, &effects[0]); + if (eid < 0) { + fprintf(stderr, "ERROR: Effect is not uploaded! %s\n", SDL_GetError()); + m_haptic = nullptr; + break; + } + } + } + + fprintf(stdout, "onepad: controller (%s) detected%s, GUID:%s\n", + devname, m_haptic ? " with rumble support" : "", guid); + + m_no_error = true; +} + +const char *JoystickInfo::GetName() +{ + return SDL_JoystickName(SDL_GameControllerGetJoystick(m_controller)); +} + +size_t JoystickInfo::GetUniqueIdentifier() +{ + return m_unique_id; +} + +bool JoystickInfo::TestForce(float strength = 0.60) +{ + // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox + if (m_haptic == nullptr) + return false; // Otherwise, core dump! + + SDL_HapticRumbleInit(m_haptic); + + // Make the haptic pad rumble 60% strength for half a second, shoudld be enough for user to see if it works or not + if (SDL_HapticRumblePlay(m_haptic, strength, 400) != 0) { + fprintf(stderr, "ERROR: Rumble is not working! %s\n", SDL_GetError()); + return false; + } + + return true; +} + +int JoystickInfo::GetInput(gamePadValues input) +{ + float k = g_conf.get_sensibility() / 100.0; // convert sensibility to float + + // Handle analog inputs which range from -32k to +32k. Range conversion is handled later in the controller + if (IsAnalogKey(input)) { + int value = SDL_GameControllerGetAxis(m_controller, (SDL_GameControllerAxis)m_pad_to_sdl[input]); + value *= k; + return (abs(value) > m_deadzone) ? value : 0; + } + + // Handle triggers which range from 0 to +32k. They must be converted to 0-255 range + if (input == PAD_L2 || input == PAD_R2) { + int value = SDL_GameControllerGetAxis(m_controller, (SDL_GameControllerAxis)m_pad_to_sdl[input]); + return (value > m_deadzone) ? value / 128 : 0; + } + + // Remain buttons + int value = SDL_GameControllerGetButton(m_controller, (SDL_GameControllerButton)m_pad_to_sdl[input]); + return value ? 0xFF : 0; // Max pressure +} + +void JoystickInfo::UpdateGamePadState() +{ + SDL_GameControllerUpdate(); +} diff --git a/pcsx2/PAD/Linux/SDL/joystick.h b/pcsx2/PAD/Linux/SDL/joystick.h new file mode 100644 index 0000000000..d10dba6d69 --- /dev/null +++ b/pcsx2/PAD/Linux/SDL/joystick.h @@ -0,0 +1,63 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#pragma once + +#include +#include + +#include "GamePad.h" +#include "onepad.h" +#include "controller.h" +#define NB_EFFECT 2 // Don't use more than two, ps2 only has one for big motor and one for small(like most systems) +// holds all joystick info +class JoystickInfo : public GamePad +{ +public: + JoystickInfo(int id); + ~JoystickInfo(); + + JoystickInfo(const JoystickInfo &) = delete; // copy constructor + JoystickInfo &operator=(const JoystickInfo &) = delete; // assignment + + + // opens handles to all possible joysticks + static void EnumerateJoysticks(std::vector> &vjoysticks); + + void Rumble(unsigned type, unsigned pad) override; + + bool TestForce(float) override; + + const char *GetName() final; + + int GetInput(gamePadValues input) final; + + void UpdateGamePadState() final; + + size_t GetUniqueIdentifier() final; + +private: + SDL_GameController *m_controller; + SDL_Haptic *m_haptic; + std::array m_effects_id; + size_t m_unique_id; + std::array m_pad_to_sdl; +}; diff --git a/pcsx2/PAD/Linux/bitwise.h b/pcsx2/PAD/Linux/bitwise.h new file mode 100644 index 0000000000..bb4a2751bc --- /dev/null +++ b/pcsx2/PAD/Linux/bitwise.h @@ -0,0 +1,44 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +template +static void __forceinline set_bit(T &value, int bit) +{ + value |= (1 << bit); +} + +template +static void __forceinline clear_bit(T &value, int bit) +{ + value &= ~(1 << bit); +} + +template +static void __forceinline toggle_bit(T &value, int bit) +{ + value ^= (1 << bit); +} + +template +static bool __forceinline test_bit(T &value, int bit) +{ + return (value & (1 << bit)); +} diff --git a/pcsx2/PAD/Linux/controller.cpp b/pcsx2/PAD/Linux/controller.cpp new file mode 100644 index 0000000000..339ca823d1 --- /dev/null +++ b/pcsx2/PAD/Linux/controller.cpp @@ -0,0 +1,44 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#include "onepad.h" +#include "controller.h" + +__forceinline void set_keyboard_key(int pad, int keysym, int index) +{ + g_conf.keysym_map[pad][keysym] = index; +} + +__forceinline int get_keyboard_key(int pad, int keysym) +{ + // You must use find instead of [] + // [] will create an element if the key does not exist and return 0 + std::map::iterator it = g_conf.keysym_map[pad].find(keysym); + if (it != g_conf.keysym_map[pad].end()) + return it->second; + else + return -1; +} + +__forceinline bool IsAnalogKey(int index) +{ + return ((index >= PAD_L_UP) && (index <= PAD_R_LEFT)); +} diff --git a/pcsx2/PAD/Linux/controller.h b/pcsx2/PAD/Linux/controller.h new file mode 100644 index 0000000000..c0710c9ca9 --- /dev/null +++ b/pcsx2/PAD/Linux/controller.h @@ -0,0 +1,129 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#pragma once +#include // for memset +#define MAX_KEYS 24 + +extern void set_keyboard_key(int pad, int keysym, int index); +extern int get_keyboard_key(int pad, int keysym); +extern bool IsAnalogKey(int index); + +class PADconf +{ + u32 ff_intensity; + u32 sensibility; + +public: + union + { + struct + { + u16 forcefeedback : 1; + u16 reverse_lx : 1; + u16 reverse_ly : 1; + u16 reverse_rx : 1; + u16 reverse_ry : 1; + u16 mouse_l : 1; + u16 mouse_r : 1; + u16 _free : 9; // The 9 remaining bits are unused, do what you wish with them ;) + } pad_options[GAMEPAD_NUMBER]; // One for each pads + u32 packed_options; // Only first 8 bits of each 16 bits series are really used, rest is padding + }; + + u32 log; + u32 ftw; + std::map keysym_map[GAMEPAD_NUMBER]; + std::array unique_id; + std::vector sdl2_mapping; + + PADconf() { init(); } + + void init() + { + log = 0; + ftw = 1; + packed_options = 0; + ff_intensity = 0x7FFF; // set it at max value by default + sensibility = 100; + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + keysym_map[pad].clear(); + } + unique_id.fill(0); + sdl2_mapping.clear(); + } + + void set_joy_uid(u32 pad, size_t uid) + { + if (pad < GAMEPAD_NUMBER) + unique_id[pad] = uid; + } + + size_t get_joy_uid(u32 pad) + { + if (pad < GAMEPAD_NUMBER) + return unique_id[pad]; + else + return 0; + } + + /** + * Return (a copy of) private memner ff_instensity + **/ + u32 get_ff_intensity() + { + return ff_intensity; + } + + /** + * Set intensity while checking that the new value is within + * valid range, more than 0x7FFF will cause pad not to rumble(and less than 0 is obviously bad) + **/ + void set_ff_intensity(u32 new_intensity) + { + if (new_intensity <= 0x7FFF) { + ff_intensity = new_intensity; + } + } + + /** + * Set sensibility value. + * There will be an upper range, and less than 0 is obviously wrong. + * We are doing object oriented code, so members are definitely not supposed to be public. + **/ + void set_sensibility(u32 new_sensibility) + { + if (new_sensibility > 0) + { + sensibility = new_sensibility; + } + else + { + sensibility = 1; + } + } + + u32 get_sensibility() + { + return sensibility; + } +}; +extern PADconf g_conf; diff --git a/pcsx2/PAD/Linux/ini.cpp b/pcsx2/PAD/Linux/ini.cpp new file mode 100644 index 0000000000..41f27addca --- /dev/null +++ b/pcsx2/PAD/Linux/ini.cpp @@ -0,0 +1,132 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#include + +#include "GamePad.h" +#include "keyboard.h" +#include "onepad.h" + +extern std::string s_strIniPath; + +void DefaultKeyboardValues() +{ + set_keyboard_key(0, XK_a, PAD_L2); + set_keyboard_key(0, XK_semicolon, PAD_R2); + set_keyboard_key(0, XK_w, PAD_L1); + set_keyboard_key(0, XK_p, PAD_R1); + set_keyboard_key(0, XK_i, PAD_TRIANGLE); + set_keyboard_key(0, XK_l, PAD_CIRCLE); + set_keyboard_key(0, XK_k, PAD_CROSS); + set_keyboard_key(0, XK_j, PAD_SQUARE); + set_keyboard_key(0, XK_v, PAD_SELECT); + set_keyboard_key(0, XK_n, PAD_START); + set_keyboard_key(0, XK_e, PAD_UP); + set_keyboard_key(0, XK_f, PAD_RIGHT); + set_keyboard_key(0, XK_d, PAD_DOWN); + set_keyboard_key(0, XK_s, PAD_LEFT); +} + +void SaveConfig() +{ + FILE *f; + + const std::string iniFile(s_strIniPath + "OnePAD2.ini"); + f = fopen(iniFile.c_str(), "w"); + if (f == NULL) { + printf("OnePAD: failed to save ini %s\n", iniFile.c_str()); + return; + } + + fprintf(f, "first_time_wizard = %d\n", g_conf.ftw); + fprintf(f, "log = %d\n", g_conf.log); + fprintf(f, "options = %d\n", g_conf.packed_options); + fprintf(f, "mouse_sensibility = %d\n", g_conf.get_sensibility()); + fprintf(f, "ff_intensity = %d\n", g_conf.get_ff_intensity()); + fprintf(f, "uid[0] = %zu\n", g_conf.get_joy_uid(0)); + fprintf(f, "uid[1] = %zu\n", g_conf.get_joy_uid(1)); + + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) + for (auto const &it : g_conf.keysym_map[pad]) + fprintf(f, "PAD %d:KEYSYM 0x%x = %d\n", pad, it.first, it.second); + + for (auto const &it : g_conf.sdl2_mapping) + fprintf(f, "SDL2 = %s\n", it.c_str()); + + fclose(f); +} + +void LoadConfig() +{ + FILE *f; + bool have_user_setting = false; + + g_conf.init(); + + const std::string iniFile(s_strIniPath + "OnePAD2.ini"); + f = fopen(iniFile.c_str(), "r"); + if (f == NULL) { + printf("OnePAD: failed to load ini %s\n", iniFile.c_str()); + SaveConfig(); //save and return + return; + } + + u32 value; + + if (fscanf(f, "first_time_wizard = %u\n", &value) == 1) + g_conf.ftw = value; + + if (fscanf(f, "log = %u\n", &value) == 1) + g_conf.log = value; + + if (fscanf(f, "options = %u\n", &value) == 1) + g_conf.packed_options = value; + + if (fscanf(f, "mouse_sensibility = %u\n", &value) == 1) + g_conf.set_sensibility(value); + + if (fscanf(f, "ff_intensity = %u\n", &value) == 1) + g_conf.set_ff_intensity(value); + + size_t uid; + if (fscanf(f, "uid[0] = %zu\n", &uid) == 1) + g_conf.set_joy_uid(0, uid); + if (fscanf(f, "uid[1] = %zu\n", &uid) == 1) + g_conf.set_joy_uid(1, uid); + + u32 pad; + u32 keysym; + u32 index; + while (fscanf(f, "PAD %u:KEYSYM 0x%x = %u\n", &pad, &keysym, &index) == 3) { + set_keyboard_key(pad & 1, keysym, index); + if (pad == 0) + have_user_setting = true; + } + + char sdl2[512]; + while (fscanf(f, "SDL2 = %511[^\n]\n", sdl2) == 1) + g_conf.sdl2_mapping.push_back(std::string(sdl2)); + + if (!have_user_setting) + DefaultKeyboardValues(); + + fclose(f); +} diff --git a/pcsx2/PAD/Linux/keyboard.cpp b/pcsx2/PAD/Linux/keyboard.cpp new file mode 100644 index 0000000000..81c962b969 --- /dev/null +++ b/pcsx2/PAD/Linux/keyboard.cpp @@ -0,0 +1,359 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +/* + * Theoretically, this header is for anything to do with keyboard input. + * Pragmatically, event handing's going in here too. + */ + +#if defined(__unix__) +#include +#include +#elif defined(__APPLE__) +#include +#endif + +#include "keyboard.h" + +#ifdef _WIN32 +char *KeysymToChar(int keysym) +{ + LPWORD temp; + + ToAscii((UINT)keysym, NULL, NULL, temp, NULL); + return (char *)temp; +} +#endif + +/// g_key_status.press but with proper handling for analog buttons +static void PressButton(u32 pad, u32 button) { + // Analog controls. + if (IsAnalogKey(button)) { + switch (button) { + case PAD_R_LEFT: + case PAD_R_UP: + case PAD_L_LEFT: + case PAD_L_UP: + g_key_status.press(pad, button, -MAX_ANALOG_VALUE); + break; + case PAD_R_RIGHT: + case PAD_R_DOWN: + case PAD_L_RIGHT: + case PAD_L_DOWN: + g_key_status.press(pad, button, MAX_ANALOG_VALUE); + break; + } + } else { + g_key_status.press(pad, button); + } +} + +#if defined(__APPLE__) +// Mac keyboard input code is based on Dolphin's Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ + +// All keycodes are 16 bits or less, so we use top 16 bits to differentiate source +// Keyboard keys use discriminator 0 +// Mouse buttons use discriminator 1 + +void UpdateKeyboardInput() { + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + const auto& map = g_conf.keysym_map[pad]; + // If we loop over all keys press/release based on current state, + // joystick axes (which have two bound keys) will always go to the later-polled key + // Instead, release all keys first and then set the ones that are pressed + for (const auto& key : map) g_key_status.release(pad, key.second); + for (const auto& key : map) { + bool state; + if (key.first >> 16 == 0) { + state = CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key.first); + } else { + state = CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, (CGMouseButton)(key.first & 0xFFFF)); + } + if (state) PressButton(pad, key.second); + } + } +} + +bool PollForNewKeyboardKeys(u32 &pkey) { + // All keycodes in are 0x7e or lower. If you notice + // keys that aren't being recognized, bump this number up! + for (int key = 0; key < 0x80; key++) { + if (CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, key)) { + pkey = key == kVK_Escape ? 0 : key; + return true; + } + } + for (auto btn : {kCGMouseButtonLeft, kCGMouseButtonCenter, kCGMouseButtonRight}) { + if (CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, btn)) { + pkey = btn | (1 << 16); + return true; + } + } + return false; +} +#elif defined(__unix__) +static bool s_grab_input = false; +static bool s_Shift = false; +static unsigned int s_previous_mouse_x = 0; +static unsigned int s_previous_mouse_y = 0; + +void AnalyzeKeyEvent(keyEvent &evt) +{ + KeySym key = (KeySym)evt.key; + int pad = 0; + int index = -1; + + for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { + int tmp_index = get_keyboard_key(cpad, key); + if (tmp_index != -1) { + pad = cpad; + index = tmp_index; + } + } + + switch (evt.evt) { + case KeyPress: + // Shift F12 is not yet use by pcsx2. So keep it to grab/ungrab input + // I found it very handy vs the automatic fullscreen detection + // 1/ Does not need to detect full-screen + // 2/ Can use a debugger in full-screen + // 3/ Can grab input in window without the need of a pixelated full-screen + if (key == XK_Shift_R || key == XK_Shift_L) + s_Shift = true; + if (key == XK_F12 && s_Shift) { + if (!s_grab_input) { + s_grab_input = true; + XGrabPointer(GSdsp, GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, GSwin, None, CurrentTime); + XGrabKeyboard(GSdsp, GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } else { + s_grab_input = false; + XUngrabPointer(GSdsp, CurrentTime); + XUngrabKeyboard(GSdsp, CurrentTime); + } + } + + if (index != -1) + PressButton(pad, index); + + //PAD_LOG("Key pressed:%d\n", index); + + event.evt = KEYPRESS; + event.key = key; + break; + + case KeyRelease: + if (key == XK_Shift_R || key == XK_Shift_L) + s_Shift = false; + + if (index != -1) + g_key_status.release(pad, index); + + event.evt = KEYRELEASE; + event.key = key; + break; + + case FocusIn: + break; + + case FocusOut: + s_Shift = false; + break; + + case ButtonPress: + if (index != -1) + g_key_status.press(pad, index); + break; + + case ButtonRelease: + if (index != -1) + g_key_status.release(pad, index); + break; + + case MotionNotify: + // FIXME: How to handle when the mouse does not move, no event generated!!! + // 1/ small move == no move. Cons : can not do small movement + // 2/ use a watchdog timer thread + // 3/ ??? idea welcome ;) + if (g_conf.pad_options[pad].mouse_l | g_conf.pad_options[pad].mouse_r) { + unsigned int pad_x; + unsigned int pad_y; + // Note when both PADOPTION_MOUSE_R and PADOPTION_MOUSE_L are set, take only the right one + if (g_conf.pad_options[pad].mouse_r) { + pad_x = PAD_R_RIGHT; + pad_y = PAD_R_UP; + } else { + pad_x = PAD_L_RIGHT; + pad_y = PAD_L_UP; + } + + unsigned x = evt.key & 0xFFFF; + unsigned int value = (s_previous_mouse_x > x) ? s_previous_mouse_x - x : x - s_previous_mouse_x; + value *= g_conf.get_sensibility(); + + if (x == 0) + g_key_status.press(pad, pad_x, -MAX_ANALOG_VALUE); + else if (x == 0xFFFF) + g_key_status.press(pad, pad_x, MAX_ANALOG_VALUE); + else if (x < (s_previous_mouse_x - 2)) + g_key_status.press(pad, pad_x, -value); + else if (x > (s_previous_mouse_x + 2)) + g_key_status.press(pad, pad_x, value); + else + g_key_status.release(pad, pad_x); + + + unsigned y = evt.key >> 16; + value = (s_previous_mouse_y > y) ? s_previous_mouse_y - y : y - s_previous_mouse_y; + value *= g_conf.get_sensibility(); + + if (y == 0) + g_key_status.press(pad, pad_y, -MAX_ANALOG_VALUE); + else if (y == 0xFFFF) + g_key_status.press(pad, pad_y, MAX_ANALOG_VALUE); + else if (y < (s_previous_mouse_y - 2)) + g_key_status.press(pad, pad_y, -value); + else if (y > (s_previous_mouse_y + 2)) + g_key_status.press(pad, pad_y, value); + else + g_key_status.release(pad, pad_y); + + s_previous_mouse_x = x; + s_previous_mouse_y = y; + } + + break; + } +} + +void UpdateKeyboardInput() +{ + keyEvent evt = {0}; + XEvent E = {0}; + + // Keyboard input send by PCSX2 + g_ev_fifo.consume_all(AnalyzeKeyEvent); + + // keyboard input + while (XPending(GSdsp) > 0) { + XNextEvent(GSdsp, &E); + + // Change the format of the structure to be compatible with GSOpen2 + // mode (event come from pcsx2 not X) + evt.evt = E.type; + switch (E.type) { + case MotionNotify: + evt.key = (E.xbutton.x & 0xFFFF) | (E.xbutton.y << 16); + break; + case ButtonRelease: + case ButtonPress: + evt.key = E.xbutton.button; + break; + default: + evt.key = (int)XLookupKeysym(&E.xkey, 0); + } + + AnalyzeKeyEvent(evt); + } +} + +bool PollForNewKeyboardKeys(u32 &pkey) +{ + GdkEvent *ev = gdk_event_get(); + + if (ev != NULL) { + if (ev->type == GDK_KEY_PRESS) { + pkey = ev->key.keyval != GDK_KEY_Escape ? ev->key.keyval : 0; + return true; + } else if (ev->type == GDK_BUTTON_PRESS) { + pkey = ev->button.button; + return true; + } + } + + return false; +} + +#else +LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static bool lbutton = false, rbutton = false; + for (int pad = 0; pad < GAMEPAD_NUMBER; ++pad) + { + g_key_status.keyboard_state_acces(pad); + } + + switch (msg) { + case WM_KEYDOWN: + if (lParam & 0x40000000) + return TRUE; + + for (int pad = 0; pad < GAMEPAD_NUMBER; ++pad) { + for (int i = 0; i < MAX_KEYS; i++) { + assert(0); +#if 0 + if (wParam == get_key(pad, i)) { + g_key_status.press(pad, i); + break; + } +#endif + } + } + + event.evt = KEYPRESS; + event.key = wParam; + break; + + case WM_KEYUP: + for (int pad = 0; pad < GAMEPAD_NUMBER; ++pad) { + for (int i = 0; i < MAX_KEYS; i++) { + assert(0); +#if 0 + if (wParam == get_key(pad, i)) { + g_key_status.release(pad, i); + break; + } +#endif + } + } + + + event.evt = KEYRELEASE; + event.key = wParam; + break; + + case WM_DESTROY: + case WM_QUIT: + event.evt = KEYPRESS; + event.key = VK_ESCAPE; + return GSwndProc(hWnd, msg, wParam, lParam); + + default: + return GSwndProc(hWnd, msg, wParam, lParam); + } + + for (int pad = 0; pad < GAMEPAD_NUMBER; ++pad) + g_key_status.commit_status(pad); + + return TRUE; +} +#endif diff --git a/pcsx2/PAD/Linux/keyboard.h b/pcsx2/PAD/Linux/keyboard.h new file mode 100644 index 0000000000..3a4d4a7f77 --- /dev/null +++ b/pcsx2/PAD/Linux/keyboard.h @@ -0,0 +1,45 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#ifndef __KEYBOARD_H__ +#define __KEYBOARD_H__ + +#include "onepad.h" + +#if defined(__unix__) || defined(__APPLE__) + +extern void AnalyzeKeyEvent(keyEvent &evt); +extern void UpdateKeyboardInput(); +extern bool PollForNewKeyboardKeys(u32 &pkey); +#ifndef __APPLE__ +extern Display *GSdsp; +extern Window GSwin; +#endif + +#else + +extern char *KeysymToChar(int keysym); +extern WNDPROC GSwndProc; +extern HWND GShwnd; + +#endif + +#endif diff --git a/pcsx2/PAD/Linux/linux.cpp b/pcsx2/PAD/Linux/linux.cpp new file mode 100644 index 0000000000..8390212ce9 --- /dev/null +++ b/pcsx2/PAD/Linux/linux.cpp @@ -0,0 +1,141 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#include "GamePad.h" +#include "onepad.h" +#include "keyboard.h" +#include "state_management.h" + +#include +#include "wx_dialog/dialog.h" + +#ifndef __APPLE__ +Display *GSdsp; +Window GSwin; +#endif + +static void SysMessage(const char *fmt, ...) +{ + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg) - 1] == '\n') + msg[strlen(msg) - 1] = 0; + + wxMessageDialog dialog(nullptr, msg, "Info", wxOK); + dialog.ShowModal(); +} + +EXPORT_C_(void) +PADabout() +{ + SysMessage("OnePad is a rewrite of Zerofrog's ZeroPad, done by arcum42."); +} + +EXPORT_C_(s32) +PADtest() +{ + return 0; +} + +s32 _PADopen(void *pDsp) +{ +#ifndef __APPLE__ + GSdsp = *(Display **)pDsp; + GSwin = (Window) * (((u32 *)pDsp) + 1); +#endif + + return 0; +} + +void _PADclose() +{ + s_vgamePad.clear(); +} + +void PollForJoystickInput(int cpad) +{ + int index = GamePad::uid_to_index(cpad); + if (index < 0) + return; + + auto &gamePad = s_vgamePad[index]; + + gamePad->UpdateGamePadState(); + + for (int i = 0; i < MAX_KEYS; i++) { + s32 value = gamePad->GetInput((gamePadValues)i); + if (value != 0) + g_key_status.press(cpad, i, value); + else + g_key_status.release(cpad, i); + } +} + +EXPORT_C_(void) +PADupdate(int pad) +{ +#ifndef __APPLE__ + // Gamepad inputs don't count as an activity. Therefore screensaver will + // be fired after a couple of minute. + // Emulate an user activity + static int count = 0; + count++; + if ((count & 0xFFF) == 0) { + // 1 call every 4096 Vsync is enough + XResetScreenSaver(GSdsp); + } +#endif + + // Actually PADupdate is always call with pad == 0. So you need to update both + // pads -- Gregory + + // Poll keyboard/mouse event. There is currently no way to separate pad0 from pad1 event. + // So we will populate both pad in the same time + for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { + g_key_status.keyboard_state_acces(cpad); + } + UpdateKeyboardInput(); + + // Get joystick state + Commit + for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { + g_key_status.joystick_state_acces(cpad); + + PollForJoystickInput(cpad); + + g_key_status.commit_status(cpad); + } + + Pad::rumble_all(); +} + +EXPORT_C_(void) +PADconfigure() +{ + LoadConfig(); + + DisplayDialog(); + return; +} diff --git a/pcsx2/PAD/Linux/onepad.cpp b/pcsx2/PAD/Linux/onepad.cpp new file mode 100644 index 0000000000..3375472808 --- /dev/null +++ b/pcsx2/PAD/Linux/onepad.cpp @@ -0,0 +1,358 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include "keyboard.h" +#include "onepad.h" +#include "svnrev.h" +#include "state_management.h" + +#ifdef __linux__ +#include +#endif +#ifdef _MSC_VER +#define snprintf sprintf_s +#endif + +PADconf g_conf; +static char libraryName[256]; + +keyEvent event; + +static keyEvent s_event; +std::string s_strIniPath("inis/"); +std::string s_strLogPath("logs/"); + +const u32 version = PS2E_PAD_VERSION; +const u32 revision = 2; +const u32 build = 0; // increase that with each version +#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0)) + +FILE *padLog = NULL; + +KeyStatus g_key_status; + +MtQueue g_ev_fifo; + +static void InitLibraryName() +{ +#ifdef PUBLIC + + // Public Release! + // Output a simplified string that's just our name: + + strcpy(libraryName, "OnePAD"); + +#else + + // Use TortoiseSVN's SubWCRev utility's output + // to label the specific revision: + + snprintf(libraryName, 255, "OnePAD %lld%s" +#ifdef PCSX2_DEBUG + "-Debug" +#elif defined(PCSX2_DEVBUILD) + "-Dev" +#endif + , + SVN_REV, + SVN_MODS ? "m" : ""); +#endif +} + +EXPORT_C_(u32) +PS2EgetLibType() +{ + return PS2E_LT_PAD; +} + +EXPORT_C_(const char *) +PS2EgetLibName() +{ + InitLibraryName(); + return libraryName; +} + +EXPORT_C_(u32) +PS2EgetLibVersion2(u32 type) +{ + return (version << 16) | (revision << 8) | build; +} + +void __Log(const char *fmt, ...) +{ + va_list list; + + if (padLog == NULL) + return; + va_start(list, fmt); + vfprintf(padLog, fmt, list); + va_end(list); +} + +void __LogToConsole(const char *fmt, ...) +{ + va_list list; + + va_start(list, fmt); + + if (padLog != NULL) + vfprintf(padLog, fmt, list); + + printf("OnePAD: "); + vprintf(fmt, list); + va_end(list); +} + +void initLogging() +{ +#ifdef PAD_LOG + if (padLog) + return; + + const std::string LogFile(s_strLogPath + "padLog.txt"); + padLog = fopen(LogFile.c_str(), "w"); + + if (padLog) + setvbuf(padLog, NULL, _IONBF, 0); + + PAD_LOG("PADinit\n"); +#endif +} + +void CloseLogging() +{ +#ifdef PAD_LOG + if (padLog) { + fclose(padLog); + padLog = NULL; + } +#endif +} + +EXPORT_C_(s32) +PADinit(u32 flags) +{ + initLogging(); + + LoadConfig(); + + Pad::reset_all(); + + query.reset(); + + for (int port = 0; port < 2; port++) + slots[port] = 0; + + return 0; +} + +EXPORT_C_(void) +PADshutdown() +{ + CloseLogging(); +} + +EXPORT_C_(s32) +PADopen(void *pDsp) +{ + memset(&event, 0, sizeof(event)); + g_key_status.Init(); + + g_ev_fifo.reset(); + +#if defined(__unix__) || defined(__APPLE__) + GamePad::EnumerateGamePads(s_vgamePad); +#endif + return _PADopen(pDsp); +} + +EXPORT_C_(void) +PADsetSettingsDir(const char *dir) +{ + // Get the path to the ini directory. + s_strIniPath = (dir == NULL) ? "inis/" : dir; +} + +EXPORT_C_(void) +PADsetLogDir(const char *dir) +{ + // Get the path to the log directory. + s_strLogPath = (dir == NULL) ? "logs/" : dir; + + // Reload the log file after updated the path + CloseLogging(); + initLogging(); +} + +EXPORT_C_(void) +PADclose() +{ + _PADclose(); +} + +EXPORT_C_(u32) +PADquery() +{ + return 3; // both +} + +EXPORT_C_(s32) +PADsetSlot(u8 port, u8 slot) +{ + port--; + slot--; + if (port > 1 || slot > 3) { + return 0; + } + // Even if no pad there, record the slot, as it is the active slot regardless. + slots[port] = slot; + + return 1; +} + +EXPORT_C_(s32) +PADfreeze(int mode, freezeData *data) +{ + if (!data) + return -1; + + if (mode == FREEZE_SIZE) { + data->size = sizeof(PadPluginFreezeData); + + } else if (mode == FREEZE_LOAD) { + PadPluginFreezeData *pdata = (PadPluginFreezeData *)(data->data); + + Pad::stop_vibrate_all(); + + if (data->size != sizeof(PadPluginFreezeData) || pdata->version != PAD_SAVE_STATE_VERSION || + strncmp(pdata->format, "OnePad", sizeof(pdata->format))) + return 0; + + query = pdata->query; + if (pdata->query.slot < 4) { + query = pdata->query; + } + + // Tales of the Abyss - pad fix + // - restore data for both ports + for (int port = 0; port < 2; port++) { + for (int slot = 0; slot < 4; slot++) { + u8 mode = pdata->padData[port][slot].mode; + + if (mode != MODE_DIGITAL && mode != MODE_ANALOG && mode != MODE_DS2_NATIVE) { + break; + } + + memcpy(&pads[port][slot], &pdata->padData[port][slot], sizeof(PadFreezeData)); + } + + if (pdata->slot[port] < 4) + slots[port] = pdata->slot[port]; + } + + } else if (mode == FREEZE_SAVE) { + if (data->size != sizeof(PadPluginFreezeData)) + return 0; + + PadPluginFreezeData *pdata = (PadPluginFreezeData *)(data->data); + + // Tales of the Abyss - pad fix + // - PCSX2 only saves port0 (save #1), then port1 (save #2) + + memset(pdata, 0, data->size); + strncpy(pdata->format, "OnePad", sizeof(pdata->format)); + pdata->version = PAD_SAVE_STATE_VERSION; + pdata->query = query; + + for (int port = 0; port < 2; port++) { + for (int slot = 0; slot < 4; slot++) { + pdata->padData[port][slot] = pads[port][slot]; + } + + pdata->slot[port] = slots[port]; + } + + } else { + return -1; + } + + return 0; +} + +EXPORT_C_(u8) +PADstartPoll(int pad) +{ + return pad_start_poll(pad); +} + +EXPORT_C_(u8) +PADpoll(u8 value) +{ + return pad_poll(value); +} + +// PADkeyEvent is called every vsync (return NULL if no event) +EXPORT_C_(keyEvent *) +PADkeyEvent() +{ +#ifdef SDL_BUILD + // Take the opportunity to handle hot plugging here + SDL_Event events; + while (SDL_PollEvent(&events)) { + switch (events.type) { + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + GamePad::EnumerateGamePads(s_vgamePad); + break; + default: + break; + } + } +#endif + if (g_ev_fifo.size() == 0) { + // PAD_LOG("No events in queue, returning empty event\n"); + s_event = event; + event.evt = 0; + event.key = 0; + return &s_event; + } + s_event = g_ev_fifo.dequeue(); + AnalyzeKeyEvent(s_event); + // PAD_LOG("Returning Event. Event Type: %d, Key: %d\n", s_event.evt, s_event.key); + return &s_event; +} + +#if defined(__unix__) +EXPORT_C_(void) +PADWriteEvent(keyEvent &evt) +{ + // if (evt.evt != 6) { // Skip mouse move events for logging + // PAD_LOG("Pushing Event. Event Type: %d, Key: %d\n", evt.evt, evt.key); + // } + g_ev_fifo.push(evt); +} +#endif diff --git a/pcsx2/PAD/Linux/onepad.h b/pcsx2/PAD/Linux/onepad.h new file mode 100644 index 0000000000..b20abd5290 --- /dev/null +++ b/pcsx2/PAD/Linux/onepad.h @@ -0,0 +1,138 @@ +/* OnePAD - author: arcum42(@gmail.com) + * Copyright (C) 2009 + * + * Based on ZeroPAD, author zerofrog@gmail.com + * Copyright (C) 2006-2007 + * + * 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 + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#define GAMEPAD_NUMBER 2 // numbers of gamepad + +#include +#include + +#ifdef _WIN32 +#include +#include + +#else + +#include +#include +#include + +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define PADdefs +#include "PS2Edefs.h" + +enum PadOptions { + PADOPTION_FORCEFEEDBACK = 0x1, + PADOPTION_REVERSELX = 0x2, + PADOPTION_REVERSELY = 0x4, + PADOPTION_REVERSERX = 0x8, + PADOPTION_REVERSERY = 0x10, + PADOPTION_MOUSE_L = 0x20, + PADOPTION_MOUSE_R = 0x40, +}; + +enum PadCommands { + CMD_SET_VREF_PARAM = 0x40, + CMD_QUERY_DS2_ANALOG_MODE = 0x41, + CMD_READ_DATA_AND_VIBRATE = 0x42, + CMD_CONFIG_MODE = 0x43, + CMD_SET_MODE_AND_LOCK = 0x44, + CMD_QUERY_MODEL_AND_MODE = 0x45, + CMD_QUERY_ACT = 0x46, // ?? + CMD_QUERY_COMB = 0x47, // ?? + CMD_QUERY_MODE = 0x4C, // QUERY_MODE ?? + CMD_VIBRATION_TOGGLE = 0x4D, + CMD_SET_DS2_NATIVE_MODE = 0x4F // SET_DS2_NATIVE_MODE +}; + +enum gamePadValues { + PAD_L2 = 0, // L2 button + PAD_R2, // R2 button + PAD_L1, // L1 button + PAD_R1, // R1 button + PAD_TRIANGLE, // Triangle button ▲ + PAD_CIRCLE, // Circle button ● + PAD_CROSS, // Cross button ✖ + PAD_SQUARE, // Square button ■ + PAD_SELECT, // Select button + PAD_L3, // Left joystick button (L3) + PAD_R3, // Right joystick button (R3) + PAD_START, // Start button + PAD_UP, // Directional pad ↑ + PAD_RIGHT, // Directional pad → + PAD_DOWN, // Directional pad ↓ + PAD_LEFT, // Directional pad ← + PAD_L_UP, // Left joystick (Up) ↑ + PAD_L_RIGHT, // Left joystick (Right) → + PAD_L_DOWN, // Left joystick (Down) ↓ + PAD_L_LEFT, // Left joystick (Left) ← + PAD_R_UP, // Right joystick (Up) ↑ + PAD_R_RIGHT, // Right joystick (Right) → + PAD_R_DOWN, // Right joystick (Down) ↓ + PAD_R_LEFT // Right joystick (Left) ← +}; + +#if defined(__unix__) || defined(__APPLE__) +#include "GamePad.h" +#endif +#include "bitwise.h" +#include "controller.h" +#include "KeyStatus.h" +#include "mt_queue.h" + +#ifdef _MSC_VER +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type CALLBACK +#else +#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type +#endif + +extern FILE *padLog; +extern void initLogging(); + +#define PAD_LOG __Log +//#define PAD_LOG __LogToConsole + +extern keyEvent event; +extern MtQueue g_ev_fifo; + +s32 _PADopen(void *pDsp); +void _PADclose(); +void PADsetMode(int pad, int mode); + +void __Log(const char *fmt, ...); +void __LogToConsole(const char *fmt, ...); +void LoadConfig(); +void SaveConfig(); + +void SysMessage(char *fmt, ...); + +#endif diff --git a/pcsx2/PAD/Linux/res/game_controller_db.txt b/pcsx2/PAD/Linux/res/game_controller_db.txt new file mode 100644 index 0000000000..105ad9b45a --- /dev/null +++ b/pcsx2/PAD/Linux/res/game_controller_db.txt @@ -0,0 +1,499 @@ +# Mac OS, Linux - from # https://github.com/gabomdq/ +# Mac OS X +030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,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, +03000000c82d00000650000001000000,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:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,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, +030000003512000012ab000001000000,8BitDo NES30 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, +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, +03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,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+,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+,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, +03000000c82d00000031000001000000,8BitDo Wireless Adapter,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, +03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,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, +03000000a00500003232000008010000,8Bitdo Zero GamePad,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 GamePad,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, +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, +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,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, +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 V.3 Rumble 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:+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, +03000000ad1b000001f9000000000000,Gamestop BB-070 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,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000102000000000000,GameStop Xbox 360 Wired 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, +030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,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, +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, +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,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, +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,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, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro Pad,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, +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,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 mini4,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, +030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000830500006020000000010000,iBuffalo SNES 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, +03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,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 Wireless 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, +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 Gamepad (DInput),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 Gamepad (DInput),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 Gamepad (XInput),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 USB,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, +030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),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 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:Mac OS X, +03000000380700005082000000010000,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,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,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:Mac OS X, +03000000380700008483000000010000,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,x:b0,y:b3,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, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,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, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),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, +03000000d8140000cecf000000000000,MC 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, +030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2 HID,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 XP5-A 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 XP5-A 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, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000011a7000000020000,Nintendo Switch Core (Plus) 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: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, +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, +03000000550900001472000025050000,NVIDIA Controller v01.04,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, +030000006f0e00000901000002010000,PDP Versus Fighting Pad,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,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, +030000004c050000da0c000000010000,Playstation Classic 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: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, +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, +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,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,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,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,x:b0,y:b3,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),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,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 Fightpad for 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,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, +03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,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, +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, +03000000c6240000fefa000000000000,Rock Candy Gamepad for 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, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,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 USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,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, +30000004c050000e60c0000000100000,Sony DualSense,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: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,x:b0,y:b3,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,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,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,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, +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, +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, +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, +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, +03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee SNES USB 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, +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, +030000006f0e00000302000025040000,Victrix Pro Fight Stick for 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,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix Pro Fight Stick for 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,x:b0,y:b3,platform:Mac OS X, +03000000791d00000103000009010000,Wii Classic Controller,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, +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,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, +03000000c6240000045d000000000000,Xbox 360 Wired 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 Wireless 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, +030000005e040000d102000000000000,Xbox One Wired 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 Wired 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, +030000005e040000e302000000000000,Xbox One Wired 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 Wireless 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 Wireless 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, +030000005e040000ea02000000000000,Xbox Wireless 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 Wireless 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, +03000000172700004431000029010000,XiaoMi Game 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 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:Mac OS X, +03000000120c0000101e000000010000,ZEROPLUS P4 Wired 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:Mac OS X, + +# 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, +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, +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, +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, +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, +03000000c82d00000190000011010000,8Bitdo NES30 Pro 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, +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, +03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +030000003512000012ab000010010000,8Bitdo SFC30 GamePad,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, +05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,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+,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, +05000000c82d00000261000000010000,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, +05000000202800000900000000010000,8BitDo SNES30 Gamepad,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, +030000005e0400008e02000020010000,8BitDo Wireless Adapter,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, +03000000c82d00000031000011010000,8BitDo Wireless Adapter,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, +03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,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, +05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8Bitdo Zero GamePad,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, +030000006f0e00001302000000010000,Afterglow,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 Controller for 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, +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 Wired 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, +03000000100000008200000011010000,Akishop Customs PS360+ v1.66,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 Pad,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 Game 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, +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, +03000000120c00000500000010010000,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, +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,x:b0,y:b3,platform:Linux, +03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux, +030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +03000000666600006706000000010000,boom PSX to PC Converter,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, +03000000ffff0000ffff000000010000,Chinese-made 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, +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, +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 V.3 Rumble 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:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB 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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +030000004f04000004b3000010010000,Dual Power 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, +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, +03000000341a000005f7000010010000,GameCube {HuiJia USB box},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, +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, +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 Co. Ltd PS(R) 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, +030000006f0e00001304000000010000,Generic X-Box pad,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, +03000000f0250000c183000010010000,Goodbetterbest Ltd USB 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, +030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,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 Inc. USB 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 Game 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,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Game 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, +03000000632500002605000010010000,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, +030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 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, +030000000d0f0000c100000011010000,HORI CO. LTD. HORIPAD S,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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006a00000011010000,HORI CO. LTD. 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 CO. LTD. 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, +030000000d0f00002200000011010000,HORI CO. LTD. 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,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008500000010010000,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: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,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, +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,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, +030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,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, +030000000d0f0000aa00000011010000,HORI Real Arcade Pro,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, +030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),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, +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,x:b0,y:b3,platform:Linux, +030000000d0f0000ee00000011010000,HORIPAD mini4,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, +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, +030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,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, +03000000830500006020000010010000,iBuffalo SNES 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, +050000006964726f69643a636f6e0000,idroid:con,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 PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, +03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux, +0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,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 - Bluetooth 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, +030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,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, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,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 Pad,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 USB Game 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, +03000000242f00002d00000011010000,JYS Wireless 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 Wireless 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, +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 Gamepad (XInput),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 Gamepad (XInput),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 Gamepad (XInput),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 Gamepad (DInput),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 Gamepad (XInput),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, +030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux, +030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,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, +05000000380700006652000025010000,Mad Catz C.T.R.L.R ,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, +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,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,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,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Wired 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 Wired Xbox 360 Controller (SFIV),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, +03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,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,MadCatz PC USB Wired Stick 8838,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, +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, +03000000790000004418000010010000,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:Linux, +03000000790000004318000010010000,Mayflash GameCube Controller Adapter,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: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, +0300000025090000e803000001010000,Mayflash Wii Classic Controller,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, +03000000780000000600000010010000,Microntek USB 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, +030000005e0400000e00000000010000,Microsoft SideWinder,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, +030000005e0400008e02000004010000,Microsoft X-Box 360 pad,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 X-Box 360 pad,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, +030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,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, +050000005e040000050b000003090000,Microsoft X-Box One Elite 2 pad,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, +030000005e040000e302000003020000,Microsoft X-Box One Elite pad,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 S pad - Wired,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, +030000005e040000d102000001010000,Microsoft X-Box One pad,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 X-Box One pad (Firmware 2015),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 X-Box One pad v2,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, +030000005e0400008502000000010000,Microsoft X-Box pad (Japan),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 X-Box pad v2 (US),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, +03000000c62400001a53000000010000,Mini PE,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, +05000000d6200000e589000001000000,Moga 2 HID,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 HID,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 XP5-A 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 XP5-A 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, +03000000250900006688000000010000,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: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, +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, +030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux, +060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,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:b2,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:b0,y:b3,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),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,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),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,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500003003000001000000,Nintendo Wii Remote 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, +05000000010000000100000003000000,Nintendo Wiimote,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, +030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,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, +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, +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,odroidgo2_joypad,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,odroidgo2_joypad_v11,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, +030000005e0400000202000000010000,Old Xbox pad,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, +05000000362800000100000002010000,OUYA Game 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 Game 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, +03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB 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, +03000000790000001c18000011010000,PC Game 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, +03000000ff1100003133000010010000,PC Game 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 Wired Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006f0e0000b802000013020000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,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, +030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,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, +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, +030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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, +030000006f0e00000901000011010000,PDP Versus Fighting Pad,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, +030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,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, +030000006f0e00008501000011010000,PDP Wired Fight Pad 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, +0500000049190000030400001b010000,PG-9099,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, +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, +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, +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, +03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,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, +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, +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,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,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,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,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,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, +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,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,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, +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, +030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,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 Technologies GC/N64 to USB v3.6,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, +030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,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, +030000008916000000fd000024010000,Razer Onza Tournament Edition,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, +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,x:b0,y:b3,platform:Linux, +03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b13,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,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, +03000000321500000011000011010000,Razer Raion Fightpad for 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,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, +03000000790000001100000010010000,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: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, +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, +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, +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 V.1 Game 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b10,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, +03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,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, +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 Pad,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, +03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,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, +03000000a306000020f6000011010000,Saitek PS2700 Rumble 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek 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, +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, +03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux, +03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired 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, +03000000632500007505000010010000,SHANWAN PS3/PC 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 PS3/PC Wired 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, +03000000632500002305000010010000,ShanWan 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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00000908000010010000,SL-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:Linux, +030000004c050000e60c000011010000,Sony DualSense,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:Linux, +050000004c050000e60c000000010000,Sony DualSense,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: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 Wireless 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, +030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,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, +03000000de2800000112000001000000,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:Linux, +03000000de2800000211000001000000,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: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,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,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,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,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +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:Linux, +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: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, +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 for USB,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: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,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +03000000457500002211000010010000,SZMY-POWER CO. LTD. 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, +030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. 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:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,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, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,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, +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, +030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,x:b1,y:b3,leftshoulder:b4,rightshoulder:b6,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux, +030000004f04000026b3000002040000,Thrustmaster Gamepad 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 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, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,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 Wireless 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, +030000004f04000007d0000000010000,Thrustmaster T Mini Wireless,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, +03000000bd12000015d0000010010000,Tomee SNES USB 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, +03000000100800000100000010010000,Twin USB 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, +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 Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +030000006f0e00000302000011010000,Victrix Pro Fight Stick for 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,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fight Stick for 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,x:b0,y:b3,platform:Linux, +05000000ac0500003232000001000000,VR-BOX,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, +03000000791d00000103000010010000,Wii Classic Controller,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, +050000000d0f0000f600000001000000,Wireless 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, +030000005e0400008e02000010010000,X360 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,X360 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, +030000005e0400001907000000010000,X360 Wireless 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, +030000005e0400009102000007010000,X360 Wireless 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,X360 Wireless 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,X360 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, +0000000058626f782033363020576900,Xbox 360 Wireless 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, +030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),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, +0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),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, +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, +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, +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, +030000005e040000ea02000000000000,Xbox One 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, +050000005e040000e002000003090000,Xbox One Wireless 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 Wireless 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, +030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),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,xbox360 Wireless 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, +03000000450c00002043000010010000,XEOX Gamepad SL-6556-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, +03000000ac0500005b05000010010000,Xiaoji 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, +05000000172700004431000029010000,XiaoMi Game 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,Xin-Mo Xin-Mo 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, +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 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:Linux, +03000000120c0000101e000011010000,ZEROPLUS P4 Wired 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:Linux, diff --git a/pcsx2/PAD/Linux/res/onepad-res.xml b/pcsx2/PAD/Linux/res/onepad-res.xml new file mode 100644 index 0000000000..b231d41004 --- /dev/null +++ b/pcsx2/PAD/Linux/res/onepad-res.xml @@ -0,0 +1,6 @@ + + + + game_controller_db.txt + + diff --git a/pcsx2/PAD/Linux/state_management.cpp b/pcsx2/PAD/Linux/state_management.cpp new file mode 100644 index 0000000000..aff9cedd7a --- /dev/null +++ b/pcsx2/PAD/Linux/state_management.cpp @@ -0,0 +1,468 @@ +/* OnePAD + * Copyright (C) 2016 + * + * Based on LilyPad + * Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver + * + * 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 + */ + +#include "state_management.h" +#include "GamePad.h" + +// Typical packet response on the bus +static const u8 ConfigExit[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const u8 noclue[7] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5A}; +static const u8 setMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const u8 queryModelDS2[7] = {0x5A, 0x03, 0x02, 0x00, 0x02, 0x01, 0x00}; +static const u8 queryModelDS1[7] = {0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00}; +static const u8 queryComb[7] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}; +static const u8 queryMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const u8 setNativeMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A}; + +static u8 queryMaskMode[7] = {0x5A, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x5A}; + +static const u8 queryAct[2][7] = { + {0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}, + {0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14}}; + +QueryInfo query; +Pad pads[2][4]; +int slots[2] = {0, 0}; + +////////////////////////////////////////////////////////////////////// +// QueryInfo implementation +////////////////////////////////////////////////////////////////////// + +void QueryInfo::reset() +{ + port = 0; + slot = 0; + lastByte = 1; + currentCommand = 0; + numBytes = 0; + queryDone = 1; + memset(response, 0xF3, sizeof(response)); +} + +u8 QueryInfo::start_poll(int _port) +{ + if (port > 1) { + reset(); + return 0; + } + + queryDone = 0; + port = _port; + slot = slots[port]; + numBytes = 2; + lastByte = 0; + + return 0xFF; +} + +////////////////////////////////////////////////////////////////////// +// Pad implementation +////////////////////////////////////////////////////////////////////// + +void Pad::set_mode(int _mode) +{ + mode = _mode; + +#if 0 + fprintf(stdout, "OnePad: set new pad mode="); + if (mode == MODE_DIGITAL) + fprintf(stdout, "DIGITAL\n"); + else if (mode == MODE_ANALOG) + fprintf(stdout, "ANALOG\n"); + else if (mode == MODE_DS2_NATIVE) + fprintf(stdout, "DS2 NATIVE\n"); + else + fprintf(stdout, "??? 0x%x\n", mode); +#endif +} + +void Pad::set_vibrate(int motor, u8 val) +{ + nextVibrate[motor] = val; +} + +void Pad::reset_vibrate() +{ + set_vibrate(0, 0); + set_vibrate(1, 0); + memset(vibrate, 0xFF, sizeof(vibrate)); + vibrate[0] = 0x5A; +} + +void Pad::reset() +{ + memset(this, 0, sizeof(PadFreezeData)); + + set_mode(MODE_DIGITAL); + umask[0] = umask[1] = 0xFF; + + // Sets up vibrate variable. + reset_vibrate(); +} + +void Pad::rumble(unsigned port) +{ + for (unsigned motor = 0; motor < 2; motor++) { + // TODO: Probably be better to send all of these at once. + if (nextVibrate[motor] | currentVibrate[motor]) { + currentVibrate[motor] = nextVibrate[motor]; + + GamePad::DoRumble(motor, port); + } + } +} + +void Pad::stop_vibrate_all() +{ +#if 0 + for (int i=0; i<8; i++) { + SetVibrate(i&1, i>>1, 0, 0); + SetVibrate(i&1, i>>1, 1, 0); + } +#endif + // FIXME equivalent ? + for (int port = 0; port < 2; port++) + for (int slot = 0; slot < 4; slot++) + pads[port][slot].reset_vibrate(); +} + +void Pad::reset_all() +{ + for (int port = 0; port < 2; port++) + for (int slot = 0; slot < 4; slot++) + pads[port][slot].reset(); +} + +void Pad::rumble_all() +{ + for (unsigned port = 0; port < 2; port++) + for (unsigned slot = 0; slot < 4; slot++) + pads[port][slot].rumble(port); +} + +////////////////////////////////////////////////////////////////////// +// Pad implementation +////////////////////////////////////////////////////////////////////// + +inline bool IsDualshock2() +{ +// FIXME +#if 0 + return config.padConfigs[query.port][query.slot].type == Dualshock2Pad || + (config.padConfigs[query.port][query.slot].type == GuitarPad && config.GH2); +#else + return true; +#endif +} + +u8 pad_start_poll(u8 pad) +{ + return query.start_poll(pad - 1); +} + +u8 pad_poll(u8 value) +{ + if (query.lastByte + 1 >= query.numBytes) { + return 0; + } + if (query.lastByte && query.queryDone) { + return query.response[++query.lastByte]; + } + + Pad *pad = &pads[query.port][query.slot]; + + if (query.lastByte == 0) { + query.lastByte++; + query.currentCommand = value; + + switch (value) { + case CMD_CONFIG_MODE: + if (pad->config) { + // In config mode. Might not actually be leaving it. + query.set_result(ConfigExit); + return 0xF3; + } + [[fallthrough]]; // fallthrough on purpose (but I don't know why) + + case CMD_READ_DATA_AND_VIBRATE: { + query.response[2] = 0x5A; +#if 0 + int i; + Update(query.port, query.slot); + ButtonSum *sum = &pad->sum; + + u8 b1 = 0xFF, b2 = 0xFF; + for (i = 0; i<4; i++) { + b1 -= (sum->buttons[i] > 0) << i; + } + for (i = 0; i<8; i++) { + b2 -= (sum->buttons[i+4] > 0) << i; + } +#endif + +// FIXME +#if 0 + if (config.padConfigs[query.port][query.slot].type == GuitarPad && !config.GH2) { + sum->buttons[15] = 255; + // Not sure about this. Forces wammy to be from 0 to 0x7F. + // if (sum->sticks[2].vert > 0) sum->sticks[2].vert = 0; + } +#endif + +#if 0 + for (i = 4; i<8; i++) { + b1 -= (sum->buttons[i+8] > 0) << i; + } +#endif + +// FIXME +#if 0 + //Left, Right and Down are always pressed on Pop'n Music controller. + if (config.padConfigs[query.port][query.slot].type == PopnPad) + b1=b1 & 0x1f; +#endif + + uint16_t buttons = g_key_status.get(query.port); + + query.numBytes = 5; + + query.response[3] = (buttons >> 8) & 0xFF; + query.response[4] = (buttons >> 0) & 0xFF; + + if (pad->mode != MODE_DIGITAL) { // ANALOG || DS2 native + query.numBytes = 9; + + query.response[5] = g_key_status.get(query.port, PAD_R_RIGHT); + query.response[6] = g_key_status.get(query.port, PAD_R_UP); + query.response[7] = g_key_status.get(query.port, PAD_L_RIGHT); + query.response[8] = g_key_status.get(query.port, PAD_L_UP); + + if (pad->mode != MODE_ANALOG) { // DS2 native + query.numBytes = 21; + + query.response[9] = !test_bit(buttons, 13) ? g_key_status.get(query.port, PAD_RIGHT) : 0; + query.response[10] = !test_bit(buttons, 15) ? g_key_status.get(query.port, PAD_LEFT) : 0; + query.response[11] = !test_bit(buttons, 12) ? g_key_status.get(query.port, PAD_UP) : 0; + query.response[12] = !test_bit(buttons, 14) ? g_key_status.get(query.port, PAD_DOWN) : 0; + + query.response[13] = !test_bit(buttons, 4) ? g_key_status.get(query.port, PAD_TRIANGLE) : 0; + query.response[14] = !test_bit(buttons, 5) ? g_key_status.get(query.port, PAD_CIRCLE) : 0; + query.response[15] = !test_bit(buttons, 6) ? g_key_status.get(query.port, PAD_CROSS) : 0; + query.response[16] = !test_bit(buttons, 7) ? g_key_status.get(query.port, PAD_SQUARE) : 0; + query.response[17] = !test_bit(buttons, 2) ? g_key_status.get(query.port, PAD_L1) : 0; + query.response[18] = !test_bit(buttons, 3) ? g_key_status.get(query.port, PAD_R1) : 0; + query.response[19] = !test_bit(buttons, 0) ? g_key_status.get(query.port, PAD_L2) : 0; + query.response[20] = !test_bit(buttons, 1) ? g_key_status.get(query.port, PAD_R2) : 0; + } + } + +#if 0 + query.response[3] = b1; + query.response[4] = b2; + + query.numBytes = 5; + if (pad->mode != MODE_DIGITAL) { + query.response[5] = Cap((sum->sticks[0].horiz+255)/2); + query.response[6] = Cap((sum->sticks[0].vert+255)/2); + query.response[7] = Cap((sum->sticks[1].horiz+255)/2); + query.response[8] = Cap((sum->sticks[1].vert+255)/2); + + query.numBytes = 9; + if (pad->mode != MODE_ANALOG) { + // Good idea? No clue. + //query.response[3] &= pad->mask[0]; + //query.response[4] &= pad->mask[1]; + + // No need to cap these, already done int CapSum(). + query.response[9] = (unsigned char)sum->buttons[13]; //D-pad right + query.response[10] = (unsigned char)sum->buttons[15]; //D-pad left + query.response[11] = (unsigned char)sum->buttons[12]; //D-pad up + query.response[12] = (unsigned char)sum->buttons[14]; //D-pad down + + query.response[13] = (unsigned char) sum->buttons[8]; + query.response[14] = (unsigned char) sum->buttons[9]; + query.response[15] = (unsigned char) sum->buttons[10]; + query.response[16] = (unsigned char) sum->buttons[11]; + query.response[17] = (unsigned char) sum->buttons[6]; + query.response[18] = (unsigned char) sum->buttons[7]; + query.response[19] = (unsigned char) sum->buttons[4]; + query.response[20] = (unsigned char) sum->buttons[5]; + query.numBytes = 21; + } + } +#endif + } + + query.lastByte = 1; + return pad->mode; + + case CMD_SET_VREF_PARAM: + query.set_final_result(noclue); + break; + + case CMD_QUERY_DS2_ANALOG_MODE: + // Right? Wrong? No clue. + if (pad->mode == MODE_DIGITAL) { + queryMaskMode[1] = queryMaskMode[2] = queryMaskMode[3] = 0; + queryMaskMode[6] = 0x00; + } else { + queryMaskMode[1] = pad->umask[0]; + queryMaskMode[2] = pad->umask[1]; + queryMaskMode[3] = 0x03; + // Not entirely sure about this. + //queryMaskMode[3] = 0x01 | (pad->mode == MODE_DS2_NATIVE)*2; + queryMaskMode[6] = 0x5A; + } + query.set_final_result(queryMaskMode); + break; + + case CMD_SET_MODE_AND_LOCK: + query.set_result(setMode); + pad->reset_vibrate(); + break; + + case CMD_QUERY_MODEL_AND_MODE: + if (IsDualshock2()) { + query.set_final_result(queryModelDS2); + } else { + query.set_final_result(queryModelDS1); + } + // Not digital mode. + query.response[5] = (pad->mode & 0xF) != 1; + break; + + case CMD_QUERY_ACT: + query.set_result(queryAct[0]); + break; + + case CMD_QUERY_COMB: + query.set_final_result(queryComb); + break; + + case CMD_QUERY_MODE: + query.set_result(queryMode); + break; + + case CMD_VIBRATION_TOGGLE: + memcpy(query.response + 2, pad->vibrate, 7); + query.numBytes = 9; + //query.set_result(pad->vibrate); // warning copy 7b not 8 (but it is really important?) + pad->reset_vibrate(); + break; + + case CMD_SET_DS2_NATIVE_MODE: + if (IsDualshock2()) { + query.set_result(setNativeMode); + } else { + query.set_final_result(setNativeMode); + } + break; + + default: + query.numBytes = 0; + query.queryDone = 1; + break; + } + + return 0xF3; + + } else { + query.lastByte++; + + switch (query.currentCommand) { + case CMD_READ_DATA_AND_VIBRATE: + if (query.lastByte == pad->vibrateI[0]) + pad->set_vibrate(1, 255 * (value & 1)); + else if (query.lastByte == pad->vibrateI[1]) + pad->set_vibrate(0, value); + + break; + + case CMD_CONFIG_MODE: + if (query.lastByte == 3) { + query.queryDone = 1; + pad->config = value; + } + break; + + case CMD_SET_MODE_AND_LOCK: + if (query.lastByte == 3 && value < 2) { + pad->set_mode(value ? MODE_ANALOG : MODE_DIGITAL); + } else if (query.lastByte == 4) { + if (value == 3) + pad->modeLock = 3; + else + pad->modeLock = 0; + + query.queryDone = 1; + } + break; + + case CMD_QUERY_ACT: + if (query.lastByte == 3) { + if (value < 2) + query.set_result(queryAct[value]); + // bunch of 0's + // else query.set_result(setMode); + query.queryDone = 1; + } + break; + + case CMD_QUERY_MODE: + if (query.lastByte == 3 && value < 2) { + query.response[6] = 4 + value * 3; + query.queryDone = 1; + } + // bunch of 0's + //else data = setMode; + break; + + case CMD_VIBRATION_TOGGLE: + if (query.lastByte >= 3) { + if (value == 0) { + pad->vibrateI[0] = (u8)query.lastByte; + } else if (value == 1) { + pad->vibrateI[1] = (u8)query.lastByte; + } + pad->vibrate[query.lastByte - 2] = value; + } + break; + + case CMD_SET_DS2_NATIVE_MODE: + if (query.lastByte == 3 || query.lastByte == 4) { + pad->umask[query.lastByte - 3] = value; + } else if (query.lastByte == 5) { + if (!(value & 1)) + pad->set_mode(MODE_DIGITAL); + else if (!(value & 2)) + pad->set_mode(MODE_ANALOG); + else + pad->set_mode(MODE_DS2_NATIVE); + } + break; + + default: + return 0; + } + + return query.response[query.lastByte]; + } +} diff --git a/pcsx2/PAD/Linux/state_management.h b/pcsx2/PAD/Linux/state_management.h new file mode 100644 index 0000000000..8f02e21c20 --- /dev/null +++ b/pcsx2/PAD/Linux/state_management.h @@ -0,0 +1,119 @@ +/* OnePAD + * Copyright (C) 2016 + * + * Based on LilyPad + * Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver + * + * 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 + */ + +#include "onepad.h" + +#define MODE_DIGITAL 0x41 +#define MODE_ANALOG 0x73 +#define MODE_DS2_NATIVE 0x79 + +// The state of the PS2 bus +struct QueryInfo +{ + u8 port; + u8 slot; + u8 lastByte; + u8 currentCommand; + u8 numBytes; + u8 queryDone; + u8 response[42]; + + void reset(); + u8 start_poll(int port); + + template + void set_result(const u8 (&rsp)[S]) + { + memcpy(response + 2, rsp, S); + numBytes = 2 + S; + } + + template + void set_final_result(const u8 (&rsp)[S]) + { + set_result(rsp); + queryDone = 1; + } +}; + +// Freeze data, for a single pad. Basically has all pad state that +// a PS2 can set. +struct PadFreezeData +{ + // Digital / Analog / DS2 Native + u8 mode; + + u8 modeLock; + + // In config mode + u8 config; + + u8 vibrate[8]; + u8 umask[2]; + + // Vibration indices. + u8 vibrateI[2]; + + // Last vibration value sent to controller. + // Only used so as not to call vibration + // functions when old and new values are both 0. + u8 currentVibrate[2]; + + // Next vibrate val to send to controller. If next and current are + // both 0, nothing is sent to the controller. Otherwise, it's sent + // on every update. + u8 nextVibrate[2]; +}; + +class Pad : public PadFreezeData +{ +public: + // Lilypad store here the state of PC pad + + void rumble(unsigned port); + void set_vibrate(int motor, u8 val); + void reset_vibrate(); + void reset(); + + void set_mode(int mode); + + static void reset_all(); + static void stop_vibrate_all(); + static void rumble_all(); +}; + +// Full state to manage save state +struct PadPluginFreezeData +{ + char format[8]; + u32 version; + // active slot for port + u8 slot[2]; + PadFreezeData padData[2][4]; + QueryInfo query; +}; + +extern QueryInfo query; +extern Pad pads[2][4]; +extern int slots[2]; + +extern u8 pad_start_poll(u8 pad); +extern u8 pad_poll(u8 value); diff --git a/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.cpp b/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.cpp new file mode 100644 index 0000000000..757c675c8d --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.cpp @@ -0,0 +1,185 @@ +/* GamepadConfiguration.cpp + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#include "GamepadConfiguration.h" + +GamepadConfiguration::GamepadConfiguration(int pad, wxWindow *parent) + : wxDialog(parent, wxID_ANY, _T("Gamepad"), wxDefaultPosition, wxDefaultSize, + wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN) +{ + m_pad_id = pad; + + wxBoxSizer *gamepad_box = new wxBoxSizer(wxVERTICAL); + + wxArrayString choices; + for (const auto &j : s_vgamePad) { + choices.Add(j->GetName()); + } + + m_joy_map = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices); + m_cb_rumble = new wxCheckBox(this, enable_rumble_id, _T("&Enable rumble")); + + wxStaticBoxSizer *rumble_box = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Rumble intensity")); + m_sl_rumble_intensity = new wxSlider(this, rumble_slider_id, 0, 0, 0x7FFF, wxDefaultPosition, wxDefaultSize, + wxSL_HORIZONTAL | wxSL_LABELS | wxSL_BOTTOM); + + wxStaticBoxSizer *joy_box = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Joystick sensibility")); + m_sl_joystick_sensibility = new wxSlider(this, joy_slider_id, 0, 0, 200, wxDefaultPosition, wxDefaultSize, + wxSL_HORIZONTAL | wxSL_LABELS | wxSL_BOTTOM); + + gamepad_box->Add(m_joy_map, wxSizerFlags().Expand().Border(wxALL, 5)); + gamepad_box->Add(m_cb_rumble, wxSizerFlags().Expand()); + + rumble_box->Add(m_sl_rumble_intensity, wxSizerFlags().Expand().Border(wxALL, 5)); + joy_box->Add(m_sl_joystick_sensibility, wxSizerFlags().Expand().Border(wxALL, 5)); + + gamepad_box->Add(rumble_box, wxSizerFlags().Expand().Border(wxALL, 5)); + gamepad_box->Add(joy_box, wxSizerFlags().Expand().Border(wxALL, 5)); + + gamepad_box->Add(CreateSeparatedButtonSizer(wxOK), wxSizerFlags().Right().Border(wxALL, 5)); + + Bind(wxEVT_BUTTON, &GamepadConfiguration::OnOk, this, wxID_OK); + Bind(wxEVT_SCROLL_THUMBRELEASE, &GamepadConfiguration::OnSliderReleased, this); + Bind(wxEVT_CHECKBOX, &GamepadConfiguration::OnCheckboxChange, this); + Bind(wxEVT_CHOICE, &GamepadConfiguration::OnChoiceChange, this); + + repopulate(); + + SetSizerAndFit(gamepad_box); +} + +/** + Initialize the frame + Check if a gamepad is detected + Check if the gamepad support rumbles +*/ +void GamepadConfiguration::InitGamepadConfiguration() +{ + repopulate(); // Set label and fit simulated key array + /* + * Check if there exist at least one pad available + * if the pad id is 0, you need at least 1 gamepad connected, + * if the pad id is 1, you need at least 2 gamepads connected, + * Prevent to use a none initialized value on s_vgamePad (core dump) + */ + if (s_vgamePad.size() >= m_pad_id + 1) { + /* + * Determine if the device can use rumble + * Use TestForce with a very low strength (can't be felt) + * May be better to create a new function in order to check only that + */ + + // Bad idea. Some connected devices might support rumble but not all connected devices. + // if (!s_vgamePad[m_pad_id]->TestForce(0.001f)) { + // wxMessageBox(L"Rumble is not available for your device."); + // m_cb_rumble->Disable(); // disable the rumble checkbox + // m_sl_rumble_intensity->Disable(); // disable the rumble intensity slider + // } + } else { + wxMessageBox(L"No gamepad detected."); + m_sl_joystick_sensibility->Disable(); // disable the joystick sensibility slider + m_cb_rumble->Disable(); // disable the rumble checkbox + m_sl_rumble_intensity->Disable(); // disable the rumble intensity slider + } +} + +void GamepadConfiguration::OnOk(wxCommandEvent &event) +{ + Destroy(); +} + +/** + * Slider event, called when the use release the slider button + * @FIXME The current solution can't change the joystick sensibility and the rumble intensity + * for a specific gamepad. The same value is used for both +*/ +void GamepadConfiguration::OnSliderReleased(wxCommandEvent &event) +{ + wxSlider *sl_tmp = (wxSlider *)event.GetEventObject(); + int sl_id = sl_tmp->GetId(); + + if (sl_id == rumble_slider_id) + { + g_conf.set_ff_intensity(m_sl_rumble_intensity->GetValue()); + + // convert in a float value between 0 and 1, and run rumble feedback. + // 0 to 1 scales to 0x0 to 0x7FFF + s_vgamePad[m_pad_id]->TestForce(m_sl_rumble_intensity->GetValue() / 0x7FFF); + } + else if (sl_id == joy_slider_id) + { + g_conf.set_sensibility(m_sl_joystick_sensibility->GetValue()); + } +} + +/** + * Checkbox event, called when the value of the checkbox change +*/ +void GamepadConfiguration::OnCheckboxChange(wxCommandEvent &event) +{ + wxCheckBox *cb_tmp = (wxCheckBox *)event.GetEventObject(); // get the slider object + int cb_id = cb_tmp->GetId(); + + if (cb_id == enable_rumble_id) + { + g_conf.pad_options[m_pad_id].forcefeedback = (m_cb_rumble->GetValue()) ? (u32)1 : (u32)0; + if (m_cb_rumble->GetValue()) + { + s_vgamePad[m_pad_id]->TestForce(); + m_sl_rumble_intensity->Enable(); + } + else + { + m_sl_rumble_intensity->Disable(); + } + } +} + +/* + * Checkbox event, called when the value of the choice box change + */ +void GamepadConfiguration::OnChoiceChange(wxCommandEvent &event) +{ + wxChoice *choice_tmp = (wxChoice *)event.GetEventObject(); + int id = choice_tmp->GetSelection(); + if (id != wxNOT_FOUND) + { + g_conf.set_joy_uid(m_pad_id, GamePad::index_to_uid(id)); + } +} + +/****************************************/ +/*********** Methods functions **********/ +/****************************************/ + +// Set button values +void GamepadConfiguration::repopulate() +{ + m_cb_rumble->SetValue(g_conf.pad_options[m_pad_id].forcefeedback); + + m_sl_rumble_intensity->SetValue(g_conf.get_ff_intensity()); + m_sl_joystick_sensibility->SetValue(g_conf.get_sensibility()); + + u32 joyid = GamePad::uid_to_index(m_pad_id); + if (joyid < m_joy_map->GetCount() && !m_joy_map->IsEmpty()) + m_joy_map->SetSelection(joyid); + + // enable rumble intensity slider if the checkbox is checked + m_sl_rumble_intensity->Enable(m_cb_rumble->GetValue()); +} diff --git a/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.h b/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.h new file mode 100644 index 0000000000..26ef8cefa7 --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/GamepadConfiguration.h @@ -0,0 +1,57 @@ +/* GamepadConfiguration.h + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#pragma once + +#ifndef __GAMEPADCONFIGURATION_H__ +#define __GAMEPADCONFIGURATION_H__ + +#include + +#include "../GamePad.h" +#include "../keyboard.h" +#include "../onepad.h" + +static const s32 rumble_slider_id = wxID_HIGHEST + 200 + 1; +static const s32 joy_slider_id = wxID_HIGHEST + 200 + 2; +static const s32 enable_rumble_id = wxID_HIGHEST + 200 + 3; + +class GamepadConfiguration : public wxDialog +{ + wxCheckBox *m_cb_rumble; + wxSlider *m_sl_rumble_intensity, *m_sl_joystick_sensibility; + wxChoice *m_joy_map; + + u32 m_pad_id; + + // Methods + void repopulate(); + + // Events + void OnOk(wxCommandEvent &); + void OnSliderReleased(wxCommandEvent &); + void OnCheckboxChange(wxCommandEvent &); + void OnChoiceChange(wxCommandEvent &); + +public: + GamepadConfiguration(int, wxWindow *); + void InitGamepadConfiguration(); +}; + +#endif // __GAMEPADCONFIGURATION_H__ diff --git a/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.cpp b/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.cpp new file mode 100644 index 0000000000..dc4ac70c96 --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.cpp @@ -0,0 +1,211 @@ +/* JoystickConfiguration.cpp + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#include "JoystickConfiguration.h" + +// Constructor of JoystickConfiguration +JoystickConfiguration::JoystickConfiguration(int pad, bool left, wxWindow *parent) + : wxDialog(parent, wxID_ANY, _T("Joystick configuration"), wxDefaultPosition, wxDefaultSize, + wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN) +{ + m_init_reverse_Lx = m_init_reverse_Ly = + m_init_reverse_Rx = m_init_reverse_Ry = + m_init_mouse_Ljoy = m_init_mouse_Rjoy = false; + + m_pad_id = pad; + m_isForLeftJoystick = left; + + wxBoxSizer *joy_conf_box = new wxBoxSizer(wxVERTICAL); + + if (m_isForLeftJoystick) + { + m_cb_reverse_Lx = new wxCheckBox(this, Lx_check_id, _T("Reverse Lx")); + m_cb_reverse_Ly = new wxCheckBox(this, Ly_check_id, _T("Reverse Ly")); + m_cb_mouse_Ljoy = new wxCheckBox(this, Ljoy_check_id, _T("Use mouse for left analog joystick")); + + joy_conf_box->Add(m_cb_reverse_Lx, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + joy_conf_box->Add(m_cb_reverse_Ly, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + joy_conf_box->Add(m_cb_mouse_Ljoy, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + + m_cb_reverse_Rx = m_cb_reverse_Ry = m_cb_mouse_Rjoy = nullptr; + + } + else + { + m_cb_reverse_Rx = new wxCheckBox(this, Rx_check_id, _T("Reverse Rx")); + m_cb_reverse_Ry = new wxCheckBox(this, Ry_check_id, _T("Reverse Ry")); + m_cb_mouse_Rjoy = new wxCheckBox(this, Rjoy_check_id, _T("Use mouse for right analog joystick")); + + joy_conf_box->Add(m_cb_reverse_Rx, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + joy_conf_box->Add(m_cb_reverse_Ry, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + joy_conf_box->Add(m_cb_mouse_Rjoy, wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT, 5)); + + m_cb_reverse_Lx = m_cb_reverse_Ly = m_cb_mouse_Ljoy = nullptr; + } + + joy_conf_box->Add(CreateSeparatedButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Border(wxALL, 5).Right()); + + Bind(wxEVT_BUTTON, &JoystickConfiguration::OnOk, this, wxID_OK); + Bind(wxEVT_BUTTON, &JoystickConfiguration::OnCancel, this, wxID_CANCEL); + Bind(wxEVT_CHECKBOX, &JoystickConfiguration::OnCheckboxChange, this); + + SetSizerAndFit(joy_conf_box); +} + +/** + Initialize the frame + Check if a gamepad is detected +*/ +void JoystickConfiguration::InitJoystickConfiguration() +{ + repopulate(); // Set label and fit simulated key array + /* + * Check if there exist at least one pad available + * if the pad id is 0, you need at least 1 gamepad connected, + * if the pad id is 1, you need at least 2 gamepads connected, + * Prevent to use a none initialized value on s_vgamePad (core dump) + */ + if (s_vgamePad.size() < m_pad_id + 1) { + if (s_vgamePad.empty()) + wxMessageBox(L"No gamepad detected."); + else + wxMessageBox(L"No second gamepad detected."); + + // disable all checkboxes + if (m_isForLeftJoystick) + { + m_cb_reverse_Lx->Disable(); + m_cb_reverse_Ly->Disable(); + } + else + { + m_cb_reverse_Rx->Disable(); + m_cb_reverse_Ry->Disable(); + } + } +} + +void JoystickConfiguration::OnOk(wxCommandEvent &event) +{ + Destroy(); +} + +void JoystickConfiguration::OnCancel(wxCommandEvent &event) +{ + reset(); + Destroy(); +} + +/** + * Checkbox event, called when the value of the checkbox change +*/ +void JoystickConfiguration::OnCheckboxChange(wxCommandEvent &event) +{ + wxCheckBox *cb_tmp = (wxCheckBox *)event.GetEventObject(); // get the slider object + int cb_id = cb_tmp->GetId(); + + if (m_isForLeftJoystick) + { + switch (cb_id) + { + case Lx_check_id: + g_conf.pad_options[m_pad_id].reverse_lx = m_cb_reverse_Lx->GetValue(); + break; + + case Ly_check_id: + g_conf.pad_options[m_pad_id].reverse_ly = m_cb_reverse_Ly->GetValue(); + break; + + case Ljoy_check_id: + g_conf.pad_options[m_pad_id].mouse_l = m_cb_mouse_Ljoy->GetValue(); + break; + + default: + break; + } + } + else + { + switch (cb_id) + { + case Rx_check_id: + g_conf.pad_options[m_pad_id].reverse_rx = m_cb_reverse_Rx->GetValue(); + break; + + case Ry_check_id: + g_conf.pad_options[m_pad_id].reverse_ry = m_cb_reverse_Ry->GetValue(); + break; + + case Rjoy_check_id: + g_conf.pad_options[m_pad_id].mouse_r = m_cb_mouse_Rjoy->GetValue(); + break; + + default: + break; + } + } +} + +/****************************************/ +/*********** Methods functions **********/ +/****************************************/ + +// Reset checkbox and slider values +void JoystickConfiguration::reset() +{ + if (m_isForLeftJoystick) + { + m_cb_reverse_Lx->SetValue(m_init_reverse_Lx); + m_cb_reverse_Ly->SetValue(m_init_reverse_Ly); + m_cb_mouse_Ljoy->SetValue(m_init_mouse_Ljoy); + } + else + { + m_cb_reverse_Rx->SetValue(m_init_reverse_Rx); + m_cb_reverse_Ry->SetValue(m_init_reverse_Ry); + m_cb_mouse_Rjoy->SetValue(m_init_mouse_Rjoy); + } +} + +// Set button values +void JoystickConfiguration::repopulate() +{ + if (m_isForLeftJoystick) + { + m_init_reverse_Lx = g_conf.pad_options[m_pad_id].reverse_lx; + m_cb_reverse_Lx->SetValue(m_init_reverse_Lx); + + m_init_reverse_Ly = g_conf.pad_options[m_pad_id].reverse_ly; + m_cb_reverse_Ly->SetValue(m_init_reverse_Ly); + + m_init_mouse_Ljoy = g_conf.pad_options[m_pad_id].mouse_l; + m_cb_mouse_Ljoy->SetValue(m_init_mouse_Ljoy); + } + else + { + m_init_reverse_Rx = g_conf.pad_options[m_pad_id].reverse_rx; + m_cb_reverse_Rx->SetValue(m_init_reverse_Rx); + + m_init_reverse_Ry = g_conf.pad_options[m_pad_id].reverse_ry; + m_cb_reverse_Ry->SetValue(m_init_reverse_Ry); + + m_init_mouse_Rjoy = g_conf.pad_options[m_pad_id].mouse_r; + m_cb_mouse_Rjoy->SetValue(m_init_mouse_Rjoy); + } +} diff --git a/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.h b/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.h new file mode 100644 index 0000000000..ba8dc0f9b8 --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/JoystickConfiguration.h @@ -0,0 +1,64 @@ +/* JoystickConfiguration.h + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#pragma once + +#ifndef __JOYSTICKCONFIGURATION_H__ +#define __JOYSTICKCONFIGURATION_H__ + +#include + +#include "../GamePad.h" +#include "../keyboard.h" +#include "../onepad.h" + +static const s32 Lx_check_id = wxID_HIGHEST + 100 + 1; +static const s32 Ly_check_id = wxID_HIGHEST + 100 + 2; +static const s32 Ljoy_check_id = wxID_HIGHEST + 100 + 3; + +static const s32 Rx_check_id = wxID_HIGHEST + 100 + 4; +static const s32 Ry_check_id = wxID_HIGHEST + 100 + 5; +static const s32 Rjoy_check_id = wxID_HIGHEST + 100 + 6; + +class JoystickConfiguration : public wxDialog +{ + wxCheckBox *m_cb_reverse_Lx, *m_cb_reverse_Ly, *m_cb_reverse_Rx, *m_cb_reverse_Ry, + *m_cb_mouse_Ljoy, // Use mouse for left joystick + *m_cb_mouse_Rjoy; // Use mouse for right joystick + + u32 m_pad_id; + // isForLeftJoystick -> true is for Left Joystick, false is for Right Joystick + bool m_init_reverse_Lx, m_init_reverse_Ly, m_init_reverse_Rx, m_init_reverse_Ry, + m_init_mouse_Ljoy, m_init_mouse_Rjoy, m_isForLeftJoystick; + + // Methods + void repopulate(); + void reset(); + + // Events + void OnCheckboxChange(wxCommandEvent &); + void OnOk(wxCommandEvent &); + void OnCancel(wxCommandEvent &); + +public: + JoystickConfiguration(int, bool, wxWindow *); + void InitJoystickConfiguration(); +}; + +#endif // __JOYSTICKCONFIGURATION_H__ diff --git a/pcsx2/PAD/Linux/wx_dialog/dialog.cpp b/pcsx2/PAD/Linux/wx_dialog/dialog.cpp new file mode 100644 index 0000000000..fa8cd93366 --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/dialog.cpp @@ -0,0 +1,640 @@ +/* dialog.cpp + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#include "dialog.h" + +#ifdef __APPLE__ +#include + +static std::string KeyName(int pad, int key, int keysym) +{ + // Mouse + if (keysym >> 16) { + switch (keysym & 0xFFFF) { + case kCGMouseButtonLeft: + return "Mouse Left"; + case kCGMouseButtonRight: + return "Mouse Right"; + case kCGMouseButtonCenter: + return "Mouse Middle"; + default: // Use only number for extra button + return "Mouse " + std::to_string(keysym & 0xFFFF); + } + } + + switch (keysym) { + case kVK_ANSI_A: return "A"; + case kVK_ANSI_B: return "B"; + case kVK_ANSI_C: return "C"; + case kVK_ANSI_D: return "D"; + case kVK_ANSI_E: return "E"; + case kVK_ANSI_F: return "F"; + case kVK_ANSI_G: return "G"; + case kVK_ANSI_H: return "H"; + case kVK_ANSI_I: return "I"; + case kVK_ANSI_J: return "J"; + case kVK_ANSI_K: return "K"; + case kVK_ANSI_L: return "L"; + case kVK_ANSI_M: return "M"; + case kVK_ANSI_N: return "N"; + case kVK_ANSI_O: return "O"; + case kVK_ANSI_P: return "P"; + case kVK_ANSI_Q: return "Q"; + case kVK_ANSI_R: return "R"; + case kVK_ANSI_S: return "S"; + case kVK_ANSI_T: return "T"; + case kVK_ANSI_U: return "U"; + case kVK_ANSI_V: return "V"; + case kVK_ANSI_W: return "W"; + case kVK_ANSI_X: return "X"; + case kVK_ANSI_Y: return "Y"; + case kVK_ANSI_Z: return "Z"; + case kVK_ANSI_0: return "0"; + case kVK_ANSI_1: return "1"; + case kVK_ANSI_2: return "2"; + case kVK_ANSI_3: return "3"; + case kVK_ANSI_4: return "4"; + case kVK_ANSI_5: return "5"; + case kVK_ANSI_6: return "6"; + case kVK_ANSI_7: return "7"; + case kVK_ANSI_8: return "8"; + case kVK_ANSI_9: return "9"; + case kVK_ANSI_Grave: return "`"; + case kVK_ANSI_Minus: return "-"; + case kVK_ANSI_Equal: return "="; + case kVK_ANSI_LeftBracket: return "["; + case kVK_ANSI_RightBracket: return "]"; + case kVK_ANSI_Backslash: return "\\"; + case kVK_ANSI_Semicolon: return ";"; + case kVK_ANSI_Quote: return "'"; + case kVK_ANSI_Comma: return ","; + case kVK_ANSI_Period: return "."; + case kVK_ANSI_Slash: return "/"; + case kVK_Escape: return "⎋"; + case kVK_Tab: return "⇥"; + case kVK_Delete: return "⌫"; + case kVK_ForwardDelete: return "⌦"; + case kVK_Return: return "↩"; + case kVK_Space: return "␣"; + case kVK_ANSI_KeypadDecimal: return "Keypad ."; + case kVK_ANSI_KeypadMultiply: return "Keypad *"; + case kVK_ANSI_KeypadPlus: return "Keypad +"; + case kVK_ANSI_KeypadClear: return "⌧"; + case kVK_ANSI_KeypadDivide: return "Keypad /"; + case kVK_ANSI_KeypadEnter: return "⌤"; + case kVK_ANSI_KeypadMinus: return "Keypad -"; + case kVK_ANSI_KeypadEquals: return "Keypad ="; + case kVK_ANSI_Keypad0: return "Keypad 0"; + case kVK_ANSI_Keypad1: return "Keypad 1"; + case kVK_ANSI_Keypad2: return "Keypad 2"; + case kVK_ANSI_Keypad3: return "Keypad 3"; + case kVK_ANSI_Keypad4: return "Keypad 4"; + case kVK_ANSI_Keypad5: return "Keypad 5"; + case kVK_ANSI_Keypad6: return "Keypad 6"; + case kVK_ANSI_Keypad7: return "Keypad 7"; + case kVK_ANSI_Keypad8: return "Keypad 8"; + case kVK_ANSI_Keypad9: return "Keypad 9"; + case kVK_Command: return "Left ⌘"; + case kVK_Shift: return "Left ⇧"; + case kVK_CapsLock: return "⇪"; + case kVK_Option: return "Left ⌥"; + case kVK_Control: return "Left ⌃"; + case kVK_RightCommand: return "Right ⌘"; + case kVK_RightShift: return "Right ⇧"; + case kVK_RightOption: return "Right ⌥"; + case kVK_RightControl: return "Right ⌃"; + case kVK_Function: return "fn"; + case kVK_VolumeUp: return "Volume Up"; + case kVK_VolumeDown: return "Volume Down"; + case kVK_Mute: return "Mute"; + case kVK_F1: return "F1"; + case kVK_F2: return "F2"; + case kVK_F3: return "F3"; + case kVK_F4: return "F4"; + case kVK_F5: return "F5"; + case kVK_F6: return "F6"; + case kVK_F7: return "F7"; + case kVK_F8: return "F8"; + case kVK_F9: return "F9"; + case kVK_F10: return "F10"; + case kVK_F11: return "F11"; + case kVK_F12: return "F12"; + case kVK_F13: return "F13"; + case kVK_F14: return "F14"; + case kVK_F15: return "F15"; + case kVK_F16: return "F16"; + case kVK_F17: return "F17"; + case kVK_F18: return "F18"; + case kVK_F19: return "F19"; + case kVK_F20: return "F20"; + case kVK_Help: return "Help"; + case kVK_Home: return "↖"; + case kVK_PageUp: return "⇞"; + case kVK_End: return "↘"; + case kVK_PageDown: return "⇟"; + case kVK_LeftArrow: return "←"; + case kVK_RightArrow: return "→"; + case kVK_DownArrow: return "↓"; + case kVK_UpArrow: return "↑"; + case kVK_ISO_Section: return "Section"; + case kVK_JIS_Yen: return "¥"; + case kVK_JIS_Underscore: return "_"; + case kVK_JIS_KeypadComma: return "Keypad ,"; + case kVK_JIS_Eisu: return "英数"; + case kVK_JIS_Kana: return "かな"; + default: return "Key " + std::to_string(keysym); + } +} +#else +static std::string KeyName(int pad, int key, int keysym) +{ + // Mouse + if (keysym < 10) { + switch (keysym) { + case 0: + return ""; + case 1: + return "Mouse Left"; + case 2: + return "Mouse Middle"; + case 3: + return "Mouse Right"; + default: // Use only number for extra button + return "Mouse " + std::to_string(keysym); + } + } + + return std::string(XKeysymToString(keysym)); +} +#endif + +// Construtor of Dialog +Dialog::Dialog() + : wxDialog(NULL, // Parent + wxID_ANY, // ID + _T("OnePad configuration"), // Title + wxDefaultPosition, // Position + wxSize(DEFAULT_WIDTH, DEFAULT_HEIGHT), // Width + Lenght + // Style + wxSYSTEM_MENU | + wxCAPTION | + wxCLOSE_BOX | + wxCLIP_CHILDREN) +{ + + /* + * Define the size and the position of each button : + * padding[ButtonID][0] : Width + * padding[ButtonID][1] : Height + * padding[ButtonID][2] : x position + * padding[ButtonID][3] : y position + */ + int padding[BUTTONS_LENGHT][4]; + + // L1 + padding[PAD_L1][0] = 218; // Width + padding[PAD_L1][1] = 28; // Height + padding[PAD_L1][2] = 50; // X + padding[PAD_L1][3] = 175; // Y + + // L2 + padding[PAD_L2][0] = 218; // Width + padding[PAD_L2][1] = 28; // Height + padding[PAD_L2][2] = 50; // X + padding[PAD_L2][3] = 104; // Y + + // R1 + padding[PAD_R1][0] = 218; // Width + padding[PAD_R1][1] = 28; // Height + padding[PAD_R1][2] = 726; // X + padding[PAD_R1][3] = 175; // Y + + // R2 + padding[PAD_R2][0] = 218; // Width + padding[PAD_R2][1] = 28; // Height + padding[PAD_R2][2] = 726; // X + padding[PAD_R2][3] = 104; // Y + + // Triangle + padding[PAD_TRIANGLE][0] = 218; // Width + padding[PAD_TRIANGLE][1] = 28; // Height + padding[PAD_TRIANGLE][2] = 726; // X + padding[PAD_TRIANGLE][3] = 246; // Y + + // Circle + padding[PAD_CIRCLE][0] = 218; // Width + padding[PAD_CIRCLE][1] = 28; // Height + padding[PAD_CIRCLE][2] = 726; // X + padding[PAD_CIRCLE][3] = 319; // Y + + // Cross + padding[PAD_CROSS][0] = 218; // Width + padding[PAD_CROSS][1] = 28; // Height + padding[PAD_CROSS][2] = 726; // X + padding[PAD_CROSS][3] = 391; // Y + + // Square + padding[PAD_SQUARE][0] = 218; // Width + padding[PAD_SQUARE][1] = 28; // Height + padding[PAD_SQUARE][2] = 726; // X + padding[PAD_SQUARE][3] = 463; // Y + + // Directional pad up + padding[PAD_UP][0] = 100; // Width + padding[PAD_UP][1] = 25; // Height + padding[PAD_UP][2] = 108; // X + padding[PAD_UP][3] = 290; // Y + + // Directional pad down + padding[PAD_DOWN][0] = 100; // Width + padding[PAD_DOWN][1] = 25; // Height + padding[PAD_DOWN][2] = 108; // X + padding[PAD_DOWN][3] = 340; // Y + + // Directional pad right + padding[PAD_RIGHT][0] = 109; // Width + padding[PAD_RIGHT][1] = 25; // Height + padding[PAD_RIGHT][2] = 159; // X + padding[PAD_RIGHT][3] = 315; // Y + + // Directional pad left + padding[PAD_LEFT][0] = 109; // Width + padding[PAD_LEFT][1] = 25; // Height + padding[PAD_LEFT][2] = 50; // X + padding[PAD_LEFT][3] = 315; // Y + + // Left Joystick up + padding[PAD_L_UP][0] = 100; // Width + padding[PAD_L_UP][1] = 25; // Height + padding[PAD_L_UP][2] = 325; // X + padding[PAD_L_UP][3] = 527; // Y + + // Left Joystick down + padding[PAD_L_DOWN][0] = 100; // Width + padding[PAD_L_DOWN][1] = 25; // Height + padding[PAD_L_DOWN][2] = 325; // X + padding[PAD_L_DOWN][3] = 577; // Y + + // Left Joystick right + padding[PAD_L_RIGHT][0] = 109; // Width + padding[PAD_L_RIGHT][1] = 25; // Height + padding[PAD_L_RIGHT][2] = 377; // X + padding[PAD_L_RIGHT][3] = 552; // Y + + // Left Joystick left + padding[PAD_L_LEFT][0] = 109; // Width + padding[PAD_L_LEFT][1] = 25; // Height + padding[PAD_L_LEFT][2] = 268; // X + padding[PAD_L_LEFT][3] = 552; // Y + + // L3 + padding[PAD_L3][0] = 218; // Width + padding[PAD_L3][1] = 28; // Height + padding[PAD_L3][2] = 268; // X + padding[PAD_L3][3] = 641; // Y + + // Right Joystick up + padding[PAD_R_UP][0] = 100; // Width + padding[PAD_R_UP][1] = 25; // Height + padding[PAD_R_UP][2] = 555; // X + padding[PAD_R_UP][3] = 527; // Y + + // Right Joystick down + padding[PAD_R_DOWN][0] = 100; // Width + padding[PAD_R_DOWN][1] = 25; // Height + padding[PAD_R_DOWN][2] = 555; // X + padding[PAD_R_DOWN][3] = 577; // Y + + // Right Joystick right + padding[PAD_R_RIGHT][0] = 109; // Width + padding[PAD_R_RIGHT][1] = 25; // Height + padding[PAD_R_RIGHT][2] = 607; // X + padding[PAD_R_RIGHT][3] = 552; // Y + + // Right Joystick left + padding[PAD_R_LEFT][0] = 109; // Width + padding[PAD_R_LEFT][1] = 25; // Height + padding[PAD_R_LEFT][2] = 498; // X + padding[PAD_R_LEFT][3] = 552; // Y + + // R3 + padding[PAD_R3][0] = 218; // Width + padding[PAD_R3][1] = 28; // Height + padding[PAD_R3][2] = 498; // X + padding[PAD_R3][3] = 641; // Y + + // Start + padding[PAD_START][0] = 218; // Width + padding[PAD_START][1] = 28; // Height + padding[PAD_START][2] = 503; // X + padding[PAD_START][3] = 34; // Y + + // Select + padding[PAD_SELECT][0] = 218; // Width + padding[PAD_SELECT][1] = 28; // Height + padding[PAD_SELECT][2] = 273; // X + padding[PAD_SELECT][3] = 34; // Y + + // Analog + padding[Analog][0] = 218; // Width + padding[Analog][1] = 28; // Height + padding[Analog][2] = 50; // X + padding[Analog][3] = 452; // Y + + // Left Joystick Configuration + padding[JoyL_config][0] = 180; // Width + padding[JoyL_config][1] = 28; // Height + padding[JoyL_config][2] = 50; // X + padding[JoyL_config][3] = 550; // Y + + // Right Joystick Configuration + padding[JoyR_config][0] = 180; // Width + padding[JoyR_config][1] = 28; // Height + padding[JoyR_config][2] = 764; // X + padding[JoyR_config][3] = 550; // Y + + // Gamepad Configuration + padding[Gamepad_config][0] = 180; // Width + padding[Gamepad_config][1] = 28; // Height + padding[Gamepad_config][2] = 50; // X + padding[Gamepad_config][3] = 585; // Y + + // Set All Buttons + padding[Set_all][0] = 180; // Width + padding[Set_all][1] = 28; // Height + padding[Set_all][2] = 764; // X + padding[Set_all][3] = 585; // Y + + // Apply modifications without exit + padding[Apply][0] = 70; // Width + padding[Apply][1] = 28; // Height + padding[Apply][2] = 833; // X + padding[Apply][3] = 642; // Y + + // Ok button + padding[Ok][0] = 70; // Width + padding[Ok][1] = 28; // Height + padding[Ok][2] = 913; // X + padding[Ok][3] = 642; // Y + + // Cancel button + padding[Cancel][0] = 70; // Width + padding[Cancel][1] = 28; // Height + padding[Cancel][2] = 753; // X + padding[Cancel][3] = 642; // Y + + // create a new Notebook + m_tab_gamepad = new wxNotebook(this, wxID_ANY); + for (int i = 0; i < GAMEPAD_NUMBER; ++i) { + // Tabs panels + m_pan_tabs[i] = new opPanel( + m_tab_gamepad, + wxID_ANY, + wxDefaultPosition, + wxSize(DEFAULT_WIDTH, DEFAULT_HEIGHT)); + // Add new page + // Define label + std::stringstream sstm; + std::string label = "Gamepad "; + sstm << label << i; + // New page creation + m_tab_gamepad->AddPage( + m_pan_tabs[i], // Parent + wxString(sstm.str().c_str(), wxConvUTF8) // Title + ); + + for (int j = 0; j < BUTTONS_LENGHT; ++j) { + // Gamepad buttons + m_bt_gamepad[i][j] = new wxButton( + m_pan_tabs[i], // Parent + wxID_HIGHEST + j + 1, // ID + _T("Undefined"), // Label + wxPoint(padding[j][2], padding[j][3]), // Position + wxSize(padding[j][0], padding[j][1]) // Size + ); + } + // Redefine others gui buttons label + m_bt_gamepad[i][JoyL_config]->SetLabel(_T("&Left Joystick Config")); + m_bt_gamepad[i][JoyR_config]->SetLabel(_T("&Right Joystick Config")); + m_bt_gamepad[i][Gamepad_config]->SetLabel(_T("&Gamepad Configuration")); + m_bt_gamepad[i][Set_all]->SetLabel(_T("&Set All Buttons")); + m_bt_gamepad[i][Cancel]->SetLabel(_T("&Cancel")); + m_bt_gamepad[i][Apply]->SetLabel(_T("&Apply")); + m_bt_gamepad[i][Ok]->SetLabel(_T("&Ok")); + + // Disable analog button (not yet supported) + m_bt_gamepad[i][Analog]->Disable(); + } + + Bind(wxEVT_BUTTON, &Dialog::OnButtonClicked, this); + + for (int i = 0; i < GAMEPAD_NUMBER; ++i) { + for (int j = 0; j < NB_IMG; ++j) { + m_pressed[i][j] = false; + } + } +} + +void Dialog::InitDialog() +{ + GamePad::EnumerateGamePads(s_vgamePad); // activate gamepads + LoadConfig(); // Load configuration from the ini file + repopulate(); // Set label and fit simulated key array +} + +/****************************************/ +/*********** Events functions ***********/ +/****************************************/ + +void Dialog::OnButtonClicked(wxCommandEvent &event) +{ + // Affichage d'un message à chaque clic sur le bouton + wxButton *bt_tmp = (wxButton *)event.GetEventObject(); // get the button object + int bt_id = bt_tmp->GetId() - wxID_HIGHEST - 1; // get the real ID + int gamepad_id = m_tab_gamepad->GetSelection(); // get the tab ID (equivalent to the gamepad id) + if (bt_id >= 0 && bt_id <= PAD_R_LEFT) { // if the button ID is a gamepad button + bt_tmp->Disable(); // switch the button state to "Disable" + config_key(gamepad_id, bt_id); + bt_tmp->Enable(); // switch the button state to "Enable" + } else if (bt_id == Gamepad_config) { // If the button ID is equals to the Gamepad_config button ID + GamepadConfiguration gamepad_config(gamepad_id, this); + + gamepad_config.InitGamepadConfiguration(); + gamepad_config.ShowModal(); + } else if (bt_id == JoyL_config) { // If the button ID is equals to the JoyL_config button ID + JoystickConfiguration joystick_config(gamepad_id, true, this); + + joystick_config.InitJoystickConfiguration(); + joystick_config.ShowModal(); + } else if (bt_id == JoyR_config) { // If the button ID is equals to the JoyR_config button ID + JoystickConfiguration joystick_config(gamepad_id, false, this); + + joystick_config.InitJoystickConfiguration(); + joystick_config.ShowModal(); + } else if (bt_id == Set_all) { // If the button ID is equals to the Set_all button ID + for (int i = 0; i < MAX_KEYS; ++i) { + bt_tmp = m_bt_gamepad[gamepad_id][i]; + switch (i) { + case PAD_L_UP: // Left joystick (Up) ↑ + m_pan_tabs[gamepad_id]->ShowImg(img_l_arrow_up); + break; + case PAD_L_RIGHT: // Left joystick (Right) → + m_pan_tabs[gamepad_id]->ShowImg(img_l_arrow_right); + break; + case PAD_L_DOWN: // Left joystick (Down) ↓ + m_pan_tabs[gamepad_id]->ShowImg(img_l_arrow_bottom); + break; + case PAD_L_LEFT: // Left joystick (Left) ← + m_pan_tabs[gamepad_id]->ShowImg(img_l_arrow_left); + break; + case PAD_R_UP: // Right joystick (Up) ↑ + m_pan_tabs[gamepad_id]->ShowImg(img_r_arrow_up); + break; + case PAD_R_RIGHT: // Right joystick (Right) → + m_pan_tabs[gamepad_id]->ShowImg(img_r_arrow_right); + break; + case PAD_R_DOWN: // Right joystick (Down) ↓ + m_pan_tabs[gamepad_id]->ShowImg(img_r_arrow_bottom); + break; + case PAD_R_LEFT: // Right joystick (Left) ← + m_pan_tabs[gamepad_id]->ShowImg(img_r_arrow_left); + break; + default: + m_pan_tabs[gamepad_id]->ShowImg(i); + break; + } + m_pan_tabs[gamepad_id]->Refresh(); + m_pan_tabs[gamepad_id]->Update(); + config_key(gamepad_id, i); + switch (i) { + case PAD_L_UP: // Left joystick (Up) ↑ + m_pan_tabs[gamepad_id]->HideImg(img_l_arrow_up); + break; + case PAD_L_RIGHT: // Left joystick (Right) → + m_pan_tabs[gamepad_id]->HideImg(img_l_arrow_right); + break; + case PAD_L_DOWN: // Left joystick (Down) ↓ + m_pan_tabs[gamepad_id]->HideImg(img_l_arrow_bottom); + break; + case PAD_L_LEFT: // Left joystick (Left) ← + m_pan_tabs[gamepad_id]->HideImg(img_l_arrow_left); + break; + case PAD_R_UP: // Right joystick (Up) ↑ + m_pan_tabs[gamepad_id]->HideImg(img_r_arrow_up); + break; + case PAD_R_RIGHT: // Right joystick (Right) → + m_pan_tabs[gamepad_id]->HideImg(img_r_arrow_right); + break; + case PAD_R_DOWN: // Right joystick (Down) ↓ + m_pan_tabs[gamepad_id]->HideImg(img_r_arrow_bottom); + break; + case PAD_R_LEFT: // Right joystick (Left) ← + m_pan_tabs[gamepad_id]->HideImg(img_r_arrow_left); + break; + default: + m_pan_tabs[gamepad_id]->HideImg(i); + break; + } + m_pan_tabs[gamepad_id]->Refresh(); + m_pan_tabs[gamepad_id]->Update(); + usleep(500000); // give enough time to the user to release the button + } + } else if (bt_id == Ok) { // If the button ID is equals to the Ok button ID + SaveConfig(); // Save the configuration + Close(); // Close the window + } else if (bt_id == Apply) { // If the button ID is equals to the Apply button ID + SaveConfig(); // Save the configuration + } else if (bt_id == Cancel) { // If the button ID is equals to the cancel button ID + Close(); // Close the window + } +} + +/****************************************/ +/*********** Methods functions **********/ +/****************************************/ + +void Dialog::config_key(int pad, int key) +{ + bool captured = false; + u32 key_pressed = 0; + + while (!captured) { + if (PollForNewKeyboardKeys(key_pressed)) { + // special case for keyboard/mouse to handle multiple keys + // Note: key_pressed == 0 when ESC is hit to abort the capture + if (key_pressed > 0) { + clear_key(pad, key); + set_keyboard_key(pad, key_pressed, key); + m_simulatedKeys[pad][key] = key_pressed; + } + captured = true; + } + } + m_bt_gamepad[pad][key]->SetLabel( + KeyName(pad, key, m_simulatedKeys[pad][key]).c_str()); +} + +void Dialog::clear_key(int pad, int key) +{ + // Erase the keyboard binded key + u32 keysim = m_simulatedKeys[pad][key]; + m_simulatedKeys[pad][key] = 0; + + // erase gamepad entry (keysim map) + g_conf.keysym_map[pad].erase(keysim); +} + + +// Set button values +void Dialog::repopulate() +{ + for (int gamepad_id = 0; gamepad_id < GAMEPAD_NUMBER; ++gamepad_id) { + // keyboard/mouse key + for (const auto &it : g_conf.keysym_map[gamepad_id]) { + int keysym = it.first; + int key = it.second; + + m_bt_gamepad[gamepad_id][key]->SetLabel( + KeyName(gamepad_id, key, keysym).c_str()); + + m_simulatedKeys[gamepad_id][key] = keysym; + } + } +} + +// Main +void DisplayDialog() +{ + if (g_conf.ftw) { + wxString info("The OnePad GUI is provided to map the keyboard/mouse to the virtual PS2 pad.\n\n" + "Gamepads/Joysticks are plug and play. The active gamepad can be selected in the 'Gamepad Configuration' panel.\n\n" + "If you prefer to manually map your gamepad, you should use the 'onepad-legacy' plugin instead."); + + wxMessageDialog ftw(nullptr, info); + ftw.ShowModal(); + + g_conf.ftw = 0; + SaveConfig(); + } + + Dialog dialog; + + dialog.InitDialog(); + dialog.ShowModal(); +} diff --git a/pcsx2/PAD/Linux/wx_dialog/dialog.h b/pcsx2/PAD/Linux/wx_dialog/dialog.h new file mode 100644 index 0000000000..ac0228b552 --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/dialog.h @@ -0,0 +1,98 @@ +/* dialog.h + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#pragma once + +#ifndef __DIALOG_H__ +#define __DIALOG_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../GamePad.h" +#include "../keyboard.h" +#include "../onepad.h" +#include "opPanel.h" + +#include "GamepadConfiguration.h" +#include "JoystickConfiguration.h" + +// Allow to found quickly button id +// e.g L2 → 0, triangle → 4, ... +// see onepad.h for more details about gamepad button id + +enum gui_buttons { + Analog = PAD_R_LEFT + 1, // Analog button (not yet supported ?) + JoyL_config, // Left Joystick Configuration + JoyR_config, // Right Joystick Configuration + Gamepad_config, // Gamepad Configuration + Set_all, // Set all buttons + Apply, // Apply modifications without exit + Ok, // Apply modifications and exit + Cancel // Exit without apply modificatons +}; + +#define BUTTONS_LENGHT 32 // numbers of buttons on the gamepad +#define UPDATE_TIME 5 +#define DEFAULT_WIDTH 1000 +#define DEFAULT_HEIGHT 740 + +class Dialog : public wxDialog +{ + // Panels + opPanel *m_pan_tabs[GAMEPAD_NUMBER]; // Gamepad Tabs box + // Notebooks + wxNotebook *m_tab_gamepad; // Joysticks Tabs + // Buttons + wxButton *m_bt_gamepad[GAMEPAD_NUMBER][BUTTONS_LENGHT]; // Joystick button use to modify the button mapping + // Contain all simulated key + u32 m_simulatedKeys[GAMEPAD_NUMBER][MAX_KEYS]; + // Timer + wxTimer m_time_update_gui; + // Check if the gui must display feddback image + bool m_pressed[GAMEPAD_NUMBER][NB_IMG]; + + // methods + void config_key(int, int); + void clear_key(int, int); + void repopulate(); + + // Events + void OnButtonClicked(wxCommandEvent &); + void JoystickEvent(wxTimerEvent &); + +public: + Dialog(); + void InitDialog(); + void show(); +}; + +extern void DisplayDialog(); // Main function + +#endif // __DIALOG_H__ diff --git a/pcsx2/PAD/Linux/wx_dialog/opPanel.cpp b/pcsx2/PAD/Linux/wx_dialog/opPanel.cpp new file mode 100644 index 0000000000..dfc2a4dafe --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/opPanel.cpp @@ -0,0 +1,237 @@ +/* opPanel.cpp + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#include "opPanel.h" +#include "ImgHeader/dualshock2.h" +#include "ImgHeader/cross.h" +#include "ImgHeader/circle.h" +#include "ImgHeader/square.h" +#include "ImgHeader/triangle.h" +#include "ImgHeader/dp_left.h" +#include "ImgHeader/dp_right.h" +#include "ImgHeader/dp_up.h" +#include "ImgHeader/dp_bottom.h" +#include "ImgHeader/l1.h" +#include "ImgHeader/r1.h" +#include "ImgHeader/l2.h" +#include "ImgHeader/l3.h" +#include "ImgHeader/r2.h" +#include "ImgHeader/r3.h" +#include "ImgHeader/start.h" +#include "ImgHeader/select.h" +#include "ImgHeader/analog.h" +#include "ImgHeader/joystick_cursor.h" +#include "ImgHeader/arrow_up.h" +#include "ImgHeader/arrow_right.h" +#include "ImgHeader/arrow_bottom.h" +#include "ImgHeader/arrow_left.h" + +opPanel::opPanel(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize) + : wxPanel(parent, id, pos, size) +{ + m_picture[img_background] = EmbeddedImage().Get(); + + m_picture[img_start] = EmbeddedImage().Get(); + m_picture[img_select] = EmbeddedImage().Get(); + m_picture[img_analog] = EmbeddedImage().Get(); + + m_picture[img_dp_left] = EmbeddedImage().Get(); + m_picture[img_dp_right] = EmbeddedImage().Get(); + m_picture[img_dp_up] = EmbeddedImage().Get(); + m_picture[img_dp_bottom] = EmbeddedImage().Get(); + + m_picture[img_square] = EmbeddedImage().Get(); + m_picture[img_circle] = EmbeddedImage().Get(); + m_picture[img_cross] = EmbeddedImage().Get(); + m_picture[img_triangle] = EmbeddedImage().Get(); + + m_picture[img_l1] = EmbeddedImage().Get(); + m_picture[img_l3] = EmbeddedImage().Get(); + m_picture[img_l2] = EmbeddedImage().Get(); + + m_picture[img_r1] = EmbeddedImage().Get(); + m_picture[img_r3] = EmbeddedImage().Get(); + m_picture[img_r2] = EmbeddedImage().Get(); + + m_picture[img_left_cursor] = EmbeddedImage().Get(); + m_picture[img_right_cursor] = EmbeddedImage().Get(); + + m_picture[img_l_arrow_up] = EmbeddedImage().Get(); + m_picture[img_l_arrow_right] = EmbeddedImage().Get(); + m_picture[img_l_arrow_bottom] = EmbeddedImage().Get(); + m_picture[img_l_arrow_left] = EmbeddedImage().Get(); + + m_picture[img_r_arrow_up] = EmbeddedImage().Get(); + m_picture[img_r_arrow_right] = EmbeddedImage().Get(); + m_picture[img_r_arrow_bottom] = EmbeddedImage().Get(); + m_picture[img_r_arrow_left] = EmbeddedImage().Get(); + + for (int i = 0; i < NB_IMG; ++i) { + m_show_image[i] = false; + HideImg(i); + } + ShowImg(img_background); + m_show_image[img_background] = true; + + m_left_cursor_x = 0; + m_left_cursor_y = 0; + m_right_cursor_x = 0; + m_right_cursor_y = 0; +} + +void opPanel::HideImg(int id) +{ + if (id < NB_IMG) { + m_show_image[id] = false; + Refresh(); + } +} + +void opPanel::ShowImg(int id) +{ + if (id < NB_IMG) { + m_show_image[id] = true; + Refresh(); + } +} + +void opPanel::MoveJoystick(int axe, int value) +{ + if (axe == 0) { + m_left_cursor_x = value * 30 / 40000; + } else if (axe == 1) { + m_left_cursor_y = value * 30 / 40000; + } else if (axe == 2) { + m_right_cursor_x = value * 30 / 40000; + } else { + m_right_cursor_y = value * 30 / 40000; + } +} + +wxBEGIN_EVENT_TABLE(opPanel, wxPanel) +EVT_PAINT(opPanel::OnPaint) +wxEND_EVENT_TABLE() + +void opPanel::OnPaint(wxPaintEvent &event) +{ + wxPaintDC dc(this); + + wxMemoryDC temp_background, temp_start, temp_select, temp_analog, temp_dp_left, + temp_dp_right, temp_dp_up, temp_dp_bottom, temp_l1, temp_r1, temp_L3, temp_l2_2, + temp_R3, temp_r2_2, temp_square, temp_circle, temp_cross, temp_triangle, + temp_left_cursor, temp_right_cursor, temp_l_arrow_up, temp_l_arrow_right, + temp_l_arrow_bottom, temp_l_arrow_left, temp_r_arrow_up, temp_r_arrow_right, + temp_r_arrow_bottom, temp_r_arrow_left; + + temp_background.SelectObject(m_picture[img_background]); + temp_start.SelectObject(m_picture[img_start]); + temp_select.SelectObject(m_picture[img_select]); + temp_analog.SelectObject(m_picture[img_analog]); + temp_dp_left.SelectObject(m_picture[img_dp_left]); + + temp_dp_right.SelectObject(m_picture[img_dp_right]); + temp_dp_up.SelectObject(m_picture[img_dp_up]); + temp_dp_bottom.SelectObject(m_picture[img_dp_bottom]); + temp_l1.SelectObject(m_picture[img_l1]); + temp_r1.SelectObject(m_picture[img_r1]); + temp_L3.SelectObject(m_picture[img_l3]); + temp_l2_2.SelectObject(m_picture[img_l2]); + + temp_R3.SelectObject(m_picture[img_r3]); + temp_r2_2.SelectObject(m_picture[img_r2]); + temp_square.SelectObject(m_picture[img_square]); + temp_circle.SelectObject(m_picture[img_circle]); + temp_cross.SelectObject(m_picture[img_cross]); + temp_triangle.SelectObject(m_picture[img_triangle]); + + temp_left_cursor.SelectObject(m_picture[img_left_cursor]); + temp_right_cursor.SelectObject(m_picture[img_right_cursor]); + + temp_l_arrow_up.SelectObject(m_picture[img_l_arrow_up]); + temp_l_arrow_right.SelectObject(m_picture[img_l_arrow_right]); + temp_l_arrow_bottom.SelectObject(m_picture[img_l_arrow_bottom]); + temp_l_arrow_left.SelectObject(m_picture[img_l_arrow_left]); + + temp_r_arrow_up.SelectObject(m_picture[img_r_arrow_up]); + temp_r_arrow_right.SelectObject(m_picture[img_r_arrow_right]); + temp_r_arrow_bottom.SelectObject(m_picture[img_r_arrow_bottom]); + temp_r_arrow_left.SelectObject(m_picture[img_r_arrow_left]); + + if (m_show_image[img_background]) + dc.Blit(wxPoint(0, 0), temp_background.GetSize(), &temp_background, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_start]) + dc.Blit(wxPoint(526, 296), temp_start.GetSize(), &temp_start, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_select]) + dc.Blit(wxPoint(450, 297), temp_select.GetSize(), &temp_select, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_analog]) + dc.Blit(wxPoint(489, 358), temp_analog.GetSize(), &temp_analog, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_dp_left]) + dc.Blit(wxPoint(334, 292), temp_dp_left.GetSize(), &temp_dp_left, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_dp_right]) + dc.Blit(wxPoint(378, 292), temp_dp_right.GetSize(), &temp_dp_right, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_dp_up]) + dc.Blit(wxPoint(358, 269), temp_dp_up.GetSize(), &temp_dp_up, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_dp_bottom]) + dc.Blit(wxPoint(358, 312), temp_dp_bottom.GetSize(), &temp_dp_bottom, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l1]) + dc.Blit(wxPoint(343, 186), temp_l1.GetSize(), &temp_l1, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r1]) + dc.Blit(wxPoint(593, 186), temp_r1.GetSize(), &temp_r1, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l3]) + dc.Blit(wxPoint(409, 344), temp_L3.GetSize(), &temp_L3, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l2]) + dc.Blit(wxPoint(346, 158), temp_l2_2.GetSize(), &temp_l2_2, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r3]) + dc.Blit(wxPoint(525, 344), temp_R3.GetSize(), &temp_R3, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r2]) + dc.Blit(wxPoint(582, 158), temp_r2_2.GetSize(), &temp_r2_2, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_square]) + dc.Blit(wxPoint(573, 287), temp_square.GetSize(), &temp_square, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_circle]) + dc.Blit(wxPoint(647, 287), temp_circle.GetSize(), &temp_circle, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_cross]) + dc.Blit(wxPoint(610, 324), temp_cross.GetSize(), &temp_cross, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_triangle]) + dc.Blit(wxPoint(610, 250), temp_triangle.GetSize(), &temp_triangle, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_left_cursor]) + dc.Blit(wxPoint(439 + m_left_cursor_x, 374 + m_left_cursor_y), temp_left_cursor.GetSize(), &temp_left_cursor, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_right_cursor]) + dc.Blit(wxPoint(555 + m_right_cursor_x, 374 + m_right_cursor_y), temp_right_cursor.GetSize(), &temp_right_cursor, wxPoint(0, 0), wxCOPY, true); + + if (m_show_image[img_l_arrow_up]) + dc.Blit(wxPoint(433, 357), temp_l_arrow_up.GetSize(), &temp_l_arrow_up, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l_arrow_right]) + dc.Blit(wxPoint(423, 368), temp_l_arrow_right.GetSize(), &temp_l_arrow_right, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l_arrow_bottom]) + dc.Blit(wxPoint(433, 357), temp_l_arrow_bottom.GetSize(), &temp_l_arrow_bottom, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_l_arrow_left]) + dc.Blit(wxPoint(423, 368), temp_l_arrow_left.GetSize(), &temp_l_arrow_left, wxPoint(0, 0), wxCOPY, true); + + if (m_show_image[img_r_arrow_up]) + dc.Blit(wxPoint(548, 357), temp_r_arrow_up.GetSize(), &temp_r_arrow_up, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r_arrow_right]) + dc.Blit(wxPoint(539, 368), temp_r_arrow_right.GetSize(), &temp_r_arrow_right, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r_arrow_bottom]) + dc.Blit(wxPoint(548, 357), temp_r_arrow_bottom.GetSize(), &temp_r_arrow_bottom, wxPoint(0, 0), wxCOPY, true); + if (m_show_image[img_r_arrow_left]) + dc.Blit(wxPoint(539, 368), temp_r_arrow_left.GetSize(), &temp_r_arrow_left, wxPoint(0, 0), wxCOPY, true); +} diff --git a/pcsx2/PAD/Linux/wx_dialog/opPanel.h b/pcsx2/PAD/Linux/wx_dialog/opPanel.h new file mode 100644 index 0000000000..ba8fa902ea --- /dev/null +++ b/pcsx2/PAD/Linux/wx_dialog/opPanel.h @@ -0,0 +1,77 @@ +/* opPanel.h + * PCSX2 Dev Team + * Copyright (C) 2015 + * + * 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 + */ + +#pragma once + +#ifndef __OPPANEL_H__ +#define __OPPANEL_H__ + +#include + +#include "EmbeddedImage.h" + +enum gui_img { + img_l2, + img_r2, + img_l1, + img_r1, + img_triangle, + img_circle, + img_cross, + img_square, + img_select, + img_l3, + img_r3, + img_start, + img_dp_up, + img_dp_right, + img_dp_bottom, + img_dp_left, + img_left_cursor, + img_right_cursor, + img_analog, + img_background, // background pic + img_l_arrow_up, + img_l_arrow_right, + img_l_arrow_bottom, + img_l_arrow_left, + img_r_arrow_up, + img_r_arrow_right, + img_r_arrow_bottom, + img_r_arrow_left +}; + +#define NB_IMG 28 + +class opPanel : public wxPanel +{ + wxBitmap m_picture[NB_IMG]; + bool m_show_image[NB_IMG]; + int m_left_cursor_x, m_left_cursor_y, m_right_cursor_x, m_right_cursor_y; + wxDECLARE_EVENT_TABLE(); + void OnPaint(wxPaintEvent &event); + +public: + opPanel(wxWindow *, wxWindowID, const wxPoint &, const wxSize &); + void HideImg(int); + void ShowImg(int); + void MoveJoystick(int, int); +}; + +#endif // __OPPANEL_H__