/* 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 . */ #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; iapi = 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++) { free(pads[port][slot].bindings); for (i=0; i=0; i--) { if (physicalControls[i].name) free(physicalControls[i].name); } free(physicalControls); free(displayName); free(instanceID); free(productID); if (ffAxes) { for (i=0; iaxes = (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; ibaseVirtualControlIndex; 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>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. #ifdef __linux__ double mul = FULLY_DOWN / std::max(fabs(South), fabs(East)); #else double mul = FULLY_DOWN / max(fabs(South), fabs(East)); #endif 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; iuid = 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; imotor == 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; ienabled) { 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; iactive) 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; iactive) { for (j=0; jnumVirtualControls; 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; iactive) devices[i]->Deactivate(); } } void InputDeviceManager::EnableDevices(DeviceType type, DeviceAPI api) { for (int i=0; iapi == api && devices[i]->type == type) { EnableDevice(i); } } } void InputDeviceManager::DisableAllDevices() { for (int i=0; ienabled = 0; if (devices[index]->active) { devices[index]->Deactivate(); } } ForceFeedbackEffectType *Device::GetForcefeedbackEffect(wchar_t *id) { for (int i=0; ipads[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= 0) continue; for (j=0; 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; iapi, old->type, old->displayName, old->instanceID, old->productID); dev->attached = 0; AddDevice(dev); for (j=0; jnumVirtualControls; j++) { VirtualControl *c = old->virtualControls+j; dev->AddVirtualControl(c->uid, -1); } for (j=0; jnumFFEffectTypes; j++) { ForceFeedbackEffectType * effect = old->ffEffectTypes + j; dev->AddFFEffectType(effect->displayName, effect->effectID, effect->type); } for (j=0; jnumFFAxes; 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; jpads[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; jpads[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; knumFFAxes; 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; ienabled && dev->numFFEffectTypes) { dev->SetEffects(port, slot, motor, force); } } }