pcsx2/plugins/LilyPad/InputManager.h
FlatOutPS2 f3a89f59e4 LilyPad: General fixes and UI improvements
Some general fixes and UI improvements.

Adds Reset Configuration to Input/Force Feedback configuration screens that resets the configuration for the selected control(s).

Adds Restore Defaults button to the General tab that deletes all LilyPad
Settings and bindings and resets to the default settings.

Adds double-click functionality to the PAD list on the General tab,
which will now send the user straight to the corresponding PAD tab.
2017-03-16 22:43:53 +00:00

404 lines
12 KiB
C++

/* LilyPad - Pad plugin for PS2 Emulator
* Copyright (C) 2002-2017 PCSX2 Dev Team/ChickenLiver
*
* PCSX2 is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Found- ation, either version 3 of the License, or (at your option)
* any later version.
*
* PCSX2 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 PCSX2. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INPUT_MANAGER_H
#define INPUT_MANAGER_H
// Both of these are hard coded in a lot of places, so don't modify them.
// Base sensitivity means that a sensitivity of that corresponds to a factor of 1.
// Fully down means that value corresponds to a button being fully down (255).
// a value of 128 or more corresponds to that button being pressed, for binary
// values.
#define BASE_SENSITIVITY (1 << 16)
#define BASE_ANALOG_SENSITIVITY (87183)
#define FULLY_DOWN (1 << 16)
#define DEFAULT_DEADZONE (BASE_SENSITIVITY * 201 / 1000)
/* Idea is for this file and the associated cpp file to be Windows independent.
* Still more effort than it's worth to port to Linux, however.
*/
enum PadType {
DisabledPad,
Dualshock2Pad,
GuitarPad,
PopnPad,
MousePad,
neGconPad,
numPadTypes // total number of PadTypes. Add new PadType above this line.
};
// Mostly match DirectInput8 values. Note that these are for physical controls.
// One physical axis maps to 3 virtual ones, and one physical POV control maps to
// 4 virtual ones.
enum ControlType {
NO_CONTROL = 0,
// Axes are ints. Relative axes are for mice, mice wheels, etc,
// and are always reported relative to their last value.
// Absolute axes range from -65536 to 65536 and are absolute positions,
// like for joysticks and pressure sensitive buttons.
RELAXIS = 1,
ABSAXIS = 2,
// Buttons range from 0 to 65536.
PSHBTN = 4,
TGLBTN = 8,
// POV controls are ints, values range from -1 to 36000.
// -1 means not pressed, otherwise it's an angle.
// For easy DirectInput compatibility, anything outside.
// that range is treated as -1 (Though 36000-37000 is treated
// like 0 to 1000, just in case).
POV = 16,
// Pressure sensitive buttons. Only a different type because
// they have configurable dead zones, unlike push or toggle buttons.
PRESSURE_BTN = 32,
};
// Masks to determine button type. Don't need one for POV.
#define BUTTON (PSHBTN | TGLBTN | PRESSURE_BTN)
#define BINARY_BUTTON (PSHBTN | TGLBTN)
#define AXIS 3
struct Binding
{
int controlIndex;
int command;
int sensitivity;
int deadZone;
int skipDeadZone;
unsigned char rapidFire;
};
#define UID_AXIS (1U << 31)
#define UID_POV (1 << 30)
#define UID_AXIS_POS (1U << 24)
#define UID_AXIS_NEG (2U << 24)
#define UID_POV_N (3 << 24)
#define UID_POV_E (4 << 24)
#define UID_POV_S (5 << 24)
#define UID_POV_W (6 << 24)
// One of these exists for each bindable object.
// Bindable objects consist of buttons, axis, pov controls,
// and individual axis/pov directions. Not that pov controls
// cannot actually be bound, but when trying to bind as an axis,
// all directions are assigned individually.
struct VirtualControl
{
// Unique id for control, given device. Based on source control's id,
// source control type, axis/pov flags if it's a pov/axis (Rather than
// a button or a pov/axis control's individual button), and an index,
// if the control is split.
unsigned int uid;
// virtual key code. 0 if none.
int physicalControlIndex;
};
// Need one for each button, axis, and pov control.
// API-specific code creates the PhysicalControls and
// updates their state, standard function then populates
// the VirtualControls and queues the keyboard messages, if
// needed.
struct PhysicalControl
{
// index of the first virtual control corresponding to this.
// Buttons have 1 virtual control, axes 3, and povs 5, all
// in a row.
int baseVirtualControlIndex;
ControlType type;
// id. Must be unique for control type.
// short so can be combined with other values to get
// uid for virtual controls.
unsigned short id;
unsigned short vkey;
wchar_t *name;
};
enum DeviceAPI {
NO_API = 0,
DI = 1,
WM = 2,
RAW = 3,
XINPUT = 4,
DS3 = 5,
// Not currently used.
LLHOOK = 6,
// Not a real API, obviously. Only used with keyboards,
// to ignore individual buttons. Wrapper itself takes care
// of ignoring bound keys. Otherwise, works normally.
IGNORE_KEYBOARD = 7,
// XXX
LNX_KEYBOARD = 16,
LNX_JOY = 17,
};
enum DeviceType {
NO_DEVICE = 0,
KEYBOARD = 1,
MOUSE = 2,
OTHER = 3
};
enum EffectType {
EFFECT_CONSTANT,
EFFECT_PERIODIC,
EFFECT_RAMP
};
// force range sfrom -BASE_SENSITIVITY to BASE_SENSITIVITY.
// Order matches ForceFeedbackAxis order. force of 0 means to
// ignore that axis completely. Force of 1 or -1 means to initialize
// the axis with minimum force (Possibly 0 force), if applicable.
struct AxisEffectInfo
{
int force;
};
struct ForceFeedbackBinding
{
AxisEffectInfo *axes;
int effectIndex;
unsigned char motor;
};
// Bindings listed by effect, so I don't have to bother with
// indexing effects.
struct ForceFeedbackEffectType
{
wchar_t *displayName;
// Because I'm lazy, can only have ASCII characters and no spaces.
wchar_t *effectID;
// constant, ramp, or periodic
EffectType type;
};
struct ForceFeedbackAxis
{
wchar_t *displayName;
int id;
};
// Used both for active devices and for sets of settings for devices.
// Way things work:
// LoadSettings() will delete all device info, then load settings to get
// one set of generic devices. Then I enumerate all devices. Then I merge
// them, moving settings from the generic devices to the enumerated ones.
struct PadBindings
{
Binding *bindings;
int numBindings;
ForceFeedbackBinding *ffBindings;
int numFFBindings;
};
class WndProcEater;
struct InitInfo
{
// 1 when binding key to ignore.
int bindingIgnore;
// 1 when binding.
int binding;
#ifdef _MSC_VER
HWND hWndTop;
// For config screen, need to eat button's message handling.
//HWND hWndButton;
WndProcEater *hWndProc;
#else
// Linux equivalent to HWND
Display *GSdsp;
Window GSwin;
#endif
};
// Mostly self-contained, but bindings are modified by config.cpp, to make
// updating the ListView simpler.
class Device
{
public:
DeviceAPI api;
DeviceType type;
char active;
char attached;
// Based on input modes.
char enabled;
#ifdef _MSC_VER
// Not all devices need to subclass the windproc, but most do so might as well
// put it here... --air
WndProcEater *hWndProc;
#endif
union
{
// Allows for one loop to compare all 3 in order.
wchar_t *IDs[3];
struct
{
// Same as DisplayName, when not given. Absolutely must be unique.
// Used for loading/saving controls. If matches, all other strings
// are ignored, so must be unique.
wchar_t *instanceID;
// Not required. Used when a device's instance id changes, doesn't have to
// be unique. For devices that can only have one instance, not needed.
wchar_t *productID;
wchar_t *displayName;
};
};
PadBindings pads[2][4][numPadTypes];
// Virtual controls. All basically act like pressure sensitivity buttons, with
// values between 0 and 2^16. 2^16 is fully down, 0 is up. Larger values
// are allowed, but *only* for absolute axes (Which don't support the flip checkbox).
// Each control on a device must have a unique id, used for binding.
VirtualControl *virtualControls;
int numVirtualControls;
int *virtualControlState;
int *oldVirtualControlState;
PhysicalControl *physicalControls;
int numPhysicalControls;
int *physicalControlState;
ForceFeedbackEffectType *ffEffectTypes;
int numFFEffectTypes;
ForceFeedbackAxis *ffAxes;
int numFFAxes;
void AddFFAxis(const wchar_t *displayName, int id);
void AddFFEffectType(const wchar_t *displayName, const wchar_t *effectID, EffectType type);
Device(DeviceAPI, DeviceType, const wchar_t *displayName, const wchar_t *instanceID = 0, const wchar_t *deviceID = 0);
virtual ~Device();
// Allocates memory for old and new state, sets everything to 0.
// all old states are in one array, buttons, axes, and then POVs.
// start of each section is int aligned. This makes it DirectInput
// compatible.
void AllocState();
// Doesn't actually flip. Copies current state to old state.
void FlipState();
// Frees state variables.
void FreeState();
ForceFeedbackEffectType *GetForcefeedbackEffect(wchar_t *id);
ForceFeedbackAxis *GetForceFeedbackAxis(int id);
VirtualControl *GetVirtualControl(unsigned int uid);
PhysicalControl *AddPhysicalControl(ControlType type, unsigned short id, unsigned short vkey, const wchar_t *name = 0);
VirtualControl *AddVirtualControl(unsigned int uid, int physicalControlIndex);
virtual wchar_t *GetVirtualControlName(VirtualControl *c);
virtual wchar_t *GetPhysicalControlName(PhysicalControl *c);
void CalcVirtualState();
virtual int Activate(InitInfo *args)
{
return 0;
}
inline virtual void Deactivate()
{
FreeState();
active = 0;
}
// Default update proc. All that's needed for post-based APIs.
inline virtual int Update()
{
return active;
}
// force is from -FULLY_DOWN to FULLY_DOWN.
// Either function can be overridden. Second one by default calls the first
// for every bound effect that's affected.
// Note: Only used externally for binding, so if override the other one, can assume
// all other forces are currently 0.
inline virtual void SetEffect(ForceFeedbackBinding *binding, unsigned char force) {}
virtual void SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);
// Called after reading. Basically calls FlipState().
// Some device types (Those that don't incrementally update)
// could call FlipState elsewhere, but this makes it simpler to ignore
// while binding.
virtual void PostRead();
};
class InputDeviceManager
{
public:
Device **devices;
int numDevices;
void ClearDevices();
// When refreshing devices, back up old devices, then
// populate this with new devices, then call copy bindings.
// All old bindings are copied to matching devices.
// When old devices are missing, I do a slightly more careful search
// using productIDs and then (in desperation) displayName.
// Finally create new dummy devices if no matches found.
void CopyBindings(int numDevices, Device **devices);
InputDeviceManager();
~InputDeviceManager();
void AddDevice(Device *d);
Device *GetActiveDevice(InitInfo *info, unsigned int *uid, int *index, int *value);
void Update(InitInfo *initInfo);
// Called after reading state, after Update().
void PostRead();
void SetEffect(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);
// Update does this as needed.
// void GetInput(void *v);
void ReleaseInput();
void DisableDevice(int index);
inline void EnableDevice(int i)
{
devices[i]->enabled = 1;
}
void EnableDevices(DeviceType type, DeviceAPI api);
void DisableAllDevices();
};
extern InputDeviceManager *dm;
#endif