pcsx2/plugins/LilyPad/InputManager.h

403 lines
12 KiB
C
Raw Normal View History

/* LilyPad - Pad plugin for PS2 Emulator
* Copyright (C) 2002-2014 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 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,
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 turbo;
};
#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