NRage plugin enhancements (#2469)

* Updated NRage plugin

- sensitivity adjustment
- stick Visualizer
- respect for the N64 octagonal shape
- adjustable stick range and N64 range
- XInput axis inversion support
- Virtual corners in octagon
- Small UI fixes

* Update default Xinput settings

* Typo error
This commit is contained in:
pcca-matrix 2025-06-06 06:30:37 +02:00 committed by GitHub
parent ed759444b4
commit c74939e16e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 652 additions and 210 deletions

View File

@ -149,7 +149,6 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
*pdwData = 0; *pdwData = 0;
WORD w_Buttons = 0; WORD w_Buttons = 0;
// WORD w_Axes = 0; // WORD w_Axes = 0;
LPCONTROLLER pcController = &g_pcControllers[indexController]; // Still needs to be here, but not as important (comment by rabid) LPCONTROLLER pcController = &g_pcControllers[indexController]; // Still needs to be here, but not as important (comment by rabid)
bool b_Value; bool b_Value;
@ -157,11 +156,9 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
long lAxisValueX = ZEROVALUE; long lAxisValueX = ZEROVALUE;
long lAxisValueY = ZEROVALUE; long lAxisValueY = ZEROVALUE;
// Take this info from the N64 controller struct, regardless of input devices // Take this info from the N64 controller struct, regardless of input devices
float d_ModifierX = (float)pcController->bStickRange / 100.0f; float d_ModifierX = 0;
float d_ModifierY = (float)pcController->bStickRange / 100.0f; float d_ModifierY = 0;
int i; int i;
// Do N64-Buttons / modifiers // Do N64-Buttons / modifiers
@ -210,8 +207,8 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
case MDT_MOVE: case MDT_MOVE:
{ {
LPMODSPEC_MOVE args = (LPMODSPEC_MOVE)&pcController->pModifiers[i].dwSpecific; LPMODSPEC_MOVE args = (LPMODSPEC_MOVE)&pcController->pModifiers[i].dwSpecific;
d_ModifierX *= args->XModification / 100.0f; d_ModifierX = args->XModification / 100.0f;
d_ModifierY *= args->YModification / 100.0f; d_ModifierY = args->YModification / 100.0f;
} }
break; break;
case MDT_MACRO: case MDT_MACRO:
@ -228,7 +225,7 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
if(!args->fPrevFireState) // This round, a firing is needed if(!args->fPrevFireState) // This round, a firing is needed
{ {
w_Buttons |= args->aButtons; w_Buttons |= args->aButtons;
if( args->fAnalogRight ) if( args->fAnalogRight )
lAxisValueX += MAXAXISVALUE; lAxisValueX += MAXAXISVALUE;
else if( args->fAnalogLeft ) else if( args->fAnalogLeft )
lAxisValueX -= MAXAXISVALUE; lAxisValueX -= MAXAXISVALUE;
@ -324,9 +321,6 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
w_Buttons |= (((WORD)b_Value) << i); w_Buttons |= (((WORD)b_Value) << i);
} // End N64 buttons for } // End N64 buttons for
long lDeadZoneValue = pcController->bPadDeadZone * RANGERELATIVE / 100;
float fDeadZoneRelation = (float)RANGERELATIVE / (float)( RANGERELATIVE - lDeadZoneValue );
// Do N64 joystick axes // Do N64 joystick axes
for ( i = 0; i < 4; i++ ) for ( i = 0; i < 4; i++ )
{ {
@ -350,21 +344,16 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
case DT_JOYSLIDER: case DT_JOYSLIDER:
case DT_JOYAXE: case DT_JOYAXE:
l_Value = plRawState[btnButton.bOffset] - ZEROVALUE; l_Value = plRawState[btnButton.bOffset] - ZEROVALUE;
if( btnButton.bAxisID ) // Negative range if( btnButton.bAxisID ) // Negative range
{ {
fNegInput = !fNegInput; fNegInput = !fNegInput;
b_Value = ( l_Value <= -ZEROVALUE );
b_Value = ( l_Value <= -lDeadZoneValue );
if( b_Value )
l_Value = (long) ((float)(l_Value + lDeadZoneValue ) * fDeadZoneRelation );
} }
else else
{ {
b_Value = ( l_Value >= lDeadZoneValue ); b_Value = ( l_Value >= ZEROVALUE );
if( b_Value )
l_Value = (long) ((float)(l_Value - lDeadZoneValue ) * fDeadZoneRelation );
} }
break; break;
case DT_JOYPOV: case DT_JOYPOV:
@ -517,44 +506,18 @@ bool GetNControllerInput ( const int indexController, LPDWORD pdwData )
} }
} }
if( pcController->fRealN64Range && ( lAxisValueX || lAxisValueY )) if( ( lAxisValueX || lAxisValueY ) )
{ {
long lAbsoluteX = ( lAxisValueX > 0 ) ? lAxisValueX : -lAxisValueX; float LX, LY;
long lAbsoluteY = ( lAxisValueY > 0 ) ? lAxisValueY : -lAxisValueY; float modX = lAxisValueX * (d_ModifierX == 0 ? d_ModifierX = 1 : d_ModifierX);
float modY = lAxisValueY * (d_ModifierY == 0 ? d_ModifierY = 1 : d_ModifierY);
lAxisValueX = (min<long>( max<long>( MINAXISVALUE, modX), MAXAXISVALUE));
lAxisValueY = (min<long>( max<long>( MINAXISVALUE, modY), MAXAXISVALUE));
processStickInput(pcController, lAxisValueX , lAxisValueY, LX, LY);
long lRangeX; *pdwData = MAKELONG(w_Buttons, MAKEWORD( LX * pcController->bN64Range / MAXAXISVALUE, LY * pcController->bN64Range / MAXAXISVALUE) );
long lRangeY; }else{
*pdwData = MAKELONG(w_Buttons, MAKEWORD(ZEROVALUE, ZEROVALUE));
if( lAbsoluteX > lAbsoluteY )
{
lRangeX = MAXAXISVALUE;
lRangeY = lRangeX * lAbsoluteY / lAbsoluteX;
}
else
{
lRangeY = MAXAXISVALUE;
lRangeX = lRangeY * lAbsoluteX / lAbsoluteY;
}
// TODO: We should optimize this (comment by rabid)
double dRangeDiagonal = sqrt((double)(lRangeX * lRangeX + lRangeY * lRangeY));
// __asm{
// fld fRangeDiagonal
// fsqrt
// fstp fRangeDiagonal
// fwait
// }
double dRel = MAXAXISVALUE / dRangeDiagonal;
*pdwData = MAKELONG(w_Buttons,
MAKEWORD( (BYTE)(min<long>( max<long>( MINAXISVALUE, (long)(lAxisValueX * d_ModifierX * dRel )), MAXAXISVALUE) / N64DIVIDER ),
(BYTE)(min<long>( max<long>( MINAXISVALUE, (long)(lAxisValueY * d_ModifierY * dRel )), MAXAXISVALUE) / N64DIVIDER )));
}
else
{
*pdwData = MAKELONG(w_Buttons,
MAKEWORD( (BYTE)(min<long>( max<long>( MINAXISVALUE, (long)(lAxisValueX * d_ModifierX )), MAXAXISVALUE) / N64DIVIDER ),
(BYTE)(min<long>( max<long>( MINAXISVALUE, (long)(lAxisValueY * d_ModifierY )), MAXAXISVALUE) / N64DIVIDER )));
} }
return true; return true;

View File

@ -307,6 +307,18 @@ bool ProcessKey( DWORD dwKey, DWORD dwSection, LPCSTR pszLine, LPTSTR pszFFDevic
if (pController) if (pController)
pController->bPadDeadZone = atoi(pszLine); pController->bPadDeadZone = atoi(pszLine);
break; break;
case CHK_SENSITIVITY:
if (pController)
pController->bPadSensitivity = atoi(pszLine);
break;
case CHK_VIRTUALCORNERS:
if (pController)
pController->bVirtualCorners = atoi(pszLine);
break;
case CHK_N64RANGE:
if (pController)
pController->bN64Range = atoi(pszLine);
break;
case CHK_MOUSESENSITIVITYX: case CHK_MOUSESENSITIVITYX:
if (pController) if (pController)
pController->wMouseSensitivityX = atoi(pszLine); pController->wMouseSensitivityX = atoi(pszLine);
@ -1501,6 +1513,8 @@ void DumpControllerSettings(FILE * fFile, int i, bool bIsINI)
fprintf(fFile, STRING_INI_RAPIDFIREENABLED "=%u\n", g_ivConfig->Controllers[i].bRapidFireEnabled); fprintf(fFile, STRING_INI_RAPIDFIREENABLED "=%u\n", g_ivConfig->Controllers[i].bRapidFireEnabled);
fprintf(fFile, STRING_INI_RAPIDFIRERATE "=%u\n", g_ivConfig->Controllers[i].bRapidFireRate); fprintf(fFile, STRING_INI_RAPIDFIRERATE "=%u\n", g_ivConfig->Controllers[i].bRapidFireRate);
fprintf(fFile, STRING_INI_STICKRANGE "=%u\n", g_ivConfig->Controllers[i].bStickRange); fprintf(fFile, STRING_INI_STICKRANGE "=%u\n", g_ivConfig->Controllers[i].bStickRange);
fprintf(fFile, STRING_INI_N64RANGE "=%u\n", g_ivConfig->Controllers[i].bN64Range);
fprintf(fFile, STRING_INI_VIRTUALCORNERS "=%u\n", g_ivConfig->Controllers[i].bVirtualCorners);
fprintf(fFile, STRING_INI_MOUSEMOVEX "=%u\n", g_ivConfig->Controllers[i].bMouseMoveX); fprintf(fFile, STRING_INI_MOUSEMOVEX "=%u\n", g_ivConfig->Controllers[i].bMouseMoveX);
fprintf(fFile, STRING_INI_MOUSEMOVEY "=%u\n", g_ivConfig->Controllers[i].bMouseMoveY); fprintf(fFile, STRING_INI_MOUSEMOVEY "=%u\n", g_ivConfig->Controllers[i].bMouseMoveY);
fprintf(fFile, STRING_INI_AXISSET "=%u\n", g_ivConfig->Controllers[i].bAxisSet); fprintf(fFile, STRING_INI_AXISSET "=%u\n", g_ivConfig->Controllers[i].bAxisSet);
@ -1512,6 +1526,7 @@ void DumpControllerSettings(FILE * fFile, int i, bool bIsINI)
fprintf(fFile, STRING_INI_RUMBLETYPE "=%u\n", g_ivConfig->Controllers[i].bRumbleTyp); fprintf(fFile, STRING_INI_RUMBLETYPE "=%u\n", g_ivConfig->Controllers[i].bRumbleTyp);
fprintf(fFile, STRING_INI_RUMBLESTRENGTH "=%u\n", g_ivConfig->Controllers[i].bRumbleStrength); fprintf(fFile, STRING_INI_RUMBLESTRENGTH "=%u\n", g_ivConfig->Controllers[i].bRumbleStrength);
fprintf(fFile, STRING_INI_VISUALRUMBLE "=%u\n", g_ivConfig->Controllers[i].fVisualRumble); fprintf(fFile, STRING_INI_VISUALRUMBLE "=%u\n", g_ivConfig->Controllers[i].fVisualRumble);
fprintf(fFile, STRING_INI_SENSITIVITY "=%u\n", g_ivConfig->Controllers[i].bPadSensitivity);
if (bIsINI) if (bIsINI)
{ {

View File

@ -101,6 +101,9 @@ unsigned long djbHash(const char *str);
#define STRING_INI_KEYABSOLUTEX "KeyAbsoluteX" #define STRING_INI_KEYABSOLUTEX "KeyAbsoluteX"
#define STRING_INI_KEYABSOLUTEY "KeyAbsoluteY" #define STRING_INI_KEYABSOLUTEY "KeyAbsoluteY"
#define STRING_INI_PADDEADZONE "PadDeadZone" #define STRING_INI_PADDEADZONE "PadDeadZone"
#define STRING_INI_SENSITIVITY "PadSensitivity"
#define STRING_INI_N64RANGE "N64Range"
#define STRING_INI_VIRTUALCORNERS "VirtualCorners"
#define STRING_INI_MOUSESENSX "MouseSensitivityX" #define STRING_INI_MOUSESENSX "MouseSensitivityX"
#define STRING_INI_MOUSESENSY "MouseSensitivityY" #define STRING_INI_MOUSESENSY "MouseSensitivityY"
#define STRING_INI_RUMBLETYPE "RumbleType" #define STRING_INI_RUMBLETYPE "RumbleType"
@ -171,6 +174,9 @@ unsigned long djbHash(const char *str);
#define CHK_KEYABSOLUTEX 958566277UL #define CHK_KEYABSOLUTEX 958566277UL
#define CHK_KEYABSOLUTEY 958566278UL #define CHK_KEYABSOLUTEY 958566278UL
#define CHK_PADDEADZONE 2913910084UL #define CHK_PADDEADZONE 2913910084UL
#define CHK_SENSITIVITY 3759052741UL
#define CHK_VIRTUALCORNERS 4174758280UL
#define CHK_N64RANGE 868748074UL
#define CHK_MOUSESENSITIVITYX 1513071697UL #define CHK_MOUSESENSITIVITYX 1513071697UL
#define CHK_MOUSESENSITIVITYY 1513071698UL #define CHK_MOUSESENSITIVITYY 1513071698UL
#define CHK_RUMBLETYPE 3440038446UL #define CHK_RUMBLETYPE 3440038446UL

View File

@ -67,6 +67,10 @@ INTERFACEVALUES *g_ivConfig = NULL; // This structure holds all
LPDIRECTINPUTDEVICE8 g_pConfigDevice = NULL; // One device handle for current force feedback device; between messages so it needs to be persistent LPDIRECTINPUTDEVICE8 g_pConfigDevice = NULL; // One device handle for current force feedback device; between messages so it needs to be persistent
LPDIRECTINPUTEFFECT g_pConfigEffect = NULL; // Force feedback effect handle LPDIRECTINPUTEFFECT g_pConfigEffect = NULL; // Force feedback effect handle
HWND g_hMainDialog = NULL; // Handle of base dialog HWND g_hMainDialog = NULL; // Handle of base dialog
short inputX = 0;
short inputY = 0;
ANALOGWIN AnalogW = {0};
// Main dialog control handler // Main dialog control handler
BOOL CALLBACK MainDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) BOOL CALLBACK MainDlgProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
@ -400,7 +404,6 @@ BOOL CALLBACK ControllerTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
// Call routine to show content (recursive call) // Call routine to show content (recursive call)
ControllerTabProc( hDlg, WM_USER_UPDATE, 0, 0 ); ControllerTabProc( hDlg, WM_USER_UPDATE, 0, 0 );
return FALSE; // Don't give it focus return FALSE; // Don't give it focus
case WM_NOTIFY: case WM_NOTIFY:
@ -529,6 +532,7 @@ BOOL CALLBACK ControllerTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
pcController->fXInput = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED ); pcController->fXInput = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
if( hTabControl ) if( hTabControl )
DestroyWindow( hTabControl ); DestroyWindow( hTabControl );
TabCtrl_SetCurSel(GetDlgItem(hDlg, IDC_CONTROLLERTAB), TAB_CONTROLS); // select the right tab !
if( pcController->fXInput ) if( pcController->fXInput )
hTabControl = CreateDialog(g_hResourceDLL, MAKEINTRESOURCE(IDD_XCONTROLS), hDlg, (DLGPROC)XControlsTabProc); hTabControl = CreateDialog(g_hResourceDLL, MAKEINTRESOURCE(IDD_XCONTROLS), hDlg, (DLGPROC)XControlsTabProc);
else else
@ -591,6 +595,7 @@ BOOL CALLBACK ControllerTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
MoveWindow( hTabControl, rectWindow.left + (rectTab.left - rectMain.left), rectWindow.top + (rectTab.top - rectMain.top), rectWindow.right - rectWindow.left, rectWindow.bottom - rectWindow.top, FALSE ); MoveWindow( hTabControl, rectWindow.left + (rectTab.left - rectMain.left), rectWindow.top + (rectTab.top - rectMain.top), rectWindow.right - rectWindow.left, rectWindow.bottom - rectWindow.top, FALSE );
ShowWindow( hTabControl, SW_SHOW ); ShowWindow( hTabControl, SW_SHOW );
TabCtrl_SetCurSel(GetDlgItem(hDlg, IDC_CONTROLLERTAB), TAB_CONTROLS); // select the right tab !
} }
// Call child dialog(s) to update their content as well // Call child dialog(s) to update their content as well
@ -619,12 +624,6 @@ BOOL CALLBACK ControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
switch(uMsg) switch(uMsg)
{ {
case WM_INITDIALOG: case WM_INITDIALOG:
// SetTicks on TrackBar
hDlgItem = GetDlgItem( hDlg, IDC_CTRRANGE );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 0, 100 ));
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM) 10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM) 0, 1 );
// SetTicks on RapidFire Bar // SetTicks on RapidFire Bar
hDlgItem = GetDlgItem( hDlg, IDC_RAPIDFIRERATE ); hDlgItem = GetDlgItem( hDlg, IDC_RAPIDFIRERATE );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 0, 32 )); SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 0, 32 ));
@ -640,10 +639,6 @@ BOOL CALLBACK ControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
switch( LOWORD(wParam) ) switch( LOWORD(wParam) )
{ {
case IDC_N64RANGE:
g_ivConfig->Controllers[g_ivConfig->ChosenTab].fRealN64Range = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
case IDC_RAPIDFIREENABLE: case IDC_RAPIDFIREENABLE:
g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireEnabled = (IsDlgButtonChecked( hDlg, LOWORD(wParam)) == BST_CHECKED); g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireEnabled = (IsDlgButtonChecked( hDlg, LOWORD(wParam)) == BST_CHECKED);
return TRUE; return TRUE;
@ -760,14 +755,6 @@ BOOL CALLBACK ControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
case WM_VSCROLL: case WM_VSCROLL:
switch ( GetWindowLong( (HWND)lParam, GWL_ID ) ) switch ( GetWindowLong( (HWND)lParam, GWL_ID ) )
{ {
case IDC_CTRRANGE:
TCHAR tszText[DEFAULT_BUFFER];
LoadString( g_hResourceDLL, IDS_C_RANGE, tszText, DEFAULT_BUFFER );
g_ivConfig->Controllers[g_ivConfig->ChosenTab].bStickRange = (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
wsprintf( szBuffer, tszText, g_ivConfig->Controllers[g_ivConfig->ChosenTab].bStickRange );
SendMessage( GetDlgItem( hDlg, IDT_RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
return TRUE;
case IDC_RAPIDFIRERATE: case IDC_RAPIDFIRERATE:
g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireRate = 33 - (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 ); g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireRate = 33 - (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
return TRUE; return TRUE;
@ -784,16 +771,11 @@ BOOL CALLBACK ControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
if( wParam == 0 ) if( wParam == 0 )
{ {
CheckDlgButton( hDlg, IDC_N64RANGE, g_ivConfig->Controllers[g_ivConfig->ChosenTab].fRealN64Range ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_N64REALRANGE, g_ivConfig->Controllers[g_ivConfig->ChosenTab].fRealN64Range ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_RAPIDFIREENABLE, g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireEnabled ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_RAPIDFIREENABLE, g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireEnabled ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_CONFIG1, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 0 ) ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_CONFIG1, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 0 ) ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_CONFIG2, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 1 ) ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_CONFIG2, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 1 ) ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_CONFIG3, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 2 ) ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_CONFIG3, ( g_ivConfig->Controllers[g_ivConfig->ChosenTab].bAxisSet == 2 ) ? BST_CHECKED : BST_UNCHECKED );
SendMessage( GetDlgItem( hDlg, IDC_CTRRANGE ), TBM_SETPOS, TRUE, g_ivConfig->Controllers[g_ivConfig->ChosenTab].bStickRange );
LoadString( g_hResourceDLL, IDS_C_RANGE, szTemp, 40 );
wsprintf( szBuffer, szTemp, g_ivConfig->Controllers[g_ivConfig->ChosenTab].bStickRange );
SendMessage( GetDlgItem( hDlg, IDT_RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
SendMessage( GetDlgItem( hDlg, IDC_RAPIDFIRERATE ), TBM_SETPOS, TRUE, 33 - g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireRate ); SendMessage( GetDlgItem( hDlg, IDC_RAPIDFIRERATE ), TBM_SETPOS, TRUE, 33 - g_ivConfig->Controllers[g_ivConfig->ChosenTab].bRapidFireRate );
i = 0; i = 0;
@ -857,6 +839,18 @@ BOOL CALLBACK XControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
case WM_COMMAND: case WM_COMMAND:
switch( LOWORD( wParam )) switch( LOWORD( wParam ))
{ {
case IDC_XC_INVERT_LX:
gController->stAnalogs.iInvertLX = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
case IDC_XC_INVERT_LY:
gController->stAnalogs.iInvertLY = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
case IDC_XC_INVERT_RX:
gController->stAnalogs.iInvertRX = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
case IDC_XC_INVERT_RY:
gController->stAnalogs.iInvertRY = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
case IDC_XC_USE: case IDC_XC_USE:
StoreXInputControllerKeys( hDlg, gController ); StoreXInputControllerKeys( hDlg, gController );
{ {
@ -870,6 +864,7 @@ BOOL CALLBACK XControlsTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPar
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
default: default:
return FALSE; return FALSE;
} }
@ -884,12 +879,16 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
switch(uMsg) switch(uMsg)
{ {
case WM_INITDIALOG: case WM_INITDIALOG:
{
SetTimer( hDlg, 999, 33, NULL );
// TrackBars // TrackBars
hDlgItem = GetDlgItem( hDlg, IDC_DEADZONE ); hDlgItem = GetDlgItem( hDlg, IDC_DEADZONE );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 0, 100 )); SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 0, 50 ));
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM) 10, 0 ); SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM) 10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM) 0, 1 ); SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM) 0, 1 );
@ -907,11 +906,242 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
for( i = 0; i < (sizeof(sTics) / sizeof(short)); ++i ) for( i = 0; i < (sizeof(sTics) / sizeof(short)); ++i )
SendMessage( hDlgItem, TBM_SETTIC, 0, sTics[i] ); SendMessage( hDlgItem, TBM_SETTIC, 0, sTics[i] );
} }
// TrackBars End
hDlgItem = GetDlgItem( hDlg, IDC_CTRRANGE );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( 10, 100 ));
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM) 10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM) 0, 1 );
hDlgItem = GetDlgItem( hDlg, IDC_SENSITIVITY );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(1, 100) );
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM)10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM)0, 1 );
hDlgItem = GetDlgItem( hDlg, IDC_N64RANGE );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(10, 127) );
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM)10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM)0, 1 );
hDlgItem = GetDlgItem( hDlg, IDC_VIRTUALCORNERS );
SendMessage( hDlgItem, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 45) );
SendMessage( hDlgItem, TBM_SETTICFREQ, (WPARAM)10, 0 );
SendMessage( hDlgItem, TBM_SETPAGESIZE, (WPARAM)0, 1 );
// TrackBars End
DevicesTabProc( hDlg, WM_USER_UPDATE, 0, 0 ); // Setting values DevicesTabProc( hDlg, WM_USER_UPDATE, 0, 0 ); // Setting values
return FALSE; // Don't give it focus return FALSE; // Don't give it focus
}
case WM_SIZE:
{
RECT rect;
GetClientRect(hDlg, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
RECT rcLast;
HWND hLastCtrl = GetDlgItem(hDlg, IDC_VIRTUALCORNERS);
if (hLastCtrl && GetWindowRect(hLastCtrl, &rcLast))
{
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcLast, 2);
AnalogW.Y = rcLast.bottom + 5;
AnalogW.SIZE_W = height - rcLast.bottom - 10;
AnalogW.SIZE_H = height - rcLast.bottom - 10;
AnalogW.X = (width * 0.75) - (AnalogW.SIZE_W) / 2;
}
AnalogW.CENTER_X = AnalogW.SIZE_W / 2.0f;
AnalogW.CENTER_Y = AnalogW.SIZE_H / 2.0f;
AnalogW.RADIUS = AnalogW.SIZE_W * 0.49f;
AnalogW.TRIANGLE_HEIGHT = 3.0f;
return FALSE;
}
case WM_TIMER:
if (wParam == 999)
{
if (pcController->fXInput && pcController->fPlugged){
XINPUT_STATE state;
ZeroMemory(&state, sizeof(XINPUT_STATE));
DWORD result = XInputGetState(pcController->xiController.nControl, &state);
if (result == ERROR_SUCCESS) {
if (pcController->xiController.stAnalogs.iLXAxis == 0x4000){
inputX = state.Gamepad.sThumbLX;
inputY = state.Gamepad.sThumbLY;
}else{
inputX = state.Gamepad.sThumbRX;
inputY = state.Gamepad.sThumbRY;
}
}
} else {
if(pcController->fPlugged)
{
LPDEVICE lpDevice = nullptr;
for (int i = 0; i < 14 + PF_AXESETS * 4; i++)
if (pcController->aButton[i].bBtnType == DT_JOYAXE)
lpDevice = pcController->aButton[i].parentDevice;
if (lpDevice != nullptr) {
HRESULT hr = lpDevice->didHandle->Poll();
if (FAILED(hr)) {
hr = lpDevice->didHandle->Acquire();
}
if (SUCCEEDED(hr)) {
hr = lpDevice->didHandle->GetDeviceState(sizeof(DIJOYSTATE), &lpDevice->stateAs.joyState);
if (hr == DI_OK) {
inputX = lpDevice->stateAs.joyState.lX;
inputY = -lpDevice->stateAs.joyState.lY;
}
}
}
}
}
RECT rectToInvalidate = {AnalogW.X, AnalogW.Y, AnalogW.X + AnalogW.SIZE_W, AnalogW.Y + AnalogW.SIZE_H};
InvalidateRect(hDlg, &rectToInvalidate, TRUE);
}
break;
case WM_PAINT:
{
const float OCTAGON_RADIUS = AnalogW.RADIUS * (pcController->bStickRange / 100.0f);
const float ANGLE_THRESHOLD = pcController->bVirtualCorners / 100.0f;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hDlg, &ps);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmMem = CreateCompatibleBitmap(hdc, AnalogW.SIZE_W, AnalogW.SIZE_H);
HBITMAP hbmOrigin = (HBITMAP)SelectObject(hdcMem, hbmMem);
HPEN hOldPen = nullptr;
HBRUSH hOldBrush = nullptr;
HBRUSH hBrushBackground = CreateSolidBrush(RGB(240, 240, 240));
RECT rect = {0, 0, AnalogW.SIZE_W, AnalogW.SIZE_H};
FillRect(hdcMem, &rect, hBrushBackground);
DeleteObject(hBrushBackground);
// Gamepad Range
HPEN outhPen = CreatePen(PS_SOLID, 1, RGB(55, 55, 55));
HBRUSH outhBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
hOldPen = (HPEN)SelectObject(hdcMem, outhPen);
hOldBrush = (HBRUSH)SelectObject(hdcMem, outhBrush);
RoundRect(hdcMem, AnalogW.CENTER_X - AnalogW.RADIUS, AnalogW.CENTER_Y - AnalogW.RADIUS, AnalogW.CENTER_X + AnalogW.RADIUS, AnalogW.CENTER_Y + AnalogW.RADIUS, AnalogW.RADIUS, AnalogW.RADIUS);
SelectObject(hdcMem, hOldPen);
SelectObject(hdcMem, hOldBrush);
DeleteObject(outhPen);
// Octagon
if (pcController->fRealN64Range)
{
HBRUSH hGrayBrush = CreateSolidBrush(RGB(215, 215, 215));
hOldBrush = (HBRUSH)SelectObject(hdcMem, hGrayBrush);
POINT octagon[8];
for (int i = 0; i < 8; ++i) {
double angle = i * OCTAGON_ANGLE;
double cosA = cos(angle);
double sinA = sin(angle);
octagon[i].x = AnalogW.CENTER_X + OCTAGON_RADIUS * cosA;
octagon[i].y = AnalogW.CENTER_Y - OCTAGON_RADIUS * sinA;
}
Polygon(hdcMem, octagon, 8);
SelectObject(hdcMem, hOldBrush);
DeleteObject(hGrayBrush);
// Virtual Corners
HBRUSH hTriangleBrush = CreateSolidBrush(RGB(255, 100, 0));
hOldBrush = (HBRUSH)SelectObject(hdcMem, hTriangleBrush);
for (int i = 0; i < 8; ++i) {
double angle = i * OCTAGON_ANGLE;
double cosA = cos(angle);
double sinA = sin(angle);
double cosM = cos(angle - ANGLE_THRESHOLD);
double sinM = sin(angle - ANGLE_THRESHOLD);
double cosP = cos(angle + ANGLE_THRESHOLD);
double sinP = sin(angle + ANGLE_THRESHOLD);
POINT triangle[3] = {
{AnalogW.CENTER_X + OCTAGON_RADIUS * cosA, AnalogW.CENTER_Y - OCTAGON_RADIUS * sinA},
{AnalogW.CENTER_X + (OCTAGON_RADIUS - AnalogW.TRIANGLE_HEIGHT) * cosM, AnalogW.CENTER_Y - (OCTAGON_RADIUS - AnalogW.TRIANGLE_HEIGHT) * sinM},
{AnalogW.CENTER_X + (OCTAGON_RADIUS - AnalogW.TRIANGLE_HEIGHT) * cosP, AnalogW.CENTER_Y - (OCTAGON_RADIUS - AnalogW.TRIANGLE_HEIGHT) * sinP}
};
Polygon(hdcMem, triangle, 3);
}
SelectObject(hdcMem, hOldBrush);
DeleteObject(hTriangleBrush);
}
// DeadZone
float DEADZONE_RADIUS = pcController->bPadDeadZone * AnalogW.RADIUS / 100.0f;
HBRUSH hBrushHatched = CreateHatchBrush(HS_BDIAGONAL, RGB(50, 50, 50));
hOldBrush = (HBRUSH)SelectObject(hdcMem, hBrushHatched);
HPEN deadZonePen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
hOldPen = (HPEN)SelectObject(hdcMem, deadZonePen);
Ellipse(hdcMem, AnalogW.CENTER_X - DEADZONE_RADIUS, AnalogW.CENTER_Y - DEADZONE_RADIUS, AnalogW.CENTER_X + DEADZONE_RADIUS, AnalogW.CENTER_Y + DEADZONE_RADIUS);
SelectObject(hdcMem, hOldBrush);
SelectObject(hdcMem, hOldPen);
DeleteObject(hBrushHatched);
DeleteObject(deadZonePen);
//Stick Position
float outputX = 0.0f, outputY = 0.0f;
processStickInput(pcController, inputX, inputY, outputX, outputY);
POINT position = {AnalogW.CENTER_X, AnalogW.CENTER_Y};
POINT real_pos = {AnalogW.CENTER_X, AnalogW.CENTER_Y};
position.x = AnalogW.CENTER_X + (outputX / (float)XC_ANALOG_MAX) * OCTAGON_RADIUS;
position.y = AnalogW.CENTER_Y - (outputY / (float)XC_ANALOG_MAX) * OCTAGON_RADIUS;
if (!pcController->xiController.stAnalogs.iInvertLX)
real_pos.x = AnalogW.CENTER_X + (inputX / (float)XC_ANALOG_MAX) * AnalogW.RADIUS;
else
real_pos.x = AnalogW.CENTER_X + (-inputX / (float)XC_ANALOG_MAX) * AnalogW.RADIUS;
if (!pcController->xiController.stAnalogs.iInvertLY)
real_pos.y = AnalogW.CENTER_Y - (inputY / (float)XC_ANALOG_MAX) * AnalogW.RADIUS;
else
real_pos.y = AnalogW.CENTER_Y - (-inputY / (float)XC_ANALOG_MAX) * AnalogW.RADIUS;
// Points
HBRUSH pointBrush = CreateSolidBrush(RGB(0, 255, 0));
hOldBrush = (HBRUSH)SelectObject(hdcMem, pointBrush);
Ellipse(hdcMem, position.x - 3, position.y - 3, position.x + 3, position.y + 3);
SelectObject(hdcMem, hOldBrush);
DeleteObject(pointBrush);
HBRUSH pointBrush2 = CreateSolidBrush(RGB(0, 0, 0));
hOldBrush = (HBRUSH)SelectObject(hdcMem, pointBrush2);
Ellipse(hdcMem, real_pos.x - 3, real_pos.y - 3, real_pos.x + 3, real_pos.y + 3);
SelectObject(hdcMem, hOldBrush);
DeleteObject(pointBrush2);
BitBlt(hdc, AnalogW.X, AnalogW.Y, AnalogW.SIZE_W, AnalogW.SIZE_H, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOrigin);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hDlg, &ps);
return 0;
}
case WM_ERASEBKGND:
{
HDC hdc = (HDC)wParam;
RECT rc;
GetClientRect(hDlg, &rc);
HBRUSH hbr = CreateSolidBrush(RGB(240, 240, 240));
FillRect(hdc, &rc, hbr);
DeleteObject(hbr);
return 1;
}
case WM_DESTROY:
KillTimer( hDlg, TIMER_BUTTON );
return 0;
case WM_COMMAND: case WM_COMMAND:
hDlgItem = GetDlgItem( hDlg, LOWORD(wParam) ); hDlgItem = GetDlgItem( hDlg, LOWORD(wParam) );
@ -950,6 +1180,9 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
case IDC_ACCELERATEY: case IDC_ACCELERATEY:
pcController->fKeyAbsoluteY = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED ); pcController->fKeyAbsoluteY = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE; return TRUE;
case IDC_N64REALRANGE:
pcController->fRealN64Range = ( IsDlgButtonChecked( hDlg, LOWORD(wParam) ) == BST_CHECKED );
return TRUE;
default: default:
return FALSE; return FALSE;
@ -980,11 +1213,41 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
wsprintf( szBuffer, szTemp, pcController->bPadDeadZone ); wsprintf( szBuffer, szTemp, pcController->bPadDeadZone );
SendMessage( GetDlgItem( hDlg, IDT_DEADZONE ), WM_SETTEXT , 0, (LPARAM)szBuffer ); SendMessage( GetDlgItem( hDlg, IDT_DEADZONE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
return TRUE; return TRUE;
case IDC_SENSITIVITY:
pcController->bPadSensitivity = (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
LoadString( g_hResourceDLL, IDS_SENSITIVITY, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bPadSensitivity );
SendMessage( GetDlgItem(hDlg, IDT_SENSITIVITY), WM_SETTEXT, 0, (LPARAM)szBuffer );
return TRUE;
case IDC_CTRRANGE:
pcController->bStickRange = (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
LoadString( g_hResourceDLL, IDS_C_RANGE, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bStickRange );
SendMessage( GetDlgItem( hDlg, IDT_RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
return TRUE;
case IDC_N64RANGE:
pcController->bN64Range = (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
LoadString( g_hResourceDLL, IDS_N64RANGE, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bN64Range );
SendMessage( GetDlgItem( hDlg, IDT_N64RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
return TRUE;
case IDC_VIRTUALCORNERS:
pcController->bVirtualCorners = (BYTE)SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0 );
LoadString( g_hResourceDLL, IDS_VIRTUALCORNERS, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bVirtualCorners );
SendMessage( GetDlgItem( hDlg, IDT_VIRTUALCORNERS ), WM_SETTEXT , 0, (LPARAM)szBuffer );
return TRUE;
default: default:
return FALSE; return FALSE;
} }
case WM_USER_UPDATE: case WM_USER_UPDATE:
if( pcController->bMouseMoveX == MM_DEAD ) if( pcController->bMouseMoveX == MM_DEAD )
CheckDlgButton( hDlg, IDC_DEADPANMOUSEX, BST_CHECKED ); CheckDlgButton( hDlg, IDC_DEADPANMOUSEX, BST_CHECKED );
else else
@ -1017,6 +1280,7 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
CheckDlgButton( hDlg, IDC_ACCELERATEX, pcController->fKeyAbsoluteX ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_ACCELERATEX, pcController->fKeyAbsoluteX ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_ACCELERATEY, pcController->fKeyAbsoluteY ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDC_ACCELERATEY, pcController->fKeyAbsoluteY ? BST_CHECKED : BST_UNCHECKED );
CheckDlgButton( hDlg, IDC_N64REALRANGE, pcController->fRealN64Range ? BST_CHECKED : BST_UNCHECKED );
// TrackBars // TrackBars
SendMessage( GetDlgItem( hDlg, IDC_DEADZONE ), TBM_SETPOS, TRUE, pcController->bPadDeadZone ); SendMessage( GetDlgItem( hDlg, IDC_DEADZONE ), TBM_SETPOS, TRUE, pcController->bPadDeadZone );
@ -1033,6 +1297,26 @@ BOOL CALLBACK DevicesTabProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
LoadString( g_hResourceDLL, IDS_D_MSY, szTemp, DEFAULT_BUFFER ); LoadString( g_hResourceDLL, IDS_D_MSY, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->wMouseSensitivityY ); wsprintf( szBuffer, szTemp, pcController->wMouseSensitivityY );
SendMessage( GetDlgItem( hDlg, IDT_MSSENSITIVITY_Y ), WM_SETTEXT , 0, (LPARAM)szBuffer ); SendMessage( GetDlgItem( hDlg, IDT_MSSENSITIVITY_Y ), WM_SETTEXT , 0, (LPARAM)szBuffer );
SendMessage( GetDlgItem( hDlg, IDC_SENSITIVITY), TBM_SETPOS, TRUE, pcController->bPadSensitivity );
LoadString( g_hResourceDLL, IDS_SENSITIVITY, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bPadSensitivity );
SendMessage( GetDlgItem( hDlg, IDT_SENSITIVITY), WM_SETTEXT, 0, (LPARAM)szBuffer );
SendMessage( GetDlgItem( hDlg, IDC_CTRRANGE ), TBM_SETPOS, TRUE, pcController->bStickRange );
LoadString( g_hResourceDLL, IDS_C_RANGE, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bStickRange );
SendMessage( GetDlgItem( hDlg, IDT_RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
SendMessage( GetDlgItem( hDlg, IDC_N64RANGE ), TBM_SETPOS, TRUE, pcController->bN64Range );
LoadString( g_hResourceDLL, IDS_N64RANGE, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bN64Range );
SendMessage( GetDlgItem( hDlg, IDT_N64RANGE ), WM_SETTEXT , 0, (LPARAM)szBuffer );
SendMessage( GetDlgItem( hDlg, IDC_VIRTUALCORNERS ), TBM_SETPOS, TRUE, pcController->bVirtualCorners );
LoadString( g_hResourceDLL, IDS_VIRTUALCORNERS, szTemp, DEFAULT_BUFFER );
wsprintf( szBuffer, szTemp, pcController->bVirtualCorners );
SendMessage( GetDlgItem( hDlg, IDT_VIRTUALCORNERS ), WM_SETTEXT , 0, (LPARAM)szBuffer );
// TrackBars End // TrackBars End
return TRUE; return TRUE;
@ -3331,7 +3615,7 @@ BOOL CALLBACK FoldersDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
// This function is confusing, but not much I can do to fix it now. I'm sorry. (comment by rabid) // This function is confusing, but not much I can do to fix it now. I'm sorry. (comment by rabid)
bool GetButtonID( LPDWORD ButtonID, const BYTE bIndex, const BYTE bButtonSet ) bool GetButtonID( LPDWORD ButtonID, const BYTE bIndex, const BYTE bButtonSet )
{ {
// TODO: Check this // TODO: Check this
// TODO: make these constant, read from a resource or a define, or something...I don't know // TODO: make these constant, read from a resource or a define, or something...I don't know
LPDWORD ButtonTable = NULL; LPDWORD ButtonTable = NULL;
int nEntries = 0; int nEntries = 0;
@ -3809,7 +4093,9 @@ void SetControllerDefaults( LPCONTROLLER pcController )
pcController->bRapidFireEnabled = false; pcController->bRapidFireEnabled = false;
pcController->bRapidFireRate = 3; // Set default rapid fire rate here pcController->bRapidFireRate = 3; // Set default rapid fire rate here
pcController->bStickRange = DEFAULT_STICKRANGE; pcController->bStickRange = DEFAULT_STICKRANGE;
pcController->bN64Range = DEFAULT_N64RANGE;
pcController->bPadDeadZone = DEFAULT_DEADZONE; pcController->bPadDeadZone = DEFAULT_DEADZONE;
pcController->bPadSensitivity = DEFAULT_SENSITIVITY;
pcController->bRumbleTyp = DEFAULT_RUMBLETYP; pcController->bRumbleTyp = DEFAULT_RUMBLETYP;
pcController->bRumbleStrength = DEFAULT_RUMBLESTRENGTH; pcController->bRumbleStrength = DEFAULT_RUMBLESTRENGTH;
pcController->wMouseSensitivityX = DEFAULT_MOUSESENSIVITY; pcController->wMouseSensitivityX = DEFAULT_MOUSESENSIVITY;

View File

@ -1305,3 +1305,95 @@ DWORD WINAPI DelayedShortcut(LPVOID lpParam)
P_free(lpParam); P_free(lpParam);
return 0; return 0;
} }
void OctagonProj(float& outputX, float& outputY, float CARDINAL_MAX, float ANGLE_THRESHOLD)
{
constexpr float DIAG_RATIO = 2.448f; //CARDINAL_MAX * 0.71f / (CARDINAL_MAX - CARDINAL_MAX * 0.71f); max 71% diagonal
const float C = CARDINAL_MAX * DIAG_RATIO;
float ax = fabs(outputX);
float ay = fabs(outputY);
float r = hypotf(ax, ay);
if (r > EPSILON)
{
float theta = atan2f(ay, ax);
float r_max = (theta <= OCTAGON_ANGLE)
? (C / (sinf(theta) + DIAG_RATIO * cosf(theta)))
: (C / (cosf(theta) + DIAG_RATIO * sinf(theta)));
if (r >= r_max)
{
float new_r = r_max;
float new_ax = new_r * cosf(theta);
float new_ay = new_r * sinf(theta);
outputX = (outputX < 0) ? -new_ax : new_ax;
outputY = (outputY < 0) ? -new_ay : new_ay;
}
if( ANGLE_THRESHOLD > 0)
{
float angles[8] = { 0.0f, OCTAGON_ANGLE, 2 * OCTAGON_ANGLE, 3 * OCTAGON_ANGLE, 4 * OCTAGON_ANGLE, 5 * OCTAGON_ANGLE, 6 * OCTAGON_ANGLE, 7 * OCTAGON_ANGLE };
if (r >= r_max)
{
for (int i = 0; i < 8; ++i)
{
float angle = angles[i];
float angleLowerBound = angle - ANGLE_THRESHOLD;
float angleUpperBound = angle + ANGLE_THRESHOLD;
// Check if we need to lock
if (theta >= angleLowerBound && theta < angleUpperBound)
{
outputX = (outputX < 0) ? -CARDINAL_MAX * cosf(angle) : CARDINAL_MAX * cosf(angle);
outputY = (outputY < 0) ? -CARDINAL_MAX * sinf(angle) : CARDINAL_MAX * sinf(angle);
break;
}
}
}
}
}
}
void processStickInput(CONTROLLER* pcController, short inputX, short inputY, float& outputX, float& outputY)
{
float DEADZONE = (XC_ANALOG_MAX * (pcController->bPadDeadZone / 100.f));
float ANGLE_THRESHOLD = pcController->bVirtualCorners / 100.f;
float stickRange = pcController->bStickRange / 100.f;
float magnitude = hypotf(static_cast<float>(inputX), static_cast<float>(inputY));
float SENSITIVITY = ((1.5f - 0.1f) * (pcController->bPadSensitivity - 1) / (100 - 1)) + 0.1f;
if (magnitude == 0.0f || magnitude <= DEADZONE)
{
outputX = 0.0f;
outputY = 0.0f;
return;
}
float adjustedMagnitude = magnitude - DEADZONE;
float normalizedMagnitude = adjustedMagnitude / (XC_ANALOG_MAX - DEADZONE);
if (normalizedMagnitude < stickRange)
normalizedMagnitude = normalizedMagnitude / stickRange;
else
normalizedMagnitude = 1.0f;
normalizedMagnitude *= 1.0f + (SENSITIVITY - 1.0f) * (1.0f - normalizedMagnitude);
//normalizedMagnitude = fmaxf(0.0f, fminf(1.0f, normalizedMagnitude * (1.0f + (SENSITIVITY - 1.0f) * (1.0f - normalizedMagnitude))));
outputX = (inputX / magnitude) * normalizedMagnitude * XC_ANALOG_MAX;
outputY = (inputY / magnitude) * normalizedMagnitude * XC_ANALOG_MAX;
if (pcController->fRealN64Range) {
OctagonProj(outputX, outputY, XC_ANALOG_MAX, ANGLE_THRESHOLD);
}
if (pcController->xiController.stAnalogs.iInvertLX)
outputX = -outputX;
if (pcController->xiController.stAnalogs.iInvertLY)
outputY = -outputY;
}

View File

@ -36,8 +36,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Maximum number of modifiers // Maximum number of modifiers
#define MAX_MODIFIERS 256 #define MAX_MODIFIERS 256
#define DEFAULT_STICKRANGE 66 #define DEFAULT_STICKRANGE 100
#define DEFAULT_N64RANGE 88
#define DEFAULT_DEADZONE 5 #define DEFAULT_DEADZONE 5
#define DEFAULT_SENSITIVITY 50
#define DEFAULT_RUMBLETYP RUMBLE_EFF1 #define DEFAULT_RUMBLETYP RUMBLE_EFF1
#define DEFAULT_RUMBLESTRENGTH 80 #define DEFAULT_RUMBLESTRENGTH 80
#define DEFAULT_MOUSESENSIVITY 100 #define DEFAULT_MOUSESENSIVITY 100
@ -153,13 +155,13 @@ typedef struct _CONTROLLER // An N64 controller
unsigned bBackgroundInput; // Allow input while main window isn't focused? unsigned bBackgroundInput; // Allow input while main window isn't focused?
unsigned XcheckTime; // Checks for newly connected gamepads timer unsigned XcheckTime; // Checks for newly connected gamepads timer
BYTE bRumbleTyp; // What type of rumble effect? None, constant, ramp, or direct? BYTE bRumbleTyp; // What type of rumble effect? None, constant, ramp, or direct?
GUID guidFFDevice; // GUID of the device that rumble gets sent to GUID guidFFDevice; // GUID of the device that rumble gets sent to
BYTE bStickRange; // Our "range modifier" BYTE bStickRange; // Stick Range
long wAxeBuffer[4]; // Makes pseudo-relative movement possible through keyboard or buttons and also acts as a mouse buffer long wAxeBuffer[4]; // Makes pseudo-relative movement possible through keyboard or buttons and also acts as a mouse buffer
@ -167,6 +169,9 @@ typedef struct _CONTROLLER // An N64 controller
WORD wMouseSensitivityY; WORD wMouseSensitivityY;
BYTE bPadDeadZone; // Our manual dead zone, set per N64 controller BYTE bPadDeadZone; // Our manual dead zone, set per N64 controller
BYTE bRumbleStrength; // Set per N64 controller BYTE bRumbleStrength; // Set per N64 controller
BYTE bPadSensitivity; // Analog Sensitivity
BYTE bN64Range; // N64 Stick Range
BYTE bVirtualCorners; // Octagon Virtual Corners
unsigned short nModifiers; // Number of modifiers unsigned short nModifiers; // Number of modifiers
bool bRapidFireEnabled; bool bRapidFireEnabled;
@ -391,4 +396,23 @@ void freeModifiers(CONTROLLER *pcController);
void CheckShortcuts(); void CheckShortcuts();
bool ErrorMessage(UINT uID, DWORD dwError, bool fUserChoose); bool ErrorMessage(UINT uID, DWORD dwError, bool fUserChoose);
// Analog Input Management
constexpr float PI = 3.14159265358979323846;
constexpr float EPSILON = 1e-6f;
constexpr float OCTAGON_ANGLE = PI / 4.0;
typedef struct _ANALOGWIN {
int SIZE_W;
int SIZE_H;
int X;
int Y;
int CENTER_X;
int CENTER_Y;
float RADIUS;
float TRIANGLE_HEIGHT;
} ANALOGWIN;
void OctagonProj(float& outputX, float& outputY, float CARDINAL_MAX, float ANGLE_THRESHOLD);
void processStickInput(CONTROLLER* pcController, short inputX, short inputY, float& outputX, float& outputY);
#endif #endif

View File

@ -31,7 +31,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO GUIDELINES DESIGNINFO
BEGIN BEGIN
IDD_MAINCFGDIALOG, DIALOG IDD_MAINCFGDIALOG, DIALOG
BEGIN BEGIN
@ -123,10 +123,8 @@ BEGIN
BEGIN BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 363 RIGHTMARGIN, 363
VERTGUIDE, 16
VERTGUIDE, 169
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 173 BOTTOMMARGIN, 187
END END
IDD_MOD_MOVE, DIALOG IDD_MOD_MOVE, DIALOG
@ -145,9 +143,9 @@ BEGIN
"IDD_MAINCFGDIALOG$(_DEBUG)", DIALOG "IDD_MAINCFGDIALOG$(_DEBUG)", DIALOG
BEGIN BEGIN
LEFTMARGIN, 6 LEFTMARGIN, 6
RIGHTMARGIN, 389 RIGHTMARGIN, 390
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 344 BOTTOMMARGIN, 312
END END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -279,19 +277,16 @@ BEGIN
CTEXT "PLACEHOLDER",IDT_CRIGHT,219,43,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE CTEXT "PLACEHOLDER",IDT_CRIGHT,219,43,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
CTEXT "PLACEHOLDER",IDT_CDOWN,219,54,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE CTEXT "PLACEHOLDER",IDT_CDOWN,219,54,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
GROUPBOX "Analog Stick",IDC_STATIC,188,70,175,97 GROUPBOX "Analog Stick",IDC_STATIC,188,70,175,97
CTEXT "R PLACEHOLDER",IDT_RANGE,194,81,110,8 CONTROL "Config 1",IDC_CONFIG1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,232,79,40,10
CONTROL "PLACEHOLDER",IDC_CTRRANGE,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,194,89,113,11 CONTROL "Config 2",IDC_CONFIG2,"Button",BS_AUTORADIOBUTTON,283,79,40,10
CONTROL "Real N64 Range",IDC_N64RANGE,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_GROUP | WS_TABSTOP,312,82,44,19 PUSHBUTTON "Up",IDC_AUP,194,92,24,10,BS_NOTIFY | WS_GROUP
CONTROL "Config 1",IDC_CONFIG1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,194,103,42,10 PUSHBUTTON "Left",IDC_ALEFT,194,103,24,10,BS_NOTIFY
CONTROL "Config 2",IDC_CONFIG2,"Button",BS_AUTORADIOBUTTON,254,103,42,10 PUSHBUTTON "Right",IDC_ARIGHT,194,114,24,10,BS_NOTIFY
PUSHBUTTON "Up",IDC_AUP,194,119,24,10,BS_NOTIFY | WS_GROUP PUSHBUTTON "Down",IDC_ADOWN,194,125,24,10,BS_NOTIFY
PUSHBUTTON "Left",IDC_ALEFT,194,130,24,10,BS_NOTIFY CTEXT "PLACEHOLDER",IDT_AUP,219,92,137,10,SS_CENTERIMAGE,WS_EX_STATICEDGE
PUSHBUTTON "Right",IDC_ARIGHT,194,141,24,10,BS_NOTIFY CTEXT "PLACEHOLDER",IDT_ALEFT,219,103,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
PUSHBUTTON "Down",IDC_ADOWN,194,152,24,10,BS_NOTIFY CTEXT "PLACEHOLDER",IDT_ARIGHT,219,114,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
CTEXT "PLACEHOLDER",IDT_AUP,219,119,137,10,SS_CENTERIMAGE,WS_EX_STATICEDGE CTEXT "PLACEHOLDER",IDT_ADOWN,219,125,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
CTEXT "PLACEHOLDER",IDT_ALEFT,219,130,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
CTEXT "PLACEHOLDER",IDT_ARIGHT,219,141,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
CTEXT "PLACEHOLDER",IDT_ADOWN,219,152,137,10,SS_CENTERIMAGE | NOT WS_GROUP,WS_EX_STATICEDGE
END END
IDD_CONTROLLERPAK DIALOGEX 0, 0, 370, 180 IDD_CONTROLLERPAK DIALOGEX 0, 0, 370, 180
@ -361,7 +356,7 @@ BEGIN
LTEXT "If you want to use regular DirectInput force-feedback, choose RumblePak instead.",IDC_STATIC,95,90,165,22 LTEXT "If you want to use regular DirectInput force-feedback, choose RumblePak instead.",IDC_STATIC,95,90,165,22
END END
IDD_DEVICES DIALOGEX 0, 0, 370, 180 IDD_DEVICES DIALOGEX 0, 0, 370, 230
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x0 FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN BEGIN
@ -379,9 +374,19 @@ BEGIN
GROUPBOX "Keyboard",IDC_STATIC,7,96,171,27 GROUPBOX "Keyboard",IDC_STATIC,7,96,171,27
CONTROL "Absolute X",IDC_ACCELERATEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,107,50,10 CONTROL "Absolute X",IDC_ACCELERATEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,107,50,10
CONTROL "Absolute Y",IDC_ACCELERATEY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,107,50,10 CONTROL "Absolute Y",IDC_ACCELERATEY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,92,107,50,10
GROUPBOX "GamePad",IDC_STATIC,7,124,171,38 GROUPBOX "N64 Analog",IDC_STATIC,7,127,170,52
CTEXT "Deadzone PLACEHOLDER",IDT_DEADZONE,16,134,153,8 CTEXT "R PLACEHOLDER",IDT_N64RANGE,17,140,153,8
CONTROL "PLACEHOLDER",IDC_DEADZONE,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,16,144,153,11 CONTROL "PLACEHOLDER",IDC_N64RANGE,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,15,151,153,11
CONTROL "Real Octa N64 Range",IDC_N64REALRANGE,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,17,160,100,19
GROUPBOX "Gamepad Analog",IDC_STATIC,190,7,171,172
CTEXT "Deadzone PLACEHOLDER",IDT_DEADZONE,199,17,153,8
CONTROL "PLACEHOLDER",IDC_DEADZONE,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,199,27,153,11
CTEXT "Sensitivity PLACEHOLDER",IDT_SENSITIVITY,199,37,153,8
CONTROL "PLACEHOLDER",IDC_SENSITIVITY,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,199,47,153,11
CTEXT "R PLACEHOLDER",IDT_RANGE,199,57,153,8
CONTROL "PLACEHOLDER",IDC_CTRRANGE,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,199,67,153,11
CTEXT "R PLACEHOLDER",IDT_VIRTUALCORNERS,199,77,153,8
CONTROL "PLACEHOLDER",IDC_VIRTUALCORNERS,"msctls_trackbar32",TBS_AUTOTICKS | WS_GROUP | WS_TABSTOP,199,87,153,11
END END
IDD_PAK_TEXT DIALOGEX 0, 0, 356, 148 IDD_PAK_TEXT DIALOGEX 0, 0, 356, 148
@ -573,12 +578,12 @@ IDR_SHORTCUTS_DEFAULT SHORTCUT "configs/Shortcuts.sc"
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""WinResrc.h""\r\n" "#include ""WinResrc.h""\r\n"
"\r\n" "\r\n"
@ -589,7 +594,7 @@ BEGIN
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
@ -603,14 +608,14 @@ END
// String Table // String Table
// //
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_ERR_DINOTFOUND "dinput8.dll could not be found.\nPlease reinstall the latest version of DirectX." IDS_ERR_DINOTFOUND "dinput8.dll could not be found.\nPlease reinstall the latest version of DirectX."
IDS_ERR_DICREATE "Could not create DirectInput object." IDS_ERR_DICREATE "Could not create DirectInput object."
IDS_DLG_MPCHOOSE "Choose a MemPak or type a new name to create one." IDS_DLG_MPCHOOSE "Choose a MemPak or type a new name to create one."
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_ERR_MPREAD "Couldn't read MemPak." IDS_ERR_MPREAD "Couldn't read MemPak."
IDS_ERR_GBROM "Can't open GB ROM file!" IDS_ERR_GBROM "Can't open GB ROM file!"
@ -630,10 +635,12 @@ BEGIN
IDS_ERR_PROFREAD "Couldn't read profile." IDS_ERR_PROFREAD "Couldn't read profile."
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_C_POLLING "...Awaiting Input %i..." IDS_C_POLLING "...Awaiting Input %i..."
IDS_C_RANGE "Range: %i%%" IDS_C_RANGE "Stick Range: %i%%"
IDS_N64RANGE "N64 Range: %i%"
IDS_VIRTUALCORNERS "Virtual Corners: %i%%"
IDS_D_MSX "Mouse Sensitivity X: %i%%" IDS_D_MSX "Mouse Sensitivity X: %i%%"
IDS_D_MSY "Mouse Sensitivity Y: %i%%" IDS_D_MSY "Mouse Sensitivity Y: %i%%"
IDS_D_DEADZONE "Deadzone: %i%%" IDS_D_DEADZONE "Deadzone: %i%%"
@ -650,7 +657,12 @@ BEGIN
IDS_M_MACRO "Macro" IDS_M_MACRO "Macro"
END END
STRINGTABLE STRINGTABLE
BEGIN
IDS_SENSITIVITY "Sensitivity: %i%%"
END
STRINGTABLE
BEGIN BEGIN
IDS_M_CONFIG "Configuration" IDS_M_CONFIG "Configuration"
IDS_M_ASSIGNED "Assigned to" IDS_M_ASSIGNED "Assigned to"
@ -670,7 +682,7 @@ BEGIN
IDS_P_ADAPTOID_NORAW "The AdaptoidPak needs RawMode to be activated." IDS_P_ADAPTOID_NORAW "The AdaptoidPak needs RawMode to be activated."
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_P_NONE_RAWNORAW "No Pak inserted." IDS_P_NONE_RAWNORAW "No Pak inserted."
IDS_P_MEM_NOCHANGE "Can't change dir while running." IDS_P_MEM_NOCHANGE "Can't change dir while running."
@ -690,7 +702,7 @@ BEGIN
IDS_DLG_SHORTCUTRESTORE "The shortcut configuration will be restored.\nAre you sure?" IDS_DLG_SHORTCUTRESTORE "The shortcut configuration will be restored.\nAre you sure?"
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_DLG_SHORTCUTRESTORE_TITLE "Restore default" IDS_DLG_SHORTCUTRESTORE_TITLE "Restore default"
IDS_C_GAMEPAD "Gamepad: " IDS_C_GAMEPAD "Gamepad: "
@ -710,7 +722,7 @@ BEGIN
IDS_DLG_ABOUT "Help us translate N-Rage Input V2 into your language!" IDS_DLG_ABOUT "Help us translate N-Rage Input V2 into your language!"
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_DLG_ABOUT_TITLE "About N-Rage Input V2" IDS_DLG_ABOUT_TITLE "About N-Rage Input V2"
IDS_ERR_NOINIT "Plugin didn't get initialized!" IDS_ERR_NOINIT "Plugin didn't get initialized!"
@ -727,11 +739,11 @@ BEGIN
IDS_ERR_MEM_NOSPEC "No MemPak specified; please configure plugin." IDS_ERR_MEM_NOSPEC "No MemPak specified; please configure plugin."
IDS_DLG_MEM_READONLY "Mempak %s opened with read-only access.\nAfter exiting the game, the MemPak will NOT be saved." IDS_DLG_MEM_READONLY "Mempak %s opened with read-only access.\nAfter exiting the game, the MemPak will NOT be saved."
IDS_ERR_MEMOPEN "Unable to read or create MemPak file %s ; please configure plugin." IDS_ERR_MEMOPEN "Unable to read or create MemPak file %s ; please configure plugin."
IDS_DLG_MEM_BADADDRESSCRC IDS_DLG_MEM_BADADDRESSCRC
"Bad AddressCRC detected!\nThis usually indicates a bad ROM.\n\nIgnore it and continue?" "Bad AddressCRC detected!\nThis usually indicates a bad ROM.\n\nIgnore it and continue?"
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_P_MEM_NOREGION "None" IDS_P_MEM_NOREGION "None"
IDS_P_MEM_BETA "Beta" IDS_P_MEM_BETA "Beta"
@ -751,7 +763,7 @@ BEGIN
IDS_ERR_MEMPAK_NONOTES "No free notes on MemPak (only 16 notes available per pak)." IDS_ERR_MEMPAK_NONOTES "No free notes on MemPak (only 16 notes available per pak)."
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_ERR_NOTEEOF "Error reading note file: unexpected end of file or read error." IDS_ERR_NOTEEOF "Error reading note file: unexpected end of file or read error."
IDS_ERR_NOTEREAD "Couldn't read note file." IDS_ERR_NOTEREAD "Couldn't read note file."
@ -785,7 +797,7 @@ LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_CHILE
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO GUIDELINES DESIGNINFO
BEGIN BEGIN
IDD_XCONTROLS, DIALOG IDD_XCONTROLS, DIALOG
BEGIN BEGIN
@ -862,15 +874,26 @@ BEGIN
COMBOBOX IDC_XC_LT,143,112,39,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_XC_LT,143,112,39,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CTEXT "RT",IDC_STATIC,101,130,36,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE CTEXT "RT",IDC_STATIC,101,130,36,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE
COMBOBOX IDC_XC_RT,143,130,39,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_XC_RT,143,130,39,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
GROUPBOX "D-Pad and Thumbsticks configuration",IDC_STATIC,188,27,175,115
CTEXT "Left Thumbstick",IDC_STATIC,194,65,62,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE GROUPBOX "D-Pad and Thumbsticks configuration",IDC_STATIC,188,7,175,160
CTEXT "Right Thumbstick",IDC_STATIC,194,89,62,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE CTEXT "XControl",IDC_STATIC,194,27,62,8
CTEXT "D-Pad",IDC_STATIC,194,112,62,12,SS_CENTERIMAGE,WS_EX_CLIENTEDGE CTEXT "N64",IDC_STATIC,262,27,94,8
COMBOBOX IDC_XC_LTS,262,65,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CTEXT "Left Thumbstick",IDC_STATIC,194,41,62,13,SS_CENTERIMAGE,WS_EX_CLIENTEDGE
COMBOBOX IDC_XC_RTS,262,88,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Invert X",IDC_XC_INVERT_LX,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,194,55,47,12
COMBOBOX IDC_XC_DPAD,262,112,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Invert Y",IDC_XC_INVERT_LY,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,242,55,47,12
CTEXT "XControl",IDC_STATIC,194,45,62,8
CTEXT "N64",IDC_STATIC,262,45,94,8 CTEXT "Right Thumbstick",IDC_STATIC,194,69,62,13,SS_CENTERIMAGE,WS_EX_CLIENTEDGE
CONTROL "Invert X",IDC_XC_INVERT_RX,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,194,83,47,12
CONTROL "Invert Y",IDC_XC_INVERT_RY,"Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,242,83,47,12
CTEXT "D-Pad",IDC_STATIC,194,97,62,13,SS_CENTERIMAGE,WS_EX_CLIENTEDGE
COMBOBOX IDC_XC_LTS,262,41,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_XC_RTS,262,69,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_XC_DPAD,262,97,94,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "NOTE: LThSB and RThSB stands for Left/Right Thumbstick button respectively.",IDC_STATIC,14,155,349,18 LTEXT "NOTE: LThSB and RThSB stands for Left/Right Thumbstick button respectively.",IDC_STATIC,14,155,349,18
CTEXT "XControl",IDC_STATIC,14,27,36,8 CTEXT "XControl",IDC_STATIC,14,27,36,8
PUSHBUTTON "Save",IDC_XC_USE,306,159,50,14 PUSHBUTTON "Save",IDC_XC_USE,306,159,50,14

View File

@ -145,34 +145,18 @@ LCleanup:
return bIsXinputDevice; 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 ) void GetXInputControllerKeys( const int indexController, LPDWORD Keys )
{ {
if (fnXInputGetState == NULL) if (fnXInputGetState == NULL)
{ {
return; return;
} }
using namespace N64_BUTTONS; using namespace N64_BUTTONS;
LPCONTROLLER pcController = &g_pcControllers[indexController]; LPCONTROLLER pcController = &g_pcControllers[indexController];
LPXCONTROLLER gController = &g_pcControllers[indexController].xiController; LPXCONTROLLER gController = &pcController->xiController;
*Keys = 0; *Keys = 0;
@ -183,44 +167,52 @@ void GetXInputControllerKeys( const int indexController, LPDWORD Keys )
XINPUT_STATE state; XINPUT_STATE state;
ULONGLONG time = GetTickCount() / 1000; ULONGLONG time = GetTickCount() / 1000;
if (g_pcControllers[indexController].XcheckTime != NULL && (time - g_pcControllers[indexController].XcheckTime) < 3) if (pcController->XcheckTime != NULL && (time - pcController->XcheckTime) < 3)
return; return;
result = fnXInputGetState(gController->nControl, &state); result = fnXInputGetState(gController->nControl, &state);
if (result == ERROR_DEVICE_NOT_CONNECTED) { if (result == ERROR_DEVICE_NOT_CONNECTED) {
g_pcControllers[indexController].XcheckTime = time; pcController->XcheckTime = time;
} }
else { else {
g_pcControllers[indexController].XcheckTime = NULL; pcController->XcheckTime = NULL;
} }
if( result != ERROR_SUCCESS ) if( result != ERROR_SUCCESS )
return; return;
DWORD wButtons = state.Gamepad.wButtons; DWORD wButtons = state.Gamepad.wButtons;
if( pcController->bPadDeadZone > 0 ) float LX, LY, RX, RY;
{ short XAx, YAx;
const int RANGERELATIVE = 32767; float N64Range = (float)pcController->bN64Range;
long lDeadZoneValue = pcController->bPadDeadZone * RANGERELATIVE / 100;
float fDeadZoneRelation = (float)RANGERELATIVE / (float)( RANGERELATIVE - lDeadZoneValue );
AxisDeadzone(state.Gamepad.sThumbLX, lDeadZoneValue, fDeadZoneRelation); if (gController->stAnalogs.iLXAxis == XAxis){
AxisDeadzone(state.Gamepad.sThumbLY, lDeadZoneValue, fDeadZoneRelation); processStickInput(pcController, state.Gamepad.sThumbLX, state.Gamepad.sThumbLY, LX , LY);
AxisDeadzone(state.Gamepad.sThumbRX, lDeadZoneValue, fDeadZoneRelation); LX *= N64Range / (float)XC_ANALOG_MAX;
AxisDeadzone(state.Gamepad.sThumbRY, lDeadZoneValue, fDeadZoneRelation); LY *= N64Range / (float)XC_ANALOG_MAX;
RY = state.Gamepad.sThumbRY * N64_ANALOG_MAX / XC_ANALOG_MAX;
RX = state.Gamepad.sThumbRX * N64_ANALOG_MAX / XC_ANALOG_MAX;
XAx = LX;
YAx = LY;
if (pcController->xiController.stAnalogs.iInvertRX)
RX = -RX;
if (pcController->xiController.stAnalogs.iInvertRY)
RY = -RY;
}else{
processStickInput(pcController, state.Gamepad.sThumbRX, state.Gamepad.sThumbRY, RX, RY);
RX *= N64Range / (float)XC_ANALOG_MAX;
RY *= N64Range / (float)XC_ANALOG_MAX;
LY = state.Gamepad.sThumbLY * N64_ANALOG_MAX / XC_ANALOG_MAX;
LX = state.Gamepad.sThumbLX * N64_ANALOG_MAX / XC_ANALOG_MAX;
XAx = RX;
YAx = RY;
if (pcController->xiController.stAnalogs.iInvertLX)
LX = -LX;
if (pcController->xiController.stAnalogs.iInvertLY)
LY = -LY;
} }
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; WORD valButtons = 0;
valButtons |= ( wButtons & gController->stButtons.iDRight ) ? DRight : 0; valButtons |= ( wButtons & gController->stButtons.iDRight ) ? DRight : 0;
valButtons |= ( wButtons & gController->stButtons.iDLeft ) ? DLeft : 0; valButtons |= ( wButtons & gController->stButtons.iDLeft ) ? DLeft : 0;
@ -258,32 +250,6 @@ void GetXInputControllerKeys( const int indexController, LPDWORD Keys )
if (RY <= -BUTTON_ANALOG_VALUE) if (RY <= -BUTTON_ANALOG_VALUE)
valButtons |= gController->stAnalogs.iRYAxis & (CDown | DDown) ? gController->stAnalogs.iRYAxis : 0; 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)); *Keys = MAKELONG(valButtons, MAKEWORD(XAx, YAx));
} }
@ -307,6 +273,10 @@ void DefaultXInputControllerKeys( LPXCONTROLLER gController)
gController->stAnalogs.iLXAxis = XAxis; gController->stAnalogs.iLXAxis = XAxis;
gController->stAnalogs.iLYAxis = YAxis; gController->stAnalogs.iLYAxis = YAxis;
gController->bConfigured = true; gController->bConfigured = true;
gController->stAnalogs.iInvertLX = false;
gController->stAnalogs.iInvertLY = false;
gController->stAnalogs.iInvertRX = false;
gController->stAnalogs.iInvertRY = false;
} }
void VibrateXInputController( DWORD nController, int LeftMotorVal, int RightMotorVal ) void VibrateXInputController( DWORD nController, int LeftMotorVal, int RightMotorVal )
@ -387,7 +357,6 @@ bool InitiateXInputController( LPXCONTROLLER gController, int nControl )
TCHAR * GetN64ButtonNameFromButtonCode( int Button ) TCHAR * GetN64ButtonNameFromButtonCode( int Button )
{ {
using namespace N64_BUTTONS; using namespace N64_BUTTONS;
static TCHAR btnName[10]; static TCHAR btnName[10];
switch( Button ) switch( Button )
@ -509,6 +478,12 @@ bool ReadXInputControllerKeys( HWND hDlg, LPXCONTROLLER gController )
SendDlgItemMessage( hDlg, IDC_XC_LTS, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonArrayFromXAnalog( gController, XC_LTBS )); 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 )); SendDlgItemMessage( hDlg, IDC_XC_RTS, CB_SELECTSTRING, -1, (LPARAM)GetN64ButtonArrayFromXAnalog( gController, XC_RTBS ));
SendDlgItemMessage(hDlg, IDC_XC_INVERT_LX, BM_SETCHECK, (gController->stAnalogs.iInvertLX ? BST_CHECKED : BST_UNCHECKED), 0);
SendDlgItemMessage(hDlg, IDC_XC_INVERT_LY, BM_SETCHECK, (gController->stAnalogs.iInvertLY ? BST_CHECKED : BST_UNCHECKED), 0);
SendDlgItemMessage(hDlg, IDC_XC_INVERT_RX, BM_SETCHECK, (gController->stAnalogs.iInvertRX ? BST_CHECKED : BST_UNCHECKED), 0);
SendDlgItemMessage(hDlg, IDC_XC_INVERT_RY, BM_SETCHECK, (gController->stAnalogs.iInvertRY ? BST_CHECKED : BST_UNCHECKED), 0);
return true; return true;
} }
@ -536,8 +511,8 @@ int GetComboBoxXInputKey( int ComboBox )
} }
int GetN64ButtonCode( TCHAR *btnName ) //esta wea esta muy fea, hay que buscar una mejor manera definitivamente.. int GetN64ButtonCode( TCHAR *btnName ) //esta wea esta muy fea, hay que buscar una mejor manera definitivamente..
{ // ^ This translated means "This wea is very ugly, we must definitely find a better way" { // ^ This translated means "This wea is very ugly, we must definitely find a better way"
// I'm assuming there must be some perceived "better way to handle this, so maybe TODO: ?" // I'm assuming there must be some perceived "better way to handle this, so maybe TODO: ?"
using namespace N64_BUTTONS; using namespace N64_BUTTONS;
int value = 0; int value = 0;
@ -597,6 +572,11 @@ void ResetXInputControllerKeys( LPXCONTROLLER gController )
gController->stAnalogs.iRightTrigger = 0; gController->stAnalogs.iRightTrigger = 0;
gController->stAnalogs.iRXAxis = 0; gController->stAnalogs.iRXAxis = 0;
gController->stAnalogs.iRYAxis = 0; gController->stAnalogs.iRYAxis = 0;
gController->stAnalogs.iInvertLX = false;
gController->stAnalogs.iInvertLY = false;
gController->stAnalogs.iInvertRX = false;
gController->stAnalogs.iInvertRY = false;
} }
void StoreAnalogConfig( LPXCONTROLLER gController, int ComboBox, int index ) void StoreAnalogConfig( LPXCONTROLLER gController, int ComboBox, int index )
@ -663,6 +643,10 @@ void StoreXInputControllerKeys( HWND hDlg, LPXCONTROLLER gController )
{ {
LRESULT index = -1; LRESULT index = -1;
DWORD value = 0; DWORD value = 0;
int invertLX = gController->stAnalogs.iInvertLX;
int invertLY = gController->stAnalogs.iInvertLY;
int invertRX = gController->stAnalogs.iInvertRX;
int invertRY = gController->stAnalogs.iInvertRY;
ResetXInputControllerKeys( gController ); ResetXInputControllerKeys( gController );
@ -711,6 +695,10 @@ void StoreXInputControllerKeys( HWND hDlg, LPXCONTROLLER gController )
case 14: gController->stButtons.iDRight |= value; break; case 14: gController->stButtons.iDRight |= value; break;
} }
} }
gController->stAnalogs.iInvertLX = invertLX;
gController->stAnalogs.iInvertLY = invertLY;
gController->stAnalogs.iInvertRX = invertRX;
gController->stAnalogs.iInvertRY = invertRY;
gController->bConfigured = true; gController->bConfigured = true;
} }
@ -738,7 +726,11 @@ void SaveXInputConfigToFile( FILE *file, LPXCONTROLLER gController )
fprintf( file, "LeftXAxis=%lu\n", gController->stAnalogs.iLXAxis ); fprintf( file, "LeftXAxis=%lu\n", gController->stAnalogs.iLXAxis );
fprintf( file, "LeftYAxis=%lu\n", gController->stAnalogs.iLYAxis ); fprintf( file, "LeftYAxis=%lu\n", gController->stAnalogs.iLYAxis );
fprintf( file, "RightXAxis=%lu\n", gController->stAnalogs.iRXAxis ); fprintf( file, "RightXAxis=%lu\n", gController->stAnalogs.iRXAxis );
fprintf( file, "RightYAxis=%lu\n\n", gController->stAnalogs.iRYAxis ); fprintf( file, "RightYAxis=%lu\n", gController->stAnalogs.iRYAxis );
fprintf( file, "InvertLX=%lu\n", gController->stAnalogs.iInvertLX );
fprintf( file, "InvertLY=%lu\n", gController->stAnalogs.iInvertLY );
fprintf( file, "InvertRX=%lu\n", gController->stAnalogs.iInvertRX );
fprintf( file, "InvertRY=%lu\n\n", gController->stAnalogs.iInvertRY );
} }
void LoadXInputConfigFromFile( FILE *file, LPXCONTROLLER gController ) void LoadXInputConfigFromFile( FILE *file, LPXCONTROLLER gController )
@ -783,6 +775,30 @@ void LoadXInputConfigFromFile( FILE *file, LPXCONTROLLER gController )
sscanf(buffer, "DRight=%lu", &gController->stButtons.iDRight); break; sscanf(buffer, "DRight=%lu", &gController->stButtons.iDRight); break;
} }
break; break;
case 'I':
switch( buffer[6] )
{
case 'L':
switch( buffer[7] )
{
case 'X':
sscanf(buffer, "InvertLX=%lu", &gController->stAnalogs.iInvertLX);
break;
case 'Y':
sscanf(buffer, "InvertLY=%lu", &gController->stAnalogs.iInvertLY); break;
}
break;
case 'R':
switch( buffer[7] )
{
case 'X':
sscanf(buffer, "InvertRX=%lu", &gController->stAnalogs.iInvertRX); break;
case 'Y':
sscanf(buffer, "InvertRY=%lu", &gController->stAnalogs.iInvertRY); break;
}
break;
}
break;
case 'L': case 'L':
switch( buffer[1] ) switch( buffer[1] )
{ {

View File

@ -61,7 +61,7 @@ number, ie. first XInput controller is first N64 player, etc.
#include <xinput.h> #include <xinput.h>
// Defines // Defines
#define N64_ANALOG_MAX 88 #define N64_ANALOG_MAX 127
#define XC_ANALOG_MAX 32767 #define XC_ANALOG_MAX 32767
#define BUTTON_ANALOG_VALUE 60 #define BUTTON_ANALOG_VALUE 60
@ -95,6 +95,7 @@ typedef struct _XCONTROLLER // XInput controller struct
{ {
int iLeftTrigger, iRightTrigger; int iLeftTrigger, iRightTrigger;
unsigned int iRXAxis, iRYAxis, iLXAxis, iLYAxis; unsigned int iRXAxis, iRYAxis, iLXAxis, iLYAxis;
unsigned int iInvertLX, iInvertLY, iInvertRX, iInvertRY;
}stAnalogs; }stAnalogs;
}XCONTROLLER; }XCONTROLLER;

View File

@ -4,13 +4,16 @@ PakType=1
RealN64Range=1 RealN64Range=1
RapidFireEnabled=0 RapidFireEnabled=0
RapidFireRate=3 RapidFireRate=3
StickRange=66 StickRange=100
VirtualCorners=0
N64Range=88
MouseMoveX=0 MouseMoveX=0
MouseMoveY=0 MouseMoveY=0
AxisSet=0 AxisSet=0
KeyAbsoluteX=0 KeyAbsoluteX=0
KeyAbsoluteY=0 KeyAbsoluteY=0
PadDeadZone=5 PadDeadZone=5
PadSensitivity=50
MouseSensitivityX=100 MouseSensitivityX=100
MouseSensitivityY=100 MouseSensitivityY=100
RumbleType=1 RumbleType=1

View File

@ -209,7 +209,6 @@
#define IDC_RUMBLE3 1036 #define IDC_RUMBLE3 1036
#define IDC_RUMBLESTRENGTH 1037 #define IDC_RUMBLESTRENGTH 1037
#define IDC_MSSENSITIVITY_X 1038 #define IDC_MSSENSITIVITY_X 1038
#define IDC_N64RANGE 1039
#define IDC_MSSENSITIVITY_Y 1039 #define IDC_MSSENSITIVITY_Y 1039
#define IDC_PLUGGED 1040 #define IDC_PLUGGED 1040
#define IDC_CTRRANGE 1041 #define IDC_CTRRANGE 1041
@ -363,6 +362,20 @@
#define IDC_XC_RTS 1195 #define IDC_XC_RTS 1195
#define IDC_N64MOUSE 1196 #define IDC_N64MOUSE 1196
#define IDC_BACKGROUNDINPUT 1197 #define IDC_BACKGROUNDINPUT 1197
#define IDC_N64REALRANGE 1198
#define IDC_SENSITIVITY 1199
#define IDT_SENSITIVITY 1200
#define IDS_SENSITIVITY 1201
#define IDC_N64RANGE 1202
#define IDT_N64RANGE 1203
#define IDS_N64RANGE 1204
#define IDC_VIRTUALCORNERS 1205
#define IDT_VIRTUALCORNERS 1206
#define IDS_VIRTUALCORNERS 1207
#define IDC_XC_INVERT_LX 1208
#define IDC_XC_INVERT_LY 1209
#define IDC_XC_INVERT_RX 1210
#define IDC_XC_INVERT_RY 1211
// Next default values for new objects // Next default values for new objects
// //
@ -370,7 +383,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 149 #define _APS_NEXT_RESOURCE_VALUE 149
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1198 #define _APS_NEXT_CONTROL_VALUE 1300
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif