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