From 3cbd298cff69e9bb03dea8573d076a784dbceb7e Mon Sep 17 00:00:00 2001 From: mattmenke Date: Thu, 6 Aug 2009 04:50:55 +0000 Subject: [PATCH] LilyPad: A number of small fixups. DirectInput devices corresponding XInput devices should be listed as "[Detached]" when XInput is enabled. No idea if this works, as it requires an XBox 360 controller to fully test. FF Axes now sorted, rather than being displayed in the order MS returns them. Small motor DirectInput binding now correctly displays "Square" effect type in list when first created. Attempt to more accurately model "soft" vs "hard" presses. Don't have a game where this matters, so no idea if it works. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1607 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/LilyPad/Config.cpp | 37 ++++--- plugins/LilyPad/DeviceEnumerator.cpp | 4 +- plugins/LilyPad/DeviceEnumerator.h | 2 +- plugins/LilyPad/DirectInput.cpp | 138 ++++++++++++++++++++++++++- plugins/LilyPad/DirectInput.h | 2 +- plugins/LilyPad/InputManager.cpp | 12 +++ plugins/LilyPad/LilyPad.cpp | 12 +-- plugins/LilyPad/LilyPad.rc | 2 +- 8 files changed, 179 insertions(+), 30 deletions(-) diff --git a/plugins/LilyPad/Config.cpp b/plugins/LilyPad/Config.cpp index e3110b988e..a5bb915bf2 100644 --- a/plugins/LilyPad/Config.cpp +++ b/plugins/LilyPad/Config.cpp @@ -130,7 +130,11 @@ void SetLogSliderVal(HWND hWnd, int id, HWND hWndText, int val) { void RefreshEnabledDevices(int updateDeviceList) { // Clears all device state. - if (updateDeviceList) EnumDevices(); + static int lastXInputState = -1; + if (updateDeviceList || lastXInputState != config.gameApis.xInput) { + EnumDevices(config.gameApis.xInput); + lastXInputState = config.gameApis.xInput; + } for (int i=0; inumDevices; i++) { Device *dev = dm->devices[i]; @@ -1094,11 +1098,16 @@ int CreateEffectBinding(Device *dev, wchar_t *effectID, unsigned int port, unsig if (port > 1 || slot>3 || motor > 1 || !dev->numFFEffectTypes) { return -1; } - if (!effectID) { - effectID = dev->ffEffectTypes[0].effectID; + ForceFeedbackEffectType *eff = 0; + if (effectID) { + eff = dev->GetForcefeedbackEffect(effectID); + } + if (!eff) { + eff = dev->ffEffectTypes; + } + if (!eff) { + return -1; } - ForceFeedbackEffectType *eff = dev->GetForcefeedbackEffect(effectID); - if (!eff) return -1; int effectIndex = eff - dev->ffEffectTypes; dev->pads[port][slot].ffBindings = (ForceFeedbackBinding*) realloc(dev->pads[port][slot].ffBindings, (dev->pads[port][slot].numFFBindings+1) * sizeof(ForceFeedbackBinding)); int newIndex = dev->pads[port][slot].numFFBindings; @@ -1404,7 +1413,14 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l if (index < (unsigned int) dm->numDevices) { Device *dev = dm->devices[index]; ForceFeedbackBinding *b; - int count = CreateEffectBinding(dev, 0, port, slot, cmd-ID_BIG_MOTOR, &b); + wchar_t *effectID = 0; + if (dev->api == DI) { + // Constant effect. + if (cmd == ID_BIG_MOTOR) effectID = L"13541C20-8E33-11D0-9AD0-00A0C9A06E35"; + // Square. + else effectID = L"13541C22-8E33-11D0-9AD0-00A0C9A06E35"; + } + int count = CreateEffectBinding(dev, effectID, port, slot, cmd-ID_BIG_MOTOR, &b); if (b) { int needSet = 1; if (dev->api == XINPUT && dev->numFFAxes == 2) { @@ -1418,7 +1434,6 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l } else if (dev->api == DI) { int bigIndex=0, littleIndex=0; - int constantEffect = 0, squareEffect = 0; int j; for (j=0; jnumFFAxes; j++) { // DI object instance. 0 is x-axis, 1 is y-axis. @@ -1430,20 +1445,14 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l littleIndex = j; } } - for (j=0; jnumFFEffectTypes; j++) { - if (!wcsicmp(L"13541C20-8E33-11D0-9AD0-00A0C9A06E35", dev->ffEffectTypes[j].effectID)) constantEffect = j; - if (!wcsicmp(L"13541C22-8E33-11D0-9AD0-00A0C9A06E35", dev->ffEffectTypes[j].effectID)) squareEffect = j; - } needSet = 0; if (cmd == ID_BIG_MOTOR) { b->axes[bigIndex].force = BASE_SENSITIVITY; b->axes[littleIndex].force = 1; - b->effectIndex = constantEffect; } else { b->axes[bigIndex].force = 1; b->axes[littleIndex].force = BASE_SENSITIVITY; - b->effectIndex = squareEffect; } } if (needSet) { @@ -1695,7 +1704,7 @@ INT_PTR CALLBACK GeneralDialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, L selected = 0; ListView_SetExtendedListViewStyleEx(hWndList, LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER, LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER); SendMessage(hWndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); - SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) L"Disabled"); + SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) L"Unplugged"); SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) L"Dualshock 2"); SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) L"Guitar"); } diff --git a/plugins/LilyPad/DeviceEnumerator.cpp b/plugins/LilyPad/DeviceEnumerator.cpp index 9c012e64c0..45b1aca7b0 100644 --- a/plugins/LilyPad/DeviceEnumerator.cpp +++ b/plugins/LilyPad/DeviceEnumerator.cpp @@ -7,7 +7,7 @@ #include "RawInput.h" #include "XInput.h" -void EnumDevices() { +void EnumDevices(int hideDXXinput) { // Needed for enumeration of some device types. dm->ReleaseInput(); InputDeviceManager *oldDm = dm; @@ -17,7 +17,7 @@ void EnumDevices() { EnumWindowsMessagingDevices(); EnumRawInputDevices(); EnumXInputDevices(); - EnumDirectInputDevices(); + EnumDirectInputDevices(hideDXXinput); dm->CopyBindings(oldDm->numDevices, oldDm->devices); diff --git a/plugins/LilyPad/DeviceEnumerator.h b/plugins/LilyPad/DeviceEnumerator.h index 5c8e0cf07f..05f99e5146 100644 --- a/plugins/LilyPad/DeviceEnumerator.h +++ b/plugins/LilyPad/DeviceEnumerator.h @@ -9,5 +9,5 @@ struct InitInfo { HWND hWndButton; }; -void EnumDevices(); +void EnumDevices(int hideDXXinput); diff --git a/plugins/LilyPad/DirectInput.cpp b/plugins/LilyPad/DirectInput.cpp index 4c7951a1f3..0afe068975 100644 --- a/plugins/LilyPad/DirectInput.cpp +++ b/plugins/LilyPad/DirectInput.cpp @@ -9,6 +9,16 @@ #include "PS2Etypes.h" #include +// All for getting GUIDs of XInput devices.... +#include +#include +// MS's code imports wmsstd.h, thus requiring the entire windows +// media SDK also be installed for a simple macro. This is +// simpler and less silly. +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } +#endif + // Aka htons, without the winsock dependency. inline static u16 flipShort(u16 s) { return (s>>8) | (s<<8); @@ -440,10 +450,126 @@ BOOL CALLBACK EnumDeviceObjectsCallback (LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOI return DIENUM_CONTINUE; } +// Evil code from MS's site. If only they'd just made a way to get +// an XInput device's GUID directly in the first place... +BOOL IsXInputDevice( const GUID* pGuidProductFromDirectInput ) +{ + IWbemLocator* pIWbemLocator = NULL; + IEnumWbemClassObject* pEnumDevices = NULL; + IWbemClassObject* pDevices[20] = {0}; + IWbemServices* pIWbemServices = NULL; + BSTR bstrNamespace = NULL; + BSTR bstrDeviceID = NULL; + BSTR bstrClassName = NULL; + DWORD uReturned = 0; + bool bIsXinputDevice= false; + UINT iDevice = 0; + VARIANT var; + HRESULT hr; + + // CoInit if needed + hr = CoInitialize(NULL); + bool bCleanupCOM = SUCCEEDED(hr); + + // Create WMI + hr = CoCreateInstance( __uuidof(WbemLocator), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IWbemLocator), + (LPVOID*) &pIWbemLocator); + if( FAILED(hr) || pIWbemLocator == NULL ) + goto LCleanup; + + bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );if( bstrNamespace == NULL ) goto LCleanup; + bstrClassName = SysAllocString( L"Win32_PNPEntity" ); if( bstrClassName == NULL ) goto LCleanup; + bstrDeviceID = SysAllocString( L"DeviceID" ); if( bstrDeviceID == NULL ) goto LCleanup; + + // Connect to WMI + hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, + 0L, NULL, NULL, &pIWbemServices ); + if( FAILED(hr) || pIWbemServices == NULL ) + goto LCleanup; + + // Switch security level to IMPERSONATE. + CoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ); + + hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices ); + if( FAILED(hr) || pEnumDevices == NULL ) + goto LCleanup; + + // Loop over all devices + for( ;; ) + { + // Get 20 at a time + hr = pEnumDevices->Next( 10000, 20, pDevices, &uReturned ); + if( FAILED(hr) ) + goto LCleanup; + if( uReturned == 0 ) + break; + + for( iDevice=0; iDeviceGet( bstrDeviceID, 0L, &var, NULL, NULL ); + if( SUCCEEDED( hr ) && var.vt == VT_BSTR && var.bstrVal != NULL ) + { + // Check if the device ID contains "IG_". If it does, then it's an XInput device + // This information can not be found from DirectInput + if( wcsstr( var.bstrVal, L"IG_" ) ) + { + // If it does, then get the VID/PID from var.bstrVal + DWORD dwPid = 0, dwVid = 0; + WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" ); + if( strVid && swscanf( strVid, L"VID_%4X", &dwVid ) != 1 ) + dwVid = 0; + WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" ); + if( strPid && swscanf( strPid, L"PID_%4X", &dwPid ) != 1 ) + dwPid = 0; + + // Compare the VID/PID to the DInput device + DWORD dwVidPid = MAKELONG( dwVid, dwPid ); + if( dwVidPid == pGuidProductFromDirectInput->Data1 ) + { + bIsXinputDevice = true; + goto LCleanup; + } + } + } + SAFE_RELEASE( pDevices[iDevice] ); + } + } + +LCleanup: + if(bstrNamespace) + SysFreeString(bstrNamespace); + if(bstrDeviceID) + SysFreeString(bstrDeviceID); + if(bstrClassName) + SysFreeString(bstrClassName); + for( iDevice=0; iDevice<20; iDevice++ ) + SAFE_RELEASE( pDevices[iDevice] ); + SAFE_RELEASE( pEnumDevices ); + SAFE_RELEASE( pIWbemLocator ); + SAFE_RELEASE( pIWbemServices ); + + if( bCleanupCOM ) + CoUninitialize(); + + return bIsXinputDevice; +} + + +struct DeviceEnumInfo { + IDirectInput8 *di8; + int ignoreXInput; +}; + BOOL CALLBACK EnumCallback (LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) { - IDirectInput8* di8 = (IDirectInput8*)pvRef; + IDirectInput8* di8 = ((DeviceEnumInfo*)pvRef)->di8; const wchar_t *name; wchar_t temp[40]; + //if (((DeviceEnumInfo*)pvRef)->ignoreXInput && lpddi-> if (lpddi->tszInstanceName[0]) { name = lpddi->tszInstanceName; } @@ -476,11 +602,13 @@ BOOL CALLBACK EnumCallback (LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) { return DIENUM_CONTINUE; } -void EnumDirectInputDevices() { - IDirectInput8* di8 = GetDirectInput(); - if (!di8) return; +void EnumDirectInputDevices(int ignoreXInput) { + DeviceEnumInfo enumInfo; + enumInfo.di8 = GetDirectInput(); + if (!enumInfo.di8) return; + enumInfo.ignoreXInput = ignoreXInput; di8d.deviceCount = 0; - di8->EnumDevices(DI8DEVCLASS_ALL, EnumCallback, di8, DIEDFL_ATTACHEDONLY); + enumInfo.di8->EnumDevices(DI8DEVCLASS_ALL, EnumCallback, &enumInfo, DIEDFL_ATTACHEDONLY); ReleaseDirectInput(); } diff --git a/plugins/LilyPad/DirectInput.h b/plugins/LilyPad/DirectInput.h index 5e7ee5dcf8..9d263f7e5a 100644 --- a/plugins/LilyPad/DirectInput.h +++ b/plugins/LilyPad/DirectInput.h @@ -1,3 +1,3 @@ #include "InputManager.h" -void EnumDirectInputDevices(); +void EnumDirectInputDevices(int ignoreXInput); diff --git a/plugins/LilyPad/InputManager.cpp b/plugins/LilyPad/InputManager.cpp index 829ed06f38..1686838e0a 100644 --- a/plugins/LilyPad/InputManager.cpp +++ b/plugins/LilyPad/InputManager.cpp @@ -112,15 +112,27 @@ void Device::AddFFAxis(const wchar_t *displayName, int id) { 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; 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() { diff --git a/plugins/LilyPad/LilyPad.cpp b/plugins/LilyPad/LilyPad.cpp index c878eed07d..f9a4313b3d 100644 --- a/plugins/LilyPad/LilyPad.cpp +++ b/plugins/LilyPad/LilyPad.cpp @@ -969,20 +969,20 @@ u8 CALLBACK PADpoll(u8 value) { u8 b1 = 0xFF, b2 = 0xFF; for (i = 0; i<4; i++) { - b1 -= (sum->buttons[i]>=128) << i; + b1 -= (sum->buttons[i]>=0xF0) << i; } for (i = 0; i<8; i++) { - b2 -= (sum->buttons[i+4]>=128) << i; + b2 -= (sum->buttons[i+4]>=0xF0) << i; } if (config.padConfigs[query.port][query.slot].type == GuitarPad && !config.GH2) { sum->sticks[0].horiz = -255; // Not sure about this. Forces wammy to be from 0 to 0x7F. // if (sum->sticks[2].vert > 0) sum->sticks[2].vert = 0; } - b1 -= ((sum->sticks[0].vert<=-128) << 4); - b1 -= ((sum->sticks[0].horiz>=128) << 5); - b1 -= ((sum->sticks[0].vert>=128) << 6); - b1 -= ((sum->sticks[0].horiz<=-128) << 7); + b1 -= ((sum->sticks[0].vert<=-0xF0) << 4); + b1 -= ((sum->sticks[0].horiz>=0xF0) << 5); + b1 -= ((sum->sticks[0].vert>=0xF0) << 6); + b1 -= ((sum->sticks[0].horiz<=-0xF0) << 7); query.response[3] = b1; query.response[4] = b2; diff --git a/plugins/LilyPad/LilyPad.rc b/plugins/LilyPad/LilyPad.rc index 5a6b1ad24c..48d82fdc84 100644 --- a/plugins/LilyPad/LilyPad.rc +++ b/plugins/LilyPad/LilyPad.rc @@ -227,7 +227,7 @@ BEGIN CONTROL "Port 1 Multitap",IDC_MULTITAP1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,152,63,10 CONTROL "Port 2 Multitap",IDC_MULTITAP2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,164,63,10 CONTROL "",IDC_PAD_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,81,151,183,50,WS_EX_CLIENTEDGE - COMBOBOX IDC_PAD_TYPE,270,152,140,41,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_PAD_TYPE,270,152,140,41,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Use analog mode whenever possible",IDC_ANALOG_START1, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,270,169,132,10 GROUPBOX "Device Diagnostics",IDC_STATIC,7,211,201,99