mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-09-09 22:32:57 +02:00
New method of ensuring thread safety. Device update code should always run in GS thread, even if the emulator really doesn't want to let me (Basically ancient versions of Pcsx2...Or any 3rd party emulators with their own version of MTGS). Updates on PADpoll, PADkeyEvent, or PADupdate, if one is called in the right thread. Updates in thread's WndProc otherwise. Overkill, perhaps, but I prefer to keep things compatible. Removed "Update in GS thread" option. Windows Messaging/Raw Input keyboard event queuing should work a little better. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1896 96395faa-99c1-11dd-bbfe-3dabce05a288
593 lines
18 KiB
C++
593 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;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|