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);