mirror of https://github.com/PCSX2/pcsx2.git
339 lines
10 KiB
C++
339 lines
10 KiB
C++
#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.
|
|
*/
|
|
|
|
// 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;
|
|
unsigned char turbo;
|
|
};
|
|
|
|
#define UID_AXIS (1<<31)
|
|
#define UID_POV (1<<30)
|
|
|
|
#define UID_AXIS_POS (1<<24)
|
|
#define UID_AXIS_NEG (2<<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,
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
struct InitInfo {
|
|
// 1 when binding key to ignore.
|
|
int bindingIgnore;
|
|
// 1 when binding.
|
|
int binding;
|
|
|
|
HWND hWndTop;
|
|
HWND hWnd;
|
|
// For config screen, need to eat button's message handling.
|
|
HWND hWndButton;
|
|
};
|
|
|
|
|
|
// 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;
|
|
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];
|
|
|
|
// 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, 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) {}
|
|
inline 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
|