From ef3435441f7a86d2062f2eeaa0508455c296feaf Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sat, 15 Apr 2017 14:57:00 +0200 Subject: [PATCH] onepad: create a legacy version for SDL1 The legacy version is the version 1.3 The new version is the version 2.0. It would be based on SDL2 only Distribution information. If you link wxWidget with SDL, you will need to be sure it is SDL2 or upgrade. You can build wxWidget with SDL2 with the following trick export SDL_CONFIG=/usr/bin/sdl2-config ./configure --with-sdl ..... --- cmake/SelectPcsx2Plugins.cmake | 14 +- plugins/CMakeLists.txt | 4 + plugins/onepad/CMakeLists.txt | 11 +- plugins/onepad/Linux/ini.cpp | 4 +- plugins/onepad/SDL/joystick.cpp | 27 +- plugins/onepad/SDL/joystick.h | 6 - plugins/onepad/onepad.cpp | 4 +- plugins/onepad_legacy/CMakeLists.txt | 132 ++++ plugins/onepad_legacy/GamePad.cpp | 55 ++ plugins/onepad_legacy/GamePad.h | 155 +++++ plugins/onepad_legacy/KeyStatus.cpp | 198 ++++++ plugins/onepad_legacy/KeyStatus.h | 80 +++ .../Linux/GamepadConfiguration.cpp | 273 ++++++++ .../Linux/GamepadConfiguration.h | 60 ++ .../Linux/JoystickConfiguration.cpp | 250 +++++++ .../Linux/JoystickConfiguration.h | 60 ++ plugins/onepad_legacy/Linux/dialog.cpp | 640 ++++++++++++++++++ plugins/onepad_legacy/Linux/dialog.h | 100 +++ plugins/onepad_legacy/Linux/ini.cpp | 217 ++++++ plugins/onepad_legacy/Linux/linux.cpp | 203 ++++++ plugins/onepad_legacy/Linux/linux.h | 26 + plugins/onepad_legacy/Linux/opPanel.cpp | 237 +++++++ plugins/onepad_legacy/Linux/opPanel.h | 77 +++ plugins/onepad_legacy/SDL/joystick.cpp | 363 ++++++++++ plugins/onepad_legacy/SDL/joystick.h | 96 +++ plugins/onepad_legacy/Windows/placeholder | 0 plugins/onepad_legacy/bitwise.h | 44 ++ plugins/onepad_legacy/controller.cpp | 114 ++++ plugins/onepad_legacy/controller.h | 144 ++++ plugins/onepad_legacy/keyboard.cpp | 311 +++++++++ plugins/onepad_legacy/keyboard.h | 46 ++ plugins/onepad_legacy/onepad.cpp | 364 ++++++++++ plugins/onepad_legacy/onepad.h | 141 ++++ plugins/onepad_legacy/state_management.cpp | 467 +++++++++++++ plugins/onepad_legacy/state_management.h | 119 ++++ 35 files changed, 4997 insertions(+), 45 deletions(-) create mode 100644 plugins/onepad_legacy/CMakeLists.txt create mode 100644 plugins/onepad_legacy/GamePad.cpp create mode 100644 plugins/onepad_legacy/GamePad.h create mode 100644 plugins/onepad_legacy/KeyStatus.cpp create mode 100644 plugins/onepad_legacy/KeyStatus.h create mode 100644 plugins/onepad_legacy/Linux/GamepadConfiguration.cpp create mode 100644 plugins/onepad_legacy/Linux/GamepadConfiguration.h create mode 100644 plugins/onepad_legacy/Linux/JoystickConfiguration.cpp create mode 100644 plugins/onepad_legacy/Linux/JoystickConfiguration.h create mode 100644 plugins/onepad_legacy/Linux/dialog.cpp create mode 100644 plugins/onepad_legacy/Linux/dialog.h create mode 100644 plugins/onepad_legacy/Linux/ini.cpp create mode 100644 plugins/onepad_legacy/Linux/linux.cpp create mode 100644 plugins/onepad_legacy/Linux/linux.h create mode 100644 plugins/onepad_legacy/Linux/opPanel.cpp create mode 100644 plugins/onepad_legacy/Linux/opPanel.h create mode 100644 plugins/onepad_legacy/SDL/joystick.cpp create mode 100644 plugins/onepad_legacy/SDL/joystick.h create mode 100644 plugins/onepad_legacy/Windows/placeholder create mode 100644 plugins/onepad_legacy/bitwise.h create mode 100644 plugins/onepad_legacy/controller.cpp create mode 100644 plugins/onepad_legacy/controller.h create mode 100644 plugins/onepad_legacy/keyboard.cpp create mode 100644 plugins/onepad_legacy/keyboard.h create mode 100644 plugins/onepad_legacy/onepad.cpp create mode 100644 plugins/onepad_legacy/onepad.h create mode 100644 plugins/onepad_legacy/state_management.cpp create mode 100644 plugins/onepad_legacy/state_management.h diff --git a/cmake/SelectPcsx2Plugins.cmake b/cmake/SelectPcsx2Plugins.cmake index 95c24fd74f..f42bcd773b 100644 --- a/cmake/SelectPcsx2Plugins.cmake +++ b/cmake/SelectPcsx2Plugins.cmake @@ -216,10 +216,10 @@ endif() #--------------------------------------- # onepad #--------------------------------------- -# requires: -SDL +# requires: -SDL2 # -X11 #--------------------------------------- -if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND) +if(wxWidgets_FOUND AND GTKn_FOUND AND SDL2_FOUND AND X11_FOUND) set(onepad TRUE) elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad") set(onepad FALSE) @@ -227,6 +227,16 @@ else() set(onepad FALSE) print_dep("Skip build of onepad: miss some dependencies" "${msg_dep_onepad}") endif() + +# old version of the plugin that still support SDL1 +if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND) + set(onepad_legacy TRUE) +elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy") + set(onepad_legacy FALSE) +else() + set(onepad_legacy FALSE) + print_dep("Skip build of onepad_legacy: miss some dependencies" "${msg_dep_onepad}") +endif() #--------------------------------------- #--------------------------------------- diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c1bd8417f6..7e3fc17de0 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -46,6 +46,10 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad" AND onepad) add_subdirectory(onepad) endif() +if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" AND onepad_legacy) + add_subdirectory(onepad_legacy) +endif() + if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/PadNull" AND PadNull) add_subdirectory(PadNull) endif() diff --git a/plugins/onepad/CMakeLists.txt b/plugins/onepad/CMakeLists.txt index 613270e239..a1a2fca1e8 100644 --- a/plugins/onepad/CMakeLists.txt +++ b/plugins/onepad/CMakeLists.txt @@ -38,7 +38,7 @@ set(onepadGuiResources ) # plugin name -set(Output onepad-1.3.0) +set(Output onepad) set(onepadFinalFlags "") # onepad sources @@ -86,13 +86,8 @@ set(onepadWindowsSources set(onepadWindowsHeaders ) -if (SDL2_API) - set(onepadFinalLibs ${SDL2_LIBRARIES}) - add_definitions(-DSDL_BUILD) -else() - set(onepadFinalLibs ${SDL_LIBRARY}) - add_definitions(-DSDL_BUILD) -endif() +set(onepadFinalLibs ${SDL2_LIBRARIES}) +add_definitions(-DSDL_BUILD) set(onepadFinalLibs ${onepadFinalLibs} diff --git a/plugins/onepad/Linux/ini.cpp b/plugins/onepad/Linux/ini.cpp index 3431abfc0f..c53cc9a9e1 100644 --- a/plugins/onepad/Linux/ini.cpp +++ b/plugins/onepad/Linux/ini.cpp @@ -122,7 +122,7 @@ void SaveConfig() { FILE *f; - const std::string iniFile(s_strIniPath + "OnePAD.ini"); + 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()); @@ -160,7 +160,7 @@ void LoadConfig() conf->init(); - const std::string iniFile(s_strIniPath + "OnePAD.ini"); + 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()); diff --git a/plugins/onepad/SDL/joystick.cpp b/plugins/onepad/SDL/joystick.cpp index 8ffba0fc70..df670ae201 100644 --- a/plugins/onepad/SDL/joystick.cpp +++ b/plugins/onepad/SDL/joystick.cpp @@ -46,20 +46,17 @@ void JoystickInfo::EnumerateJoysticks(vector &vjoysticks) { if (!s_bSDLInit) { -#if SDL_MAJOR_VERSION >= 2 // Tell SDL to catch event even if the windows isn't focussed SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0) return; + // WTF! Give me back the control of my system struct sigaction action = {0}; action.sa_handler = SIG_DFL; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); -#else - if (SDL_Init(SDL_INIT_JOYSTICK) < 0) - return; -#endif + SDL_JoystickEventState(SDL_QUERY); s_bSDLInit = true; } @@ -82,7 +79,6 @@ void JoystickInfo::EnumerateJoysticks(vector &vjoysticks) void JoystickInfo::GenerateDefaultEffect() { -#if SDL_MAJOR_VERSION >= 2 for (int i = 0; i < NB_EFFECT; i++) { SDL_HapticEffect effect; memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default @@ -99,7 +95,6 @@ void JoystickInfo::GenerateDefaultEffect() effect.periodic.attack_length = 0; effects[i] = effect; } -#endif } void JoystickInfo::Rumble(int type, int pad) @@ -109,7 +104,6 @@ void JoystickInfo::Rumble(int type, int pad) if (!(conf->pad_options[pad].forcefeedback)) return; -#if SDL_MAJOR_VERSION >= 2 if (haptic == NULL) return; @@ -142,28 +136,20 @@ void JoystickInfo::Rumble(int type, int pad) if (SDL_HapticRunEffect(haptic, id, 1) != 0) { fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id); } -#endif } void JoystickInfo::Destroy() { if (joy != NULL) { -#if SDL_MAJOR_VERSION >= 2 // Haptic must be closed before the joystick if (haptic != NULL) { SDL_HapticClose(haptic); haptic = NULL; } -#endif -#if SDL_MAJOR_VERSION >= 2 #if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly if (joy) SDL_JoystickClose(joy); -#endif -#else - if (SDL_JoystickOpened(_id)) - SDL_JoystickClose(joy); #endif joy = NULL; } @@ -183,11 +169,7 @@ bool JoystickInfo::Init(int id) numaxes = SDL_JoystickNumAxes(joy); numbuttons = SDL_JoystickNumButtons(joy); numhats = SDL_JoystickNumHats(joy); -#if SDL_MAJOR_VERSION >= 2 devname = SDL_JoystickName(joy); -#else - devname = SDL_JoystickName(id); -#endif vaxisstate.resize(numaxes); vbuttonstate.resize(numbuttons); @@ -207,7 +189,6 @@ bool JoystickInfo::Init(int id) numbuttons += 4; // the 4 hat buttons } -#if SDL_MAJOR_VERSION >= 2 if (haptic == NULL) { if (!SDL_JoystickIsHaptic(joy)) { PAD_LOG("Haptic devices not supported!\n"); @@ -216,7 +197,6 @@ bool JoystickInfo::Init(int id) first = true; } } -#endif //PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats); return true; @@ -234,7 +214,6 @@ void JoystickInfo::SaveState() bool JoystickInfo::TestForce(float strength = 0.60) { -#if SDL_MAJOR_VERSION >= 2 // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox if (haptic == NULL) return false; // Otherwise, core dump! @@ -245,8 +224,6 @@ bool JoystickInfo::TestForce(float strength = 0.60) return false; } -#endif - return true; } diff --git a/plugins/onepad/SDL/joystick.h b/plugins/onepad/SDL/joystick.h index fe76c38a3e..097b1736a6 100644 --- a/plugins/onepad/SDL/joystick.h +++ b/plugins/onepad/SDL/joystick.h @@ -22,9 +22,7 @@ #pragma once #include -#if SDL_MAJOR_VERSION >= 2 #include -#endif #include "GamePad.h" #include "onepad.h" @@ -38,12 +36,10 @@ public: : GamePad() , joy(nullptr) { -#if SDL_MAJOR_VERSION >= 2 haptic = nullptr; first = true; memset(effects, 0, sizeof(effects)); memset(effects_id, 0, sizeof(effects_id)); -#endif } ~JoystickInfo() @@ -87,10 +83,8 @@ private: void GenerateDefaultEffect(); SDL_Joystick *joy; -#if SDL_MAJOR_VERSION >= 2 SDL_Haptic *haptic; bool first; SDL_HapticEffect effects[NB_EFFECT]; int effects_id[NB_EFFECT]; -#endif }; diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index add8c38f0d..57c9a7b158 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -47,8 +47,8 @@ std::string s_strLogPath("logs/"); bool toggleAutoRepeat = false; const u32 version = PS2E_PAD_VERSION; -const u32 revision = 1; -const u32 build = 3; // increase that with each 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; diff --git a/plugins/onepad_legacy/CMakeLists.txt b/plugins/onepad_legacy/CMakeLists.txt new file mode 100644 index 0000000000..4039a685da --- /dev/null +++ b/plugins/onepad_legacy/CMakeLists.txt @@ -0,0 +1,132 @@ +# 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_legacy/ImgHeader") +set(image_sources "${CMAKE_SOURCE_DIR}/plugins/onepad/Img") +set(linux_sources "Linux") +set(linux_headers "Linux") + + +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-legacy) +set(onepadFinalFlags "") + +# onepad sources +set(onepadSources + controller.cpp + GamePad.cpp + SDL/joystick.cpp + keyboard.cpp + KeyStatus.cpp + onepad.cpp + state_management.cpp) + +# onepad headers +set(onepadHeaders + bitwise.h + controller.h + GamePad.h + SDL/joystick.h + keyboard.h + KeyStatus.h + onepad.h + state_management.h) + +# onepad Linux sources +set(onepadLinuxSources + ${linux_sources}/ini.cpp + ${linux_sources}/dialog.cpp + ${linux_sources}/linux.cpp + ${linux_sources}/opPanel.cpp + ${linux_sources}/GamepadConfiguration.cpp + ${linux_headers}/JoystickConfiguration.cpp) + +# onepad Linux headers +set(onepadLinuxHeaders + ${linux_headers}/linux.h + ${linux_headers}/opPanel.h + ${linux_headers}/GamepadConfiguration.h + ${linux_headers}/JoystickConfiguration.h) + +# onepad Windows sources +set(onepadWindowsSources + ) + +# onepad Windows headers +set(onepadWindowsHeaders + ) + +if (SDL2_API) + set(onepadFinalLibs ${SDL2_LIBRARIES}) + add_definitions(-DSDL_BUILD) +else() + set(onepadFinalLibs ${SDL_LIBRARY}) + add_definitions(-DSDL_BUILD) +endif() + +set(onepadFinalLibs + ${onepadFinalLibs} + ${wxWidgets_LIBRARIES} + ${GTK2_LIBRARIES} + ${X11_LIBRARIES} +) + +set(onepadFinalSources + ${onepadSources} + ${onepadHeaders} + ${onepadLinuxSources} + ${onepadLinuxHeaders} + ${onepadGuiResources} +) + +include_directories( + ${CMAKE_BINARY_DIR}/plugins/onepad_legacy +) + +### 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() + +if(BUILTIN_PAD) + add_pcsx2_lib(${Output} "${onepadFinalSources}" "${onepadFinalLibs}" "${onepadFinalFlags}") +else() + add_pcsx2_plugin(${Output} "${onepadFinalSources}" "${onepadFinalLibs}" "${onepadFinalFlags}") +endif() diff --git a/plugins/onepad_legacy/GamePad.cpp b/plugins/onepad_legacy/GamePad.cpp new file mode 100644 index 0000000000..0d0b8158dc --- /dev/null +++ b/plugins/onepad_legacy/GamePad.cpp @@ -0,0 +1,55 @@ +#include "GamePad.h" +#ifdef SDL_BUILD +#include "SDL/joystick.h" +#endif + +vector s_vgamePad; +bool GamePadIdWithinBounds(int GamePadId) +{ + return ((GamePadId >= 0) && (GamePadId < (int)s_vgamePad.size())); +} + +/** + * 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(vector &vgamePad) +{ +#ifdef SDL_BUILD + JoystickInfo::EnumerateJoysticks(vgamePad); +#endif +} + +void GamePad::UpdateReleaseState() +{ +#ifdef SDL_BUILD + JoystickInfo::UpdateReleaseState(); +#endif +} + +/** + * Safely dispatch to the Rumble method above + **/ +void GamePad::DoRumble(int type, int pad) +{ + u32 id = conf->get_joyid(pad); + if (GamePadIdWithinBounds(id)) { + GamePad *gamePad = s_vgamePad[id]; + if (gamePad) + gamePad->Rumble(type, pad); + } +} + +/** + * Update state of every attached devices + **/ +void GamePad::UpdateGamePadState() +{ +#ifdef SDL_BUILD + SDL_JoystickUpdate(); // No need to make yet another function call for that +#endif +} diff --git a/plugins/onepad_legacy/GamePad.h b/plugins/onepad_legacy/GamePad.h new file mode 100644 index 0000000000..030b66a0b3 --- /dev/null +++ b/plugins/onepad_legacy/GamePad.h @@ -0,0 +1,155 @@ +#pragma once + +#include "onepad.h" +#include "controller.h" +#ifdef SDL_BUILD +#include +#define HAT_UP SDL_HAT_UP +#define HAT_DOWN SDL_HAT_DOWN +#define HAT_RIGHT SDL_HAT_RIGHT +#define HAT_LEFT SDL_HAT_LEFT +#endif + +class GamePad +{ +public: + GamePad() + : devname("") + , _id(-1) + , numbuttons(0) + , numaxes(0) + , numhats(0) + , deadzone(1500) + , pad(-1) + { + vbuttonstate.clear(); + vaxisstate.clear(); + vhatstate.clear(); + } + + virtual ~GamePad() + { + return; + } + + 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(vector &vgamePad); + static void UpdateReleaseState(); + /** + * Update state of every attached devices + **/ + static void UpdateGamePadState(); + + /** + * Causes devices to rumble + * Rumble will differ according to type which is either 0(small motor) or 1(big motor) + **/ + virtual void Rumble(int type, int pad) { return; } + /** + * Safely dispatch to the Rumble method above + **/ + static void DoRumble(int type, int pad); + + virtual bool Init(int id) { return false; } // opens a handle and gets information + + /** + * Used for GUI checkbox to give feedback to the user + **/ + virtual bool TestForce(float strength = 0.6) { return false; } + + virtual bool PollButtons(u32 &pkey) { return false; } + virtual bool PollAxes(u32 &pkey) { return false; } + virtual bool PollHats(u32 &pkey) { return false; } + + virtual int GetHat(int key_to_axis) + { + return 0; + } + + virtual int GetButton(int key_to_button) + { + return 0; + } + + const string &GetName() + { + return devname; + } + + int GetPAD() + { + return pad; + } + + int GetNumButtons() + { + return numbuttons; + } + + int GetNumAxes() + { + return numaxes; + } + + int GetNumHats() + { + return numhats; + } + + virtual int GetDeadzone() + { + return deadzone; + } + + virtual void SaveState() {} + + int GetButtonState(int i) + { + return vbuttonstate[i]; + } + + int GetAxisState(int i) + { + return vaxisstate[i]; + } + + int GetHatState(int i) + { + //PAD_LOG("Getting POV State of %d.\n", i); + return vhatstate[i]; + } + + void SetButtonState(int i, int state) + { + vbuttonstate[i] = state; + } + + void SetAxisState(int i, int value) + { + vaxisstate[i] = value; + } + + void SetHatState(int i, int value) + { + //PAD_LOG("We should set %d to %d.\n", i, value); + vhatstate[i] = value; + } + + virtual int GetAxisFromKey(int pad, int index) { return 0; } + // These fields need to be inherited by child classes +protected: + string devname; // pretty device name + int _id; + int numbuttons, numaxes, numhats; + int deadzone; + int pad; + vector vbuttonstate, vaxisstate, vhatstate; +}; + +extern vector s_vgamePad; +extern bool GamePadIdWithinBounds(int joyid); diff --git a/plugins/onepad_legacy/KeyStatus.cpp b/plugins/onepad_legacy/KeyStatus.cpp new file mode 100644 index 0000000000..ce9021c90e --- /dev/null +++ b/plugins/onepad_legacy/KeyStatus.cpp @@ -0,0 +1,198 @@ +/* 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 + */ + +#include "KeyStatus.h" + +void KeyStatus::Init() +{ + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + m_button[pad] = 0xFFFF; + m_internal_button_kbd[pad] = 0xFFFF; + m_internal_button_joy[pad] = 0xFFFF; + m_state_acces[pad] = false; + + for (int index = 0; index < MAX_KEYS; index++) { + m_button_pressure[pad][index] = 0xFF; + m_internal_button_pressure[pad][index] = 0xFF; + } + + m_analog[pad].lx = m_analog_released_val; + m_analog[pad].ly = m_analog_released_val; + m_analog[pad].rx = m_analog_released_val; + m_analog[pad].ry = m_analog_released_val; + m_internal_analog_kbd[pad].lx = m_analog_released_val; + m_internal_analog_kbd[pad].ly = m_analog_released_val; + m_internal_analog_kbd[pad].rx = m_analog_released_val; + m_internal_analog_kbd[pad].ry = m_analog_released_val; + m_internal_analog_joy[pad].lx = m_analog_released_val; + m_internal_analog_joy[pad].ly = m_analog_released_val; + m_internal_analog_joy[pad].rx = m_analog_released_val; + m_internal_analog_joy[pad].ry = m_analog_released_val; + } +} + +void KeyStatus::press(u32 pad, u32 index, s32 value) +{ + if (!IsAnalogKey(index)) { + m_internal_button_pressure[pad][index] = value; + if (m_state_acces[pad]) + clear_bit(m_internal_button_kbd[pad], index); + else + clear_bit(m_internal_button_joy[pad], index); + } else { + // clamp value + if (value > 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 (conf->pad_options[pad].reverse_lx); + + case PAD_R_LEFT: + case PAD_R_RIGHT: + return (conf->pad_options[pad].reverse_rx); + + case PAD_L_UP: + case PAD_L_DOWN: + return (conf->pad_options[pad].reverse_ly); + + case PAD_R_DOWN: + case PAD_R_UP: + return (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/plugins/onepad_legacy/KeyStatus.h b/plugins/onepad_legacy/KeyStatus.h new file mode 100644 index 0000000000..340c07df4f --- /dev/null +++ b/plugins/onepad_legacy/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 *key_status; + +#endif diff --git a/plugins/onepad_legacy/Linux/GamepadConfiguration.cpp b/plugins/onepad_legacy/Linux/GamepadConfiguration.cpp new file mode 100644 index 0000000000..556613a879 --- /dev/null +++ b/plugins/onepad_legacy/Linux/GamepadConfiguration.cpp @@ -0,0 +1,273 @@ +/* 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" + +// Construtor of GamepadConfiguration +GamepadConfiguration::GamepadConfiguration(int pad, wxWindow *parent) + : wxDialog( + parent, // Parent + wxID_ANY, // ID + _T("Gamepad configuration"), // Title + wxDefaultPosition, // Position + wxSize(400, 230), // Width + Lenght + // Style + wxSYSTEM_MENU | + wxCAPTION | + wxCLOSE_BOX | + wxCLIP_CHILDREN) +{ + + m_pad_id = pad; + m_pan_gamepad_config = new wxPanel( + this, // Parent + wxID_ANY, // ID + wxDefaultPosition, // Prosition + wxSize(300, 200) // Size + ); + m_cb_rumble = new wxCheckBox( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + _T("&Enable rumble"), // Label + wxPoint(20, 20) // Position + ); + + m_cb_hack_sixaxis_usb = new wxCheckBox( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + _T("&Hack: Sixaxis/DS3 plugged in USB"), // Label + wxPoint(20, 40) // Position + ); + + m_cb_hack_sixaxis_pressure = new wxCheckBox( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + _T("&Hack: Sixaxis/DS3 pressure"), // Label + wxPoint(20, 60) // Position + ); + + wxString txt_rumble = wxT("Rumble intensity"); + m_lbl_rumble_intensity = new wxStaticText( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + txt_rumble, // Text which must be displayed + wxPoint(20, 90), // Position + wxDefaultSize // Size + ); + + m_sl_rumble_intensity = new wxSlider( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + 0, // value + 0, // min value 0x0000 + 0x7FFF, // max value 0x7FFF + wxPoint(150, 83), // Position + wxSize(200, 30) // Size + ); + + wxString txt_joystick = wxT("Joystick sensibility"); + m_lbl_rumble_intensity = new wxStaticText( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + txt_joystick, // Text which must be displayed + wxPoint(20, 120), // Position + wxDefaultSize // Size + ); + + m_sl_joystick_sensibility = new wxSlider( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + 0, // value + 0, // min value + 100, // max value + wxPoint(150, 113), // Position + wxSize(200, 30) // Size + ); + + m_bt_ok = new wxButton( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + _T("&OK"), // Label + wxPoint(250, 160), // Position + wxSize(60, 25) // Size + ); + + m_bt_cancel = new wxButton( + m_pan_gamepad_config, // Parent + wxID_ANY, // ID + _T("&Cancel"), // Label + wxPoint(320, 160), // Position + wxSize(60, 25) // Size + ); + + Bind(wxEVT_BUTTON, &GamepadConfiguration::OnButtonClicked, this); + Bind(wxEVT_SCROLL_THUMBRELEASE, &GamepadConfiguration::OnSliderReleased, this); + Bind(wxEVT_CHECKBOX, &GamepadConfiguration::OnCheckboxChange, this); + + repopulate(); +} + +/** + 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 gamepad 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 + } +} + +/****************************************/ +/*********** Events functions ***********/ +/****************************************/ + +/** + * Button event, called when a button is clicked +*/ +void GamepadConfiguration::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(); // get the real ID + if (bt_id == m_bt_ok->GetId()) { // If the button ID is equals to the Ok button ID + Close(); // Close the window + } else if (bt_id == m_bt_cancel->GetId()) { // If the button ID is equals to the cancel button ID + reset(); // reinitialize the value of each parameters + Close(); // Close the window + } +} + +/** + * 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(); // get the slider object + int sl_id = sl_tmp->GetId(); // slider id + if (sl_id == m_sl_rumble_intensity->GetId()) { // if this is the rumble intensity slider + u32 intensity = m_sl_rumble_intensity->GetValue(); // get the new value + conf->set_ff_intensity(intensity); // and set the force feedback intensity value with it + // get the rumble intensity + float strength = m_sl_rumble_intensity->GetValue(); + /* + * convert in a float value between 0 and 1, and run rumble feedback + * 1 -> 0x7FFF + * 0 -> 0x0000 + * x -> ? + * + * formula : strength = x*1/0x7FFF + * x : intensity variable + * 0x7FFF : maximum intensity + * 1 : maximum value of the intensity for the sdl rumble test + */ + s_vgamePad[m_pad_id]->TestForce(strength / 0x7FFF); + } else if (sl_id == m_sl_joystick_sensibility->GetId()) { + u32 sensibility = m_sl_joystick_sensibility->GetValue(); // get the new value + conf->set_sensibility(sensibility); // and set the joystick sensibility + } +} + +/** + * 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 == m_cb_rumble->GetId()) { + 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(); + } + } else if (cb_id == m_cb_hack_sixaxis_usb->GetId()) { + conf->pad_options[m_pad_id].sixaxis_usb = (m_cb_hack_sixaxis_usb->GetValue()) ? (u32)1 : (u32)0; + } else if (cb_id == m_cb_hack_sixaxis_pressure->GetId()) { + conf->pad_options[m_pad_id].sixaxis_pressure = (m_cb_hack_sixaxis_pressure->GetValue()) ? (u32)1 : (u32)0; + } +} + +/****************************************/ +/*********** Methods functions **********/ +/****************************************/ + +// Reset checkbox and slider values +void GamepadConfiguration::reset() +{ + m_cb_rumble->SetValue(m_init_rumble); + m_cb_hack_sixaxis_usb->SetValue(m_init_hack_sixaxis); + m_cb_hack_sixaxis_pressure->SetValue(m_init_hack_sixaxis_pressure); + m_sl_rumble_intensity->SetValue(m_init_rumble_intensity); + m_sl_joystick_sensibility->SetValue(m_init_joystick_sensibility); +} + +// Set button values +void GamepadConfiguration::repopulate() +{ + bool val = conf->pad_options[m_pad_id].forcefeedback; + m_init_rumble = val; + m_cb_rumble->SetValue(val); + val = conf->pad_options[m_pad_id].sixaxis_usb; + m_init_hack_sixaxis = val; + m_cb_hack_sixaxis_usb->SetValue(val); + val = conf->pad_options[m_pad_id].sixaxis_pressure; + m_init_hack_sixaxis_pressure = val; + m_cb_hack_sixaxis_pressure->SetValue(val); + int tmp = conf->get_ff_intensity(); + m_sl_rumble_intensity->SetValue(tmp); + m_init_rumble_intensity = tmp; + tmp = conf->get_sensibility(); + m_sl_joystick_sensibility->SetValue(tmp); + m_init_joystick_sensibility = tmp; + + // enable rumble intensity slider if the checkbox is checked + if (m_cb_rumble->GetValue()) + m_sl_rumble_intensity->Enable(); + else // disable otherwise + m_sl_rumble_intensity->Disable(); +} diff --git a/plugins/onepad_legacy/Linux/GamepadConfiguration.h b/plugins/onepad_legacy/Linux/GamepadConfiguration.h new file mode 100644 index 0000000000..9b6bd7ff21 --- /dev/null +++ b/plugins/onepad_legacy/Linux/GamepadConfiguration.h @@ -0,0 +1,60 @@ +/* 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 +#include +#include +#include +#include +#include "GamePad.h" +#include "keyboard.h" +#include "onepad.h" + +class GamepadConfiguration : public wxDialog +{ + wxPanel *m_pan_gamepad_config; + wxCheckBox *m_cb_rumble, *m_cb_hack_sixaxis_usb, *m_cb_hack_sixaxis_pressure; + wxSlider *m_sl_rumble_intensity, *m_sl_joystick_sensibility; + wxButton *m_bt_ok, *m_bt_cancel; + wxStaticText *m_lbl_rumble_intensity; + + u32 m_pad_id; + u32 m_init_rumble_intensity, m_init_joystick_sensibility; + bool m_init_rumble, m_init_hack_sixaxis, m_init_hack_sixaxis_pressure; + + // methods + void repopulate(); + void reset(); + // Events + void OnButtonClicked(wxCommandEvent &); + void OnSliderReleased(wxCommandEvent &); + void OnCheckboxChange(wxCommandEvent &); + +public: + GamepadConfiguration(int, wxWindow *); + void InitGamepadConfiguration(); +}; + +#endif // __GAMEPADCONFIGURATION_H__ diff --git a/plugins/onepad_legacy/Linux/JoystickConfiguration.cpp b/plugins/onepad_legacy/Linux/JoystickConfiguration.cpp new file mode 100644 index 0000000000..3a39047893 --- /dev/null +++ b/plugins/onepad_legacy/Linux/JoystickConfiguration.cpp @@ -0,0 +1,250 @@ +/* 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" + +// Construtor of JoystickConfiguration +JoystickConfiguration::JoystickConfiguration(int pad, bool left, wxWindow *parent) + : wxDialog( + parent, // Parent + wxID_ANY, // ID + _T("Gamepad configuration"), // Title + wxDefaultPosition, // Position + wxSize(400, 200), // Width + Lenght + // Style + wxSYSTEM_MENU | + wxCAPTION | + wxCLOSE_BOX | + wxCLIP_CHILDREN) +{ + m_init_reverse_Lx = false; + m_init_reverse_Ly = false; + m_init_reverse_Rx = false; + m_init_reverse_Ry = false; + m_init_mouse_Ljoy = false; + m_init_mouse_Rjoy = false; + + m_pad_id = pad; + m_isForLeftJoystick = left; + m_pan_joystick_config = new wxPanel( + this, // Parent + wxID_ANY, // ID + wxDefaultPosition, // Prosition + wxSize(300, 200) // Size + ); + + if (m_isForLeftJoystick) { + m_cb_reverse_Lx = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Reverse Lx"), // Label + wxPoint(20, 20) // Position + ); + + m_cb_reverse_Ly = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Reverse Ly"), // Label + wxPoint(20, 40) // Position + ); + + m_cb_mouse_Ljoy = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Use mouse for left analog joystick"), // Label + wxPoint(20, 60) // Position + ); + + m_cb_reverse_Rx = nullptr; + m_cb_reverse_Ry = nullptr; + m_cb_mouse_Rjoy = nullptr; + } else { + m_cb_reverse_Rx = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Reverse Rx"), // Label + wxPoint(20, 20) // Position + ); + + m_cb_reverse_Ry = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Reverse Ry"), // Label + wxPoint(20, 40) // Position + ); + + m_cb_mouse_Rjoy = new wxCheckBox( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("Use mouse for right analog joystick"), // Label + wxPoint(20, 60) // Position + ); + + m_cb_reverse_Lx = nullptr; + m_cb_reverse_Ly = nullptr; + m_cb_mouse_Ljoy = nullptr; + } + + m_bt_ok = new wxButton( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("&OK"), // Label + wxPoint(250, 130), // Position + wxSize(60, 25) // Size + ); + + m_bt_cancel = new wxButton( + m_pan_joystick_config, // Parent + wxID_ANY, // ID + _T("&Cancel"), // Label + wxPoint(320, 130), // Position + wxSize(60, 25) // Size + ); + + Bind(wxEVT_BUTTON, &JoystickConfiguration::OnButtonClicked, this); + Bind(wxEVT_CHECKBOX, &JoystickConfiguration::OnCheckboxChange, this); +} + +/** + 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 gamepad connected, + * Prevent to use a none initialized value on s_vgamePad (core dump) + */ + if (s_vgamePad.size() < m_pad_id + 1) { + wxMessageBox(L"No gamepad detected."); + // disable all checkbox + if (m_isForLeftJoystick) { + m_cb_reverse_Lx->Disable(); + m_cb_reverse_Ly->Disable(); + } else { + m_cb_reverse_Rx->Disable(); + m_cb_reverse_Ry->Disable(); + } + } +} + +/****************************************/ +/*********** Events functions ***********/ +/****************************************/ + +/** + * Button event, called when a button is clicked +*/ +void JoystickConfiguration::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(); // get the real ID + if (bt_id == m_bt_ok->GetId()) { // If the button ID is equals to the Ok button ID + Close(); // Close the window + } else if (bt_id == m_bt_cancel->GetId()) { // If the button ID is equals to the cancel button ID + reset(); // reinitialize the value of each parameters + Close(); // Close the window + } +} + +/** + * 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(); + bool val; + if (m_isForLeftJoystick) { + if (cb_id == m_cb_reverse_Ly->GetId()) { + val = m_cb_reverse_Ly->GetValue(); + conf->pad_options[m_pad_id].reverse_ly = val; + } else if (cb_id == m_cb_reverse_Lx->GetId()) { + val = m_cb_reverse_Lx->GetValue(); + conf->pad_options[m_pad_id].reverse_lx = val; + } else if (cb_id == m_cb_mouse_Ljoy->GetId()) { + val = m_cb_mouse_Ljoy->GetValue(); + conf->pad_options[m_pad_id].mouse_l = val; + } + } else { + if (cb_id == m_cb_reverse_Ry->GetId()) { + val = m_cb_reverse_Ry->GetValue(); + conf->pad_options[m_pad_id].reverse_ry = val; + } else if (cb_id == m_cb_reverse_Rx->GetId()) { + val = m_cb_reverse_Rx->GetValue(); + conf->pad_options[m_pad_id].reverse_rx = val; + } else if (cb_id == m_cb_mouse_Rjoy->GetId()) { + val = m_cb_mouse_Rjoy->GetValue(); + conf->pad_options[m_pad_id].mouse_r = val; + } + } +} + +/****************************************/ +/*********** 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() +{ + bool val; + if (m_isForLeftJoystick) { + val = conf->pad_options[m_pad_id].reverse_lx; + m_init_reverse_Lx = val; + m_cb_reverse_Lx->SetValue(val); + + val = conf->pad_options[m_pad_id].reverse_ly; + m_init_reverse_Ly = val; + m_cb_reverse_Ly->SetValue(val); + + val = conf->pad_options[m_pad_id].mouse_l; + m_init_mouse_Ljoy = val; + m_cb_mouse_Ljoy->SetValue(val); + } else { + val = conf->pad_options[m_pad_id].reverse_rx; + m_init_reverse_Rx = val; + m_cb_reverse_Rx->SetValue(val); + + val = conf->pad_options[m_pad_id].reverse_ry; + m_init_reverse_Ry = val; + m_cb_reverse_Ry->SetValue(val); + + val = conf->pad_options[m_pad_id].mouse_r; + m_init_mouse_Rjoy = val; + m_cb_mouse_Rjoy->SetValue(val); + } +} diff --git a/plugins/onepad_legacy/Linux/JoystickConfiguration.h b/plugins/onepad_legacy/Linux/JoystickConfiguration.h new file mode 100644 index 0000000000..d486483be0 --- /dev/null +++ b/plugins/onepad_legacy/Linux/JoystickConfiguration.h @@ -0,0 +1,60 @@ +/* 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 +#include +#include +#include +#include +#include "GamePad.h" +#include "keyboard.h" +#include "onepad.h" + +class JoystickConfiguration : public wxDialog +{ + wxPanel *m_pan_joystick_config; + 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 + wxButton *m_bt_ok, *m_bt_cancel; + + 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 OnButtonClicked(wxCommandEvent &); + void OnCheckboxChange(wxCommandEvent &); + +public: + JoystickConfiguration(int, bool, wxWindow *); + void InitJoystickConfiguration(); +}; + +#endif // __JOYSTICKCONFIGURATION_H__ diff --git a/plugins/onepad_legacy/Linux/dialog.cpp b/plugins/onepad_legacy/Linux/dialog.cpp new file mode 100644 index 0000000000..7dc220ddb8 --- /dev/null +++ b/plugins/onepad_legacy/Linux/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" + +// 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); + + m_time_update_gui.SetOwner(this); + Bind(wxEVT_TIMER, &Dialog::JoystickEvent, this); + m_time_update_gui.Start(UPDATE_TIME, wxTIMER_CONTINUOUS); + + 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 + } +} + +void Dialog::JoystickEvent(wxTimerEvent &event) +{ +#ifdef SDL_BUILD + u32 key; + int map; + std::map::iterator it; + std::map::iterator it2; + SDL_JoystickEventState(SDL_ENABLE); + SDL_Event events; + while (SDL_PollEvent(&events)) { + switch (events.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + break; + case SDL_JOYAXISMOTION: + if (events.jaxis.which < GAMEPAD_NUMBER) { + key = axis_to_key(false, (events.jaxis.value < 0), events.jaxis.axis); + it = m_map_images[events.jaxis.which].find(key); + if (it != m_map_images[events.jaxis.which].end()) { + map = m_map_images[events.jaxis.which][key]; + if (events.jaxis.value == 0) { + if (map >= PAD_L_UP && map <= PAD_L_LEFT) + m_pan_tabs[events.jaxis.which]->HideImg(img_left_cursor); + else if (map >= PAD_R_UP && map <= PAD_R_LEFT) + m_pan_tabs[events.jaxis.which]->HideImg(img_right_cursor); + else if (map < PAD_L_UP) + m_pan_tabs[events.jaxis.which]->HideImg(map); + } else { + if (map >= PAD_L_UP && map <= PAD_L_LEFT) { + m_pan_tabs[events.jaxis.which]->MoveJoystick(events.jaxis.axis, events.jaxis.value); + m_pan_tabs[events.jaxis.which]->ShowImg(img_left_cursor); + } else if (map >= PAD_R_UP && map <= PAD_R_LEFT) { + m_pan_tabs[events.jaxis.which]->MoveJoystick(events.jaxis.axis, events.jaxis.value); + m_pan_tabs[events.jaxis.which]->ShowImg(img_right_cursor); + } else if (map < PAD_L_UP) { // if this is not a joystick + m_pan_tabs[events.jaxis.which]->ShowImg(map); + } + } + break; + } + // Hack Dualshock 4 (L2, R2) + key = axis_to_key(false, (events.jaxis.value > 0), events.jaxis.axis); + it2 = m_map_images[events.jaxis.which].find(key); + if (it2 != m_map_images[events.jaxis.which].end()) { + map = m_map_images[events.jaxis.which][key]; + if (map < PAD_L_UP) { // if this is not a joystick + m_pan_tabs[events.jaxis.which]->HideImg(map); + } + break; + } + } + break; + case SDL_JOYBUTTONDOWN: + if (events.jbutton.which < GAMEPAD_NUMBER) { + key = button_to_key(events.jbutton.button); + it = m_map_images[events.jbutton.which].find(key); + if (it != m_map_images[events.jbutton.which].end()) { + map = m_map_images[events.jbutton.which][key]; + m_pan_tabs[events.jbutton.which]->ShowImg(map); + } + } + break; + case SDL_JOYBUTTONUP: + if (events.jbutton.which < GAMEPAD_NUMBER) { + key = button_to_key(events.jbutton.button); + it = m_map_images[events.jbutton.which].find(key); + if (it != m_map_images[events.jbutton.which].end()) { + map = m_map_images[events.jbutton.which][key]; + m_pan_tabs[events.jbutton.which]->HideImg(map); + } + } + break; + case SDL_JOYHATMOTION: + if (events.jhat.which < GAMEPAD_NUMBER) { + switch (events.jhat.value) { + case SDL_HAT_UP: + key = hat_to_key(events.jhat.value, events.jhat.hat); + it = m_map_images[events.jhat.which].find(key); + if (it != m_map_images[events.jhat.which].end()) { + m_pan_tabs[events.jhat.which]->ShowImg(img_dp_up); + } + break; + case SDL_HAT_DOWN: + key = hat_to_key(events.jhat.value, events.jhat.hat); + it = m_map_images[events.jhat.which].find(key); + if (it != m_map_images[events.jhat.which].end()) { + m_pan_tabs[events.jhat.which]->ShowImg(img_dp_bottom); + } + break; + case SDL_HAT_RIGHT: + key = hat_to_key(events.jhat.value, events.jhat.hat); + it = m_map_images[events.jhat.which].find(key); + if (it != m_map_images[events.jhat.which].end()) { + m_pan_tabs[events.jhat.which]->ShowImg(img_dp_right); + } + break; + case SDL_HAT_LEFT: + key = hat_to_key(events.jhat.value, events.jhat.hat); + it = m_map_images[events.jhat.which].find(key); + if (it != m_map_images[events.jhat.which].end()) { + m_pan_tabs[events.jhat.which]->ShowImg(img_dp_left); + } + break; + case SDL_HAT_CENTERED: + m_pan_tabs[events.jhat.which]->HideImg(img_dp_up); + m_pan_tabs[events.jhat.which]->HideImg(img_dp_bottom); + m_pan_tabs[events.jhat.which]->HideImg(img_dp_right); + m_pan_tabs[events.jhat.which]->HideImg(img_dp_left); + } + } + break; + default: + break; + } + } +#endif // SDL_BUILD +} + +/****************************************/ +/*********** Methods functions **********/ +/****************************************/ + +void Dialog::config_key(int pad, int key) +{ + bool captured = false; + u32 key_pressed = 0; + + // I don't have any guarantee that not-yet-pressed state is egual to released state + GamePad::UpdateReleaseState(); + while (!captured) { + vector::iterator itjoy; + if (PollX11KeyboardMouseEvent(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_keyboad_key(pad, key_pressed, key); + m_simulatedKeys[pad][key] = key_pressed; + m_map_images[pad][key_pressed] = key; + } + captured = true; + } else { + GamePad::UpdateGamePadState(); + + itjoy = s_vgamePad.begin(); + while ((itjoy != s_vgamePad.end()) && (!captured)) { + if ((*itjoy)->PollButtons(key_pressed)) { + clear_key(pad, key); + set_key(pad, key, key_pressed); + m_map_images[pad][key_pressed] = key; + captured = true; + } else if ((*itjoy)->PollAxes(key_pressed)) { + clear_key(pad, key); + set_key(pad, key, key_pressed); + m_map_images[pad][key_pressed] = key; + captured = true; + } else if ((*itjoy)->PollHats(key_pressed)) { + clear_key(pad, key); + set_key(pad, key, key_pressed); + m_map_images[pad][key_pressed] = key; + captured = true; + } + ++itjoy; + } + } + } + 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) + std::map::iterator it1; + it1 = conf->keysym_map[pad].find(keysim); + if (it1 != conf->keysym_map[pad].end()) + conf->keysym_map[pad].erase(it1); + + // erase gamepad entry (image map) + int val = get_key(pad, key); + std::map::iterator it2; + it2 = m_map_images[pad].find(val); + if (it2 != m_map_images[pad].end()) { + m_map_images[pad].erase(it2); + } + + // Erase the keyboard image map + //m_map_images[pad].erase(keysim); + // Erase the Gamepad binded key + set_key(pad, key, 0); +} + + +// Set button values +void Dialog::repopulate() +{ + for (int gamepad_id = 0; gamepad_id < GAMEPAD_NUMBER; ++gamepad_id) { + for (int key = 0; key < MAX_KEYS; key++) { + if (get_key(gamepad_id, key) != 0) { + m_bt_gamepad[gamepad_id][key]->SetLabel( + KeyName(gamepad_id, key).c_str()); + + m_map_images[gamepad_id][get_key(gamepad_id, key)] = key; + } + } + + // keyboard/mouse key + map::iterator it; + for (it = conf->keysym_map[gamepad_id].begin(); + it != conf->keysym_map[gamepad_id].end(); ++it) { + 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; + m_map_images[gamepad_id][keysym] = key; + } + } +} + +// Main +void DisplayDialog() +{ + Dialog dialog; + + dialog.InitDialog(); + dialog.ShowModal(); +} diff --git a/plugins/onepad_legacy/Linux/dialog.h b/plugins/onepad_legacy/Linux/dialog.h new file mode 100644 index 0000000000..ee10a80b86 --- /dev/null +++ b/plugins/onepad_legacy/Linux/dialog.h @@ -0,0 +1,100 @@ +/* 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]; + // Map the key pressed with the feedback image id + std::map m_map_images[GAMEPAD_NUMBER]; + + // 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/plugins/onepad_legacy/Linux/ini.cpp b/plugins/onepad_legacy/Linux/ini.cpp new file mode 100644 index 0000000000..3431abfc0f --- /dev/null +++ b/plugins/onepad_legacy/Linux/ini.cpp @@ -0,0 +1,217 @@ +/* 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" +#include "linux.h" + +extern std::string s_strIniPath; + +string KeyName(int pad, int key, int keysym) +{ + string tmp; + tmp.resize(28); + + if (keysym) { + if (keysym < 10) { + // mouse + switch (keysym) { + case 1: + sprintf(&tmp[0], "Mouse Left"); + break; + case 2: + sprintf(&tmp[0], "Mouse Middle"); + break; + case 3: + sprintf(&tmp[0], "Mouse Right"); + break; + default: // Use only number for extra button + sprintf(&tmp[0], "Mouse %d", keysym); + } + } else { + // keyboard + char *pstr = XKeysymToString(keysym); + if (pstr != NULL) + tmp = pstr; + } + } else { + // joystick + KeyType k = type_of_joykey(pad, key); + switch (k) { + case PAD_JOYBUTTONS: { + int button = key_to_button(pad, key); + sprintf(&tmp[0], "JBut %d", button); + break; + } + case PAD_AXIS: { + if (key_to_axis_type(pad, key)) + sprintf(&tmp[0], "JAxis %d Full", key_to_axis(pad, key)); + else + sprintf(&tmp[0], "JAxis %d Half%s", key_to_axis(pad, key), key_to_axis_sign(pad, key) ? "-" : "+"); + break; + } + case PAD_HAT: { + int axis = key_to_axis(pad, key); + switch (key_to_hat_dir(pad, key)) { + case HAT_UP: + sprintf(&tmp[0], "JPOVU-%d", axis); + break; + + case HAT_RIGHT: + sprintf(&tmp[0], "JPOVR-%d", axis); + break; + + case HAT_DOWN: + sprintf(&tmp[0], "JPOVD-%d", axis); + break; + + case HAT_LEFT: + sprintf(&tmp[0], "JPOVL-%d", axis); + break; + } + break; + } + default: + break; + } + } + + return tmp; +} + +void DefaultKeyboardValues() +{ + set_keyboad_key(0, XK_a, PAD_L2); + set_keyboad_key(0, XK_semicolon, PAD_R2); + set_keyboad_key(0, XK_w, PAD_L1); + set_keyboad_key(0, XK_p, PAD_R1); + set_keyboad_key(0, XK_i, PAD_TRIANGLE); + set_keyboad_key(0, XK_l, PAD_CIRCLE); + set_keyboad_key(0, XK_k, PAD_CROSS); + set_keyboad_key(0, XK_j, PAD_SQUARE); + set_keyboad_key(0, XK_v, PAD_SELECT); + set_keyboad_key(0, XK_n, PAD_START); + set_keyboad_key(0, XK_e, PAD_UP); + set_keyboad_key(0, XK_f, PAD_RIGHT); + set_keyboad_key(0, XK_d, PAD_DOWN); + set_keyboad_key(0, XK_s, PAD_LEFT); +} + +void SaveConfig() +{ + FILE *f; + + const std::string iniFile(s_strIniPath + "OnePAD.ini"); + f = fopen(iniFile.c_str(), "w"); + if (f == NULL) { + printf("OnePAD: failed to save ini %s\n", iniFile.c_str()); + return; + } + + fprintf(f, "log = %d\n", conf->log); + fprintf(f, "options = %d\n", conf->packed_options); + fprintf(f, "mouse_sensibility = %d\n", conf->get_sensibility()); + fprintf(f, "joy_pad_map = %d\n", conf->joyid_map); + fprintf(f, "ff_intensity = %d\n", conf->get_ff_intensity()); + + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + for (int key = 0; key < MAX_KEYS; key++) { + fprintf(f, "[%d][%d] = 0x%x\n", pad, key, get_key(pad, key)); + } + } + + map::iterator it; + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) + for (it = conf->keysym_map[pad].begin(); it != conf->keysym_map[pad].end(); ++it) + fprintf(f, "PAD %d:KEYSYM 0x%x = %d\n", pad, it->first, it->second); + + fclose(f); +} + +void LoadConfig() +{ + FILE *f; + char str[256]; + bool have_user_setting = false; + + if (!conf) + conf = new PADconf; + + conf->init(); + + const std::string iniFile(s_strIniPath + "OnePAD.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, "log = %u\n", &value) == 0) + goto error; + conf->log = value; + if (fscanf(f, "options = %u\n", &value) == 0) + goto error; + conf->packed_options = value; + if (fscanf(f, "mouse_sensibility = %u\n", &value) == 0) + goto error; + conf->set_sensibility(value); + if (fscanf(f, "joy_pad_map = %u\n", &value) == 0) + goto error; + // Value is now hardcoded in controller.h avoid to reload a bad + // value from an old ini file. + //conf->joyid_map = value; + if (fscanf(f, "ff_intensity = %u\n", &value) == 0) + goto error; + conf->set_ff_intensity(value); + + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + for (int key = 0; key < MAX_KEYS; key++) { + sprintf(str, "[%d][%d] = 0x%%x\n", pad, key); + u32 temp = 0; + + if (fscanf(f, str, &temp) == 0) + temp = 0; + set_key(pad, key, temp); + if (temp && pad == 0) + have_user_setting = true; + } + } + + u32 pad; + u32 keysym; + u32 index; + while (fscanf(f, "PAD %u:KEYSYM 0x%x = %u\n", &pad, &keysym, &index) != EOF) { + set_keyboad_key(pad & 1, keysym, index); + if (pad == 0) + have_user_setting = true; + } + + if (!have_user_setting) + DefaultKeyboardValues(); + +error: + fclose(f); +} diff --git a/plugins/onepad_legacy/Linux/linux.cpp b/plugins/onepad_legacy/Linux/linux.cpp new file mode 100644 index 0000000000..43f6b27820 --- /dev/null +++ b/plugins/onepad_legacy/Linux/linux.cpp @@ -0,0 +1,203 @@ +/* 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 +#include "linux.h" + +Display *GSdsp; +Window GSwin; + +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; + + GtkWidget *dialog; + dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", msg); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +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) +{ + GSdsp = *(Display **)pDsp; + GSwin = (Window) * (((u32 *)pDsp) + 1); + + SetAutoRepeat(false); + return 0; +} + +void _PADclose() +{ + SetAutoRepeat(true); + + vector::iterator it = s_vgamePad.begin(); + + // Delete everything in the vector vjoysticks. + while (it != s_vgamePad.end()) { + delete *it; + ++it; + } + + s_vgamePad.clear(); +} + +void PollForJoystickInput(int cpad) +{ + int joyid = conf->get_joyid(cpad); + if (!GamePadIdWithinBounds(joyid)) + return; + + GamePad::UpdateGamePadState(); + for (int i = 0; i < MAX_KEYS; i++) { + GamePad *gamePad = s_vgamePad[joyid]; + + switch (type_of_joykey(cpad, i)) { + case PAD_JOYBUTTONS: { + + int value = gamePad->GetButton(key_to_button(cpad, i)); + if (value) + key_status->press(cpad, i); + else + key_status->release(cpad, i); + + break; + } + case PAD_HAT: { + int value = gamePad->GetHat(key_to_axis(cpad, i)); + + // key_to_hat_dir and SDL_JoystickGetHat are a 4 bits bitmap, one for each directions. Only 1 bit can be high for + // key_to_hat_dir. SDL_JoystickGetHat handles diagonal too (2 bits) so you must check the intersection + // '&' not only equality '=='. -- Gregory + if (key_to_hat_dir(cpad, i) & value) + key_status->press(cpad, i); + else + key_status->release(cpad, i); + + break; + } + case PAD_AXIS: { + int value = gamePad->GetAxisFromKey(cpad, i); + bool sign = key_to_axis_sign(cpad, i); + bool full_axis = key_to_axis_type(cpad, i); + + if (IsAnalogKey(i)) { + if (abs(value) > gamePad->GetDeadzone()) + key_status->press(cpad, i, value); + else + key_status->release(cpad, i); + + } else { + if (full_axis) { + value += 0x8000; + if (value > gamePad->GetDeadzone()) + key_status->press(cpad, i, min(value / 256, 0xFF)); + else + key_status->release(cpad, i); + + } else { + if (sign && (-value > gamePad->GetDeadzone())) + key_status->press(cpad, i, min(-value / 128, 0xFF)); + else if (!sign && (value > gamePad->GetDeadzone())) + key_status->press(cpad, i, min(value / 128, 0xFF)); + else + key_status->release(cpad, i); + } + } + } + default: + break; + } + } +} + +EXPORT_C_(void) +PADupdate(int pad) +{ + // 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); + } + + // 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++) { + key_status->keyboard_state_acces(cpad); + } + PollForX11KeyboardInput(); + + // Get joystick state + Commit + for (int cpad = 0; cpad < GAMEPAD_NUMBER; cpad++) { + key_status->joystick_state_acces(cpad); + + PollForJoystickInput(cpad); + + key_status->commit_status(cpad); + } + + Pad::rumble_all(); +} + +EXPORT_C_(void) +PADconfigure() +{ + LoadConfig(); + + DisplayDialog(); + return; +} diff --git a/plugins/onepad_legacy/Linux/linux.h b/plugins/onepad_legacy/Linux/linux.h new file mode 100644 index 0000000000..4671aff0ea --- /dev/null +++ b/plugins/onepad_legacy/Linux/linux.h @@ -0,0 +1,26 @@ +/* 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 __LINUX_H__ +#define __LINUX_H__ +extern void DisplayDialog(); +extern string KeyName(int pad, int key, int keysym = 0); +#endif diff --git a/plugins/onepad_legacy/Linux/opPanel.cpp b/plugins/onepad_legacy/Linux/opPanel.cpp new file mode 100644 index 0000000000..159e3c543d --- /dev/null +++ b/plugins/onepad_legacy/Linux/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; + } +} + +BEGIN_EVENT_TABLE(opPanel, wxPanel) +EVT_PAINT(opPanel::OnPaint) +END_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/plugins/onepad_legacy/Linux/opPanel.h b/plugins/onepad_legacy/Linux/opPanel.h new file mode 100644 index 0000000000..eb253e78f2 --- /dev/null +++ b/plugins/onepad_legacy/Linux/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; + DECLARE_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__ diff --git a/plugins/onepad_legacy/SDL/joystick.cpp b/plugins/onepad_legacy/SDL/joystick.cpp new file mode 100644 index 0000000000..8ffba0fc70 --- /dev/null +++ b/plugins/onepad_legacy/SDL/joystick.cpp @@ -0,0 +1,363 @@ +/* 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 // sigaction + +////////////////////////// +// Joystick definitions // +////////////////////////// + +static u32 s_bSDLInit = false; + +void JoystickInfo::UpdateReleaseState() +{ + vector::iterator itjoy = s_vgamePad.begin(); + + SDL_JoystickUpdate(); + + // Save everything in the vector s_vjoysticks. + while (itjoy != s_vgamePad.end()) { + (*itjoy)->SaveState(); + ++itjoy; + } +} + +// opens handles to all possible joysticks +void JoystickInfo::EnumerateJoysticks(vector &vjoysticks) +{ + + if (!s_bSDLInit) { +#if SDL_MAJOR_VERSION >= 2 + // Tell SDL to catch event even if the windows isn't focussed + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0) + return; + // WTF! Give me back the control of my system + struct sigaction action = {0}; + action.sa_handler = SIG_DFL; + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +#else + if (SDL_Init(SDL_INIT_JOYSTICK) < 0) + return; +#endif + SDL_JoystickEventState(SDL_QUERY); + s_bSDLInit = true; + } + + vector::iterator it = vjoysticks.begin(); + + // Delete everything in the vector vjoysticks. + while (it != vjoysticks.end()) { + delete *it; + ++it; + } + + vjoysticks.resize(SDL_NumJoysticks()); + + for (int i = 0; i < (int)vjoysticks.size(); ++i) { + vjoysticks[i] = new JoystickInfo(); + vjoysticks[i]->Init(i); + } +} + +void JoystickInfo::GenerateDefaultEffect() +{ +#if SDL_MAJOR_VERSION >= 2 + 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)(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; + effects[i] = effect; + } +#endif +} + +void JoystickInfo::Rumble(int type, int pad) +{ + if (type > 1) + return; + if (!(conf->pad_options[pad].forcefeedback)) + return; + +#if SDL_MAJOR_VERSION >= 2 + if (haptic == NULL) + return; + + if (first) { // If done multiple times, device memory will be filled + first = 0; + GenerateDefaultEffect(); + /** Sine and triangle are quite probably the best, don't change that lightly and if you do + * keep effects ordered by type + **/ + /** 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 + **/ + effects[0].type = SDL_HAPTIC_SINE; + effects_id[0] = SDL_HapticNewEffect(haptic, &effects[0]); + if (effects_id[0] < 0) { + fprintf(stderr, "ERROR: Effect is not uploaded! %s, id is %d\n", SDL_GetError(), effects_id[0]); + } + + /** Effect for big motor **/ + effects[1].type = SDL_HAPTIC_TRIANGLE; + effects_id[1] = SDL_HapticNewEffect(haptic, &effects[1]); + if (effects_id[1] < 0) { + fprintf(stderr, "ERROR: Effect is not uploaded! %s, id is %d\n", SDL_GetError(), effects_id[1]); + } + } + + int id; + id = effects_id[type]; + if (SDL_HapticRunEffect(haptic, id, 1) != 0) { + fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id); + } +#endif +} + +void JoystickInfo::Destroy() +{ + if (joy != NULL) { +#if SDL_MAJOR_VERSION >= 2 + // Haptic must be closed before the joystick + if (haptic != NULL) { + SDL_HapticClose(haptic); + haptic = NULL; + } +#endif + +#if SDL_MAJOR_VERSION >= 2 +#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly + if (joy) + SDL_JoystickClose(joy); +#endif +#else + if (SDL_JoystickOpened(_id)) + SDL_JoystickClose(joy); +#endif + joy = NULL; + } +} + +bool JoystickInfo::Init(int id) +{ + Destroy(); + _id = id; + + joy = SDL_JoystickOpen(id); + if (joy == NULL) { + PAD_LOG("failed to open joystick %d\n", id); + return false; + } + + numaxes = SDL_JoystickNumAxes(joy); + numbuttons = SDL_JoystickNumButtons(joy); + numhats = SDL_JoystickNumHats(joy); +#if SDL_MAJOR_VERSION >= 2 + devname = SDL_JoystickName(joy); +#else + devname = SDL_JoystickName(id); +#endif + + vaxisstate.resize(numaxes); + vbuttonstate.resize(numbuttons); + vhatstate.resize(numhats); + + // Sixaxis, dualshock3 hack + // Most buttons are actually axes due to analog pressure support. Only the first 4 buttons + // are digital (select, start, l3, r3). To avoid conflict just forget the others. + // Keep the 4 hat buttons too (usb driver). (left pressure does not work with recent kernel). Moreover the pressure + // work sometime on half axis neg others time in fulll axis. So better keep them as button for the moment + auto found_hack = devname.find("PLAYSTATION(R)3"); + // FIXME: people need to restart the plugin to take the option into account. + bool hack_enabled = (conf->pad_options[0].sixaxis_pressure) || (conf->pad_options[1].sixaxis_pressure); + if (found_hack != string::npos && numaxes > 4 && hack_enabled) { + numbuttons = 4; // (select, start, l3, r3) + // Enable this hack in bluetooth too. It avoid to restart the onepad gui + numbuttons += 4; // the 4 hat buttons + } + +#if SDL_MAJOR_VERSION >= 2 + if (haptic == NULL) { + if (!SDL_JoystickIsHaptic(joy)) { + PAD_LOG("Haptic devices not supported!\n"); + } else { + haptic = SDL_HapticOpenFromJoystick(joy); + first = true; + } + } +#endif + + //PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats); + return true; +} + +void JoystickInfo::SaveState() +{ + for (int i = 0; i < numbuttons; ++i) + SetButtonState(i, SDL_JoystickGetButton(joy, i)); + for (int i = 0; i < numaxes; ++i) + SetAxisState(i, SDL_JoystickGetAxis(joy, i)); + for (int i = 0; i < numhats; ++i) + SetHatState(i, SDL_JoystickGetHat(joy, i)); +} + +bool JoystickInfo::TestForce(float strength = 0.60) +{ +#if SDL_MAJOR_VERSION >= 2 + // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox + if (haptic == NULL) + return false; // Otherwise, core dump! + SDL_HapticRumbleInit(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(haptic, strength, 400) != 0) { + fprintf(stderr, "ERROR: Rumble is not working! %s\n", SDL_GetError()); + return false; + } + +#endif + + return true; +} + +bool JoystickInfo::PollButtons(u32 &pkey) +{ + // MAKE sure to look for changes in the state!! + for (int i = 0; i < GetNumButtons(); ++i) { + int but = SDL_JoystickGetButton(GetJoy(), i); + if (but != GetButtonState(i)) { + // Pressure sensitive button are detected as both button (digital) and axes (analog). So better + // drop the button to emulate the pressure sensiblity of the ds2 :) + // Trick: detect the release of the button. It avoid all races condition between axes and buttons :) + // If the button support pressure it will be detected as an axis when it is pressed. + if (but) { + SetButtonState(i, but); + return false; + } + + + pkey = button_to_key(i); + return true; + } + } + + return false; +} + +bool JoystickInfo::PollAxes(u32 &pkey) +{ + auto found_hack = devname.find("PLAYSTATION(R)3"); + + for (int i = 0; i < GetNumAxes(); ++i) { + // Sixaxis, dualshock3 hack + if (found_hack != string::npos) { + // The analog mode of the hat button is quite erratic. Values can be in half- axis + // or full axis... So better keep them as button for the moment -- gregory + if (i >= 8 && i <= 11 && (conf->pad_options[pad].sixaxis_usb)) + continue; + // Disable accelerometer + if ((i >= 4 && i <= 6)) + continue; + } + + s32 value = SDL_JoystickGetAxis(GetJoy(), i); + s32 old_value = GetAxisState(i); + + if (abs(value - old_value) < 0x1000) + continue; + + if (value != old_value) { + PAD_LOG("Change in joystick %d: %d.\n", i, value); + // There are several kinds of axes + // Half+: 0 (release) -> 32768 + // Half-: 0 (release) -> -32768 + // Full (like dualshock 3): -32768 (release) ->32768 + const s32 full_axis_ceil = -0x6FFF; + const s32 half_axis_ceil = 0x1FFF; + + // Normally, old_value contains the release state so it can be used to detect the types of axis. + bool is_full_axis = (old_value < full_axis_ceil); + + if ((!is_full_axis && abs(value) <= half_axis_ceil) || (is_full_axis && value <= full_axis_ceil)) // we don't want this + { + continue; + } + + if ((!is_full_axis && abs(value) > half_axis_ceil) || (is_full_axis && value > full_axis_ceil)) { + bool sign = (value < 0); + pkey = axis_to_key(is_full_axis, sign, i); + + return true; + } + } + } + + return false; +} + +bool JoystickInfo::PollHats(u32 &pkey) +{ + for (int i = 0; i < GetNumHats(); ++i) { + int value = SDL_JoystickGetHat(GetJoy(), i); + + if ((value != GetHatState(i)) && (value != SDL_HAT_CENTERED)) { + switch (value) { + case SDL_HAT_UP: + case SDL_HAT_RIGHT: + case SDL_HAT_DOWN: + case SDL_HAT_LEFT: + pkey = hat_to_key(value, i); + PAD_LOG("Hat Pressed!"); + return true; + default: + break; + } + } + } + return false; +} + +int JoystickInfo::GetHat(int key_to_axis) +{ + return SDL_JoystickGetHat(GetJoy(), key_to_axis); +} + +int JoystickInfo::GetButton(int key_to_button) +{ + return SDL_JoystickGetButton(GetJoy(), key_to_button); +} + +int JoystickInfo::GetAxisFromKey(int pad, int index) +{ + return SDL_JoystickGetAxis(GetJoy(), key_to_axis(pad, index)); +} diff --git a/plugins/onepad_legacy/SDL/joystick.h b/plugins/onepad_legacy/SDL/joystick.h new file mode 100644 index 0000000000..fe76c38a3e --- /dev/null +++ b/plugins/onepad_legacy/SDL/joystick.h @@ -0,0 +1,96 @@ +/* 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 +#if SDL_MAJOR_VERSION >= 2 +#include +#endif + +#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 : GamePad +{ +public: + JoystickInfo() + : GamePad() + , joy(nullptr) + { +#if SDL_MAJOR_VERSION >= 2 + haptic = nullptr; + first = true; + memset(effects, 0, sizeof(effects)); + memset(effects_id, 0, sizeof(effects_id)); +#endif + } + + ~JoystickInfo() + { + Destroy(); + } + + JoystickInfo(const JoystickInfo &); // copy constructor + JoystickInfo &operator=(const JoystickInfo &); // assignment + + void Destroy(); + // opens handles to all possible joysticks + static void EnumerateJoysticks(vector &vjoysticks); + + void Rumble(int type, int pad); + + bool Init(int id); // opens a handle and gets information + + bool TestForce(float); + + bool PollButtons(u32 &pkey); + bool PollAxes(u32 &pkey); + bool PollHats(u32 &pkey); + + int GetHat(int key_to_axis); + + int GetButton(int key_to_button); + + + void SaveState(); + + int GetAxisFromKey(int pad, int index); + + static void UpdateReleaseState(); + +private: + SDL_Joystick *GetJoy() + { + return joy; + } + void GenerateDefaultEffect(); + + SDL_Joystick *joy; +#if SDL_MAJOR_VERSION >= 2 + SDL_Haptic *haptic; + bool first; + SDL_HapticEffect effects[NB_EFFECT]; + int effects_id[NB_EFFECT]; +#endif +}; diff --git a/plugins/onepad_legacy/Windows/placeholder b/plugins/onepad_legacy/Windows/placeholder new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/onepad_legacy/bitwise.h b/plugins/onepad_legacy/bitwise.h new file mode 100644 index 0000000000..bb4a2751bc --- /dev/null +++ b/plugins/onepad_legacy/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/plugins/onepad_legacy/controller.cpp b/plugins/onepad_legacy/controller.cpp new file mode 100644 index 0000000000..09badfb5ed --- /dev/null +++ b/plugins/onepad_legacy/controller.cpp @@ -0,0 +1,114 @@ +/* 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_keyboad_key(int pad, int keysym, int index) +{ + 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 + map::iterator it = conf->keysym_map[pad].find(keysym); + if (it != conf->keysym_map[pad].end()) + return it->second; + else + return -1; +} + +__forceinline void set_key(int pad, int index, int value) +{ + conf->keys[pad][index] = value; +} + +__forceinline int get_key(int pad, int index) +{ + return conf->keys[pad][index]; +} + +__forceinline KeyType type_of_joykey(int pad, int index) +{ + int key = get_key(pad, index); + + if (key >= 0x10000 && key < 0x20000) + return PAD_JOYBUTTONS; + else if (key >= 0x20000 && key < 0x30000) + return PAD_AXIS; + else if (key >= 0x30000 && key < 0x40000) + return PAD_HAT; + else + return PAD_NULL; +} + +__forceinline bool IsAnalogKey(int index) +{ + return ((index >= PAD_L_UP) && (index <= PAD_R_LEFT)); +} + +//******************************************************* +// onepad key -> joy input +//******************************************************* +__forceinline int key_to_button(int pad, int index) +{ + return (get_key(pad, index) & 0xff); +} + +__forceinline int key_to_axis(int pad, int index) +{ + return (get_key(pad, index) & 0xff); +} + +__forceinline bool key_to_axis_sign(int pad, int index) +{ + return ((get_key(pad, index) >> 8) & 0x1); +} + +__forceinline bool key_to_axis_type(int pad, int index) +{ + return ((get_key(pad, index) >> 9) & 0x1); +} + +__forceinline int key_to_hat_dir(int pad, int index) +{ + return ((get_key(pad, index) >> 8) & 0xF); +} + +//******************************************************* +// joy input -> onepad key +//******************************************************* +__forceinline int button_to_key(int button_id) +{ + return (0x10000 | button_id); +} + +__forceinline int axis_to_key(int full_axis, int sign, int axis_id) +{ + return (0x20000 | (full_axis << 9) | (sign << 8) | axis_id); +} + +__forceinline int hat_to_key(int dir, int axis_id) +{ + return (0x30000 | (dir << 8) | axis_id); +} diff --git a/plugins/onepad_legacy/controller.h b/plugins/onepad_legacy/controller.h new file mode 100644 index 0000000000..4c35a29533 --- /dev/null +++ b/plugins/onepad_legacy/controller.h @@ -0,0 +1,144 @@ +/* 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 + +enum KeyType { + PAD_JOYBUTTONS = 0, + PAD_AXIS, + PAD_HAT, + PAD_NULL = -1 +}; + +extern void set_keyboad_key(int pad, int keysym, int index); +extern int get_keyboard_key(int pad, int keysym); +extern void set_key(int pad, int index, int value); +extern int get_key(int pad, int index); +extern bool IsAnalogKey(int index); + +extern KeyType type_of_joykey(int pad, int index); +extern int key_to_button(int pad, int index); +extern int key_to_axis(int pad, int index); +extern bool key_to_axis_sign(int pad, int index); +extern bool key_to_axis_type(int pad, int index); +extern int key_to_hat_dir(int pad, int index); + +extern int button_to_key(int button_id); +extern int axis_to_key(int full_axis, int sign, int axis_id); +extern int hat_to_key(int dir, int axis_id); + +//extern int PadEnum[2][2]; // never used + +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 sixaxis_usb : 1; + u16 sixaxis_pressure : 1; + u16 _free : 7; // The 8 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 keys[GAMEPAD_NUMBER][MAX_KEYS]; + u32 log; + u32 joyid_map; + map keysym_map[GAMEPAD_NUMBER]; + + PADconf() { init(); } + + void init() + { + memset(&keys, 0, sizeof(keys)); + log = packed_options = joyid_map = 0; + ff_intensity = 0x7FFF; // set it at max value by default + sensibility = 500; + for (int pad = 0; pad < GAMEPAD_NUMBER; pad++) { + keysym_map[pad].clear(); + set_joyid((u32)pad, (u32)pad); // define id mapping for each gamepad + } + } + + void set_joyid(u32 pad, u32 joy_id) + { + int shift = 8 * pad; + joyid_map &= ~(0xFF << shift); // clear + joyid_map |= (joy_id & 0xFF) << shift; // set + } + + u32 get_joyid(u32 pad) + { + int shift = 8 * pad; + return ((joyid_map >> shift) & 0xFF); + } + + /** + * 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, sensibility is not yet implemented(and will probably be after evdev) + * However, there will be an upper range too, less than 0 is an obvious wrong + * Anyway, we are doing object oriented code, members are definitely not supposed to be public + **/ + void set_sensibility(u32 new_sensibility) + { + if (sensibility > 0) { + sensibility = new_sensibility; + } + } + + u32 get_sensibility() + { + return sensibility; + } +}; +extern PADconf *conf; diff --git a/plugins/onepad_legacy/keyboard.cpp b/plugins/onepad_legacy/keyboard.cpp new file mode 100644 index 0000000000..3b5f02f56d --- /dev/null +++ b/plugins/onepad_legacy/keyboard.cpp @@ -0,0 +1,311 @@ +/* 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. + */ + +#include +#include +#include "keyboard.h" + +#ifdef _WIN32 +char *KeysymToChar(int keysym) +{ + LPWORD temp; + + ToAscii((UINT)keysym, NULL, NULL, temp, NULL); + return (char *)temp; +} +#endif + +void SetAutoRepeat(bool autorep) +{ +#if defined(__unix__) + if (toggleAutoRepeat) { + if (autorep) + XAutoRepeatOn(GSdsp); + else + XAutoRepeatOff(GSdsp); + } +#endif +} + +#if 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); + } + } + + // Analog controls. + if (IsAnalogKey(index)) { + switch (index) { + case PAD_R_LEFT: + case PAD_R_UP: + case PAD_L_LEFT: + case PAD_L_UP: + key_status->press(pad, index, -MAX_ANALOG_VALUE); + break; + case PAD_R_RIGHT: + case PAD_R_DOWN: + case PAD_L_RIGHT: + case PAD_L_DOWN: + key_status->press(pad, index, MAX_ANALOG_VALUE); + break; + } + } else if (index != -1) + key_status->press(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) + key_status->release(pad, index); + + event.evt = KEYRELEASE; + event.key = key; + break; + + case FocusIn: + //XAutoRepeatOff(GSdsp); + break; + + case FocusOut: + //XAutoRepeatOn(GSdsp); + s_Shift = false; + break; + + case ButtonPress: + if (index != -1) + key_status->press(pad, index); + break; + + case ButtonRelease: + if (index != -1) + 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 (conf->pad_options[pad].mouse_l | 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 (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 *= conf->get_sensibility(); + + if (x == 0) + key_status->press(pad, pad_x, -MAX_ANALOG_VALUE); + else if (x == 0xFFFF) + key_status->press(pad, pad_x, MAX_ANALOG_VALUE); + else if (x < (s_previous_mouse_x - 2)) + key_status->press(pad, pad_x, -value); + else if (x > (s_previous_mouse_x + 2)) + key_status->press(pad, pad_x, value); + else + 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 *= conf->get_sensibility(); + + if (y == 0) + key_status->press(pad, pad_y, -MAX_ANALOG_VALUE); + else if (y == 0xFFFF) + key_status->press(pad, pad_y, MAX_ANALOG_VALUE); + else if (y < (s_previous_mouse_y - 2)) + key_status->press(pad, pad_y, -value); + else if (y > (s_previous_mouse_y + 2)) + key_status->press(pad, pad_y, value); + else + key_status->release(pad, pad_y); + + s_previous_mouse_x = x; + s_previous_mouse_y = y; + } + + break; + } +} + +void PollForX11KeyboardInput() +{ + keyEvent evt = {0}; + XEvent E = {0}; + + // Keyboard input send by PCSX2 + while (!ev_fifo.empty()) { + AnalyzeKeyEvent(ev_fifo.front()); + pthread_spin_lock(&mutex_KeyEvent); + ev_fifo.pop(); + pthread_spin_unlock(&mutex_KeyEvent); + } + + // 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 PollX11KeyboardMouseEvent(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; + key_status->keyboard_state_acces(cpad); + + 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++) { + if (wParam == get_key(pad, i)) { + key_status->press(pad, i); + break; + } + } + } + + 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++) { + if (wParam == get_key(pad, i)) { + key_status->release(pad, i); + break; + } + } + } + + + 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) + key_status->commit_status(pad); + + return TRUE; +} +#endif diff --git a/plugins/onepad_legacy/keyboard.h b/plugins/onepad_legacy/keyboard.h new file mode 100644 index 0000000000..5c1690d8b3 --- /dev/null +++ b/plugins/onepad_legacy/keyboard.h @@ -0,0 +1,46 @@ +/* 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__) + +#include "Linux/linux.h" + +extern Display *GSdsp; +extern void PollForX11KeyboardInput(); +extern bool PollX11KeyboardMouseEvent(u32 &pkey); +extern Window GSwin; + +#else + +extern char *KeysymToChar(int keysym); +extern WNDPROC GSwndProc; +extern HWND GShwnd; + +#endif + +extern void SetAutoRepeat(bool autorep); + +#endif diff --git a/plugins/onepad_legacy/onepad.cpp b/plugins/onepad_legacy/onepad.cpp new file mode 100644 index 0000000000..add8c38f0d --- /dev/null +++ b/plugins/onepad_legacy/onepad.cpp @@ -0,0 +1,364 @@ +/* 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 "onepad.h" +#include "svnrev.h" +#include "state_management.h" + +#ifdef __linux__ +#include +#endif +#ifdef _MSC_VER +#define snprintf sprintf_s +#endif + +PADconf *conf; +static char libraryName[256]; + +keyEvent event; + +static keyEvent s_event; +std::string s_strIniPath("inis/"); +std::string s_strLogPath("logs/"); +bool toggleAutoRepeat = false; + +const u32 version = PS2E_PAD_VERSION; +const u32 revision = 1; +const u32 build = 3; // increase that with each version +#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0)) + +FILE *padLog = NULL; + +pthread_spinlock_t mutex_KeyEvent; +bool mutex_WasInit = false; +KeyStatus *key_status = NULL; + +queue 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 +} + +void clearPAD(int pad) +{ + conf->keysym_map[pad].clear(); + for (int key = 0; key < MAX_KEYS; ++key) + set_key(pad, key, 0); +} + +EXPORT_C_(s32) +PADinit(u32 flags) +{ + initLogging(); + + LoadConfig(); + + key_status = new KeyStatus(); + + Pad::reset_all(); + + query.reset(); + + for (int port = 0; port < 2; port++) + slots[port] = 0; + + return 0; +} + +EXPORT_C_(void) +PADshutdown() +{ + CloseLogging(); + + delete conf; + conf = nullptr; + + delete key_status; + key_status = nullptr; +} + +EXPORT_C_(s32) +PADopen(void *pDsp) +{ + memset(&event, 0, sizeof(event)); + key_status->Init(); + + while (!ev_fifo.empty()) + ev_fifo.pop(); + pthread_spin_init(&mutex_KeyEvent, PTHREAD_PROCESS_PRIVATE); + mutex_WasInit = true; + +#if defined(__unix__) + 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() +{ + while (!ev_fifo.empty()) + ev_fifo.pop(); + mutex_WasInit = false; + pthread_spin_destroy(&mutex_KeyEvent); + _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() +{ + s_event = event; + event.evt = 0; + event.key = 0; + return &s_event; +} + +#if defined(__unix__) +EXPORT_C_(void) +PADWriteEvent(keyEvent &evt) +{ + // This function call be called before PADopen. Therefore we cann't + // guarantee that the spin lock was initialized + if (mutex_WasInit) { + pthread_spin_lock(&mutex_KeyEvent); + ev_fifo.push(evt); + pthread_spin_unlock(&mutex_KeyEvent); + } +} +#endif diff --git a/plugins/onepad_legacy/onepad.h b/plugins/onepad_legacy/onepad.h new file mode 100644 index 0000000000..d4840e0512 --- /dev/null +++ b/plugins/onepad_legacy/onepad.h @@ -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 + */ + +#ifndef __PAD_H__ +#define __PAD_H__ + +#define GAMEPAD_NUMBER 2 // numbers of gamepad + +#include +#include +#include + +#ifdef _WIN32 +#include +#include + +#else + +#include +#include +#include + +#endif + +#include +#include +#include +#include +using namespace std; + +#define PADdefs +#include "PS2Edefs.h" + +#if defined(__unix__) +#include "GamePad.h" +#endif +#include "bitwise.h" +#include "controller.h" +#include "KeyStatus.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 + +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, + PADOPTION_SIXAXIS_USB = 0x80, + PADOPTION_SIXAXIS_PRESSURE = 0x100 +}; + +extern FILE *padLog; +extern void initLogging(); +extern bool toggleAutoRepeat; + +#define PAD_LOG __Log +//#define PAD_LOG __LogToConsole + +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) ← +}; + +extern keyEvent event; +extern queue ev_fifo; +extern pthread_spinlock_t mutex_KeyEvent; + +void clearPAD(int pad); +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/plugins/onepad_legacy/state_management.cpp b/plugins/onepad_legacy/state_management.cpp new file mode 100644 index 0000000000..c275b0d662 --- /dev/null +++ b/plugins/onepad_legacy/state_management.cpp @@ -0,0 +1,467 @@ +/* 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" + +// 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(int port) +{ + for (int 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 (int port = 0; port < 2; port++) + for (int 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 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 = 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] = key_status->get(query.port, PAD_R_RIGHT); + query.response[6] = key_status->get(query.port, PAD_R_UP); + query.response[7] = key_status->get(query.port, PAD_L_RIGHT); + query.response[8] = 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) ? key_status->get(query.port, PAD_RIGHT) : 0; + query.response[10] = !test_bit(buttons, 15) ? key_status->get(query.port, PAD_LEFT) : 0; + query.response[11] = !test_bit(buttons, 12) ? key_status->get(query.port, PAD_UP) : 0; + query.response[12] = !test_bit(buttons, 14) ? key_status->get(query.port, PAD_DOWN) : 0; + + query.response[13] = !test_bit(buttons, 4) ? key_status->get(query.port, PAD_TRIANGLE) : 0; + query.response[14] = !test_bit(buttons, 5) ? key_status->get(query.port, PAD_CIRCLE) : 0; + query.response[15] = !test_bit(buttons, 6) ? key_status->get(query.port, PAD_CROSS) : 0; + query.response[16] = !test_bit(buttons, 7) ? key_status->get(query.port, PAD_SQUARE) : 0; + query.response[17] = !test_bit(buttons, 2) ? key_status->get(query.port, PAD_L1) : 0; + query.response[18] = !test_bit(buttons, 3) ? key_status->get(query.port, PAD_R1) : 0; + query.response[19] = !test_bit(buttons, 0) ? key_status->get(query.port, PAD_L2) : 0; + query.response[20] = !test_bit(buttons, 1) ? 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/plugins/onepad_legacy/state_management.h b/plugins/onepad_legacy/state_management.h new file mode 100644 index 0000000000..f5c4eba107 --- /dev/null +++ b/plugins/onepad_legacy/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(int 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);