mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-04-02 10:52:54 -04:00
Adds a skip deadzone option to the Pad tabs. With the normal deadzone, if the control input value is below the deadzone threshold, the input is ignored. However, some controllers also benefit from shortening the input range by skipping a deadzone.
662 lines
24 KiB
C++
662 lines
24 KiB
C++
/* 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/>.
|
|
*/
|
|
|
|
#include "Global.h"
|
|
#include "InputManager.h"
|
|
#include "KeyboardQueue.h"
|
|
#include "Config.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, const 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;
|
|
|
|
#ifdef _MSC_VER
|
|
hWndProc = 0;
|
|
#endif
|
|
|
|
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++) {
|
|
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
|
free(pads[port][slot][padtype].bindings);
|
|
for (i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
|
free(pads[port][slot][padtype].ffBindings[i].axes);
|
|
}
|
|
free(pads[port][slot][padtype].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 padtype = 0; padtype < numPadTypes; padtype++) {
|
|
for (int i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
|
ForceFeedbackBinding *b = pads[port][slot][padtype].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) {
|
|
int i;
|
|
for (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)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i < numPhysicalControls)
|
|
continue;
|
|
}
|
|
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 / std::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)
|
|
{
|
|
int padtype = config.padConfigs[port][slot].type;
|
|
for (int i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
|
ForceFeedbackBinding *binding = pads[port][slot][padtype].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 {
|
|
wcscpy(name, 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/SCP buttons.
|
|
if ((devices[i]->api == DS3 || devices[i]->api == XINPUT) && (((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;
|
|
}
|
|
} 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++) {
|
|
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
|
if (old->pads[port][slot][padtype].numBindings + old->pads[port][slot][padtype].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(id1, id2)) {
|
|
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++) {
|
|
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
|
if (old->pads[port][slot][padtype].numBindings) {
|
|
dev->pads[port][slot][padtype].bindings = (Binding *)malloc(old->pads[port][slot][padtype].numBindings * sizeof(Binding));
|
|
for (int j = 0; j < old->pads[port][slot][padtype].numBindings; j++) {
|
|
Binding *bo = old->pads[port][slot][padtype].bindings + j;
|
|
Binding *bn = dev->pads[port][slot][padtype].bindings + dev->pads[port][slot][padtype].numBindings;
|
|
VirtualControl *cn = dev->GetVirtualControl(old->virtualControls[bo->controlIndex].uid);
|
|
if (cn) {
|
|
*bn = *bo;
|
|
bn->controlIndex = cn - dev->virtualControls;
|
|
dev->pads[port][slot][padtype].numBindings++;
|
|
}
|
|
}
|
|
}
|
|
if (old->pads[port][slot][padtype].numFFBindings) {
|
|
dev->pads[port][slot][padtype].ffBindings = (ForceFeedbackBinding *)malloc(old->pads[port][slot][padtype].numFFBindings * sizeof(ForceFeedbackBinding));
|
|
for (int j = 0; j < old->pads[port][slot][padtype].numFFBindings; j++) {
|
|
ForceFeedbackBinding *bo = old->pads[port][slot][padtype].ffBindings + j;
|
|
ForceFeedbackBinding *bn = dev->pads[port][slot][padtype].ffBindings + dev->pads[port][slot][padtype].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][padtype].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);
|
|
}
|
|
}
|
|
}
|