project64/Source/nragev20/XInputController.cpp

823 lines
28 KiB
C++

/*
XInput Controller support for N-Rage`s Dinput8 Plugin by tecnicors
(C) 2009 Daniel Rehren - XInput Controller support
Author's Email: rehren_007@hotmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//code from http://msdn.microsoft.com/en-us/library/ee417014(VS.85).aspx
#include <windows.h>
#include <wbemidl.h>
#include "XInputController.h"
#include "FileAccess.h"
#include <wchar.h>
#include <tchar.h>
#include "resource.h"
#include <stdio.h>
//We need to keep track of XInput control id's
int iXinputControlId = 0;
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; iDevice<uReturned; iDevice++ )
{
// For each device, get its device ID
hr = pDevices[iDevice]->Get( bstrDeviceID, 0L, &var, NULL, NULL );
if( SUCCEEDED( hr ) )
{
if(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 && wscanf(strVid, L"VID_%4X", &dwVid) != 1)
dwVid = 0;
WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
if (strPid && wscanf(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;
}
}
}
VariantClear(&var);
}
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;
}
void AxisDeadzone( SHORT &AxisValue, long lDeadZoneValue, float fDeadZoneRelation )
{
short sign = AxisValue < 0 ? -1 : 1;
float value = (float)(AxisValue < 0 ? -AxisValue : AxisValue);
if(value < lDeadZoneValue)
value = 0;
else
{
value = (value - lDeadZoneValue) * fDeadZoneRelation;
value = value > 32767.0f ? 32767.0f : value;
}
AxisValue = (SHORT)(value * sign);
}
void GetXInputControllerKeys( const int indexController, LPDWORD Keys )
{
if (fnXInputGetState == NULL)
{
return;
}
using namespace N64_BUTTONS;
LPCONTROLLER pcController = &g_pcControllers[indexController];
LPXCONTROLLER gController = &g_pcControllers[indexController].xiController;
*Keys = 0;
if ( !gController->bConfigured )
return;
DWORD result;
XINPUT_STATE state;
result = fnXInputGetState(gController->nControl, &state);
if( result != ERROR_SUCCESS )
return;
DWORD wButtons = state.Gamepad.wButtons;
if( pcController->bPadDeadZone > 0 )
{
const int RANGERELATIVE = 32767;
long lDeadZoneValue = pcController->bPadDeadZone * RANGERELATIVE / 100;
float fDeadZoneRelation = (float)RANGERELATIVE / (float)( RANGERELATIVE - lDeadZoneValue );
AxisDeadzone(state.Gamepad.sThumbLX, lDeadZoneValue, fDeadZoneRelation);
AxisDeadzone(state.Gamepad.sThumbLY, lDeadZoneValue, fDeadZoneRelation);
AxisDeadzone(state.Gamepad.sThumbRX, lDeadZoneValue, fDeadZoneRelation);
AxisDeadzone(state.Gamepad.sThumbRY, lDeadZoneValue, fDeadZoneRelation);
}
short LY = state.Gamepad.sThumbLY * N64_ANALOG_MAX / XC_ANALOG_MAX;
short LX = state.Gamepad.sThumbLX * N64_ANALOG_MAX / XC_ANALOG_MAX;
short RY = state.Gamepad.sThumbRY * N64_ANALOG_MAX / XC_ANALOG_MAX;
short RX = state.Gamepad.sThumbRX * N64_ANALOG_MAX / XC_ANALOG_MAX;
short XAx = 0, XAxc = 0;
short YAx = 0, YAxc = 0;
WORD valButtons = 0;
valButtons |= ( wButtons & gController->stButtons.iDRight ) ? DRight : 0;
valButtons |= ( wButtons & gController->stButtons.iDLeft ) ? DLeft : 0;
valButtons |= ( wButtons & gController->stButtons.iDDown ) ? DDown : 0;
valButtons |= ( wButtons & gController->stButtons.iDUp ) ? DUp : 0;
valButtons |= ( wButtons & gController->stButtons.iStart ) ? Start : 0;
valButtons |= ( wButtons & gController->stButtons.iZ ) ? Z : 0;
valButtons |= ( wButtons & gController->stButtons.iB ) ? B : 0;
valButtons |= ( wButtons & gController->stButtons.iA ) ? A : 0;
valButtons |= ( wButtons & gController->stButtons.iCRight ) ? CRight : 0;
valButtons |= ( wButtons & gController->stButtons.iCLeft ) ? CLeft : 0;
valButtons |= ( wButtons & gController->stButtons.iCDown ) ? CDown : 0;
valButtons |= ( wButtons & gController->stButtons.iCUp ) ? CUp : 0;
valButtons |= ( wButtons & gController->stButtons.iR ) ? R : 0;
valButtons |= ( wButtons & gController->stButtons.iL ) ? L : 0;
valButtons |= state.Gamepad.bLeftTrigger > 30 ? gController->stAnalogs.iLeftTrigger : 0;
valButtons |= state.Gamepad.bRightTrigger > 30 ? gController->stAnalogs.iRightTrigger : 0;
if (LX >= BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iLXAxis & ((CRight | DRight) << 16) ? gController->stAnalogs.iLXAxis >> 16 : 0;
if (LX <= -BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iLXAxis & (CLeft | DLeft) ? gController->stAnalogs.iLXAxis : 0;
if (LY >= BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iLYAxis & ((CUp | DUp) << 16) ? gController->stAnalogs.iLYAxis >> 16 : 0;
if (LY <= -BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iLYAxis & (CDown | DDown) ? gController->stAnalogs.iLYAxis : 0;
if (RX >= BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iRXAxis & ((CRight | DRight) << 16) ? gController->stAnalogs.iRXAxis >> 16 : 0;
if (RX <= -BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iRXAxis & (CLeft | DLeft) ? gController->stAnalogs.iRXAxis : 0;
if (RY >= BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iRYAxis & ((CUp | DUp) << 16) ? gController->stAnalogs.iRYAxis >> 16 : 0;
if (RY <= -BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iRYAxis & (CDown | DDown) ? gController->stAnalogs.iRYAxis : 0;
if (gController->stAnalogs.iLXAxis == XAxis)
{
XAx += LX;
XAxc += LX > 0 ? 1 : 0;
}
if (gController->stAnalogs.iRXAxis == XAxis)
{
XAx += RX;
XAxc += RX > 0 ? 1 : 0;
}
if( XAxc )
XAx /= XAxc;
if (gController->stAnalogs.iLYAxis == YAxis)
{
YAx += LY;
YAxc += LY > 0 ? 1 : 0;
}
if (gController->stAnalogs.iRYAxis == YAxis)
{
YAx += RY;
YAxc += RY > 0 ? 1 : 0;
}
if( YAxc )
YAx /= YAxc;
*Keys = MAKELONG(valButtons, MAKEWORD(XAx, YAx));
}
void DefaultXInputControllerKeys( LPXCONTROLLER gController)
{
using namespace N64_BUTTONS;
gController->stButtons.iA = XINPUT_GAMEPAD_A | XINPUT_GAMEPAD_Y;
gController->stButtons.iB = XINPUT_GAMEPAD_B | XINPUT_GAMEPAD_X;
gController->stButtons.iStart = XINPUT_GAMEPAD_START | XINPUT_GAMEPAD_BACK;
gController->stButtons.iDDown = XINPUT_GAMEPAD_DPAD_DOWN;
gController->stButtons.iDLeft = XINPUT_GAMEPAD_DPAD_LEFT;
gController->stButtons.iDRight = XINPUT_GAMEPAD_DPAD_RIGHT;
gController->stButtons.iDUp = XINPUT_GAMEPAD_DPAD_UP;
gController->stButtons.iL = XINPUT_GAMEPAD_LEFT_SHOULDER;
gController->stButtons.iR = XINPUT_GAMEPAD_RIGHT_SHOULDER;
gController->stAnalogs.iLeftTrigger = Z;
gController->stAnalogs.iRightTrigger = R;
gController->stAnalogs.iRXAxis = (CRight << 16) | CLeft;
gController->stAnalogs.iRYAxis = (CUp << 16) | CDown;
gController->stAnalogs.iLXAxis = XAxis;
gController->stAnalogs.iLYAxis = YAxis;
gController->bConfigured = true;
}
void VibrateXInputController( DWORD nController, int LeftMotorVal, int RightMotorVal )
{
if (fnXInputSetState == NULL)
{
return;
}
XINPUT_VIBRATION vibration;
ZeroMemory( &vibration, sizeof( XINPUT_VIBRATION ) );
vibration.wLeftMotorSpeed = LeftMotorVal;
vibration.wRightMotorSpeed = RightMotorVal;
fnXInputSetState(nController, &vibration);
}
bool InitXinput()
{
//Lets dynamically load in the XInput library
if (g_hXInputDLL == NULL)
g_hXInputDLL = LoadLibrary("Xinput1_4.dll");
if (g_hXInputDLL == NULL)
{
//Ok since 1.4 is present, try 9.1.0 as its present on Vista and newer
g_hXInputDLL = LoadLibrary("Xinput9_1_0.dll");
}
if (g_hXInputDLL == NULL)
{
return false;
}
//Prepare the functions where going to use, nice and simple for XInput
fnXInputSetState = (DWORD(WINAPI *) (DWORD, XINPUT_VIBRATION*))GetProcAddress(g_hXInputDLL, "XInputSetState");
fnXInputGetState = (DWORD(WINAPI *) (DWORD, XINPUT_STATE*))GetProcAddress(g_hXInputDLL, "XInputGetState");
return true;
}
void FreeXinput()
{
//Unload the Library
if (g_hXInputDLL != NULL)
{
FreeLibrary(g_hXInputDLL);
g_hXInputDLL = NULL;
}
}
bool InitiateXInputController( LPXCONTROLLER gController, int nControl )
{
if (fnXInputGetState == NULL || fnXInputSetState == NULL)
{
return false;
}
gController->nControl = iXinputControlId;
iXinputControlId++;
TCHAR buffer[MAX_PATH];
GetDirectory( buffer, DIRECTORY_CONFIG );
_stprintf_s( buffer, _T("%sXInput Controller %d Config.xcc"), buffer, nControl + 1 );
FILE *file = _tfopen( buffer, _T("rS") );
if( file )
{
LoadXInputConfigFromFile( file, gController );
fclose( file );
}
if( !gController->bConfigured )
DefaultXInputControllerKeys( gController );
return true;
}
TCHAR * GetN64ButtonNameFromButtonCode( int Button )
{
using namespace N64_BUTTONS;
TCHAR *btnName;
btnName = new TCHAR[10];
switch( Button )
{
case A: _tcscpy_s( btnName, 10, _T( "A" )); break;
case B: _tcscpy_s( btnName, 10, _T( "B" )); break;
case Z: _tcscpy_s( btnName, 10, _T( "Z" )); break;
case L: _tcscpy_s( btnName, 10, _T( "L" )); break;
case R: _tcscpy_s( btnName, 10, _T( "R" )); break;
case Start: _tcscpy_s( btnName, 10, _T( "Start" )); break;
case CUp: _tcscpy_s( btnName, 10, _T( "C-Up" )); break;
case CDown: _tcscpy_s( btnName, 10, _T( "C-Down" )); break;
case CRight: _tcscpy_s( btnName, 10, _T( "C-Right" )); break;
case CLeft: _tcscpy_s( btnName, 10, _T( "C-Left" )); break;
case DUp: _tcscpy_s( btnName, 10, _T( "D-Up" )); break;
case DDown: _tcscpy_s( btnName, 10, _T( "D-Down" )); break;
case DRight: _tcscpy_s( btnName, 10, _T( "D-Right" )); break;
case DLeft: _tcscpy_s( btnName, 10, _T( "D-Left" )); break;
default: _tcscpy_s( btnName, 10, _T( "None" ));
}
return btnName;
}
TCHAR * GetN64ButtonFromXInputControl( LPXCONTROLLER gController, int XInputButton )
{
using namespace N64_BUTTONS;
if( !gController || !gController->bConfigured )
return GetN64ButtonNameFromButtonCode( 0 );
int N64ButtonCode = 0;
N64ButtonCode |= gController->stButtons.iA & XInputButton ? A : 0;
N64ButtonCode |= gController->stButtons.iB & XInputButton ? B : 0;
N64ButtonCode |= gController->stButtons.iCDown & XInputButton ? CDown : 0;
N64ButtonCode |= gController->stButtons.iCLeft & XInputButton ? CLeft : 0;
N64ButtonCode |= gController->stButtons.iCRight & XInputButton ? CRight : 0;
N64ButtonCode |= gController->stButtons.iCUp & XInputButton ? CUp : 0;
N64ButtonCode |= gController->stButtons.iDDown & XInputButton ? DDown : 0;
N64ButtonCode |= gController->stButtons.iDLeft & XInputButton ? DLeft : 0;
N64ButtonCode |= gController->stButtons.iDRight & XInputButton ? DRight : 0;
N64ButtonCode |= gController->stButtons.iDUp & XInputButton ? DUp : 0;
N64ButtonCode |= gController->stButtons.iL & XInputButton ? L : 0;
N64ButtonCode |= gController->stButtons.iR & XInputButton ? R : 0;
N64ButtonCode |= gController->stButtons.iStart & XInputButton ? Start : 0;
N64ButtonCode |= gController->stButtons.iZ & XInputButton ? Z : 0;
return GetN64ButtonNameFromButtonCode( N64ButtonCode );
}
TCHAR * GetN64ButtonArrayFromXAnalog( LPXCONTROLLER gController, int XThStickOrXDpad )
{
using namespace N64_BUTTONS;
if( !gController || !gController->bConfigured )
return NULL;
TCHAR *name;
name = new TCHAR[15];
switch( XThStickOrXDpad )
{
case XC_LTBS:
if( gController->stAnalogs.iLXAxis == XAxis )
_tcscpy_s( name, 15, _T( "Analog Stick" ));
else if( gController->stAnalogs.iLXAxis & CLeft )
_tcscpy_s( name, 15, _T( "C Buttons" ));
else if( gController->stAnalogs.iLXAxis & DLeft )
_tcscpy_s( name, 15, _T( "DPad" ));
else
_tcscpy_s( name, 15, _T( "None" ));
break;
case XC_RTBS:
if( gController->stAnalogs.iRXAxis == XAxis )
_tcscpy_s( name, 15, _T( "Analog Stick" ));
else if( gController->stAnalogs.iRXAxis & CLeft )
_tcscpy_s( name, 15, _T( "C Buttons" ));
else if( gController->stAnalogs.iRXAxis & DLeft )
_tcscpy_s( name, 15, _T( "DPad" ));
else
_tcscpy_s( name, 15, _T( "None" ));
break;
case XC_DPAD:
if( gController->stButtons.iCDown == XINPUT_GAMEPAD_DPAD_DOWN )
_tcscpy_s( name, 15, _T( "C Button" ));
else if( gController->stButtons.iDDown == XINPUT_GAMEPAD_DPAD_DOWN )
_tcscpy_s( name, 15, _T( "DPad" ));
else
_tcscpy_s( name, 15, _T( "None" ));
break;
default:
_tcscpy_s( name, 15, _T( "None" ));
}
return name;
}
bool ReadXInputControllerKeys( HWND hDlg, LPXCONTROLLER gController )
{
if( hDlg == NULL || gController == NULL || !gController->bConfigured)
return false;
SendDlgItemMessage( hDlg, IDC_XC_A, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_A ));
SendDlgItemMessage( hDlg, IDC_XC_B, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_B ));
SendDlgItemMessage( hDlg, IDC_XC_X, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_X ));
SendDlgItemMessage( hDlg, IDC_XC_Y, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_Y ));
SendDlgItemMessage( hDlg, IDC_XC_BACK, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_BACK ));
SendDlgItemMessage( hDlg, IDC_XC_START, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_START ));
SendDlgItemMessage( hDlg, IDC_XC_LB, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_LEFT_SHOULDER ));
SendDlgItemMessage( hDlg, IDC_XC_RB, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_RIGHT_SHOULDER ));
SendDlgItemMessage( hDlg, IDC_XC_LTSB, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_LEFT_THUMB ));
SendDlgItemMessage( hDlg, IDC_XC_RTSB, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonFromXInputControl( gController, XINPUT_GAMEPAD_RIGHT_THUMB ));
SendDlgItemMessage( hDlg, IDC_XC_LT, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonNameFromButtonCode( gController->stAnalogs.iLeftTrigger ));
SendDlgItemMessage( hDlg, IDC_XC_RT, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonNameFromButtonCode( gController->stAnalogs.iRightTrigger ));
SendDlgItemMessage( hDlg, IDC_XC_DPAD, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonArrayFromXAnalog( gController, XC_DPAD ));
SendDlgItemMessage( hDlg, IDC_XC_LTS, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonArrayFromXAnalog( gController, XC_LTBS ));
SendDlgItemMessage( hDlg, IDC_XC_RTS, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonArrayFromXAnalog( gController, XC_RTBS ));
return true;
}
int GetComboBoxXInputKey( int ComboBox )
{
switch( ComboBox )
{
case IDC_XC_A: return XINPUT_GAMEPAD_A;
case IDC_XC_B: return XINPUT_GAMEPAD_B;
case IDC_XC_X: return XINPUT_GAMEPAD_X;
case IDC_XC_Y: return XINPUT_GAMEPAD_Y;
case IDC_XC_BACK: return XINPUT_GAMEPAD_BACK;
case IDC_XC_START: return XINPUT_GAMEPAD_START;
case IDC_XC_LB: return XINPUT_GAMEPAD_LEFT_SHOULDER;
case IDC_XC_RB: return XINPUT_GAMEPAD_RIGHT_SHOULDER;
case IDC_XC_LT: return -1; // triggers don't use these macros
case IDC_XC_RT: return -1;
case IDC_XC_LTSB: return XINPUT_GAMEPAD_LEFT_THUMB;
case IDC_XC_RTSB: return XINPUT_GAMEPAD_RIGHT_THUMB;
case IDC_XC_DPAD: return -2; // to handle analogs and dpad
case IDC_XC_LTS: return -2;
case IDC_XC_RTS: return -2;
default: return 0;
}
}
int GetN64ButtonCode( TCHAR *btnName ) //esta wea esta muy fea, hay que buscar una mejor manera definitivamente..
{
using namespace N64_BUTTONS;
int value = 0;
if( !_tcscmp( btnName, _T( "A" )))
value = A;
else if( !_tcscmp( btnName, _T( "B" )))
value = B;
else if( !_tcscmp( btnName, _T( "R" )))
value = R;
else if( !_tcscmp( btnName, _T( "L" )))
value = L;
else if( !_tcscmp( btnName, _T( "Z" )))
value = Z;
else if( !_tcscmp( btnName, _T( "Start" )))
value = Start;
else if( !_tcscmp( btnName, _T( "C-Up" )))
value = CUp;
else if( !_tcscmp( btnName, _T( "C-Down" )))
value = CDown;
else if( !_tcscmp( btnName, _T( "C-Left" )))
value = CLeft;
else if( !_tcscmp( btnName, _T( "C-Right" )))
value = CRight;
else if( !_tcscmp( btnName, _T( "D-Up" )))
value = DUp;
else if( !_tcscmp( btnName, _T( "D-Down" )))
value = DDown;
else if( !_tcscmp( btnName, _T( "D-Left" )))
value = DLeft;
else if( !_tcscmp( btnName, _T( "D-Right" )))
value = DRight;
return value;
}
void ResetXInputControllerKeys( LPXCONTROLLER gController )
{
gController->stButtons.iA = 0;
gController->stButtons.iB = 0;
gController->stButtons.iZ = 0;
gController->stButtons.iL = 0;
gController->stButtons.iR = 0;
gController->stButtons.iStart = 0;
gController->stButtons.iCUp = 0;
gController->stButtons.iCLeft = 0;
gController->stButtons.iCDown = 0;
gController->stButtons.iCRight = 0;
gController->stButtons.iDUp = 0;
gController->stButtons.iDLeft = 0;
gController->stButtons.iDDown = 0;
gController->stButtons.iDRight = 0;
gController->stAnalogs.iLeftTrigger = 0;
gController->stAnalogs.iLXAxis = 0;
gController->stAnalogs.iLYAxis = 0;
gController->stAnalogs.iRightTrigger = 0;
gController->stAnalogs.iRXAxis = 0;
gController->stAnalogs.iRYAxis = 0;
}
void StoreAnalogConfig( LPXCONTROLLER gController, int ComboBox, int index )
{
using namespace N64_BUTTONS;
switch( index )
{
case 1: // DPAD
switch( ComboBox )
{
case IDC_XC_DPAD:
gController->stButtons.iDDown |= XINPUT_GAMEPAD_DPAD_DOWN;
gController->stButtons.iDUp |= XINPUT_GAMEPAD_DPAD_UP;
gController->stButtons.iDLeft |= XINPUT_GAMEPAD_DPAD_LEFT;
gController->stButtons.iDRight |= XINPUT_GAMEPAD_DPAD_RIGHT;
break;
case IDC_XC_LTS:
gController->stAnalogs.iLXAxis = ( DRight << 16 ) | DLeft;
gController->stAnalogs.iLYAxis = ( DUp << 16 ) | DDown;
break;
case IDC_XC_RTS:
gController->stAnalogs.iRXAxis = ( DRight << 16 ) | DLeft;
gController->stAnalogs.iRYAxis = ( DUp << 16 ) | DDown;
break;
}
break;
case 2: // C Buttons
switch( ComboBox )
{
case IDC_XC_DPAD:
gController->stButtons.iCDown |= XINPUT_GAMEPAD_DPAD_DOWN;
gController->stButtons.iCUp |= XINPUT_GAMEPAD_DPAD_UP;
gController->stButtons.iCLeft |= XINPUT_GAMEPAD_DPAD_LEFT;
gController->stButtons.iCRight |= XINPUT_GAMEPAD_DPAD_RIGHT;
break;
case IDC_XC_LTS:
gController->stAnalogs.iLXAxis = ( CRight << 16 ) | CLeft;
gController->stAnalogs.iLYAxis = ( CUp << 16 ) | CDown;
break;
case IDC_XC_RTS:
gController->stAnalogs.iRXAxis = ( CRight << 16 ) | CLeft;
gController->stAnalogs.iRYAxis = ( CUp << 16 ) | CDown;
break;
}
break;
case 3: // Analog
switch( ComboBox )
{
case IDC_XC_LTS:
gController->stAnalogs.iLXAxis = XAxis;
gController->stAnalogs.iLYAxis = YAxis;
break;
case IDC_XC_RTS:
gController->stAnalogs.iRXAxis = XAxis;
gController->stAnalogs.iRYAxis = YAxis;
break;
}
break;
}
}
void StoreXInputControllerKeys( HWND hDlg, LPXCONTROLLER gController )
{
LRESULT index = -1;
DWORD value = 0;
ResetXInputControllerKeys( gController );
for( int i = IDC_XC_A; i <= IDC_XC_RTS; i++ )
{
index = SendDlgItemMessage( hDlg, i, CB_GETCURSEL, 0, 0 );
value = GetComboBoxXInputKey( i );
if( value == 0 )
continue;
else if ( value == -1 )
{
TCHAR btnName[10] = _T( "\0" );
SendDlgItemMessage( hDlg, i, CB_GETLBTEXT, index, (LPARAM)(LPTSTR)btnName );
switch( i )
{
case IDC_XC_LT:
gController->stAnalogs.iLeftTrigger = GetN64ButtonCode( btnName );
break;
case IDC_XC_RT:
gController->stAnalogs.iRightTrigger = GetN64ButtonCode( btnName );
break;
}
continue;
}
else if ( value == -2 )
{
StoreAnalogConfig( gController, i, index);
continue;
}
switch( index )
{
case 1: gController->stButtons.iA |= value; break;
case 2: gController->stButtons.iB |= value; break;
case 3: gController->stButtons.iZ |= value; break;
case 4: gController->stButtons.iL |= value; break;
case 5: gController->stButtons.iR |= value; break;
case 6: gController->stButtons.iStart |= value; break;
case 7: gController->stButtons.iCUp |= value; break;
case 8: gController->stButtons.iCLeft |= value; break;
case 9: gController->stButtons.iCDown |= value; break;
case 10: gController->stButtons.iCRight |= value; break;
case 11: gController->stButtons.iDUp |= value; break;
case 12: gController->stButtons.iDLeft |= value; break;
case 13: gController->stButtons.iDDown |= value; break;
case 14: gController->stButtons.iDRight |= value; break;
}
}
gController->bConfigured = true;
}
void SaveXInputConfigToFile( FILE *file, LPXCONTROLLER gController )
{
// fprintf( file, "[XInput Controller %d]\n", gController->nControl );
fprintf( file, "A=%lu\n", gController->stButtons.iA );
fprintf( file, "B=%lu\n", gController->stButtons.iB );
fprintf( file, "CDown=%lu\n", gController->stButtons.iCDown );
fprintf( file, "CLeft=%lu\n", gController->stButtons.iCLeft );
fprintf( file, "CRight=%lu\n", gController->stButtons.iCRight );
fprintf( file, "CUp=%lu\n", gController->stButtons.iCUp );
fprintf( file, "DDown=%lu\n", gController->stButtons.iDDown );
fprintf( file, "DLeft=%lu\n", gController->stButtons.iDLeft );
fprintf( file, "DRight=%lu\n", gController->stButtons.iDRight );
fprintf( file, "DUp=%lu\n", gController->stButtons.iDUp );
fprintf( file, "L=%lu\n", gController->stButtons.iL );
fprintf( file, "R=%lu\n", gController->stButtons.iR );
fprintf( file, "Start=%lu\n", gController->stButtons.iStart );
fprintf( file, "Z=%lu\n", gController->stButtons.iZ );
fprintf( file, "XAxis=%lu\n", gController->stButtons.iXAxis );
fprintf( file, "YAxis=%lu\n", gController->stButtons.iYAxis );
fprintf( file, "LeftTrigger=%lu\n", gController->stAnalogs.iLeftTrigger );
fprintf( file, "RightTrigger=%lu\n", gController->stAnalogs.iRightTrigger );
fprintf( file, "LeftXAxis=%lu\n", gController->stAnalogs.iLXAxis );
fprintf( file, "LeftYAxis=%lu\n", gController->stAnalogs.iLYAxis );
fprintf( file, "RightXAxis=%lu\n", gController->stAnalogs.iRXAxis );
fprintf( file, "RightYAxis=%lu\n\n", gController->stAnalogs.iRYAxis );
}
void LoadXInputConfigFromFile( FILE *file, LPXCONTROLLER gController )
{
char buffer[4096];
int c = 0;
while( fgets( buffer, 4096, file ))
{
if( strlen( buffer ) == 1 ) // means end of controller config
break;
c++;
switch( buffer[0] )
{
case 'A':
sscanf(buffer, "A=%lu", &gController->stButtons.iA); break;
case 'B':
sscanf(buffer, "B=%lu", &gController->stButtons.iB); break;
case 'C':
switch( buffer[1] )
{
case 'U':
sscanf(buffer, "CUp=%lu", &gController->stButtons.iCUp); break;
case 'D':
sscanf(buffer, "CDown=%lu", &gController->stButtons.iCDown); break;
case 'L':
sscanf(buffer, "CLeft=%lu", &gController->stButtons.iCLeft); break;
case 'R':
sscanf(buffer, "CRight=%lu", &gController->stButtons.iCRight); break;
}
break;
case 'D':
switch( buffer[1] )
{
case 'U':
sscanf(buffer, "DUp=%lu", &gController->stButtons.iDUp); break;
case 'D':
sscanf(buffer, "DDown=%lu", &gController->stButtons.iDDown); break;
case 'L':
sscanf(buffer, "DLeft=%lu", &gController->stButtons.iDLeft); break;
case 'R':
sscanf(buffer, "DRight=%lu", &gController->stButtons.iDRight); break;
}
break;
case 'L':
switch( buffer[1] )
{
case '=':
sscanf(buffer, "L=%lu", &gController->stButtons.iL); break;
case 'e':
switch( buffer[4] )
{
case 'T':
sscanf(buffer, "LeftTrigger=%lu", &gController->stAnalogs.iLeftTrigger); break;
case 'X':
sscanf(buffer, "LeftXAxis=%lu", &gController->stAnalogs.iLXAxis); break;
case 'Y':
sscanf(buffer, "LeftYAxis=%lu", &gController->stAnalogs.iLYAxis); break;
}
break;
}
break;
case 'R':
switch( buffer[1] )
{
case '=':
sscanf(buffer, "R=%lu", &gController->stButtons.iR); break;
case 'i':
switch( buffer[5] )
{
case 'T':
sscanf(buffer, "RightTrigger=%lu", &gController->stAnalogs.iRightTrigger); break;
case 'X':
sscanf(buffer, "RightXAxis=%lu", &gController->stAnalogs.iRXAxis); break;
case 'Y':
sscanf(buffer, "RightYAxis=%lu", &gController->stAnalogs.iRYAxis); break;
}
break;
}
break;
case 'Z':
sscanf(buffer, "Z=%lu", &gController->stButtons.iZ); break;
case 'S':
sscanf(buffer, "Start=%lu", &gController->stButtons.iStart); break;
case 'X':
sscanf(buffer, "XAxis=%lu", &gController->stButtons.iXAxis); break;
case 'Y':
sscanf(buffer, "YAxis=%lu", &gController->stButtons.iYAxis); break;
}
}
gController->bConfigured = c > 20 ;
}