mirror of https://github.com/PCSX2/pcsx2.git
591 lines
18 KiB
C++
591 lines
18 KiB
C++
#include "InputManager.h"
|
|
#include "Global.h"
|
|
#include "KeyboardQueue.h"
|
|
#include <math.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;
|
|
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(void *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(void *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);
|
|
}
|
|
}
|
|
}
|
|
|