mirror of https://github.com/PCSX2/pcsx2.git
Merge branch 'greg/onepad-legacy'
This commit is contained in:
commit
c115a4cf76
|
@ -216,10 +216,10 @@ endif()
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
# onepad
|
# onepad
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
# requires: -SDL
|
# requires: -SDL2
|
||||||
# -X11
|
# -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)
|
set(onepad TRUE)
|
||||||
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad")
|
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad")
|
||||||
set(onepad FALSE)
|
set(onepad FALSE)
|
||||||
|
@ -227,6 +227,16 @@ else()
|
||||||
set(onepad FALSE)
|
set(onepad FALSE)
|
||||||
print_dep("Skip build of onepad: miss some dependencies" "${msg_dep_onepad}")
|
print_dep("Skip build of onepad: miss some dependencies" "${msg_dep_onepad}")
|
||||||
endif()
|
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()
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
|
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
|
|
|
@ -46,6 +46,10 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad" AND onepad)
|
||||||
add_subdirectory(onepad)
|
add_subdirectory(onepad)
|
||||||
endif()
|
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)
|
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/PadNull" AND PadNull)
|
||||||
add_subdirectory(PadNull)
|
add_subdirectory(PadNull)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -38,7 +38,7 @@ set(onepadGuiResources
|
||||||
)
|
)
|
||||||
|
|
||||||
# plugin name
|
# plugin name
|
||||||
set(Output onepad-1.3.0)
|
set(Output onepad)
|
||||||
set(onepadFinalFlags "")
|
set(onepadFinalFlags "")
|
||||||
|
|
||||||
# onepad sources
|
# onepad sources
|
||||||
|
@ -86,13 +86,8 @@ set(onepadWindowsSources
|
||||||
set(onepadWindowsHeaders
|
set(onepadWindowsHeaders
|
||||||
)
|
)
|
||||||
|
|
||||||
if (SDL2_API)
|
set(onepadFinalLibs ${SDL2_LIBRARIES})
|
||||||
set(onepadFinalLibs ${SDL2_LIBRARIES})
|
add_definitions(-DSDL_BUILD)
|
||||||
add_definitions(-DSDL_BUILD)
|
|
||||||
else()
|
|
||||||
set(onepadFinalLibs ${SDL_LIBRARY})
|
|
||||||
add_definitions(-DSDL_BUILD)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(onepadFinalLibs
|
set(onepadFinalLibs
|
||||||
${onepadFinalLibs}
|
${onepadFinalLibs}
|
||||||
|
|
|
@ -122,7 +122,7 @@ void SaveConfig()
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
const std::string iniFile(s_strIniPath + "OnePAD.ini");
|
const std::string iniFile(s_strIniPath + "OnePAD2.ini");
|
||||||
f = fopen(iniFile.c_str(), "w");
|
f = fopen(iniFile.c_str(), "w");
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
printf("OnePAD: failed to save ini %s\n", iniFile.c_str());
|
printf("OnePAD: failed to save ini %s\n", iniFile.c_str());
|
||||||
|
@ -160,7 +160,7 @@ void LoadConfig()
|
||||||
|
|
||||||
conf->init();
|
conf->init();
|
||||||
|
|
||||||
const std::string iniFile(s_strIniPath + "OnePAD.ini");
|
const std::string iniFile(s_strIniPath + "OnePAD2.ini");
|
||||||
f = fopen(iniFile.c_str(), "r");
|
f = fopen(iniFile.c_str(), "r");
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
printf("OnePAD: failed to load ini %s\n", iniFile.c_str());
|
printf("OnePAD: failed to load ini %s\n", iniFile.c_str());
|
||||||
|
|
|
@ -46,20 +46,17 @@ void JoystickInfo::EnumerateJoysticks(vector<GamePad *> &vjoysticks)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!s_bSDLInit) {
|
if (!s_bSDLInit) {
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
// Tell SDL to catch event even if the windows isn't focussed
|
// Tell SDL to catch event even if the windows isn't focussed
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0)
|
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// WTF! Give me back the control of my system
|
// WTF! Give me back the control of my system
|
||||||
struct sigaction action = {0};
|
struct sigaction action = {0};
|
||||||
action.sa_handler = SIG_DFL;
|
action.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGINT, &action, NULL);
|
sigaction(SIGINT, &action, NULL);
|
||||||
sigaction(SIGTERM, &action, NULL);
|
sigaction(SIGTERM, &action, NULL);
|
||||||
#else
|
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
SDL_JoystickEventState(SDL_QUERY);
|
SDL_JoystickEventState(SDL_QUERY);
|
||||||
s_bSDLInit = true;
|
s_bSDLInit = true;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +79,6 @@ void JoystickInfo::EnumerateJoysticks(vector<GamePad *> &vjoysticks)
|
||||||
|
|
||||||
void JoystickInfo::GenerateDefaultEffect()
|
void JoystickInfo::GenerateDefaultEffect()
|
||||||
{
|
{
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
for (int i = 0; i < NB_EFFECT; i++) {
|
for (int i = 0; i < NB_EFFECT; i++) {
|
||||||
SDL_HapticEffect effect;
|
SDL_HapticEffect effect;
|
||||||
memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default
|
memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default
|
||||||
|
@ -99,7 +95,6 @@ void JoystickInfo::GenerateDefaultEffect()
|
||||||
effect.periodic.attack_length = 0;
|
effect.periodic.attack_length = 0;
|
||||||
effects[i] = effect;
|
effects[i] = effect;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoystickInfo::Rumble(int type, int pad)
|
void JoystickInfo::Rumble(int type, int pad)
|
||||||
|
@ -109,7 +104,6 @@ void JoystickInfo::Rumble(int type, int pad)
|
||||||
if (!(conf->pad_options[pad].forcefeedback))
|
if (!(conf->pad_options[pad].forcefeedback))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
if (haptic == NULL)
|
if (haptic == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -142,28 +136,20 @@ void JoystickInfo::Rumble(int type, int pad)
|
||||||
if (SDL_HapticRunEffect(haptic, id, 1) != 0) {
|
if (SDL_HapticRunEffect(haptic, id, 1) != 0) {
|
||||||
fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id);
|
fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JoystickInfo::Destroy()
|
void JoystickInfo::Destroy()
|
||||||
{
|
{
|
||||||
if (joy != NULL) {
|
if (joy != NULL) {
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
// Haptic must be closed before the joystick
|
// Haptic must be closed before the joystick
|
||||||
if (haptic != NULL) {
|
if (haptic != NULL) {
|
||||||
SDL_HapticClose(haptic);
|
SDL_HapticClose(haptic);
|
||||||
haptic = NULL;
|
haptic = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly
|
#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly
|
||||||
if (joy)
|
if (joy)
|
||||||
SDL_JoystickClose(joy);
|
SDL_JoystickClose(joy);
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
if (SDL_JoystickOpened(_id))
|
|
||||||
SDL_JoystickClose(joy);
|
|
||||||
#endif
|
#endif
|
||||||
joy = NULL;
|
joy = NULL;
|
||||||
}
|
}
|
||||||
|
@ -183,11 +169,7 @@ bool JoystickInfo::Init(int id)
|
||||||
numaxes = SDL_JoystickNumAxes(joy);
|
numaxes = SDL_JoystickNumAxes(joy);
|
||||||
numbuttons = SDL_JoystickNumButtons(joy);
|
numbuttons = SDL_JoystickNumButtons(joy);
|
||||||
numhats = SDL_JoystickNumHats(joy);
|
numhats = SDL_JoystickNumHats(joy);
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
devname = SDL_JoystickName(joy);
|
devname = SDL_JoystickName(joy);
|
||||||
#else
|
|
||||||
devname = SDL_JoystickName(id);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vaxisstate.resize(numaxes);
|
vaxisstate.resize(numaxes);
|
||||||
vbuttonstate.resize(numbuttons);
|
vbuttonstate.resize(numbuttons);
|
||||||
|
@ -207,7 +189,6 @@ bool JoystickInfo::Init(int id)
|
||||||
numbuttons += 4; // the 4 hat buttons
|
numbuttons += 4; // the 4 hat buttons
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
if (haptic == NULL) {
|
if (haptic == NULL) {
|
||||||
if (!SDL_JoystickIsHaptic(joy)) {
|
if (!SDL_JoystickIsHaptic(joy)) {
|
||||||
PAD_LOG("Haptic devices not supported!\n");
|
PAD_LOG("Haptic devices not supported!\n");
|
||||||
|
@ -216,7 +197,6 @@ bool JoystickInfo::Init(int id)
|
||||||
first = true;
|
first = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
|
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
|
||||||
return true;
|
return true;
|
||||||
|
@ -234,7 +214,6 @@ void JoystickInfo::SaveState()
|
||||||
|
|
||||||
bool JoystickInfo::TestForce(float strength = 0.60)
|
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
|
// This code just use standard rumble to check that SDL handles the pad correctly! --3kinox
|
||||||
if (haptic == NULL)
|
if (haptic == NULL)
|
||||||
return false; // Otherwise, core dump!
|
return false; // Otherwise, core dump!
|
||||||
|
@ -245,8 +224,6 @@ bool JoystickInfo::TestForce(float strength = 0.60)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
#include <SDL_haptic.h>
|
#include <SDL_haptic.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "GamePad.h"
|
#include "GamePad.h"
|
||||||
#include "onepad.h"
|
#include "onepad.h"
|
||||||
|
@ -38,12 +36,10 @@ public:
|
||||||
: GamePad()
|
: GamePad()
|
||||||
, joy(nullptr)
|
, joy(nullptr)
|
||||||
{
|
{
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
haptic = nullptr;
|
haptic = nullptr;
|
||||||
first = true;
|
first = true;
|
||||||
memset(effects, 0, sizeof(effects));
|
memset(effects, 0, sizeof(effects));
|
||||||
memset(effects_id, 0, sizeof(effects_id));
|
memset(effects_id, 0, sizeof(effects_id));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~JoystickInfo()
|
~JoystickInfo()
|
||||||
|
@ -87,10 +83,8 @@ private:
|
||||||
void GenerateDefaultEffect();
|
void GenerateDefaultEffect();
|
||||||
|
|
||||||
SDL_Joystick *joy;
|
SDL_Joystick *joy;
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
|
||||||
SDL_Haptic *haptic;
|
SDL_Haptic *haptic;
|
||||||
bool first;
|
bool first;
|
||||||
SDL_HapticEffect effects[NB_EFFECT];
|
SDL_HapticEffect effects[NB_EFFECT];
|
||||||
int effects_id[NB_EFFECT];
|
int effects_id[NB_EFFECT];
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,8 +47,8 @@ std::string s_strLogPath("logs/");
|
||||||
bool toggleAutoRepeat = false;
|
bool toggleAutoRepeat = false;
|
||||||
|
|
||||||
const u32 version = PS2E_PAD_VERSION;
|
const u32 version = PS2E_PAD_VERSION;
|
||||||
const u32 revision = 1;
|
const u32 revision = 2;
|
||||||
const u32 build = 3; // increase that with each version
|
const u32 build = 0; // increase that with each version
|
||||||
#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0))
|
#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0))
|
||||||
|
|
||||||
FILE *padLog = NULL;
|
FILE *padLog = NULL;
|
||||||
|
|
|
@ -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()
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "GamePad.h"
|
||||||
|
#ifdef SDL_BUILD
|
||||||
|
#include "SDL/joystick.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vector<GamePad *> 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<GamePad *> &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
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "onepad.h"
|
||||||
|
#include "controller.h"
|
||||||
|
#ifdef SDL_BUILD
|
||||||
|
#include <SDL.h>
|
||||||
|
#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<GamePad *> &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<int> vbuttonstate, vaxisstate, vhatstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern vector<GamePad *> s_vgamePad;
|
||||||
|
extern bool GamePadIdWithinBounds(int joyid);
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
|
@ -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 <wx/wx.h>
|
||||||
|
#include <wx/frame.h>
|
||||||
|
#include <wx/window.h>
|
||||||
|
#include <wx/button.h>
|
||||||
|
#include <wx/checkbox.h>
|
||||||
|
#include <wx/slider.h>
|
||||||
|
#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__
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <wx/wx.h>
|
||||||
|
#include <wx/frame.h>
|
||||||
|
#include <wx/window.h>
|
||||||
|
#include <wx/button.h>
|
||||||
|
#include <wx/checkbox.h>
|
||||||
|
#include <wx/slider.h>
|
||||||
|
#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__
|
|
@ -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<u32, int>::iterator it;
|
||||||
|
std::map<u32, int>::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<GamePad *>::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<u32, u32>::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<u32, int>::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<u32, u32>::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();
|
||||||
|
}
|
|
@ -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 <wx/wx.h>
|
||||||
|
#include <wx/notebook.h>
|
||||||
|
#include <wx/frame.h>
|
||||||
|
#include <wx/button.h>
|
||||||
|
#include <wx/panel.h>
|
||||||
|
#include <wx/effects.h>
|
||||||
|
#include <wx/rawbmp.h>
|
||||||
|
#include <wx/graphics.h>
|
||||||
|
#include <wx/timer.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#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<u32, int> 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__
|
|
@ -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 <string.h>
|
||||||
|
|
||||||
|
#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<u32, u32>::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);
|
||||||
|
}
|
|
@ -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 <string.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#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<GamePad *>::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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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<res_dualshock2>().Get();
|
||||||
|
|
||||||
|
m_picture[img_start] = EmbeddedImage<res_start>().Get();
|
||||||
|
m_picture[img_select] = EmbeddedImage<res_select>().Get();
|
||||||
|
m_picture[img_analog] = EmbeddedImage<res_analog>().Get();
|
||||||
|
|
||||||
|
m_picture[img_dp_left] = EmbeddedImage<res_dp_left>().Get();
|
||||||
|
m_picture[img_dp_right] = EmbeddedImage<res_dp_right>().Get();
|
||||||
|
m_picture[img_dp_up] = EmbeddedImage<res_dp_up>().Get();
|
||||||
|
m_picture[img_dp_bottom] = EmbeddedImage<res_dp_bottom>().Get();
|
||||||
|
|
||||||
|
m_picture[img_square] = EmbeddedImage<res_square>().Get();
|
||||||
|
m_picture[img_circle] = EmbeddedImage<res_circle>().Get();
|
||||||
|
m_picture[img_cross] = EmbeddedImage<res_cross>().Get();
|
||||||
|
m_picture[img_triangle] = EmbeddedImage<res_triangle>().Get();
|
||||||
|
|
||||||
|
m_picture[img_l1] = EmbeddedImage<res_l1>().Get();
|
||||||
|
m_picture[img_l3] = EmbeddedImage<res_l3>().Get();
|
||||||
|
m_picture[img_l2] = EmbeddedImage<res_l2>().Get();
|
||||||
|
|
||||||
|
m_picture[img_r1] = EmbeddedImage<res_r1>().Get();
|
||||||
|
m_picture[img_r3] = EmbeddedImage<res_r3>().Get();
|
||||||
|
m_picture[img_r2] = EmbeddedImage<res_r2>().Get();
|
||||||
|
|
||||||
|
m_picture[img_left_cursor] = EmbeddedImage<res_joystick_cursor>().Get();
|
||||||
|
m_picture[img_right_cursor] = EmbeddedImage<res_joystick_cursor>().Get();
|
||||||
|
|
||||||
|
m_picture[img_l_arrow_up] = EmbeddedImage<res_arrow_up>().Get();
|
||||||
|
m_picture[img_l_arrow_right] = EmbeddedImage<res_arrow_right>().Get();
|
||||||
|
m_picture[img_l_arrow_bottom] = EmbeddedImage<res_arrow_bottom>().Get();
|
||||||
|
m_picture[img_l_arrow_left] = EmbeddedImage<res_arrow_left>().Get();
|
||||||
|
|
||||||
|
m_picture[img_r_arrow_up] = EmbeddedImage<res_arrow_up>().Get();
|
||||||
|
m_picture[img_r_arrow_right] = EmbeddedImage<res_arrow_right>().Get();
|
||||||
|
m_picture[img_r_arrow_bottom] = EmbeddedImage<res_arrow_bottom>().Get();
|
||||||
|
m_picture[img_r_arrow_left] = EmbeddedImage<res_arrow_left>().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);
|
||||||
|
}
|
|
@ -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 <wx/wx.h>
|
||||||
|
|
||||||
|
#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__
|
|
@ -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 <signal.h> // sigaction
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// Joystick definitions //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
static u32 s_bSDLInit = false;
|
||||||
|
|
||||||
|
void JoystickInfo::UpdateReleaseState()
|
||||||
|
{
|
||||||
|
vector<GamePad *>::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<GamePad *> &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<GamePad *>::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));
|
||||||
|
}
|
|
@ -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 <SDL.h>
|
||||||
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
|
#include <SDL_haptic.h>
|
||||||
|
#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<GamePad *> &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
|
||||||
|
};
|
|
@ -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 <class T>
|
||||||
|
static void __forceinline set_bit(T &value, int bit)
|
||||||
|
{
|
||||||
|
value |= (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static void __forceinline clear_bit(T &value, int bit)
|
||||||
|
{
|
||||||
|
value &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static void __forceinline toggle_bit(T &value, int bit)
|
||||||
|
{
|
||||||
|
value ^= (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static bool __forceinline test_bit(T &value, int bit)
|
||||||
|
{
|
||||||
|
return (value & (1 << bit));
|
||||||
|
}
|
|
@ -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<u32, u32>::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);
|
||||||
|
}
|
|
@ -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 <string.h> // 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<u32, u32> 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;
|
|
@ -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 <gtk/gtk.h>
|
||||||
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
#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
|
|
@ -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
|
|
@ -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 <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "onepad.h"
|
||||||
|
#include "svnrev.h"
|
||||||
|
#include "state_management.h"
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <unistd.h>
|
||||||
|
#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<keyEvent> 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
|
|
@ -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 <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <windowsx.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <pthread.h>
|
||||||
|
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<keyEvent> 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
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <size_t S>
|
||||||
|
void set_result(const u8 (&rsp)[S])
|
||||||
|
{
|
||||||
|
memcpy(response + 2, rsp, S);
|
||||||
|
numBytes = 2 + S;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t S>
|
||||||
|
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);
|
Loading…
Reference in New Issue