2020-02-09 11:36:49 +00:00
/*
2021-05-18 11:51:36 +00:00
N - Rage ` s Dinput8 Plugin
( C ) 2002 , 2006 Norbert Wladyka
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
Author ` s Email : norbert . wladyka @ chello . at
Website : http : //go.to/nrage
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
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 .
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
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 .
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
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
2016-01-27 09:11:59 +00:00
*/
2020-02-09 11:25:05 +00:00
# include <algorithm>
# include <math.h>
2016-01-27 09:11:59 +00:00
2020-02-10 09:57:07 +00:00
# include <initguid.h>
# include <cguid.h>
2016-01-27 09:11:59 +00:00
# include <dinput.h>
2020-02-09 11:25:05 +00:00
# include "commonIncludes.h"
# include "DirectInput.h"
2016-01-27 09:11:59 +00:00
# include "NRagePluginV2.h"
# include "PakIO.h"
# include "XInputController.h"
2020-02-09 11:25:05 +00:00
using std : : min ;
using std : : max ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// Prototypes
2016-01-27 09:11:59 +00:00
HRESULT AcquireDevice ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice ) ;
2021-05-18 11:51:36 +00:00
// Global variables
2020-02-09 11:36:49 +00:00
LPDIRECTINPUT8 g_pDIHandle = NULL ; // Base DirectInput8-Handle
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
//LPDIRECTINPUTDEVICE8 g_apInputDevice[6] = { NULL, NULL, NULL, NULL, NULL, NULL }; // Array of handles for devices
// 0:keyboard, 1:mouse, the rest are force feedback gamepads
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// BYTE g_acKeystate[256]; // Use g_sysKeyboard.stateAs.rgbButtons instead
2020-02-09 11:36:49 +00:00
// DIMOUSESTATE2 g_msMouseState = { 0, 0, 0 }; // Store our mouse state data between reads (because every time we read data, it resets the device data)
2021-05-18 11:51:36 +00:00
// Moved to g_sysMouse.stateAs...
2016-01-27 09:11:59 +00:00
// Update device data tables (so we only have to poll and read the devices once). This is called by GetKeys and ReadController.
void GetDeviceDatas ( )
{
2020-02-09 11:36:49 +00:00
HRESULT hr ;
/* if( g_sysKeyboard.didHandle )
{
hr = g_sysKeyboard . didHandle - > Poll ( ) ;
if ( FAILED ( hr ) )
2021-05-18 11:51:36 +00:00
AcquireDevice ( g_sysKeyboard . didHandle ) ; // We'll try again next time
2020-02-09 11:36:49 +00:00
hr = g_sysKeyboard . didHandle - > GetDeviceState ( sizeof ( g_sysKeyboard . stateAs . rgbButtons ) , & g_sysKeyboard . stateAs . rgbButtons ) ;
if ( FAILED ( hr ) )
ZeroMemory ( g_sysKeyboard . stateAs . rgbButtons , sizeof ( g_sysKeyboard . stateAs . rgbButtons ) ) ;
} */
if ( g_sysMouse . didHandle )
{
hr = g_sysMouse . didHandle - > Poll ( ) ;
if ( FAILED ( hr ) )
2021-05-18 11:51:36 +00:00
AcquireDevice ( g_sysMouse . didHandle ) ; // We'll try again next time
2020-02-09 11:36:49 +00:00
hr = g_sysMouse . didHandle - > GetDeviceState ( sizeof ( DIMOUSESTATE2 ) , & g_sysMouse . stateAs . mouseState ) ;
if ( FAILED ( hr ) )
ZeroMemory ( & g_sysMouse . stateAs . mouseState , sizeof ( DIMOUSESTATE2 ) ) ;
}
2021-05-18 11:51:36 +00:00
// Need to just poll every device we're using
2020-02-09 11:36:49 +00:00
for ( int i = 0 ; i < g_nDevices ; i + + )
{
if ( g_devList [ i ] . didHandle )
{
if ( FAILED ( g_devList [ i ] . didHandle - > Poll ( ) ) )
2021-05-18 11:51:36 +00:00
AcquireDevice ( g_devList [ i ] . didHandle ) ; // We'll try again next time
2020-02-09 11:36:49 +00:00
switch ( LOBYTE ( g_devList [ i ] . dwDevType ) )
{
case DI8DEVTYPE_KEYBOARD :
hr = g_devList [ i ] . didHandle - > GetDeviceState ( sizeof ( g_devList [ i ] . stateAs . rgbButtons ) , g_devList [ i ] . stateAs . rgbButtons ) ;
break ;
case DI8DEVTYPE_MOUSE :
hr = g_devList [ i ] . didHandle - > GetDeviceState ( sizeof ( g_devList [ i ] . stateAs . mouseState ) , & g_devList [ i ] . stateAs . mouseState ) ;
break ;
default :
hr = g_devList [ i ] . didHandle - > GetDeviceState ( sizeof ( g_devList [ i ] . stateAs . joyState ) , & g_devList [ i ] . stateAs . joyState ) ;
}
}
else
hr = DIERR_NOTACQUIRED ;
2021-05-18 11:51:36 +00:00
if ( hr = = DIERR_NOTACQUIRED ) // Changed this because in the rare condition that we lose input between polling and GetDeviceState we don't want to
// reset our current controls (comment by rabid)
2020-02-09 11:36:49 +00:00
{
ZeroMemory ( & g_devList [ i ] . stateAs . joyState , sizeof ( DEVICE : : INPUTSTATE ) ) ;
if ( g_devList [ i ] . dwDevType ! = DI8DEVTYPE_KEYBOARD & & g_devList [ i ] . dwDevType ! = DI8DEVTYPE_MOUSE )
FillMemory ( g_devList [ i ] . stateAs . joyState . rgdwPOV , sizeof ( g_devList [ i ] . stateAs . joyState . rgdwPOV ) , 0xFF ) ; // g_devList[i].stateAs.joyState.rgdwPOV = -1; // -1 is neutral
}
}
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Hacked up, but it works
2016-01-27 09:11:59 +00:00
inline bool GetJoyPadPOV ( PDWORD dwDegree , BYTE AxeId )
2021-05-18 11:51:36 +00:00
// True if specified direction is pressed
2016-01-27 09:11:59 +00:00
{
2020-02-09 11:36:49 +00:00
if ( LOWORD ( * dwDegree ) = = 0xFFFF )
return false ;
bool bPressed ;
switch ( AxeId )
{
case AI_POV_DOWN :
bPressed = ( ( * dwDegree > = 18000 - POVANGLETHRESH ) & & ( * dwDegree < = 18000 + POVANGLETHRESH ) ) ;
break ;
case AI_POV_LEFT :
bPressed = ( ( * dwDegree > = 27000 - POVANGLETHRESH ) & & ( * dwDegree < = 27000 + POVANGLETHRESH ) ) ;
break ;
case AI_POV_RIGHT :
bPressed = ( ( * dwDegree > = 9000 - POVANGLETHRESH ) & & ( * dwDegree < = 9000 + POVANGLETHRESH ) ) ;
break ;
case AI_POV_UP :
bPressed = ( ( * dwDegree > = 36000 - POVANGLETHRESH ) | | ( * dwDegree < = 0 + POVANGLETHRESH ) ) ;
break ;
default :
bPressed = false ;
}
return bPressed ;
2016-01-27 09:11:59 +00:00
}
// Fill in button states and axis states for controller indexController, into the struct pdwData.
2021-05-18 11:51:36 +00:00
// pdwData is a pointer to a 4 byte BUTTONS union, if matters to anybody
2016-01-27 09:11:59 +00:00
bool GetNControllerInput ( const int indexController , LPDWORD pdwData )
{
2020-02-09 11:36:49 +00:00
* pdwData = 0 ;
WORD w_Buttons = 0 ;
// WORD w_Axes = 0;
2021-05-18 11:51:36 +00:00
LPCONTROLLER pcController = & g_pcControllers [ indexController ] ; // Still needs to be here, but not as important (comment by rabid)
2020-02-09 11:36:49 +00:00
bool b_Value ;
long l_Value = 0 ;
long lAxisValueX = ZEROVALUE ;
long lAxisValueY = ZEROVALUE ;
2021-05-18 11:51:36 +00:00
// Take this info from the N64 controller struct, regardless of input devices
2020-02-09 11:36:49 +00:00
float d_ModifierX = ( float ) pcController - > bStickRange / 100.0f ;
float d_ModifierY = ( float ) pcController - > bStickRange / 100.0f ;
int i ;
2021-05-18 11:51:36 +00:00
// Do N64-Buttons / modifiers
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < pcController - > nModifiers ; i + + )
{
BUTTON btnButton = pcController - > pModifiers [ i ] . btnButton ;
b_Value = IsBtnPressed ( btnButton ) ;
bool fChangeMod = false ;
if ( pcController - > pModifiers [ i ] . bModType = = MDT_CONFIG )
2021-05-18 11:51:36 +00:00
{ // Config type
2020-02-09 11:36:49 +00:00
if ( pcController - > pModifiers [ i ] . fToggle )
{
if ( b_Value & & ! btnButton . fPrevPressed )
{
pcController - > pModifiers [ i ] . fStatus = ! pcController - > pModifiers [ i ] . fStatus ;
fChangeMod = true ;
}
}
else
{
if ( b_Value ! = ( bool ) ( btnButton . fPrevPressed ) )
fChangeMod = true ;
}
}
else
2021-05-18 11:51:36 +00:00
{ // Move / macro type
2020-02-09 11:36:49 +00:00
if ( pcController - > pModifiers [ i ] . fToggle )
{
if ( b_Value & & ! btnButton . fPrevPressed )
pcController - > pModifiers [ i ] . fStatus = ! pcController - > pModifiers [ i ] . fStatus ;
fChangeMod = ( pcController - > pModifiers [ i ] . fStatus ! = 0 ) ;
}
else
{
fChangeMod = b_Value ;
}
}
if ( fChangeMod )
{
switch ( pcController - > pModifiers [ i ] . bModType )
{
case MDT_MOVE :
{
LPMODSPEC_MOVE args = ( LPMODSPEC_MOVE ) & pcController - > pModifiers [ i ] . dwSpecific ;
d_ModifierX * = args - > XModification / 100.0f ;
d_ModifierY * = args - > YModification / 100.0f ;
}
break ;
case MDT_MACRO :
{
LPMODSPEC_MACRO args = ( LPMODSPEC_MACRO ) & pcController - > pModifiers [ i ] . dwSpecific ;
2021-05-18 11:51:36 +00:00
if ( args - > fRapidFire ) // Rapid fire here
2020-02-09 11:36:49 +00:00
{
if ( ( unsigned ) b_Value ! = btnButton . fPrevPressed ) // New macro pressed
{
args - > fPrevFireState = 0 ;
args - > fPrevFireState2 = 0 ;
}
if ( ! args - > fPrevFireState ) // This round, a firing is needed
{
w_Buttons | = args - > aButtons ;
if ( args - > fAnalogRight )
lAxisValueX + = MAXAXISVALUE ;
else if ( args - > fAnalogLeft )
lAxisValueX - = MAXAXISVALUE ;
if ( args - > fAnalogDown )
lAxisValueY - = MAXAXISVALUE ;
else if ( args - > fAnalogUp ) // up
lAxisValueY + = MAXAXISVALUE ;
}
2021-05-18 11:51:36 +00:00
// OK, update the firing counters here
2020-02-09 11:36:49 +00:00
if ( args - > fRapidFireRate ) // Do the rapid fire slowly
2021-05-18 11:51:36 +00:00
{ // Note that this updates State2 before State...makes a nice slower square-wave type pulse for the update
2020-02-09 11:36:49 +00:00
args - > fPrevFireState2 = ( args - > fPrevFireState2 + 1 ) & 1 ;
if ( ! args - > fPrevFireState2 )
{
args - > fPrevFireState = ( args - > fPrevFireState + 1 ) & 1 ;
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Slow rapid fire - Mark 2 \n " ) ;
2020-02-09 11:36:49 +00:00
}
}
else // Do a fast rapid fire
{
args - > fPrevFireState = ( args - > fPrevFireState + 1 ) & 1 ;
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Fast rapid fire \n " ) ;
2020-02-09 11:36:49 +00:00
}
}
else
{
w_Buttons | = args - > aButtons ; // Note this: It lets you push buttons as well as the macro buttons
if ( args - > fAnalogRight )
lAxisValueX + = MAXAXISVALUE ;
else if ( args - > fAnalogLeft )
lAxisValueX - = MAXAXISVALUE ;
if ( args - > fAnalogDown )
lAxisValueY - = MAXAXISVALUE ;
2021-05-18 11:51:36 +00:00
else if ( args - > fAnalogUp ) // Up
2020-02-09 11:36:49 +00:00
lAxisValueY + = MAXAXISVALUE ;
args - > fPrevFireState = 0 ;
}
}
break ;
case MDT_CONFIG :
{
LPMODSPEC_CONFIG args = ( LPMODSPEC_CONFIG ) & pcController - > pModifiers [ i ] . dwSpecific ;
if ( args - > fChangeAnalogConfig )
{
BYTE bConfig = ( BYTE ) args - > fAnalogStickMode ;
if ( bConfig < PF_AXESETS )
pcController - > bAxisSet = bConfig ;
else
{
if ( pcController - > bAxisSet = = PF_AXESETS - 1 )
pcController - > bAxisSet = 0 ;
else
+ + pcController - > bAxisSet ;
}
}
if ( args - > fChangeMouseXAxis )
if ( pcController - > bMouseMoveX = = MM_BUFF )
pcController - > bMouseMoveX = MM_ABS ;
else if ( pcController - > bMouseMoveX = = MM_ABS )
pcController - > bMouseMoveX = MM_BUFF ;
if ( args - > fChangeMouseYAxis )
if ( pcController - > bMouseMoveY = = MM_BUFF )
pcController - > bMouseMoveY = MM_ABS ;
else if ( pcController - > bMouseMoveY = = MM_ABS )
pcController - > bMouseMoveY = MM_BUFF ;
if ( args - > fChangeKeyboardXAxis )
pcController - > fKeyAbsoluteX = ! pcController - > fKeyAbsoluteX ;
if ( args - > fChangeKeyboardYAxis )
pcController - > fKeyAbsoluteY = ! pcController - > fKeyAbsoluteY ;
}
break ;
}
}
btnButton . fPrevPressed = b_Value ;
pcController - > pModifiers [ i ] . btnButton = btnButton ;
2021-05-18 11:51:36 +00:00
} // End N64 modifiers for
2020-02-09 11:36:49 +00:00
2021-05-18 11:51:36 +00:00
// Do N64 buttons / modifiers
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < PF_APADR ; i + + )
{
BUTTON btnButton = pcController - > aButton [ i ] ;
b_Value = IsBtnPressed ( btnButton ) ;
w_Buttons | = ( ( ( WORD ) b_Value ) < < i ) ;
2021-05-18 11:51:36 +00:00
} // End N64 buttons for
2020-02-09 11:36:49 +00:00
long lDeadZoneValue = pcController - > bPadDeadZone * RANGERELATIVE / 100 ;
float fDeadZoneRelation = ( float ) RANGERELATIVE / ( float ) ( RANGERELATIVE - lDeadZoneValue ) ;
2021-05-18 11:51:36 +00:00
// Do N64 joystick axes
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < 4 ; i + + )
{
// 0 : right
// 1 : left
// 2 : down
// 3 : up
bool fNegInput = ( ( i = = 1 ) | | ( i = = 2 ) ) ; // Input has to be negated
BUTTON btnButton = pcController - > aButton [ PF_APADR + pcController - > bAxisSet * 4 + i ] ;
LPLONG plRawState = ( LPLONG ) & btnButton . parentDevice - > stateAs . joyState ;
switch ( btnButton . bBtnType )
{
case DT_JOYBUTTON :
l_Value = MAXAXISVALUE ;
b_Value = ( btnButton . parentDevice - > stateAs . joyState . rgbButtons [ btnButton . bOffset ] & 0x80 ) ! = 0 ;
break ;
case DT_JOYSLIDER :
case DT_JOYAXE :
l_Value = plRawState [ btnButton . bOffset ] - ZEROVALUE ;
2021-05-18 11:51:36 +00:00
if ( btnButton . bAxisID ) // Negative range
2020-02-09 11:36:49 +00:00
{
fNegInput = ! fNegInput ;
b_Value = ( l_Value < = - lDeadZoneValue ) ;
if ( b_Value )
l_Value = ( long ) ( ( float ) ( l_Value + lDeadZoneValue ) * fDeadZoneRelation ) ;
}
else
{
b_Value = ( l_Value > = lDeadZoneValue ) ;
if ( b_Value )
l_Value = ( long ) ( ( float ) ( l_Value - lDeadZoneValue ) * fDeadZoneRelation ) ;
}
break ;
case DT_JOYPOV :
l_Value = MAXAXISVALUE ;
b_Value = GetJoyPadPOV ( ( PDWORD ) & plRawState [ btnButton . bOffset ] , btnButton . bAxisID ) ;
break ;
case DT_KEYBUTTON :
if ( btnButton . parentDevice - > stateAs . rgbButtons [ btnButton . bOffset ] & 0x80 )
{
b_Value = true ;
if ( ( pcController - > fKeyAbsoluteX & & i < 2 )
| | ( pcController - > fKeyAbsoluteY & & i > 1 ) )
{
if ( pcController - > wAxeBuffer [ i ] < MAXAXISVALUE )
{
l_Value = pcController - > wAxeBuffer [ i ] = min < long > ( ( pcController - > wAxeBuffer [ i ] + N64DIVIDER * 3 ) , MAXAXISVALUE ) ;
}
else
l_Value = MAXAXISVALUE ;
}
else
{
if ( pcController - > wAxeBuffer [ i ] < MAXAXISVALUE )
{
l_Value = pcController - > wAxeBuffer [ i ] = min < long > ( ( pcController - > wAxeBuffer [ i ] * 2 + N64DIVIDER * 5 ) , MAXAXISVALUE ) ;
}
else
l_Value = MAXAXISVALUE ;
}
}
else
{
if ( ( pcController - > fKeyAbsoluteX & & i < 2 )
| | ( pcController - > fKeyAbsoluteY & & i > 1 ) )
{
l_Value = pcController - > wAxeBuffer [ i ] ;
b_Value = true ;
}
else
{
if ( pcController - > wAxeBuffer [ i ] > N64DIVIDER )
{
b_Value = true ;
l_Value = pcController - > wAxeBuffer [ i ] = pcController - > wAxeBuffer [ i ] / 2 ;
}
else
b_Value = false ;
}
}
break ;
case DT_MOUSEBUTTON :
l_Value = MAXAXISVALUE ;
b_Value = ( btnButton . parentDevice - > stateAs . mouseState . rgbButtons [ btnButton . bOffset ] & 0x80 ) ! = 0 ;
break ;
case DT_MOUSEAXE :
if ( i < 2 )
pcController - > wAxeBuffer [ i ] + = plRawState [ btnButton . bOffset ] * pcController - > wMouseSensitivityX * MOUSESCALEVALUE ; // l_Value = btnButton.parentDevice->stateAs.mouseState[btnButton.bOffset];
else
pcController - > wAxeBuffer [ i ] + = plRawState [ btnButton . bOffset ] * pcController - > wMouseSensitivityY * MOUSESCALEVALUE ; // l_Value = btnButton.parentDevice->stateAs.mouseState[btnButton.bOffset];
l_Value = pcController - > wAxeBuffer [ i ] ;
// wAxeBuffer is positive for axes 0 and 3 if buffer remains, else zero
// wAxeBuffer is negative for axes 1 and 2 if buffer remains, else zero
if ( ( pcController - > bMouseMoveX = = MM_ABS & & i < 2 ) | | ( pcController - > bMouseMoveY = = MM_ABS & & i > 1 ) )
pcController - > wAxeBuffer [ i ] = min < long > ( max < long > ( MINAXISVALUE , pcController - > wAxeBuffer [ i ] ) , MAXAXISVALUE ) ;
else if ( ( pcController - > bMouseMoveX = = MM_BUFF & & i < 2 ) | | ( pcController - > bMouseMoveY = = MM_BUFF & & i > 1 ) )
pcController - > wAxeBuffer [ i ] = pcController - > wAxeBuffer [ i ] * MOUSEBUFFERDECAY / 100 ;
else // "deadpan" mouse
{
pcController - > wAxeBuffer [ i ] = 0 ;
}
2021-05-18 11:51:36 +00:00
if ( btnButton . bAxisID = = AI_AXE_N ) // The mouse axis has the '-' flag set
2020-02-09 11:36:49 +00:00
{
fNegInput = ! fNegInput ;
b_Value = ( l_Value < ZEROVALUE ) ;
}
else
{
b_Value = ( l_Value > ZEROVALUE ) ;
}
break ;
case DT_UNASSIGNED :
default :
b_Value = false ;
}
if ( b_Value )
{
if ( fNegInput )
l_Value = - l_Value ;
if ( i < 2 )
lAxisValueX + = l_Value ;
else
lAxisValueY + = l_Value ;
}
}
if ( pcController - > fKeyboard )
{
if ( pcController - > fKeyAbsoluteX )
{
if ( pcController - > wAxeBuffer [ 0 ] > pcController - > wAxeBuffer [ 1 ] )
{
pcController - > wAxeBuffer [ 0 ] - = pcController - > wAxeBuffer [ 1 ] ;
pcController - > wAxeBuffer [ 1 ] = 0 ;
}
else
{
pcController - > wAxeBuffer [ 1 ] - = pcController - > wAxeBuffer [ 0 ] ;
pcController - > wAxeBuffer [ 0 ] = 0 ;
}
}
if ( pcController - > fKeyAbsoluteY )
{
if ( pcController - > wAxeBuffer [ 2 ] > pcController - > wAxeBuffer [ 3 ] )
{
pcController - > wAxeBuffer [ 2 ] - = pcController - > wAxeBuffer [ 3 ] ;
pcController - > wAxeBuffer [ 3 ] = 0 ;
}
else
{
pcController - > wAxeBuffer [ 3 ] - = pcController - > wAxeBuffer [ 2 ] ;
pcController - > wAxeBuffer [ 2 ] = 0 ;
}
}
}
if ( pcController - > bRapidFireEnabled )
{
if ( pcController - > bRapidFireCounter > = pcController - > bRapidFireRate )
{
w_Buttons = ( w_Buttons & 0xFF1F ) ;
pcController - > bRapidFireCounter = 0 ;
}
else
{
pcController - > bRapidFireCounter = pcController - > bRapidFireCounter + 1 ;
}
}
if ( pcController - > fRealN64Range & & ( lAxisValueX | | lAxisValueY ) )
{
long lAbsoluteX = ( lAxisValueX > 0 ) ? lAxisValueX : - lAxisValueX ;
long lAbsoluteY = ( lAxisValueY > 0 ) ? lAxisValueY : - lAxisValueY ;
long lRangeX ;
long lRangeY ;
if ( lAbsoluteX > lAbsoluteY )
{
lRangeX = MAXAXISVALUE ;
lRangeY = lRangeX * lAbsoluteY / lAbsoluteX ;
}
else
{
lRangeY = MAXAXISVALUE ;
lRangeX = lRangeY * lAbsoluteX / lAbsoluteY ;
}
2021-05-18 11:51:36 +00:00
// TODO: We should optimize this (comment by rabid)
2020-02-09 11:36:49 +00:00
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 ;
2016-01-27 09:11:59 +00:00
}
bool InitDirectInput ( HWND hWnd )
{
2020-02-09 11:36:49 +00:00
if ( g_hDirectInputDLL = = NULL )
g_hDirectInputDLL = LoadLibrary ( _T ( " dinput8.dll " ) ) ;
if ( g_hDirectInputDLL = = NULL )
{
ErrorMessage ( IDS_ERR_DINOTFOUND , 0 , false ) ;
}
2021-05-18 11:51:36 +00:00
else if ( ! g_pDIHandle ) // This is NULL if not yet initialized
2020-02-09 11:36:49 +00:00
{
HRESULT ( WINAPI * lpGetDIHandle ) ( HINSTANCE , DWORD , REFIID , LPVOID * , LPUNKNOWN ) = NULL ;
lpGetDIHandle = ( HRESULT ( WINAPI * ) ( HINSTANCE , DWORD , REFIID , LPVOID * , LPUNKNOWN ) ) GetProcAddress ( g_hDirectInputDLL , " DirectInput8Create " ) ;
if ( lpGetDIHandle ! = NULL )
{
HRESULT hr ;
hr = lpGetDIHandle ( g_strEmuInfo . hinst , DIRECTINPUT_VERSION ,
IID_IDirectInput8 , ( LPVOID * ) & g_pDIHandle , NULL ) ;
if ( FAILED ( hr ) )
{
ErrorMessage ( IDS_ERR_DICREATE , 0 , false ) ;
g_pDIHandle = NULL ;
FreeLibrary ( g_hDirectInputDLL ) ;
g_hDirectInputDLL = NULL ;
}
}
}
return ( g_pDIHandle ! = NULL ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Release a DirectInput device since we don't need it anymore
2016-01-27 09:11:59 +00:00
void ReleaseDevice ( LPDIRECTINPUTDEVICE8 & lpDirectInputDevice )
{
2020-02-09 11:36:49 +00:00
if ( lpDirectInputDevice ! = NULL )
{
lpDirectInputDevice - > Unacquire ( ) ;
lpDirectInputDevice - > Release ( ) ;
lpDirectInputDevice = NULL ;
}
return ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Release a DirectInput device since we don't need it anymore
2016-01-27 09:11:59 +00:00
void ReleaseEffect ( LPDIRECTINPUTEFFECT & lpDirectEffect )
{
2020-02-09 11:36:49 +00:00
if ( lpDirectEffect ! = NULL )
{
2021-05-18 11:51:36 +00:00
// We should unload the effect on release
2020-02-09 11:36:49 +00:00
lpDirectEffect - > Release ( ) ;
lpDirectEffect = NULL ;
}
return ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Release our DirectInput effects and devices, our DirectInput handle, and then unload DInput library
2016-01-27 09:11:59 +00:00
void FreeDirectInput ( )
{
2020-02-09 11:36:49 +00:00
int i ;
2021-05-18 11:51:36 +00:00
// Release effects
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < ARRAYSIZE ( g_apdiEffect ) ; + + i )
ReleaseEffect ( g_apdiEffect [ i ] ) ;
ZeroMemory ( g_apdiEffect , sizeof ( g_apdiEffect ) ) ;
2021-05-18 11:51:36 +00:00
// Release force feedback devices
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < < ARRAYSIZE ( g_apFFDevice ) ; + + i )
ReleaseDevice ( g_apFFDevice [ i ] ) ;
ZeroMemory ( g_apFFDevice , sizeof ( g_apFFDevice ) ) ;
2021-05-18 11:51:36 +00:00
// Release normal devices
2020-02-09 11:36:49 +00:00
for ( i = 0 ; i < g_nDevices ; i + + )
ReleaseDevice ( g_devList [ i ] . didHandle ) ;
ZeroMemory ( g_devList , sizeof ( g_devList ) ) ;
g_nDevices = 0 ;
2021-05-18 11:51:36 +00:00
// Release mouse device
2020-02-09 11:36:49 +00:00
ReleaseDevice ( g_sysMouse . didHandle ) ;
ZeroMemory ( & g_sysMouse , sizeof ( g_sysMouse ) ) ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// Release any DirectInput handles
2020-02-09 11:36:49 +00:00
if ( g_pDIHandle ! = NULL )
{
g_pDIHandle - > Release ( ) ;
g_pDIHandle = NULL ;
}
2021-05-18 11:51:36 +00:00
// Unload the library
2020-02-09 11:36:49 +00:00
if ( g_hDirectInputDLL ! = NULL )
{
FreeLibrary ( g_hDirectInputDLL ) ;
g_hDirectInputDLL = NULL ;
}
return ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Acquire our device. Our device might get unacquired for many many reasons, and we need to be able to reacquire it to get input again.
2016-01-27 09:11:59 +00:00
// We use this a LOT.
inline HRESULT AcquireDevice ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice )
{
2020-02-09 11:36:49 +00:00
HRESULT hResult = lpDirectInputDevice - > Acquire ( ) ;
while ( hResult = = DIERR_INPUTLOST )
hResult = lpDirectInputDevice - > Acquire ( ) ;
if ( SUCCEEDED ( hResult ) )
lpDirectInputDevice - > Poll ( ) ;
return hResult ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Called by the DirectInput enumerator for each force feedback device. What kind of force feedback effects does this device support? We'll store it in pvRef.
2016-01-27 09:11:59 +00:00
BOOL CALLBACK EnumGetEffectTypes ( LPCDIEFFECTINFO pdei , LPVOID pvRef )
{
2020-02-09 11:36:49 +00:00
BYTE bFFType = * ( LPBYTE ) pvRef ;
bFFType | = ( pdei - > dwEffType & DIEFT_CONSTANTFORCE ) ? RUMBLE_CONSTANT : 0 ;
bFFType | = ( pdei - > dwEffType & DIEFT_RAMPFORCE ) ? RUMBLE_RAMP : 0 ;
bFFType | = ( pdei - > dwEffType & DIEFT_CONDITION ) ? RUMBLE_CONDITION : 0 ;
bFFType | = ( pdei - > dwEffType & DIEFT_PERIODIC ) ? RUMBLE_PERIODIC : 0 ;
bFFType | = ( pdei - > dwEffType & DIEFT_CUSTOMFORCE ) ? RUMBLE_CUSTOM : 0 ;
* ( WORD * ) pvRef = bFFType ;
return DIENUM_CONTINUE ;
2016-01-27 09:11:59 +00:00
}
// Called by the DirectInput enumerator for each attached DI device. We use it to make a list of devices.
2021-05-18 11:51:36 +00:00
// EnumMakeDeviceList has been rewritten (comment by rabid)
2016-01-27 09:11:59 +00:00
BOOL CALLBACK EnumMakeDeviceList ( LPCDIDEVICEINSTANCE lpddi , LPVOID pvRef )
{
2020-02-09 11:36:49 +00:00
switch ( GET_DIDEVICE_TYPE ( lpddi - > dwDevType ) ) {
2021-05-18 11:51:36 +00:00
// We don't need to do anything with these generic devices
2020-02-09 11:36:49 +00:00
case DI8DEVTYPE_DEVICE :
return DIENUM_CONTINUE ;
break ;
2021-05-18 11:51:36 +00:00
// These are potential XInput controllers, check them
2020-02-09 11:36:49 +00:00
case DI8DEVTYPE_GAMEPAD :
case DI8DEVTYPE_DRIVING :
case DI8DEVTYPE_JOYSTICK :
case DI8DEVTYPE_FLIGHT :
2021-05-18 11:51:36 +00:00
if ( IsXInputDevice ( & lpddi - > guidProduct ) ) // Check if is XInput device (comment by tecnicors)
2020-02-09 11:36:49 +00:00
return DIENUM_CONTINUE ;
break ;
2021-05-18 11:51:36 +00:00
// For all other devices, continue on
2020-02-09 11:36:49 +00:00
default :
break ;
}
if ( IsEqualGUID ( g_sysMouse . guidInstance , lpddi - > guidInstance ) )
return DIENUM_CONTINUE ;
for ( int i = 0 ; i < g_nDevices ; i + + )
if ( IsEqualGUID ( g_devList [ i ] . guidInstance , lpddi - > guidInstance ) )
return ( g_nDevices < ARRAYSIZE ( g_devList ) ) ? DIENUM_CONTINUE : DIENUM_STOP ;
2021-05-18 11:51:36 +00:00
if ( g_nDevices < ARRAYSIZE ( g_devList ) ) // Our buffer isn't full yet and the device doesn't already exist in our table
2020-02-09 11:36:49 +00:00
{
lstrcpyn ( g_devList [ g_nDevices ] . szProductName , lpddi - > tszProductName , MAX_PATH ) ;
g_devList [ g_nDevices ] . dwDevType = lpddi - > dwDevType ;
g_devList [ g_nDevices ] . guidInstance = lpddi - > guidInstance ;
2021-05-18 11:51:36 +00:00
g_devList [ g_nDevices ] . bProductCounter = 0 ; // Counting similar devices
2020-02-09 11:36:49 +00:00
for ( int i = 0 ; i < g_nDevices ; + + i )
{
if ( ! lstrcmp ( lpddi - > tszProductName , g_devList [ i ] . szProductName ) )
{
if ( g_devList [ g_nDevices ] . bProductCounter = = 0 )
{
g_devList [ g_nDevices ] . bProductCounter = 2 ;
if ( g_devList [ i ] . bProductCounter = = 0 )
g_devList [ i ] . bProductCounter = 1 ;
}
else
2021-05-18 11:51:36 +00:00
g_devList [ g_nDevices ] . bProductCounter + + ; // Give them instance numbers
2020-02-09 11:36:49 +00:00
}
}
if ( ! lstrcmp ( lpddi - > tszProductName , TEXT ( STRING_ADAPTOID ) ) )
g_devList [ g_nDevices ] . bEffType = RUMBLE_DIRECT ;
else
g_devList [ g_nDevices ] . bEffType = RUMBLE_NONE ;
if ( GetInputDevice ( g_strEmuInfo . hMainWindow , g_devList [ g_nDevices ] . didHandle , lpddi - > guidInstance , lpddi - > dwDevType , DIB_DEVICE ) )
{
g_devList [ g_nDevices ] . didHandle - > EnumEffects ( EnumGetEffectTypes , & g_devList [ g_nDevices ] . bEffType , DIEFT_ALL ) ;
g_nDevices + + ;
}
else
ZeroMemory ( & g_devList [ g_nDevices ] , sizeof ( DEVICE ) ) ;
}
return ( g_nDevices < ARRAYSIZE ( g_devList ) ) ? DIENUM_CONTINUE : DIENUM_STOP ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Called by an enumerator in GetInputDevice to determine if a device is attached at all
2016-01-27 09:11:59 +00:00
BOOL CALLBACK EnumIsDeviceAvailable ( LPCDIDEVICEINSTANCE lpddi , LPVOID pvRef )
{
2020-02-09 11:36:49 +00:00
if ( lpddi - > guidInstance = = * ( GUID * ) ( ( LPVOID * ) pvRef ) [ 0 ] )
{
* ( bool * ) ( ( LPVOID * ) pvRef ) [ 1 ] = true ;
return DIENUM_STOP ;
}
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
return DIENUM_CONTINUE ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Called by an axis enumerator in GetInputDevice. Set the minimum and maximum range so we can pass the recorded value right to the emulator
2016-01-27 09:11:59 +00:00
BOOL CALLBACK EnumSetObjectsAxis ( LPCDIDEVICEOBJECTINSTANCE lpddoi , LPVOID pvRef )
{
2020-02-09 11:36:49 +00:00
LPDIRECTINPUTDEVICE8 lpDirectInputDevice = ( LPDIRECTINPUTDEVICE8 ) pvRef ;
DIPROPRANGE diprg ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
diprg . diph . dwSize = sizeof ( DIPROPRANGE ) ;
diprg . diph . dwHeaderSize = sizeof ( DIPROPHEADER ) ;
diprg . diph . dwHow = DIPH_BYID ;
diprg . diph . dwObj = lpddoi - > dwType ;
diprg . lMin = MINAXISVALUE ;
diprg . lMax = MAXAXISVALUE ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
lpDirectInputDevice - > SetProperty ( DIPROP_RANGE , & diprg . diph ) ; // HACK: Usually works, but not all devices support setting range
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
return DIENUM_CONTINUE ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
/*
If passed an existing DirectInputDevice which matches gGuid
unacquires it , and sets its cooperative level ( reinitialize )
If the existing device does not match the passed gGuid , the existing device is released
If no device was passed or gGuid did not match it searches for the controller matching gGuid in connected and available devices
Creates a DirectInputDevice , sets its data format , sets its cooperative level for joysticks , calls EnumSetObjectsAxis for each axis
GetInputDevice always leaves the returned device in an UNACQUIRED state .
*/
2016-01-27 09:11:59 +00:00
bool GetInputDevice ( HWND hWnd , LPDIRECTINPUTDEVICE8 & lpDirectInputDevice , GUID gGuid , DWORD dwDevType , DWORD dwCooperativeLevel )
{
2020-02-09 11:36:49 +00:00
DebugWriteA ( " GetInputDevice: gGuid is {%08.8lX-%04.4hX-%04.4hX-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X} \n " , gGuid . Data1 , gGuid . Data2 , gGuid . Data3 , gGuid . Data4 [ 0 ] , gGuid . Data4 [ 1 ] , gGuid . Data4 [ 2 ] , gGuid . Data4 [ 3 ] , gGuid . Data4 [ 4 ] , gGuid . Data4 [ 5 ] , gGuid . Data4 [ 6 ] , gGuid . Data4 [ 7 ] ) ;
if ( lpDirectInputDevice ! = NULL )
{
DIDEVICEINSTANCE didDev ;
didDev . dwSize = sizeof ( DIDEVICEINSTANCE ) ;
lpDirectInputDevice - > GetDeviceInfo ( & didDev ) ;
if ( didDev . guidInstance = = gGuid )
2021-05-18 11:51:36 +00:00
{ // We've already gotten this device; unacquire it and initialize
DebugWriteA ( " GetInputDevice: Already created, attempting to reinitialize \n " ) ;
2020-02-09 11:36:49 +00:00
lpDirectInputDevice - > Unacquire ( ) ;
lpDirectInputDevice - > SetCooperativeLevel ( hWnd , dwCooperativeLevel ) ;
return true ;
}
else
ReleaseDevice ( lpDirectInputDevice ) ;
}
HRESULT hResult ;
LPCDIDATAFORMAT ppDiDataFormat = NULL ;
bool Success = false ;
switch ( LOBYTE ( dwDevType ) )
{
case DI8DEVTYPE_KEYBOARD :
ppDiDataFormat = & c_dfDIKeyboard ;
break ;
case DI8DEVTYPE_MOUSE :
ppDiDataFormat = & c_dfDIMouse2 ;
break ;
//case DI8DEVTYPE_GAMEPAD:
//case DI8DEVTYPE_JOYSTICK:
//case DI8DEVTYPE_DRIVING:
//case DI8DEVTYPE_1STPERSON:
//case DI8DEVTYPE_FLIGHT:
2021-05-18 11:51:36 +00:00
default : // Assume everything else is a controller; probably not the best idea but it works
2020-02-09 11:36:49 +00:00
ppDiDataFormat = & c_dfDIJoystick ;
break ;
}
bool bDeviceAvailable = false ;
VOID * aRef [ 2 ] = { & gGuid , & bDeviceAvailable } ;
2021-05-18 11:51:36 +00:00
// For each available device in our dwDevType category, run EnumIsDeviceAvailable with params "aRef"
2020-02-09 11:36:49 +00:00
g_pDIHandle - > EnumDevices ( DI8DEVCLASS_ALL , EnumIsDeviceAvailable , ( LPVOID ) aRef , DIEDFL_ATTACHEDONLY ) ;
if ( ! bDeviceAvailable )
{
DebugWriteA ( " GetInputDevice: Device does not appear available \n " ) ;
return false ;
}
hResult = g_pDIHandle - > CreateDevice ( gGuid , & lpDirectInputDevice , NULL ) ;
if ( SUCCEEDED ( hResult ) )
{
hResult = lpDirectInputDevice - > SetDataFormat ( ppDiDataFormat ) ;
hResult = lpDirectInputDevice - > SetCooperativeLevel ( hWnd , dwCooperativeLevel ) ;
Success = SUCCEEDED ( hResult ) ;
if ( ! Success )
{
DebugWriteA ( " GetInputDevice: SetCooperativeLevel failed \n " ) ;
}
}
else
DebugWriteA ( " GetInputDevice: CreateDevice failed \n " ) ;
if ( Success & & ( ppDiDataFormat = = & c_dfDIJoystick ) )
lpDirectInputDevice - > EnumObjects ( EnumSetObjectsAxis , lpDirectInputDevice , DIDFT_AXIS ) ;
return Success ;
2016-01-27 09:11:59 +00:00
}
// How many force feedback axes (motors) does our device have? We want to rumble them all.
BOOL CALLBACK EnumCountFFAxes ( LPCDIDEVICEOBJECTINSTANCE lpddoi , LPVOID pnAxes )
{
2020-02-09 11:36:49 +00:00
* ( DWORD * ) pnAxes + = 1 ;
return DIENUM_CONTINUE ;
2016-01-27 09:11:59 +00:00
}
// Create a force feedback effect handle and downloads the effect. Parameters are self-explanatory.
bool CreateEffectHandle ( HWND hWnd , LPDIRECTINPUTDEVICE8 lpDirectInputDevice , LPDIRECTINPUTEFFECT & pDIEffect , BYTE bRumbleTyp , long lStrength )
{
2020-02-09 11:36:49 +00:00
if ( pDIEffect )
ReleaseEffect ( pDIEffect ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
if ( ! lpDirectInputDevice | | bRumbleTyp = = RUMBLE_DIRECT )
return false ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DWORD nAxes = 0 ;
DWORD rgdwAxes [ ] = { DIJOFS_X , DIJOFS_Y } ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
HRESULT hResult ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// Count the force feedback - axes of the joystick
2020-02-09 11:36:49 +00:00
lpDirectInputDevice - > EnumObjects ( EnumCountFFAxes , & nAxes , DIDFT_FFACTUATOR | DIDFT_AXIS ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
if ( nAxes = = 0 )
return false ;
nAxes = min < long > ( nAxes , 2 ) ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// Must be unaquired for setting stuff like co-op level
2020-02-09 11:36:49 +00:00
hResult = lpDirectInputDevice - > Unacquire ( ) ;
2021-05-18 11:51:36 +00:00
// Force feedback Requires EXCLUSIVE LEVEL, took me hours to find the reason why it wasn't working
2020-02-09 11:36:49 +00:00
hResult = lpDirectInputDevice - > SetCooperativeLevel ( hWnd , DIB_FF ) ;
2016-01-27 09:11:59 +00:00
2021-05-18 11:51:36 +00:00
// Fail if we can't set coop level (comment by rabid)
2020-02-09 11:36:49 +00:00
if ( hResult ! = DI_OK )
{
DebugWriteA ( " CreateEffectHandle: couldn't set coop level: %08X \n " , hResult ) ;
return false ;
}
2016-01-27 09:11:59 +00:00
// Since we will be playing force feedback effects, we should disable the
// auto-centering spring.
2020-02-09 11:36:49 +00:00
DIPROPDWORD dipdw ;
2016-01-27 09:11:59 +00:00
dipdw . diph . dwSize = sizeof ( DIPROPDWORD ) ;
dipdw . diph . dwHeaderSize = sizeof ( DIPROPHEADER ) ;
dipdw . diph . dwObj = 0 ;
dipdw . diph . dwHow = DIPH_DEVICE ;
dipdw . dwData = FALSE ;
2020-02-09 11:36:49 +00:00
hResult = lpDirectInputDevice - > SetProperty ( DIPROP_AUTOCENTER , & dipdw . diph ) ;
long rglDirection [ ] = { 1 , 1 } ;
LPGUID EffectGuid ;
2016-01-27 09:11:59 +00:00
DIEFFECT eff ;
ZeroMemory ( & eff , sizeof ( eff ) ) ;
2020-02-09 11:36:49 +00:00
eff . dwSize = sizeof ( DIEFFECT ) ;
eff . dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS ;
eff . dwGain = lStrength * 100 ;
2016-01-27 09:11:59 +00:00
eff . dwTriggerButton = DIEB_NOTRIGGER ;
eff . dwTriggerRepeatInterval = 0 ;
2021-05-18 11:51:36 +00:00
eff . cAxes = nAxes ; // Number of axes
2016-01-27 09:11:59 +00:00
eff . rgdwAxes = rgdwAxes ;
eff . rglDirection = rglDirection ;
eff . lpEnvelope = NULL ;
2020-02-09 11:36:49 +00:00
eff . dwStartDelay = 0 ;
DICONSTANTFORCE cf ;
DIRAMPFORCE rf ;
DIPERIODIC pf ;
switch ( bRumbleTyp )
{
case RUMBLE_CONSTANT :
EffectGuid = ( GUID * ) & GUID_ConstantForce ;
2021-05-18 11:51:36 +00:00
eff . dwDuration = 150000 ; // Microseconds
2020-02-09 11:36:49 +00:00
eff . dwSamplePeriod = 0 ;
eff . cbTypeSpecificParams = sizeof ( DICONSTANTFORCE ) ;
eff . lpvTypeSpecificParams = & cf ;
cf . lMagnitude = 10000 ;
break ;
case RUMBLE_RAMP :
EffectGuid = ( GUID * ) & GUID_RampForce ;
2021-05-18 11:51:36 +00:00
eff . dwDuration = 300000 ; // Microseconds
2020-02-09 11:36:49 +00:00
eff . dwSamplePeriod = 0 ;
eff . cbTypeSpecificParams = sizeof ( DIRAMPFORCE ) ;
eff . lpvTypeSpecificParams = & rf ;
rf . lStart = 10000 ;
rf . lEnd = 2000 ;
break ;
case RUMBLE_CONDITION :
case RUMBLE_PERIODIC :
EffectGuid = ( GUID * ) & GUID_Sine ;
2021-05-18 11:51:36 +00:00
eff . dwDuration = 150000 ; // Microseconds
2020-02-09 11:36:49 +00:00
eff . dwSamplePeriod = 0 ;
eff . cbTypeSpecificParams = sizeof ( DIPERIODIC ) ;
eff . lpvTypeSpecificParams = & pf ;
pf . dwMagnitude = 10000 ;
pf . lOffset = 0 ;
pf . dwPhase = 0 ;
pf . dwPeriod = 2000 ;
break ;
case RUMBLE_NONE :
case RUMBLE_CUSTOM :
default :
return false ;
}
hResult = lpDirectInputDevice - > CreateEffect ( * EffectGuid , & eff , & pDIEffect , NULL ) ;
if ( hResult = = DI_OK )
{
hResult = lpDirectInputDevice - > Acquire ( ) ;
hResult = pDIEffect - > Download ( ) ;
}
else
{
DebugWriteA ( " CreateEffectHandle: didn't CreateEffect: %08X \n " , hResult ) ;
}
return SUCCEEDED ( hResult ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Counts how many of each type of button assignment (keyboard, mouse, controller)
2016-01-27 09:11:59 +00:00
DWORD CountControllerStructDevs ( CONTROLLER * pController )
{
2020-02-09 11:36:49 +00:00
BYTE bMouse = 0 , bKeyboard = 0 , bGamePad = 0 ;
BYTE bDType ;
bool fModifier = ( pController - > pModifiers ! = NULL ) ;
int i = ( fModifier ) ? pController - > nModifiers : ARRAYSIZE ( pController - > aButton ) ;
i - - ;
for ( ; i > = 0 | | fModifier ; - - i )
{
if ( i < 0 )
{
i = ARRAYSIZE ( pController - > aButton ) - 1 ;
fModifier = false ;
}
bDType = ( fModifier ) ? pController - > pModifiers [ i ] . btnButton . bBtnType
: pController - > aButton [ i ] . bBtnType ;
switch ( bDType )
{
case DT_JOYBUTTON :
case DT_JOYAXE :
case DT_JOYSLIDER :
case DT_JOYPOV :
+ + bGamePad ;
break ;
case DT_KEYBUTTON :
+ + bKeyboard ;
break ;
case DT_MOUSEBUTTON :
case DT_MOUSEAXE :
+ + bMouse ;
break ;
}
}
pController - > fGamePad = bGamePad ! = 0 ;
pController - > fKeyboard = bKeyboard ! = 0 ;
pController - > fMouse = bMouse ! = 0 ;
return MAKELONG ( MAKEWORD ( bGamePad , bMouse ) , MAKEWORD ( bKeyboard , ( bMouse + bKeyboard + bGamePad ) ) ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// PrepareInputDevices rewritten (comment by rabid)
2016-01-27 09:11:59 +00:00
bool PrepareInputDevices ( )
{
2020-02-09 11:36:49 +00:00
bool fKeyboard = false ;
bool fMouse = false ;
bool fGamePad = false ;
for ( int i = 0 ; i < ARRAYSIZE ( g_pcControllers ) ; + + i )
{
fGamePad = false ;
if ( g_pcControllers [ i ] . fPlugged )
{
CountControllerStructDevs ( & g_pcControllers [ i ] ) ;
fKeyboard = g_pcControllers [ i ] . fKeyboard ! = 0 ;
fMouse = g_pcControllers [ i ] . fMouse ! = 0 ;
2021-05-18 11:51:36 +00:00
fGamePad = ( g_pcControllers [ i ] . fGamePad ! = 0 ) ; // We'll assume for now that there's a controller to go with those buttons
2020-02-09 11:36:49 +00:00
}
ReleaseEffect ( g_apdiEffect [ i ] ) ;
2021-05-18 11:51:36 +00:00
if ( g_pcControllers [ i ] . guidFFDevice ! = GUID_NULL & & GetInputDevice ( g_strEmuInfo . hMainWindow , g_apFFDevice [ i ] , g_pcControllers [ i ] . guidFFDevice , DI8DEVTYPE_JOYSTICK , DIB_FF ) ) // Not necessarily a joystick type device, but we don't use the data anyway
2020-02-09 11:36:49 +00:00
{
DIDEVICEINSTANCE diDev ;
diDev . dwSize = sizeof ( DIDEVICEINSTANCE ) ;
g_apFFDevice [ i ] - > GetDeviceInfo ( & diDev ) ;
if ( ! lstrcmp ( diDev . tszProductName , _T ( STRING_ADAPTOID ) ) )
{
g_pcControllers [ i ] . fIsAdaptoid = true ;
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Force feedback device on controller %d is of type Adaptoid \n " , i + 1 ) ;
2020-02-09 11:36:49 +00:00
}
else
{
g_pcControllers [ i ] . fIsAdaptoid = false ;
}
if ( CreateEffectHandle ( i , g_pcControllers [ i ] . bRumbleTyp , g_pcControllers [ i ] . bRumbleStrength ) )
{
AcquireDevice ( g_apFFDevice [ i ] ) ;
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Got force feedback device %d \n " , i ) ;
2020-02-09 11:36:49 +00:00
}
else
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Couldn't get force feedback device: CreateEffectHandle failed! \n " ) ;
2020-02-09 11:36:49 +00:00
}
else
{
g_apFFDevice [ i ] = NULL ;
2021-05-18 11:51:36 +00:00
DebugWriteA ( " Didn't get force feedback device %d \n " , i ) ;
2020-02-09 11:36:49 +00:00
}
}
if ( fMouse )
{
if ( ! g_sysMouse . didHandle )
{
if ( GetInputDevice ( g_strEmuInfo . hMainWindow , g_sysMouse . didHandle , GUID_SysMouse , DI8DEVTYPE_MOUSE , g_bExclusiveMouse ? DIB_MOUSE : DIB_KEYBOARD ) )
{
AcquireDevice ( g_sysMouse . didHandle ) ;
}
}
}
else
{
g_bExclusiveMouse = false ;
}
return true ;
2016-01-27 09:11:59 +00:00
}
bool IsAdaptoidCommandSupported ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice , DWORD cmd )
{
DIEFFESCAPE esc ;
DWORD inbuf , outbuf ;
HRESULT hr ;
2020-02-09 11:36:49 +00:00
esc . dwSize = sizeof ( esc ) ;
2021-05-18 11:51:36 +00:00
esc . dwCommand = ADAPT_TEST ; // Command to determine if a command is supported
2020-02-09 11:36:49 +00:00
esc . lpvInBuffer = & inbuf ;
esc . cbInBuffer = 4 ;
esc . lpvOutBuffer = & outbuf ;
esc . cbOutBuffer = 4 ;
2021-05-18 11:51:36 +00:00
inbuf = cmd ; // Command that we are asking is supported
2020-02-09 11:36:49 +00:00
outbuf = 0 ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
hr = lpDirectInputDevice - > Escape ( & esc ) ;
2016-01-27 09:11:59 +00:00
return ( SUCCEEDED ( hr ) & & esc . cbOutBuffer = = 4 & & outbuf = = 0xB0CAB0CA ) ;
}
# ifdef _DEBUG
2021-05-18 11:51:36 +00:00
// Direct Adaptoid debugging stuff
2016-01-27 09:11:59 +00:00
void _debugAd ( LPCSTR szMessage , HRESULT res )
{
2020-02-09 11:36:49 +00:00
LPCSTR suc = ( SUCCEEDED ( res ) ) ? " OK " : " FAILED " ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DebugWriteA ( " %s: %s (RC:%08X) \n " , szMessage , suc , res ) ;
2016-01-27 09:11:59 +00:00
}
# endif // #ifdef _DEBUG
HRESULT DirectRumbleCommand ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice , DWORD cmd )
{
DIEFFESCAPE esc ;
esc . dwSize = sizeof ( esc ) ;
2021-05-18 11:51:36 +00:00
esc . dwCommand = ADAPT_RUMBLE ; // Send rumble command
2016-01-27 09:11:59 +00:00
esc . lpvInBuffer = & cmd ; // 1=go, 0=stop
esc . cbInBuffer = 4 ;
esc . lpvOutBuffer = NULL ;
esc . cbOutBuffer = 0 ;
2020-02-09 11:36:49 +00:00
HRESULT hr = lpDirectInputDevice - > Escape ( & esc ) ;
2016-01-27 09:11:59 +00:00
# ifdef _DEBUG
2020-02-09 11:36:49 +00:00
_debugAd ( " Direct Adaptoid RumbleCommand " , hr ) ;
2016-01-27 09:11:59 +00:00
# endif // #ifdef _DEBUG
return hr ;
}
HRESULT InitializeAdaptoid ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice , LPBYTE status )
{
DIEFFESCAPE esc ;
esc . dwSize = sizeof ( esc ) ;
2021-05-18 11:51:36 +00:00
esc . dwCommand = ADAPT_INIT ; // Initialize pak
2016-01-27 09:11:59 +00:00
esc . lpvInBuffer = NULL ;
esc . cbInBuffer = 0 ;
2020-02-09 11:36:49 +00:00
esc . lpvOutBuffer = status ;
2016-01-27 09:11:59 +00:00
esc . cbOutBuffer = 1 ;
2020-02-09 11:36:49 +00:00
HRESULT hr = lpDirectInputDevice - > Escape ( & esc ) ;
2016-01-27 09:11:59 +00:00
# ifdef _DEBUG
2020-02-09 11:36:49 +00:00
_debugAd ( " Direct Adaptoid InitPak " , hr ) ;
2016-01-27 09:11:59 +00:00
# endif // #ifdef _DEBUG
return hr ;
}
HRESULT ReadAdaptoidPak ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice , DWORD addr , LPBYTE data )
{
DIEFFESCAPE esc ;
esc . dwSize = sizeof ( esc ) ;
esc . dwCommand = ADAPT_READPAK ; // Read 32 bytes from pak
esc . lpvInBuffer = & addr ;
esc . cbInBuffer = 4 ;
2020-02-09 11:36:49 +00:00
esc . lpvOutBuffer = data ;
2016-01-27 09:11:59 +00:00
esc . cbOutBuffer = 32 ;
2020-02-09 11:36:49 +00:00
HRESULT hr = lpDirectInputDevice - > Escape ( & esc ) ;
2016-01-27 09:11:59 +00:00
# ifdef _DEBUG
2020-02-09 11:36:49 +00:00
LPCSTR suc = ( SUCCEEDED ( hr ) ) ? " OK " : " FAILED " ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DebugWriteA ( " Direct Adaptoid ReadPak(Addr:%04X): %s (RC:%08X) \n " , addr , suc , hr ) ;
2016-01-27 09:11:59 +00:00
# endif // #ifdef _DEBUG
return hr ;
}
HRESULT WriteAdaptoidPak ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice , DWORD addr , LPBYTE data )
{
DIEFFESCAPE esc ;
struct
{
DWORD addr ;
BYTE data [ 32 ] ;
} buf ;
buf . addr = addr ;
CopyMemory ( buf . data , data , 32 ) ;
esc . dwSize = sizeof ( esc ) ;
esc . dwCommand = ADAPT_WRITEPAK ; // Write 32 bytes to pak
esc . lpvInBuffer = & buf ;
esc . cbInBuffer = 36 ;
2020-02-09 11:36:49 +00:00
esc . lpvOutBuffer = NULL ;
2016-01-27 09:11:59 +00:00
esc . cbOutBuffer = 0 ;
2020-02-09 11:36:49 +00:00
HRESULT hr = lpDirectInputDevice - > Escape ( & esc ) ;
2016-01-27 09:11:59 +00:00
# ifdef _DEBUG
2020-02-09 11:36:49 +00:00
LPCSTR suc = ( SUCCEEDED ( hr ) ) ? " OK " : " FAILED " ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DebugWriteA ( " Direct Adaptoid WritePak(Addr:%04X): %s (RC:%08X) \n " , addr , suc , hr ) ;
2016-01-27 09:11:59 +00:00
# endif // #ifdef _DEBUG
return hr ;
}
BYTE GetAdaptoidStatus ( LPDIRECTINPUTDEVICE8 lpDirectInputDevice )
{
2020-02-09 11:36:49 +00:00
HRESULT hr ;
BYTE bStatus = 0 ;
hr = InitializeAdaptoid ( lpDirectInputDevice , & bStatus ) ;
int iRetrys = 10 ;
while ( FAILED ( hr ) & & iRetrys > 0 )
{
Sleep ( 5 ) ;
hr = AcquireDevice ( lpDirectInputDevice ) ;
hr = InitializeAdaptoid ( lpDirectInputDevice , & bStatus ) ;
iRetrys - - ;
}
return ( SUCCEEDED ( hr ) ) ? bStatus : RD_NOPLUGIN | RD_NOTINITIALIZED ;
2016-01-27 09:11:59 +00:00
}
// Fill the handle for g_sysMouse properly
void InitMouse ( )
{
2020-02-09 11:36:49 +00:00
if ( GetInputDevice ( g_strEmuInfo . hMainWindow , g_sysMouse . didHandle , GUID_SysMouse , DI8DEVTYPE_MOUSE , DIB_KEYBOARD ) )
{
g_sysMouse . guidInstance = GUID_SysMouse ;
g_sysMouse . dwDevType = DI8DEVTYPE_MOUSE ;
_tcsncpy ( g_sysMouse . szProductName , STRING_GUID_SYSMOUSE , ARRAYSIZE ( g_sysMouse . szProductName ) ) ;
}
else
g_sysMouse . didHandle = NULL ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Treat btnButton as a b_Value, and return whether it is pressed or not
2016-01-27 09:11:59 +00:00
bool IsBtnPressed ( BUTTON btnButton )
{
2020-02-09 11:36:49 +00:00
long l_Value ;
LPLONG plRawState = ( LPLONG ) & btnButton . parentDevice - > stateAs . joyState ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
switch ( btnButton . bBtnType )
{
case DT_JOYBUTTON :
return ( btnButton . parentDevice - > stateAs . joyState . rgbButtons [ btnButton . bOffset ] & 0x80 ) ! = 0 ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_JOYSLIDER :
case DT_JOYAXE :
l_Value = plRawState [ btnButton . bOffset ] - ZEROVALUE ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
if ( btnButton . bAxisID )
return ( l_Value < = - ABSTHRESHOLD ) ;
else
return ( l_Value > = ABSTHRESHOLD ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_JOYPOV :
return GetJoyPadPOV ( ( PDWORD ) & plRawState [ btnButton . bOffset ] , btnButton . bAxisID ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_KEYBUTTON :
return ( btnButton . parentDevice - > stateAs . rgbButtons [ btnButton . bOffset ] & 0x80 ) ! = 0 ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_MOUSEBUTTON :
return ( btnButton . parentDevice - > stateAs . mouseState . rgbButtons [ btnButton . bOffset ] & 0x80 ) ! = 0 ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_MOUSEAXE :
2021-05-18 11:51:36 +00:00
l_Value = MOUSEMOVE ; // AKA lvalue is button threshold
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
if ( btnButton . bAxisID )
return ( ( ( LPLONG ) ( & btnButton . parentDevice - > stateAs . mouseState ) ) [ btnButton . bOffset ] < - l_Value ) ;
else
return ( ( ( LPLONG ) ( & btnButton . parentDevice - > stateAs . mouseState ) ) [ btnButton . bOffset ] > l_Value ) ;
break ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
case DT_UNASSIGNED :
default :
return false ;
}
2016-01-27 09:11:59 +00:00
}