Files
pcsx2/plugins/LilyPad/InputManager.cpp
T
mattmenke 3a0ad40159 LilyPad: Experimental deadzone code. Old pressure sensitive button bindings must be rebound (DS3 buttons, XInput triggers).
Currently anything below deadzone is mapped to 0.  deadzone and above are mapped as if the control's true zero is 0 and 1/sensitivity is fully down (As opposed to deadzone being zero).  May change in the future.
Modified precompiled header to fix no-CRT build.
List of bindings noew automatically jumps to new bindings.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1914 96395faa-99c1-11dd-bbfe-3dabce05a288
2009-09-25 08:36:42 +00:00

597 lines
18 KiB
C++

#include "Global.h"
#include "InputManager.h"
#include "KeyboardQueue.h"
InputDeviceManager *dm = 0;
InputDeviceManager::InputDeviceManager() {
memset(this, 0, sizeof(*this));
}
void InputDeviceManager::ClearDevices() {
for (int i=0; i<numDevices; i++) {
delete devices[i];
}
free(devices);
devices = 0;
numDevices = 0;
}
InputDeviceManager::~InputDeviceManager() {
ClearDevices();
}
Device::Device(DeviceAPI api, DeviceType d, const wchar_t *displayName, const wchar_t *instanceID, wchar_t *productID) {
memset(pads, 0, sizeof(pads));
this->api = api;
type = d;
this->displayName = wcsdup(displayName);
if (instanceID)
this->instanceID = wcsdup(instanceID);
else
this->instanceID = wcsdup(displayName);
this->productID = 0;
if (productID)
this->productID = wcsdup(productID);
active = 0;
attached = 1;
enabled = 0;
virtualControls = 0;
numVirtualControls = 0;
virtualControlState = 0;
oldVirtualControlState = 0;
physicalControls = 0;
numPhysicalControls = 0;
physicalControlState = 0;
ffEffectTypes = 0;
numFFEffectTypes = 0;
ffAxes = 0;
numFFAxes = 0;
}
void Device::FreeState() {
if (virtualControlState) free(virtualControlState);
virtualControlState = 0;
oldVirtualControlState = 0;
physicalControlState = 0;
}
Device::~Device() {
Deactivate();
// Generally called by deactivate, but just in case...
FreeState();
int i;
for (int port=0; port<2; port++) {
for (int slot=0; slot<4; slot++) {
free(pads[port][slot].bindings);
for (i=0; i<pads[port][slot].numFFBindings; i++) {
free(pads[port][slot].ffBindings[i].axes);
}
free(pads[port][slot].ffBindings);
}
}
free(virtualControls);
for (i=numPhysicalControls-1; i>=0; i--) {
if (physicalControls[i].name) free(physicalControls[i].name);
}
free(physicalControls);
free(displayName);
free(instanceID);
free(productID);
if (ffAxes) {
for (i=0; i<numFFAxes; i++) {
free(ffAxes[i].displayName);
}
free(ffAxes);
}
if (ffEffectTypes) {
for (i=0; i<numFFEffectTypes; i++) {
free(ffEffectTypes[i].displayName);
free(ffEffectTypes[i].effectID);
}
free(ffEffectTypes);
}
}
void Device::AddFFEffectType(const wchar_t *displayName, const wchar_t *effectID, EffectType type) {
ffEffectTypes = (ForceFeedbackEffectType*) realloc(ffEffectTypes, sizeof(ForceFeedbackEffectType) * (numFFEffectTypes+1));
ffEffectTypes[numFFEffectTypes].displayName = wcsdup(displayName);
ffEffectTypes[numFFEffectTypes].effectID = wcsdup(effectID);
ffEffectTypes[numFFEffectTypes].type = type;
numFFEffectTypes++;
}
void Device::AddFFAxis(const wchar_t *displayName, int id) {
ffAxes = (ForceFeedbackAxis*) realloc(ffAxes, sizeof(ForceFeedbackAxis) * (numFFAxes+1));
ffAxes[numFFAxes].id = id;
ffAxes[numFFAxes].displayName = wcsdup(displayName);
numFFAxes++;
int bindingsExist = 0;
for (int port=0; port<2; port++) {
for (int slot=0; slot<4; slot++) {
for (int i=0; i<pads[port][slot].numFFBindings; i++) {
ForceFeedbackBinding *b = pads[port][slot].ffBindings+i;
b->axes = (AxisEffectInfo*) realloc(b->axes, sizeof(AxisEffectInfo) * (numFFAxes));
memset(b->axes + (numFFAxes-1), 0, sizeof(AxisEffectInfo));
bindingsExist = 1;
}
}
}
// Generally the case when not loading a binding file.
if (!bindingsExist) {
int i = numFFAxes-1;
ForceFeedbackAxis temp = ffAxes[i];
while (i && temp.id < ffAxes[i-1].id) {
ffAxes[i] = ffAxes[i-1];
i--;
}
ffAxes[i] = temp;
}
}
void Device::AllocState() {
FreeState();
virtualControlState = (int*) calloc(numVirtualControls + numVirtualControls + numPhysicalControls, sizeof(int));
oldVirtualControlState = virtualControlState + numVirtualControls;
physicalControlState = oldVirtualControlState + numVirtualControls;
}
void Device::FlipState() {
memcpy(oldVirtualControlState, virtualControlState, sizeof(int)*numVirtualControls);
}
void Device::PostRead() {
FlipState();
}
void Device::CalcVirtualState() {
for (int i=0; i<numPhysicalControls; i++) {
PhysicalControl *c = physicalControls+i;
int index = c->baseVirtualControlIndex;
int val = physicalControlState[i];
if (c->type & BUTTON) {
virtualControlState[index] = val;
// DirectInput keyboard events only.
if (this->api == DI && this->type == KEYBOARD) {
if (!(virtualControlState[index]>>15) != !(oldVirtualControlState[index]>>15) && c->vkey) {
// Check for alt-F4 to avoid toggling skip mode incorrectly.
if (c->vkey == VK_F4) {
for (int i=0; i<numPhysicalControls; i++) {
if (virtualControlState[physicalControls[i].baseVirtualControlIndex] &&
(physicalControls[i].vkey == VK_MENU ||
physicalControls[i].vkey == VK_RMENU ||
physicalControls[i].vkey == VK_LMENU)) {
return;
}
}
}
int event = KEYPRESS;
if (!(virtualControlState[index]>>15)) event = KEYRELEASE;
QueueKeyEvent(c->vkey, event);
}
}
}
else if (c->type & ABSAXIS) {
virtualControlState[index] = (val + FULLY_DOWN)/2;
// Positive. Overkill.
virtualControlState[index+1] = (val & ~(val>>31));
// Negative
virtualControlState[index+2] = (-val & (val>>31));
}
else if (c->type & RELAXIS) {
int delta = val - oldVirtualControlState[index];
virtualControlState[index] = val;
// Positive
virtualControlState[index+1] = (delta & ~(delta>>31));
// Negative
virtualControlState[index+2] = (-delta & (delta>>31));
}
else if (c->type & POV) {
virtualControlState[index] = val;
int iSouth = 0;
int iEast = 0;
if ((unsigned int)val <= 37000) {
double angle = val * (3.141592653589793/18000.0);
double East = sin(angle);
double South = -cos(angle);
// Normalize so greatest direction is 1.
double mul = FULLY_DOWN / max(fabs(South), fabs(East));
iEast = (int) floor(East * mul + 0.5);
iSouth = (int) floor(South * mul + 0.5);
}
// N
virtualControlState[index+1] = (-iSouth & (iSouth>>31));
// S
virtualControlState[index+3] = (iSouth & ~(iSouth>>31));
// E
virtualControlState[index+2] = (iEast & ~(iEast>>31));
// W
virtualControlState[index+4] = (-iEast & (iEast>>31));
}
}
}
VirtualControl *Device::GetVirtualControl(unsigned int uid) {
for (int i=0; i<numVirtualControls; i++) {
if (virtualControls[i].uid == uid)
return virtualControls + i;
}
return 0;
}
VirtualControl *Device::AddVirtualControl(unsigned int uid, int physicalControlIndex) {
// Not really necessary, as always call AllocState when activated, but doesn't hurt.
FreeState();
if (numVirtualControls % 16 == 0) {
virtualControls = (VirtualControl*) realloc(virtualControls, sizeof(VirtualControl)*(numVirtualControls+16));
}
VirtualControl *c = virtualControls + numVirtualControls;
c->uid = uid;
c->physicalControlIndex = physicalControlIndex;
numVirtualControls++;
return c;
}
PhysicalControl *Device::AddPhysicalControl(ControlType type, unsigned short id, unsigned short vkey, const wchar_t *name) {
// Not really necessary, as always call AllocState when activated, but doesn't hurt.
FreeState();
if (numPhysicalControls % 16 == 0) {
physicalControls = (PhysicalControl*) realloc(physicalControls, sizeof(PhysicalControl)*(numPhysicalControls+16));
}
PhysicalControl *control = physicalControls + numPhysicalControls;
memset(control, 0, sizeof(PhysicalControl));
control->type = type;
control->id = id;
if (name) control->name = wcsdup(name);
control->baseVirtualControlIndex = numVirtualControls;
unsigned int uid = id | (type<<16);
if (type & BUTTON) {
AddVirtualControl(uid, numPhysicalControls);
control->vkey = vkey;
}
else if (type & AXIS) {
AddVirtualControl(uid | UID_AXIS, numPhysicalControls);
AddVirtualControl(uid | UID_AXIS_POS, numPhysicalControls);
AddVirtualControl(uid | UID_AXIS_NEG, numPhysicalControls);
}
else if (type & POV) {
AddVirtualControl(uid | UID_POV, numPhysicalControls);
AddVirtualControl(uid | UID_POV_N, numPhysicalControls);
AddVirtualControl(uid | UID_POV_E, numPhysicalControls);
AddVirtualControl(uid | UID_POV_S, numPhysicalControls);
AddVirtualControl(uid | UID_POV_W, numPhysicalControls);
}
numPhysicalControls++;
return control;
}
void Device::SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force) {
for (int i=0; i<pads[port][slot].numFFBindings; i++) {
ForceFeedbackBinding *binding = pads[port][slot].ffBindings+i;
if (binding->motor == motor) {
SetEffect(binding, force);
}
}
}
wchar_t *GetDefaultControlName(unsigned short id, int type) {
static wchar_t name[20];
if (type & BUTTON) {
wsprintfW(name, L"Button %i", id);
}
else if (type & AXIS) {
wsprintfW(name, L"Axis %i", id);
}
else if (type & POV) {
wsprintfW(name, L"POV %i", id);
}
else return L"Unknown";
return name;
}
wchar_t *Device::GetVirtualControlName(VirtualControl *control) {
static wchar_t temp[100];
wchar_t *baseName = 0;
if (control->physicalControlIndex >= 0) {
baseName = physicalControls[control->physicalControlIndex].name;
if (!baseName) baseName = GetPhysicalControlName(&physicalControls[control->physicalControlIndex]);
}
unsigned int uid = control->uid;
if (!baseName) {
baseName = GetDefaultControlName(uid & 0xFFFF, (uid >> 16)& 0x1F);
}
uid &= 0xFF000000;
int len = (int)wcslen(baseName);
if (len > 99) len = 99;
memcpy(temp, baseName, len*sizeof(wchar_t));
temp[len] = 0;
if (uid) {
if (len > 95) len = 95;
wchar_t *out = temp+len;
if (uid == UID_AXIS_POS) {
wcscpy(out, L" +");
}
else if (uid == UID_AXIS_NEG) {
wcscpy(out, L" -");
}
else if (uid == UID_POV_N) {
wcscpy(out, L" N");
}
else if (uid == UID_POV_E) {
wcscpy(out, L" E");
}
else if (uid == UID_POV_S) {
wcscpy(out, L" S");
}
else if (uid == UID_POV_W) {
wcscpy(out, L" W");
}
}
return temp;
}
wchar_t *Device::GetPhysicalControlName(PhysicalControl *control) {
if (control->name) return control->name;
return GetDefaultControlName(control->id, control->type);
}
void InputDeviceManager::AddDevice(Device *d) {
devices = (Device**) realloc(devices, sizeof(Device*) * (numDevices+1));
devices[numDevices++] = d;
}
void InputDeviceManager::Update(InitInfo *info) {
for (int i=0; i<numDevices; i++) {
if (devices[i]->enabled) {
if (!devices[i]->active) {
if (!devices[i]->Activate(info) || !devices[i]->Update()) continue;
devices[i]->CalcVirtualState();
devices[i]->PostRead();
}
if (devices[i]->Update())
devices[i]->CalcVirtualState();
}
}
}
void InputDeviceManager::PostRead() {
for (int i=0; i<numDevices; i++) {
if (devices[i]->active)
devices[i]->PostRead();
}
}
Device *InputDeviceManager::GetActiveDevice(InitInfo *info, unsigned int *uid, int *index, int *value) {
int i, j;
Update(info);
int bestDiff = FULLY_DOWN/2;
Device *bestDevice = 0;
for (i=0; i<numDevices; i++) {
if (devices[i]->active) {
for (j=0; j<devices[i]->numVirtualControls; j++) {
if (devices[i]->virtualControlState[j] == devices[i]->oldVirtualControlState[j]) continue;
if (devices[i]->virtualControls[j].uid & UID_POV) continue;
// Fix for releasing button used to click on bind button
if (!((devices[i]->virtualControls[j].uid>>16) & (POV|RELAXIS|ABSAXIS))) {
if (abs(devices[i]->oldVirtualControlState[j]) > abs(devices[i]->virtualControlState[j])) {
devices[i]->oldVirtualControlState[j] = 0;
}
}
int diff = abs(devices[i]->virtualControlState[j] - devices[i]->oldVirtualControlState[j]);
// Make it require a bit more work to bind relative axes.
if (((devices[i]->virtualControls[j].uid>>16) & 0xFF) == RELAXIS) {
diff = diff/4+1;
}
// Less pressure needed to bind DS3 buttons.
if (devices[i]->api == DS3 && (((devices[i]->virtualControls[j].uid>>16) & 0xFF) & BUTTON)) {
diff *= 4;
}
if (diff > bestDiff) {
if (devices[i]->virtualControls[j].uid & UID_AXIS) {
if ((((devices[i]->virtualControls[j].uid>>16)&0xFF) != ABSAXIS)) continue;
// Very picky when binding entire axes. Prefer binding half-axes.
if (!((devices[i]->oldVirtualControlState[j] < FULLY_DOWN/32 && devices[i]->virtualControlState[j] > FULLY_DOWN/8) ||
(devices[i]->oldVirtualControlState[j] > 31*FULLY_DOWN/32 && devices[i]->virtualControlState[j] < 7*FULLY_DOWN/8))) {
continue;
}
devices[i]->virtualControls[j].uid = devices[i]->virtualControls[j].uid;
}
else if ((((devices[i]->virtualControls[j].uid>>16)&0xFF) == ABSAXIS)) {
if (devices[i]->oldVirtualControlState[j] > 15*FULLY_DOWN/16)
continue;
}
bestDiff = diff;
*uid = devices[i]->virtualControls[j].uid;
*index = j;
bestDevice = devices[i];
if (value) {
if ((devices[i]->virtualControls[j].uid>>16)& RELAXIS) {
*value = devices[i]->virtualControlState[j] - devices[i]->oldVirtualControlState[j];
}
else {
*value = devices[i]->virtualControlState[j];
}
}
}
}
}
}
// Don't call when binding.
// PostRead();
return bestDevice;
}
void InputDeviceManager::ReleaseInput() {
for (int i=0; i<numDevices; i++) {
if (devices[i]->active) devices[i]->Deactivate();
}
}
void InputDeviceManager::EnableDevices(DeviceType type, DeviceAPI api) {
for (int i=0; i<numDevices; i++) {
if (devices[i]->api == api && devices[i]->type == type) {
EnableDevice(i);
}
}
}
void InputDeviceManager::DisableAllDevices() {
for (int i=0; i<numDevices; i++) {
DisableDevice(i);
}
}
void InputDeviceManager::DisableDevice(int index) {
devices[index]->enabled = 0;
if (devices[index]->active) {
devices[index]->Deactivate();
}
}
ForceFeedbackEffectType *Device::GetForcefeedbackEffect(wchar_t *id) {
for (int i=0; i<numFFEffectTypes; i++) {
if (!wcsicmp(id, ffEffectTypes[i].effectID)) {
return &ffEffectTypes[i];
}
}
return 0;
}
ForceFeedbackAxis *Device::GetForceFeedbackAxis(int id) {
for (int i=0; i<numFFAxes; i++) {
if (ffAxes[i].id == id) return &ffAxes[i];
}
return 0;
}
void InputDeviceManager::CopyBindings(int numOldDevices, Device **oldDevices) {
int *oldMatches = (int*) malloc(sizeof(int) * numOldDevices);
int *matches = (int*) malloc(sizeof(int) * numDevices);
int i, j, port, slot;
Device *old, *dev;
for (i=0; i<numDevices; i++) {
matches[i] = -1;
}
for (i=0; i<numOldDevices; i++) {
oldMatches[i] = -2;
old = oldDevices[i];
for (port=0; port<2; port++) {
for (slot=0; slot<4; slot++) {
if (old->pads[port][slot].numBindings + old->pads[port][slot].numFFBindings) {
// Means that there are bindings.
oldMatches[i] = -1;
}
}
}
}
// Loops through ids looking for match, from most specific to most general.
for (int id=0; id<3; id++) {
for (i=0; i<numOldDevices; i++) {
if (oldMatches[i] >= 0) continue;
for (j=0; j<numDevices; j++) {
if (matches[j] >= 0) {
continue;
}
wchar_t *id1 = devices[j]->IDs[id];
wchar_t *id2 = oldDevices[i]->IDs[id];
if (!id1 || !id2) {
continue;
}
if (!wcsicmp(devices[j]->instanceID, oldDevices[i]->instanceID)) {
matches[j] = i;
oldMatches[i] = j;
break;
}
}
}
}
for (i=0; i<numOldDevices; i++) {
if (oldMatches[i] == -2) continue;
old = oldDevices[i];
if (oldMatches[i] < 0) {
dev = new Device(old->api, old->type, old->displayName, old->instanceID, old->productID);
dev->attached = 0;
AddDevice(dev);
for (j=0; j<old->numVirtualControls; j++) {
VirtualControl *c = old->virtualControls+j;
dev->AddVirtualControl(c->uid, -1);
}
for (j=0; j<old->numFFEffectTypes; j++) {
ForceFeedbackEffectType * effect = old->ffEffectTypes + j;
dev->AddFFEffectType(effect->displayName, effect->effectID, effect->type);
}
for (j=0; j<old->numFFAxes; j++) {
ForceFeedbackAxis * axis = old->ffAxes + j;
dev->AddFFAxis(axis->displayName, axis->id);
}
// Just steal the old bindings directly when there's no matching device.
// Indices will be the same.
memcpy(dev->pads, old->pads, sizeof(old->pads));
memset(old->pads, 0, sizeof(old->pads));
}
else {
dev = devices[oldMatches[i]];
for (port=0; port<2; port++) {
for (slot=0; slot<4; slot++) {
if (old->pads[port][slot].numBindings) {
dev->pads[port][slot].bindings = (Binding*) malloc(old->pads[port][slot].numBindings * sizeof(Binding));
for (int j=0; j<old->pads[port][slot].numBindings; j++) {
Binding *bo = old->pads[port][slot].bindings + j;
Binding *bn = dev->pads[port][slot].bindings + dev->pads[port][slot].numBindings;
VirtualControl *cn = dev->GetVirtualControl(old->virtualControls[bo->controlIndex].uid);
if (cn) {
*bn = *bo;
bn->controlIndex = cn - dev->virtualControls;
dev->pads[port][slot].numBindings++;
}
}
}
if (old->pads[port][slot].numFFBindings) {
dev->pads[port][slot].ffBindings = (ForceFeedbackBinding*) malloc(old->pads[port][slot].numFFBindings * sizeof(ForceFeedbackBinding));
for (int j=0; j<old->pads[port][slot].numFFBindings; j++) {
ForceFeedbackBinding *bo = old->pads[port][slot].ffBindings + j;
ForceFeedbackBinding *bn = dev->pads[port][slot].ffBindings + dev->pads[port][slot].numFFBindings;
ForceFeedbackEffectType *en = dev->GetForcefeedbackEffect(old->ffEffectTypes[bo->effectIndex].effectID);
if (en) {
*bn = *bo;
bn->effectIndex = en - dev->ffEffectTypes;
bn->axes = (AxisEffectInfo*)calloc(dev->numFFAxes, sizeof(AxisEffectInfo));
for (int k=0; k<old->numFFAxes; k++) {
ForceFeedbackAxis *newAxis = dev->GetForceFeedbackAxis(old->ffAxes[k].id);
if (newAxis) {
bn->axes[newAxis - dev->ffAxes] = bo->axes[k];
}
}
dev->pads[port][slot].numFFBindings++;
}
}
}
}
}
}
}
free(oldMatches);
free(matches);
}
void InputDeviceManager::SetEffect(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force) {
for (int i=0; i<numDevices; i++) {
Device *dev = devices[i];
if (dev->enabled && dev->numFFEffectTypes) {
dev->SetEffects(port, slot, motor, force);
}
}
}