onepad: create a legacy version for SDL1

The legacy version is the version 1.3

The new version is the version 2.0. It would be based on SDL2 only

Distribution information.
If you link wxWidget with SDL, you will need to be sure it is SDL2 or upgrade.

You can build wxWidget with SDL2 with the following trick

export SDL_CONFIG=/usr/bin/sdl2-config
./configure --with-sdl .....
This commit is contained in:
Gregory Hainaut 2017-04-15 14:57:00 +02:00
parent 92aa270062
commit ef3435441f
35 changed files with 4997 additions and 45 deletions

View File

@ -216,10 +216,10 @@ endif()
#---------------------------------------
# onepad
#---------------------------------------
# requires: -SDL
# requires: -SDL2
# -X11
#---------------------------------------
if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND)
if(wxWidgets_FOUND AND GTKn_FOUND AND SDL2_FOUND AND X11_FOUND)
set(onepad TRUE)
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad")
set(onepad FALSE)
@ -227,6 +227,16 @@ else()
set(onepad FALSE)
print_dep("Skip build of onepad: miss some dependencies" "${msg_dep_onepad}")
endif()
# old version of the plugin that still support SDL1
if(wxWidgets_FOUND AND GTKn_FOUND AND SDLn_FOUND AND X11_FOUND)
set(onepad_legacy TRUE)
elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy")
set(onepad_legacy FALSE)
else()
set(onepad_legacy FALSE)
print_dep("Skip build of onepad_legacy: miss some dependencies" "${msg_dep_onepad}")
endif()
#---------------------------------------
#---------------------------------------

View File

@ -46,6 +46,10 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad" AND onepad)
add_subdirectory(onepad)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/onepad_legacy" AND onepad_legacy)
add_subdirectory(onepad_legacy)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/plugins/PadNull" AND PadNull)
add_subdirectory(PadNull)
endif()

View File

@ -38,7 +38,7 @@ set(onepadGuiResources
)
# plugin name
set(Output onepad-1.3.0)
set(Output onepad)
set(onepadFinalFlags "")
# onepad sources
@ -86,13 +86,8 @@ set(onepadWindowsSources
set(onepadWindowsHeaders
)
if (SDL2_API)
set(onepadFinalLibs ${SDL2_LIBRARIES})
add_definitions(-DSDL_BUILD)
else()
set(onepadFinalLibs ${SDL_LIBRARY})
add_definitions(-DSDL_BUILD)
endif()
set(onepadFinalLibs ${SDL2_LIBRARIES})
add_definitions(-DSDL_BUILD)
set(onepadFinalLibs
${onepadFinalLibs}

View File

@ -122,7 +122,7 @@ void SaveConfig()
{
FILE *f;
const std::string iniFile(s_strIniPath + "OnePAD.ini");
const std::string iniFile(s_strIniPath + "OnePAD2.ini");
f = fopen(iniFile.c_str(), "w");
if (f == NULL) {
printf("OnePAD: failed to save ini %s\n", iniFile.c_str());
@ -160,7 +160,7 @@ void LoadConfig()
conf->init();
const std::string iniFile(s_strIniPath + "OnePAD.ini");
const std::string iniFile(s_strIniPath + "OnePAD2.ini");
f = fopen(iniFile.c_str(), "r");
if (f == NULL) {
printf("OnePAD: failed to load ini %s\n", iniFile.c_str());

View File

@ -46,20 +46,17 @@ 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;
}
@ -82,7 +79,6 @@ void JoystickInfo::EnumerateJoysticks(vector<GamePad *> &vjoysticks)
void JoystickInfo::GenerateDefaultEffect()
{
#if SDL_MAJOR_VERSION >= 2
for (int i = 0; i < NB_EFFECT; i++) {
SDL_HapticEffect effect;
memset(&effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default
@ -99,7 +95,6 @@ void JoystickInfo::GenerateDefaultEffect()
effect.periodic.attack_length = 0;
effects[i] = effect;
}
#endif
}
void JoystickInfo::Rumble(int type, int pad)
@ -109,7 +104,6 @@ void JoystickInfo::Rumble(int type, int pad)
if (!(conf->pad_options[pad].forcefeedback))
return;
#if SDL_MAJOR_VERSION >= 2
if (haptic == NULL)
return;
@ -142,28 +136,20 @@ void JoystickInfo::Rumble(int type, int pad)
if (SDL_HapticRunEffect(haptic, id, 1) != 0) {
fprintf(stderr, "ERROR: Effect is not working! %s, id is %d\n", SDL_GetError(), id);
}
#endif
}
void JoystickInfo::Destroy()
{
if (joy != NULL) {
#if SDL_MAJOR_VERSION >= 2
// Haptic must be closed before the joystick
if (haptic != NULL) {
SDL_HapticClose(haptic);
haptic = NULL;
}
#endif
#if SDL_MAJOR_VERSION >= 2
#if SDL_MINOR_VERSION >= 4 // Version before 2.0.4 are bugged, JoystickClose crashes randomly
if (joy)
SDL_JoystickClose(joy);
#endif
#else
if (SDL_JoystickOpened(_id))
SDL_JoystickClose(joy);
#endif
joy = NULL;
}
@ -183,11 +169,7 @@ bool JoystickInfo::Init(int id)
numaxes = SDL_JoystickNumAxes(joy);
numbuttons = SDL_JoystickNumButtons(joy);
numhats = SDL_JoystickNumHats(joy);
#if SDL_MAJOR_VERSION >= 2
devname = SDL_JoystickName(joy);
#else
devname = SDL_JoystickName(id);
#endif
vaxisstate.resize(numaxes);
vbuttonstate.resize(numbuttons);
@ -207,7 +189,6 @@ bool JoystickInfo::Init(int id)
numbuttons += 4; // the 4 hat buttons
}
#if SDL_MAJOR_VERSION >= 2
if (haptic == NULL) {
if (!SDL_JoystickIsHaptic(joy)) {
PAD_LOG("Haptic devices not supported!\n");
@ -216,7 +197,6 @@ bool JoystickInfo::Init(int id)
first = true;
}
}
#endif
//PAD_LOG("There are %d buttons, %d axises, and %d hats.\n", numbuttons, numaxes, numhats);
return true;
@ -234,7 +214,6 @@ void JoystickInfo::SaveState()
bool JoystickInfo::TestForce(float strength = 0.60)
{
#if SDL_MAJOR_VERSION >= 2
// This code just use standard rumble to check that SDL handles the pad correctly! --3kinox
if (haptic == NULL)
return false; // Otherwise, core dump!
@ -245,8 +224,6 @@ bool JoystickInfo::TestForce(float strength = 0.60)
return false;
}
#endif
return true;
}

View File

@ -22,9 +22,7 @@
#pragma once
#include <SDL.h>
#if SDL_MAJOR_VERSION >= 2
#include <SDL_haptic.h>
#endif
#include "GamePad.h"
#include "onepad.h"
@ -38,12 +36,10 @@ public:
: GamePad()
, joy(nullptr)
{
#if SDL_MAJOR_VERSION >= 2
haptic = nullptr;
first = true;
memset(effects, 0, sizeof(effects));
memset(effects_id, 0, sizeof(effects_id));
#endif
}
~JoystickInfo()
@ -87,10 +83,8 @@ private:
void GenerateDefaultEffect();
SDL_Joystick *joy;
#if SDL_MAJOR_VERSION >= 2
SDL_Haptic *haptic;
bool first;
SDL_HapticEffect effects[NB_EFFECT];
int effects_id[NB_EFFECT];
#endif
};

View File

@ -47,8 +47,8 @@ std::string s_strLogPath("logs/");
bool toggleAutoRepeat = false;
const u32 version = PS2E_PAD_VERSION;
const u32 revision = 1;
const u32 build = 3; // increase that with each version
const u32 revision = 2;
const u32 build = 0; // increase that with each version
#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0))
FILE *padLog = NULL;

View File

@ -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()

View File

@ -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
}

View File

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

View File

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

View File

@ -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

View File

@ -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();
}

View File

@ -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__

View File

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

View File

@ -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__

View File

@ -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();
}

View File

@ -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__

View File

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

View File

@ -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;
}

View File

@ -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

View File

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

View File

@ -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__

View File

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

View File

@ -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
};

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];
}
}

View File

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