2021-05-18 11:51:36 +00:00
/*
N - Rage ` s Dinput8 Plugin
( C ) 2002 , 2006 Norbert Wladyka
Author ` s Email : norbert . wladyka @ chello . at
Website : http : //go.to/nrage
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2016-01-27 09:11:59 +00:00
*/
2020-02-09 11:25:05 +00:00
# include <string>
# include <stdio.h>
2016-01-27 09:11:59 +00:00
# include <windows.h>
2020-02-10 09:57:07 +00:00
# include <commdlg.h>
2016-01-27 09:11:59 +00:00
# include <shlobj.h>
2020-02-09 11:25:05 +00:00
# include <tchar.h>
# include "commonIncludes.h"
# include "DirectInput.h"
# include "FileAccess.h"
# include "Interface.h"
2016-01-27 09:11:59 +00:00
# include "NRagePluginV2.h"
# include "PakIO.h"
2020-02-09 11:25:05 +00:00
2016-01-27 09:11:59 +00:00
using std : : string ;
# ifndef IDR_PROFILE_DEFAULT1
# define IDR_PROFILE_DEFAULT1 -1
# endif
# ifndef IDR_PROFILE_DEFAULT2
# define IDR_PROFILE_DEFAULT2 -1
# endif
# ifndef IDR_PROFILE_DEFAULT3
# define IDR_PROFILE_DEFAULT3 -1
# endif
# ifndef IDR_PROFILE_DEFAULT4
# define IDR_PROFILE_DEFAULT4 -1
# endif
void DumpStreams ( FILE * fFile , string strMouse , string strDevs [ ] , string strNull , bool bIsINI ) ;
void DumpControllerSettings ( FILE * fFile , int i , bool bIsINI ) ;
void FormatControlsBlock ( string * strMouse , string strDevs [ ] , string * strNull , int i ) ;
void FormatModifiersBlock ( string * strMouse , string strDevs [ ] , string * strNull , int i ) ;
2021-05-18 11:51:36 +00:00
// Return true if the file exists, let's just use CreateFile with OPEN_EXISTING
2016-01-27 09:11:59 +00:00
bool CheckFileExists ( LPCTSTR FileName )
{
2020-02-09 11:36:49 +00:00
HANDLE hFile = CreateFile ( FileName , GENERIC_READ , 0 , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
if ( hFile = = INVALID_HANDLE_VALUE )
{
return false ;
}
else
{
CloseHandle ( hFile ) ;
return true ;
}
2016-01-27 09:11:59 +00:00
}
// A rather ugly function, but does its job. Called by LoadProfile and LoadProfileFromResource.
// Parses the config data that gets written to profile files.
// returns:
2020-02-09 11:36:49 +00:00
// PL_CATEGORY and removes the brackets if the line looks like a keymapping
// PL_VERSIONSTRING and returns the version number if it's a version line
// for other cases, another PL return value and truncates before the equal sign; so strings like "Button=blah" -> "blah"
2021-05-18 11:51:36 +00:00
// TODO: Perhaps buffer overflow and crash potential here...needs auditing
2016-01-27 09:11:59 +00:00
DWORD ParseLine ( LPSTR pszLine )
{
2020-02-09 11:36:49 +00:00
DWORD dwReturn = PL_NOHIT ;
char * pChar = pszLine ;
switch ( pszLine [ 0 ] )
{
2021-05-18 11:51:36 +00:00
case ' \0 ' : // Shortcut out on null string
2020-02-09 11:36:49 +00:00
case ' # ' : // # indicates comment line
return PL_NOHIT ;
case ' [ ' :
while ( * pChar ! = ' ] ' & & * pChar ! = ' \0 ' )
{
* pChar = toupper ( * pChar ) ;
+ + pChar ;
}
if ( * pChar = = ' ] ' )
{
2021-05-18 11:51:36 +00:00
MoveMemory ( pszLine , pszLine + 1 , ( pChar - pszLine ) - 1 * sizeof ( pszLine [ 0 ] ) ) ; // TODO: Please double check this (comment by rabid)
* ( pChar - 1 ) = ' \0 ' ; // Since we moved everything back one character, we need to change this ref as well
2020-02-09 11:36:49 +00:00
return PL_CATEGORY ;
}
else
2021-05-18 11:51:36 +00:00
return PL_NOHIT ; // An open bracket with no closing returns no hit
2020-02-09 11:36:49 +00:00
case ' @ ' :
2021-05-18 11:51:36 +00:00
switch ( djbHash ( pszLine ) ) // The hash check is case sensitive, and includes the @ symbol
2020-02-09 11:36:49 +00:00
{
case CHK_PROFILEVERSION20 :
lstrcpyA ( pszLine , " 2.0 " ) ;
return PL_VERSIONSTRING ;
case CHK_PROFILEVERSION21 :
lstrcpyA ( pszLine , " 2.1 " ) ;
return PL_VERSIONSTRING ;
case CHK_PROFILEVERSION22 :
lstrcpyA ( pszLine , " 2.2 " ) ;
return PL_VERSIONSTRING ;
default :
DebugWriteA ( " Unknown version string found with hash %u: %s \n " , djbHash ( pszLine ) , pszLine ) ;
return PL_NOHIT ;
} // end switch (dbjHash(pszLine))
2021-05-18 11:51:36 +00:00
// Default: keep running
2020-02-09 11:36:49 +00:00
}
pChar = strchr ( pszLine , ' = ' ) ;
2021-05-18 11:51:36 +00:00
if ( ! pChar ) // No = sign
2020-02-09 11:36:49 +00:00
{
return PL_NOHIT ;
}
2021-05-18 11:51:36 +00:00
else // There is an '=' sign
2020-02-09 11:36:49 +00:00
{
// We hash the string. If the hash matches the hash of one of our targets, we compare strings to verify.
2021-05-18 11:51:36 +00:00
// If we don't use hashes, we have to compare vs many strings.
* pChar = ' \0 ' ; // Truncate at the '=' for now
2020-02-09 11:36:49 +00:00
for ( char * pIter = pszLine ; * pIter ; pIter + + )
* pIter = toupper ( * pIter ) ;
dwReturn = djbHash ( pszLine ) ;
pChar + + ;
MoveMemory ( pszLine , pChar , ( lstrlenA ( pChar ) + 1 ) * sizeof ( pszLine [ 0 ] ) ) ; // change string to match what's to the right of '='
}
return dwReturn ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Called immediately after ParseLine to assign values based on whatever the key name was
// Notes: pszFFDevice may be overwritten with whatever is in pszLine; please make sure pszLine is not too big!
2016-01-27 09:11:59 +00:00
bool ProcessKey ( DWORD dwKey , DWORD dwSection , LPCSTR pszLine , LPTSTR pszFFDevice , LPBYTE bFFDeviceNr , bool bIsInterface )
{
2020-02-09 11:36:49 +00:00
static TCHAR pszDeviceName [ MAX_PATH ] ;
static BYTE bDeviceNr = 0 ;
static GUID gGUID ;
bool bReturn = true ;
2021-05-18 11:51:36 +00:00
LPCONTROLLER pController = NULL ; // Used when we're assigning things in the [Controller X] category
2020-02-09 11:36:49 +00:00
LPSHORTCUTS pShortcuts = NULL ;
2021-05-18 11:51:36 +00:00
unsigned int iLength = lstrlenA ( pszLine ) / 2 ; // 2 hex characters correspond to one byte; thus iLength represents the length of pszLine after converting to bytes
2020-02-09 11:36:49 +00:00
switch ( dwSection )
{
case CHK_CONTROLLER_1 :
if ( bIsInterface )
pController = & ( g_ivConfig - > Controllers [ 0 ] ) ;
else
pController = & ( g_pcControllers [ 0 ] ) ;
break ;
case CHK_CONTROLLER_2 :
if ( bIsInterface )
pController = & ( g_ivConfig - > Controllers [ 1 ] ) ;
else
pController = & ( g_pcControllers [ 1 ] ) ;
break ;
case CHK_CONTROLLER_3 :
if ( bIsInterface )
pController = & ( g_ivConfig - > Controllers [ 2 ] ) ;
else
pController = & ( g_pcControllers [ 2 ] ) ;
break ;
case CHK_CONTROLLER_4 :
if ( bIsInterface )
pController = & ( g_ivConfig - > Controllers [ 3 ] ) ;
else
pController = & ( g_pcControllers [ 3 ] ) ;
break ;
case CHK_SHORTCUTS :
if ( bIsInterface )
pShortcuts = & ( g_ivConfig - > Shortcuts ) ;
else
pShortcuts = & g_scShortcuts ;
break ;
}
switch ( dwKey )
{
case PL_RESET :
ZeroMemory ( pszDeviceName , sizeof ( pszDeviceName ) ) ;
gGUID = GUID_NULL ;
bDeviceNr = 0 ;
break ;
case CHK_LANGUAGE :
if ( dwSection = = CHK_GENERAL )
if ( bIsInterface )
g_ivConfig - > Language = atoi ( pszLine ) ;
else
g_strEmuInfo . Language = atoi ( pszLine ) ;
break ;
case CHK_SHOWMESSAGES :
if ( dwSection = = CHK_GENERAL )
if ( bIsInterface )
g_ivConfig - > fDisplayShortPop = ( atoi ( pszLine ) ! = 0 ) ;
else
g_strEmuInfo . fDisplayShortPop = ( atoi ( pszLine ) ! = 0 ) ;
break ;
case CHK_MEMPAK :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_MEMPAK ] , pszLine , MAX_PATH ) ;
else if ( dwSection = = CHK_FOLDERS )
CHAR_TO_TCHAR ( g_aszDefFolders [ BF_MEMPAK ] , pszLine , MAX_PATH ) ;
break ;
case CHK_GBXROM :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_GBROM ] , pszLine , MAX_PATH ) ;
else if ( dwSection = = CHK_FOLDERS )
CHAR_TO_TCHAR ( g_aszDefFolders [ BF_GBROM ] , pszLine , MAX_PATH ) ;
break ;
case CHK_GBXSAVE :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_GBSAVE ] , pszLine , MAX_PATH ) ;
else if ( dwSection = = CHK_FOLDERS )
CHAR_TO_TCHAR ( g_aszDefFolders [ BF_GBSAVE ] , pszLine , MAX_PATH ) ;
break ;
case CHK_PROFILE :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_PROFILE ] , pszLine , MAX_PATH ) ;
break ;
case CHK_NOTE :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_NOTE ] , pszLine , MAX_PATH ) ;
break ;
case CHK_SHORTCUTS :
if ( dwSection = = CHK_LASTBROWSERDIR )
CHAR_TO_TCHAR ( g_aszLastBrowse [ BF_SHORTCUTS ] , pszLine , MAX_PATH ) ;
break ;
case CHK_PLUGGED :
if ( pController )
pController - > fPlugged = atoi ( pszLine ) ;
break ;
case CHK_RAWDATA :
if ( pController )
pController - > fRawData = atoi ( pszLine ) ;
break ;
case CHK_XINPUT :
if ( pController )
pController - > fXInput = atoi ( pszLine ) ;
break ;
case CHK_N64MOUSE :
if ( pController )
pController - > fN64Mouse = atoi ( pszLine ) ;
break ;
case CHK_BACKGROUNDINPUT :
if ( pController )
pController - > bBackgroundInput = atoi ( pszLine ) ;
break ;
case CHK_PAKTYPE :
if ( pController )
pController - > PakType = atoi ( pszLine ) ;
break ;
case CHK_REALN64RANGE :
if ( pController )
pController - > fRealN64Range = atoi ( pszLine ) ;
break ;
case CHK_RAPIDFIREENABLED :
if ( pController )
pController - > bRapidFireEnabled = atoi ( pszLine ) ! = 0 ;
break ;
case CHK_RAPIDFIRERATE :
if ( pController )
pController - > bRapidFireRate = atoi ( pszLine ) ;
break ;
case CHK_STICKRANGE :
if ( pController )
pController - > bStickRange = atoi ( pszLine ) ;
break ;
case CHK_MOUSEMOVEX :
if ( pController )
pController - > bMouseMoveX = atoi ( pszLine ) ;
break ;
case CHK_MOUSEMOVEY :
if ( pController )
pController - > bMouseMoveY = atoi ( pszLine ) ;
break ;
case CHK_AXISSET :
if ( pController )
pController - > bAxisSet = atoi ( pszLine ) ;
break ;
case CHK_KEYABSOLUTEX :
if ( pController )
pController - > fKeyAbsoluteX = atoi ( pszLine ) ;
break ;
case CHK_KEYABSOLUTEY :
if ( pController )
pController - > fKeyAbsoluteY = atoi ( pszLine ) ;
break ;
case CHK_PADDEADZONE :
if ( pController )
pController - > bPadDeadZone = atoi ( pszLine ) ;
break ;
case CHK_MOUSESENSITIVITYX :
if ( pController )
pController - > wMouseSensitivityX = atoi ( pszLine ) ;
break ;
case CHK_MOUSESENSITIVITYY :
if ( pController )
pController - > wMouseSensitivityY = atoi ( pszLine ) ;
break ;
case CHK_RUMBLETYPE :
if ( pController )
pController - > bRumbleTyp = atoi ( pszLine ) ;
break ;
case CHK_RUMBLESTRENGTH :
if ( pController )
pController - > bRumbleStrength = atoi ( pszLine ) ;
break ;
case CHK_VISUALRUMBLE :
if ( pController )
pController - > fVisualRumble = atoi ( pszLine ) ;
break ;
case CHK_FFDEVICEGUID :
if ( pController )
{
bReturn = StringtoGUIDA ( & pController - > guidFFDevice , pszLine ) ;
if ( bIsInterface & & bReturn )
{
2021-05-18 11:51:36 +00:00
// For some reason, we use only device names and numbers inside the interface for force feedback device selection. So if we don't set those,
2020-02-09 11:36:49 +00:00
// FFDevice won't load properly.
int nDevice = FindDeviceinList ( pController - > guidFFDevice ) ;
if ( nDevice ! = - 1 & & pszFFDevice & & bFFDeviceNr )
{
_tcsncpy ( pszFFDevice , g_devList [ nDevice ] . szProductName , DEFAULT_BUFFER ) ;
* bFFDeviceNr = g_devList [ nDevice ] . bProductCounter ;
}
else
{
pController - > guidFFDevice = GUID_NULL ;
return false ;
}
}
else
return bReturn ;
}
break ;
case CHK_FFDEVICENAME :
if ( pController & & pszFFDevice )
{
2021-05-18 11:51:36 +00:00
CHAR_TO_TCHAR ( pszFFDevice , pszLine , MAX_PATH ) ; // Hack: pszLine is read from a file; could overflow easily. We guessed size of pszFFDevice buffer.
2020-02-09 11:36:49 +00:00
return true ;
}
break ;
case CHK_FFDEVICENR :
if ( pController & & bFFDeviceNr & & ( iLength > = sizeof ( BYTE ) ) )
{
* bFFDeviceNr = atoi ( pszLine ) ;
return true ;
}
break ;
case CHK_MEMPAKFILE :
if ( pController )
{
CHAR_TO_TCHAR ( pController - > szMempakFile , pszLine , MAX_PATH ) ;
}
break ;
case CHK_GBROMFILE :
if ( pController )
{
CHAR_TO_TCHAR ( pController - > szTransferRom , pszLine , MAX_PATH ) ;
}
break ;
case CHK_GBROMSAVE :
if ( pController )
{
CHAR_TO_TCHAR ( pController - > szTransferSave , pszLine , MAX_PATH ) ;
}
break ;
case CHK_DINPUTNAME :
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Invalidate current GUID
2020-02-09 11:36:49 +00:00
CHAR_TO_TCHAR ( pszDeviceName , pszLine , MAX_PATH ) ;
break ;
case CHK_DINPUTNR :
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Invalidate current GUID
2020-02-09 11:36:49 +00:00
if ( iLength > = sizeof ( BYTE ) )
{
TexttoHexA ( pszLine , & bDeviceNr , sizeof ( BYTE ) ) ;
}
break ;
case CHK_DINPUTGUID :
if ( StringtoGUIDA ( & gGUID , pszLine ) )
return true ;
else
{
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Invalidate current GUID
2020-02-09 11:36:49 +00:00
return false ;
}
break ;
case CHK_BUTTON :
if ( dwSection = = CHK_CONTROLS | | pShortcuts | | pController )
{
int controlnum = 0 , buttonID = 0 ;
BUTTON btnWorking ;
ZeroMemory ( & btnWorking , sizeof ( btnWorking ) ) ;
unsigned int tOffset , tAxisID , tBtnType ;
if ( sscanf ( pszLine , " %d %d %x %u %u " , & controlnum , & buttonID , & tOffset , & tAxisID , & tBtnType ) ! = 5 )
return false ;
2021-05-18 11:51:36 +00:00
// Done to overcome issues with sscanf and "small" data blocks
2020-02-09 11:36:49 +00:00
btnWorking . bOffset = tOffset ;
btnWorking . bAxisID = tAxisID ;
btnWorking . bBtnType = tBtnType ;
if ( pController )
{
2021-05-18 11:51:36 +00:00
// Special case: if we're in one of the categories CHK_CONTROLLER_n, assume we're processing a profile file.
// Ignore the read control number and use our input controller number.
controlnum = ( int ) ( dwSection - CHK_CONTROLLER_1 ) ; // Hack: Assume our hash reproduces these linearly
2020-02-09 11:36:49 +00:00
}
2021-05-18 11:51:36 +00:00
// Now we need to assign a parent device. If we have a valid gGUID, we'll use that
2020-02-09 11:36:49 +00:00
int found = FindDeviceinList ( gGUID ) ;
if ( found ! = - 1 )
btnWorking . parentDevice = & g_devList [ found ] ;
else
{
2021-05-18 11:51:36 +00:00
// Otherwise, we do the following in order:
// 1. If bBtnType is of type DT_MOUSEBUTTON or DT_MOUSEAXE, set gGUID to that of g_sysMouse (ignoring the given name and number)
2020-02-09 11:36:49 +00:00
if ( btnWorking . bBtnType = = DT_MOUSEBUTTON | | btnWorking . bBtnType = = DT_MOUSEAXE )
{
btnWorking . parentDevice = & g_sysMouse ;
}
2021-05-18 11:51:36 +00:00
// 2. If bBtnType is of type DT_KEYBUTTON, set gGUID to that of SysKeyboard
2020-02-09 11:36:49 +00:00
else if ( btnWorking . bBtnType = = DT_KEYBUTTON )
{
gGUID = GUID_SysKeyboard ;
found = FindDeviceinList ( gGUID ) ;
if ( found ! = - 1 )
btnWorking . parentDevice = & g_devList [ found ] ;
else
btnWorking . parentDevice = NULL ;
}
2021-05-18 11:51:36 +00:00
// 3. Otherwise, look up the name and number using FindDeviceinList, and set gGUID to that
2020-02-09 11:36:49 +00:00
else
{
found = FindDeviceinList ( pszDeviceName , bDeviceNr , true ) ;
if ( found ! = - 1 )
{
gGUID = g_devList [ found ] . guidInstance ;
btnWorking . parentDevice = & g_devList [ found ] ;
}
else
{
DebugWrite ( _T ( " ProcessKey: couldn't find a device in g_devList for %s %d \n " ) , pszDeviceName , bDeviceNr ) ;
gGUID = GUID_NULL ;
btnWorking . parentDevice = NULL ;
return false ;
}
}
}
if ( pShortcuts )
{
2021-05-18 11:51:36 +00:00
// Bounds check on control number and buttonID
2020-02-09 11:36:49 +00:00
if ( ( controlnum = = - 1 & & buttonID ! = 0 ) & & ( ( controlnum < 0 ) | | ( controlnum > 3 ) | | ( buttonID < 0 ) | | ( buttonID > = SC_TOTAL ) ) )
{
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Since we may have cached an invalid GUID, invalidate it
2020-02-09 11:36:49 +00:00
return false ;
}
// Copy the completed button to the correct shortcut
if ( bIsInterface )
if ( controlnum = = - 1 )
g_ivConfig - > Shortcuts . bMouseLock = btnWorking ;
else
g_ivConfig - > Shortcuts . Player [ controlnum ] . aButtons [ buttonID ] = btnWorking ;
else // if (!bIsInterface)
if ( controlnum = = - 1 )
g_scShortcuts . bMouseLock = btnWorking ;
else
g_scShortcuts . Player [ controlnum ] . aButtons [ buttonID ] = btnWorking ;
}
2021-05-18 11:51:36 +00:00
else // It's a controller button
2020-02-09 11:36:49 +00:00
{
2021-05-18 11:51:36 +00:00
// Bounds check on control number and buttonID
2020-02-09 11:36:49 +00:00
if ( ( controlnum < 0 ) | | ( controlnum > 3 ) | | ( buttonID < 0 ) | | ( buttonID > = ARRAYSIZE ( g_pcControllers [ 0 ] . aButton ) ) )
{
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Since we may have cached an invalid GUID, invalidate it
2020-02-09 11:36:49 +00:00
return false ;
}
// Copy the completed button to the correct controller and buttonID
if ( bIsInterface )
g_ivConfig - > Controllers [ controlnum ] . aButton [ buttonID ] = btnWorking ;
else
g_pcControllers [ controlnum ] . aButton [ buttonID ] = btnWorking ;
}
}
break ;
case CHK_MODIFIER :
// Modifiers format: controlnum bOffset bAxisID bBtnType bModType fToggle fStatus dwSpecific
if ( dwSection = = CHK_MODIFIERS | | pController )
{
int controlnum = 0 ;
MODIFIER modWorking ;
ZeroMemory ( & modWorking , sizeof ( modWorking ) ) ;
unsigned int tOffset , tAxisID , tBtnType , tModType , tToggle , tStatus , tSpecific ;
if ( sscanf ( pszLine , " %u %x %u %u %u %u %u %x " , & controlnum , & tOffset , & tAxisID ,
& tBtnType , & tModType , & tToggle , & tStatus , & tSpecific ) ! = 8 )
return false ;
2021-05-18 11:51:36 +00:00
// Done to overcome issues with sscanf and "small" data blocks
2020-02-09 11:36:49 +00:00
modWorking . btnButton . bOffset = tOffset ;
modWorking . btnButton . bAxisID = tAxisID ;
modWorking . btnButton . bBtnType = tBtnType ;
modWorking . bModType = tModType ;
modWorking . fToggle = tToggle ;
modWorking . fStatus = tStatus ;
2021-05-18 11:51:36 +00:00
modWorking . dwSpecific = tSpecific ; // Looks stupid, but unsigned int might not always be DWORD32
2020-02-09 11:36:49 +00:00
2021-05-18 11:51:36 +00:00
// Now we need to assign a parent device. If we have a valid gGUID, we'll use that
2020-02-09 11:36:49 +00:00
int found = FindDeviceinList ( gGUID ) ;
if ( found ! = - 1 )
modWorking . btnButton . parentDevice = & g_devList [ found ] ;
else
{
2021-05-18 11:51:36 +00:00
// Otherwise, we do the following in order:
// 1. If bBtnType is of type DT_MOUSEBUTTON or DT_MOUSEAXE, set gGUID to that of g_sysMouse (ignoring the given name and number)
2020-02-09 11:36:49 +00:00
if ( modWorking . btnButton . bBtnType = = DT_MOUSEBUTTON | | modWorking . btnButton . bBtnType = = DT_MOUSEAXE )
{
modWorking . btnButton . parentDevice = & g_sysMouse ;
}
2021-05-18 11:51:36 +00:00
// 2. If bBtnType is of type DT_KEYBUTTON, set gGUID to that of SysKeyboard
2020-02-09 11:36:49 +00:00
else if ( modWorking . btnButton . bBtnType = = DT_KEYBUTTON )
{
gGUID = GUID_SysKeyboard ;
int found = FindDeviceinList ( gGUID ) ;
if ( found ! = - 1 )
modWorking . btnButton . parentDevice = & g_devList [ found ] ;
else
modWorking . btnButton . parentDevice = NULL ;
}
2021-05-18 11:51:36 +00:00
// 3. Otherwise, look up the name and number using FindDeviceinList, and set gGUID to that
2020-02-09 11:36:49 +00:00
else
{
found = FindDeviceinList ( pszDeviceName , bDeviceNr , true ) ;
if ( found ! = - 1 )
{
gGUID = g_devList [ found ] . guidInstance ;
modWorking . btnButton . parentDevice = & g_devList [ found ] ;
}
else
{
DebugWrite ( _T ( " ProcessKey: couldn't find a device in g_devList for %s %d \n " ) , pszDeviceName , bDeviceNr ) ;
gGUID = GUID_NULL ;
modWorking . btnButton . parentDevice = NULL ;
return false ;
}
}
}
2021-05-18 11:51:36 +00:00
// Bounds check on control number and buttonID
2020-02-09 11:36:49 +00:00
if ( ( controlnum < 0 ) | | ( controlnum > 3 ) )
{
2021-05-18 11:51:36 +00:00
gGUID = GUID_NULL ; // Since we may have cached an invalid GUID, invalidate it
2020-02-09 11:36:49 +00:00
return false ;
}
// Allocate and add the completed modifier
if ( bIsInterface )
{
if ( g_ivConfig - > Controllers [ controlnum ] . nModifiers > 0 )
{
g_ivConfig - > Controllers [ controlnum ] . pModifiers = ( LPMODIFIER ) P_realloc ( g_ivConfig - > Controllers [ controlnum ] . pModifiers , ( g_ivConfig - > Controllers [ controlnum ] . nModifiers + 1 ) * sizeof ( MODIFIER ) ) ;
}
else
{
g_ivConfig - > Controllers [ controlnum ] . pModifiers = ( LPMODIFIER ) P_malloc ( sizeof ( MODIFIER ) ) ;
}
g_ivConfig - > Controllers [ controlnum ] . pModifiers [ g_ivConfig - > Controllers [ controlnum ] . nModifiers ] = modWorking ;
( g_ivConfig - > Controllers [ controlnum ] . nModifiers ) + + ;
}
else
{
if ( g_pcControllers [ controlnum ] . nModifiers > 0 )
{
g_pcControllers [ controlnum ] . pModifiers = ( LPMODIFIER ) P_realloc ( g_pcControllers [ controlnum ] . pModifiers , ( g_pcControllers [ controlnum ] . nModifiers + 1 ) * sizeof ( MODIFIER ) ) ;
}
else
{
g_pcControllers [ controlnum ] . pModifiers = ( LPMODIFIER ) P_malloc ( sizeof ( MODIFIER ) ) ;
}
g_pcControllers [ controlnum ] . pModifiers [ g_pcControllers [ controlnum ] . nModifiers ] = modWorking ;
( g_pcControllers [ controlnum ] . nModifiers ) + + ;
}
}
break ;
}
return bReturn ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Load the default profile from the raw "resource" data (i.e. the built-in defaults contained in the DLL)
2016-01-27 09:11:59 +00:00
bool LoadProfileFromResource ( LPCTSTR pszResource , int iController , bool bIsInterface )
{
2020-02-09 11:36:49 +00:00
const DWORD dwControllerSect [ ] = { CHK_CONTROLLER_1 , CHK_CONTROLLER_2 , CHK_CONTROLLER_3 , CHK_CONTROLLER_4 } ;
if ( iController > 3 | | iController < 0 )
return false ;
HRSRC res = FindResource ( g_strEmuInfo . hinst , pszResource , _T ( " PROFILE " ) ) ;
if ( res = = NULL )
return false ;
char * profile = ( char * ) LockResource ( LoadResource ( g_strEmuInfo . hinst , res ) ) ;
char * profileend = profile + SizeofResource ( g_strEmuInfo . hinst , res ) ;
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , bIsInterface ) ;
DWORD dwCommand = PL_NOHIT ;
char szLine [ 4096 ] ;
while ( profile < profileend )
{
while ( profile < profileend & & ( CHECK_WHITESPACES ( * profile ) | | * profile = = ' ' ) )
+ + profile ;
int i = 0 ;
while ( profile < profileend & & i < sizeof ( szLine ) - 1 & & ! ( CHECK_WHITESPACES ( * profile ) ) )
szLine [ i + + ] = * profile + + ;
szLine [ i ] = ' \0 ' ;
dwCommand = ParseLine ( szLine ) ;
2021-05-18 11:51:36 +00:00
ProcessKey ( dwCommand , dwControllerSect [ iController ] , szLine , 0 , 0 , bIsInterface ) ; // Resource will not contain a force feedback device
2020-02-09 11:36:49 +00:00
}
return true ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// See overloaded function above
2016-01-27 09:11:59 +00:00
bool LoadProfileFromResource ( int indexController , bool bIsInterface )
{
2020-02-09 11:36:49 +00:00
const int resIds [ ] = { IDR_PROFILE_DEFAULT1 , IDR_PROFILE_DEFAULT2 , IDR_PROFILE_DEFAULT3 , IDR_PROFILE_DEFAULT4 } ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
TCHAR szId [ 20 ] ;
wsprintf ( szId , _T ( " #%i " ) , resIds [ indexController ] ) ;
return LoadProfileFromResource ( szId , indexController , bIsInterface ) ;
2016-01-27 09:11:59 +00:00
}
// Load a controller profile from a saved configuration file
2021-05-18 11:51:36 +00:00
// Need to incorporate type (keyboard/mouse/controller), GUID for controller, and bOffset
2016-01-27 09:11:59 +00:00
bool LoadProfileFile ( const TCHAR * pszFileName , int iController , TCHAR * pszFFDevice , BYTE * bFFDeviceNr )
{
2020-02-09 11:36:49 +00:00
const DWORD dwControllerSect [ ] = { CHK_CONTROLLER_1 , CHK_CONTROLLER_2 , CHK_CONTROLLER_3 , CHK_CONTROLLER_4 } ;
FILE * proFile = NULL ;
char szLine [ 4096 ] ;
int iVersion = 0 ;
if ( ( proFile = _tfopen ( pszFileName , _T ( " rS " ) ) ) = = NULL )
return false ;
2021-05-18 11:51:36 +00:00
// Test if right version
2020-02-09 11:36:49 +00:00
while ( ! iVersion & & ( fgets ( szLine , sizeof ( szLine ) - 1 , proFile ) ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
if ( ParseLine ( szLine ) = = PL_VERSIONSTRING )
iVersion = ( int ) ( atof ( szLine ) * 100 ) ;
}
2021-05-18 11:51:36 +00:00
if ( iVersion ! = 220 ) // TODO: Hack: this should probably not be a hardcoded value
2020-02-09 11:36:49 +00:00
{
fclose ( proFile ) ;
return false ;
}
SetControllerDefaults ( & ( g_ivConfig - > Controllers [ iController ] ) ) ;
pszFFDevice [ 0 ] = pszFFDevice [ 1 ] = ' \0 ' ;
* bFFDeviceNr = 0 ;
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , true ) ;
DWORD dwCommand = PL_NOHIT ;
while ( fgets ( szLine , sizeof ( szLine ) - 1 , proFile ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
dwCommand = ParseLine ( szLine ) ;
ProcessKey ( dwCommand , dwControllerSect [ iController ] , szLine , pszFFDevice , bFFDeviceNr , true ) ;
}
fclose ( proFile ) ;
return true ;
2016-01-27 09:11:59 +00:00
}
// Load a controller profile from a saved configuration file
2021-05-18 11:51:36 +00:00
// Need to incorporate type (keyboard/mouse/controller), GUID for controller, and bOffset
2016-01-27 09:11:59 +00:00
bool LoadShortcutsFile ( const TCHAR * pszFileName )
{
2020-02-09 11:36:49 +00:00
FILE * fShortsFile = NULL ;
char szLine [ 4096 ] ;
int iVersion = 0 ;
if ( ( fShortsFile = _tfopen ( pszFileName , _T ( " rS " ) ) ) = = NULL )
return false ;
2021-05-18 11:51:36 +00:00
// Test if right version
2020-02-09 11:36:49 +00:00
while ( ! iVersion & & ( fgets ( szLine , sizeof ( szLine ) - 1 , fShortsFile ) ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
if ( ParseLine ( szLine ) = = PL_VERSIONSTRING )
iVersion = ( int ) ( atof ( szLine ) * 100 ) ;
}
2021-05-18 11:51:36 +00:00
if ( iVersion ! = 220 ) // Hack: this should probably not be a hardcoded value
2020-02-09 11:36:49 +00:00
{
fclose ( fShortsFile ) ;
return false ;
}
ZeroMemory ( & ( g_ivConfig - > Shortcuts ) , sizeof ( SHORTCUTS ) ) ;
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , true ) ;
DWORD dwCommand = PL_NOHIT ;
while ( fgets ( szLine , sizeof ( szLine ) - 1 , fShortsFile ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
dwCommand = ParseLine ( szLine ) ;
ProcessKey ( dwCommand , CHK_SHORTCUTS , szLine , 0 , 0 , true ) ;
}
fclose ( fShortsFile ) ;
return true ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Serializes the profile for the current controller for saving to a file
// Called in one place, from within Interface.cpp, ControllerTabProc (when you click "Save Profile")
2016-01-27 09:11:59 +00:00
void FormatProfileBlock ( FILE * fFile , const int i )
{
2020-02-09 11:36:49 +00:00
DumpControllerSettings ( fFile , i , false ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
string strMouse ;
string strDevs [ MAX_DEVICES ] ;
string strNull ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
FormatControlsBlock ( & strMouse , strDevs , & strNull , i ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DumpStreams ( fFile , strMouse , strDevs , strNull , false ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
strMouse . clear ( ) ;
for ( int j = 0 ; j < g_nDevices ; j + + )
strDevs [ j ] . clear ( ) ;
strNull . clear ( ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
FormatModifiersBlock ( & strMouse , strDevs , & strNull , i ) ;
2016-01-27 09:11:59 +00:00
2020-02-09 11:36:49 +00:00
DumpStreams ( fFile , strMouse , strDevs , strNull , false ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Same as FormatProfileBlock, but saves shortcuts instead
2016-01-27 09:11:59 +00:00
void FormatShortcutsBlock ( FILE * fFile , bool bIsINI )
{
2020-02-09 11:36:49 +00:00
// I'm going to use STL strings here because I don't want to screw with buffer management
string strMouse ;
string strDevs [ MAX_DEVICES ] ;
string strNull ;
for ( int i = 0 ; i < 4 ; i + + ) // Player for
{
for ( int j = 0 ; j < SC_TOTAL ; j + + ) // aButtons for
{
2021-05-18 11:51:36 +00:00
if ( g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . parentDevice ) // Possibly unbound
2020-02-09 11:36:49 +00:00
{
if ( IsEqualGUID ( g_sysMouse . guidInstance , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , i , j , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bOffset , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bAxisID , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bBtnType ) ;
strMouse . append ( szBuf ) ;
}
else
for ( int match = 0 ; match < g_nDevices ; match + + )
if ( IsEqualGUID ( g_devList [ match ] . guidInstance , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the appropriate device stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , i , j , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bOffset , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bAxisID , g_ivConfig - > Shortcuts . Player [ i ] . aButtons [ j ] . bBtnType ) ;
strDevs [ match ] . append ( szBuf ) ;
break ;
}
}
} // end buttons for
2021-05-18 11:51:36 +00:00
} // end player for
2020-02-09 11:36:49 +00:00
2021-05-18 11:51:36 +00:00
// We have to do it again for that one pesky mouse lock button
if ( g_ivConfig - > Shortcuts . bMouseLock . parentDevice ) // Possibly unbound
2020-02-09 11:36:49 +00:00
{
if ( IsEqualGUID ( g_sysMouse . guidInstance , g_ivConfig - > Shortcuts . bMouseLock . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , - 1 , 0 , g_ivConfig - > Shortcuts . bMouseLock . bOffset , g_ivConfig - > Shortcuts . bMouseLock . bAxisID , g_ivConfig - > Shortcuts . bMouseLock . bBtnType ) ;
strMouse . append ( szBuf ) ;
}
else
for ( int match = 0 ; match < g_nDevices ; match + + )
if ( IsEqualGUID ( g_devList [ match ] . guidInstance , g_ivConfig - > Shortcuts . bMouseLock . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the appropriate device stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , - 1 , 0 , g_ivConfig - > Shortcuts . bMouseLock . bOffset , g_ivConfig - > Shortcuts . bMouseLock . bAxisID , g_ivConfig - > Shortcuts . bMouseLock . bBtnType ) ;
strDevs [ match ] . append ( szBuf ) ;
break ;
}
} // end shortcuts edge case
DumpStreams ( fFile , strMouse , strDevs , strNull , bIsINI ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Load shortcuts from "resources", i.e. built-in defaults
2016-01-27 09:11:59 +00:00
bool LoadShortcutsFromResource ( bool bIsInterface )
{
2020-02-09 11:36:49 +00:00
if ( bIsInterface )
ZeroMemory ( & ( g_ivConfig - > Shortcuts ) , sizeof ( SHORTCUTS ) ) ;
TCHAR szId [ 20 ] ;
wsprintf ( szId , _T ( " #%i " ) , IDR_SHORTCUTS_DEFAULT ) ;
HRSRC res = FindResource ( g_strEmuInfo . hinst , szId , _T ( " SHORTCUT " ) ) ;
if ( res = = NULL )
return false ;
char * profile = ( char * ) LockResource ( LoadResource ( g_strEmuInfo . hinst , res ) ) ;
char * profileend = profile + SizeofResource ( g_strEmuInfo . hinst , res ) ;
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , bIsInterface ) ;
DWORD dwCommand = PL_NOHIT ;
char szLine [ 4096 ] ;
while ( profile < profileend )
{
while ( profile < profileend & & ( CHECK_WHITESPACES ( * profile ) | | * profile = = ' ' ) )
+ + profile ;
int i = 0 ;
while ( profile < profileend & & i < sizeof ( szLine ) - 1 & & ! ( CHECK_WHITESPACES ( * profile ) ) )
szLine [ i + + ] = * profile + + ;
szLine [ i ] = ' \0 ' ;
dwCommand = ParseLine ( szLine ) ;
ProcessKey ( dwCommand , CHK_SHORTCUTS , szLine , 0 , 0 , bIsInterface ) ;
}
return true ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Returns the user-chosen default directory (path) for each of the following:
// Application directory, memory pak directory, Game Boy ROM directory, Game Boy ROM save directory
// Tries to query user settings; if blank or invalid, returns their defaults
2016-01-27 09:11:59 +00:00
// Massages the output directory a bit
bool GetDirectory ( LPTSTR pszDirectory , WORD wDirID )
{
2020-02-09 11:36:49 +00:00
bool bReturn = true ;
TCHAR szBuffer [ MAX_PATH + 1 ] ;
const TCHAR szDefaultStrings [ 3 ] [ DEFAULT_BUFFER ] = { STRING_DEF_MEMPAKFILE , STRING_DEF_GBROMFILE , STRING_DEF_GBROMSAVE } ;
TCHAR * pSlash ;
pszDirectory [ 0 ] = pszDirectory [ 1 ] = ' \0 ' ;
switch ( wDirID )
{
case DIRECTORY_MEMPAK :
case DIRECTORY_GBROMS :
case DIRECTORY_GBSAVES :
if ( g_aszDefFolders [ wDirID ] [ 0 ] = = 0 )
lstrcpyn ( pszDirectory , szDefaultStrings [ wDirID ] , MAX_PATH ) ;
else
lstrcpyn ( pszDirectory , g_aszDefFolders [ wDirID ] , MAX_PATH ) ;
break ;
case DIRECTORY_DLL :
if ( GetModuleFileName ( g_strEmuInfo . hinst , szBuffer , MAX_PATH ) )
{
GetFullPathName ( szBuffer , MAX_PATH , pszDirectory , & pSlash ) ;
* pSlash = 0 ;
}
break ;
case DIRECTORY_LOG :
case DIRECTORY_CONFIG :
case DIRECTORY_APPLICATION :
break ;
default :
2021-05-18 11:51:36 +00:00
// We don't know what you're talking about, set pszFileName to current .exe directory
2020-02-09 11:36:49 +00:00
// and return false
bReturn = false ;
}
2021-05-18 11:51:36 +00:00
if ( pszDirectory [ 1 ] = = ' : ' | | ( pszDirectory [ 1 ] = = ' \\ ' & & pszDirectory [ 0 ] = = ' \\ ' ) ) // Absolute path( x: or \\ )
2020-02-09 11:36:49 +00:00
lstrcpyn ( szBuffer , pszDirectory , MAX_PATH ) ;
else
{
GetModuleFileName ( NULL , szBuffer , MAX_PATH ) ;
pSlash = _tcsrchr ( szBuffer , ' \\ ' ) ;
+ + pSlash ;
lstrcpyn ( pSlash , pszDirectory , MAX_PATH ) ;
}
GetFullPathName ( szBuffer , MAX_PATH , pszDirectory , & pSlash ) ;
pSlash = & pszDirectory [ lstrlen ( pszDirectory ) - 1 ] ;
if ( * pSlash ! = ' \\ ' )
{
pSlash [ 1 ] = ' \\ ' ;
pSlash [ 2 ] = ' \0 ' ;
}
if ( bReturn & & wDirID = = DIRECTORY_CONFIG )
{
2020-06-09 13:04:38 +00:00
wcscat ( pszDirectory , L " Config \\ " ) ;
2020-02-09 11:36:49 +00:00
}
if ( bReturn & & wDirID = = DIRECTORY_LOG )
{
2020-06-09 13:04:38 +00:00
wcscat ( pszDirectory , L " Logs \\ " ) ;
2020-02-09 11:36:49 +00:00
}
return bReturn ;
2016-01-27 09:11:59 +00:00
}
// Attempts to store the "absolute" filename for a file;
2021-05-18 11:51:36 +00:00
// if szFileName is an absolute filename (starting with a letter and colon or two backslashes) it is simply copied
// Otherwise, it is concatenated with the known directory, such as memory pak directory (type given by wDirID)
2016-01-27 09:11:59 +00:00
void GetAbsoluteFileName ( TCHAR * szAbsolute , const TCHAR * szFileName , const WORD wDirID )
{
2020-02-09 11:36:49 +00:00
if ( szFileName [ 1 ] = = ' : ' | | ( szFileName [ 1 ] = = ' \\ ' & & szFileName [ 0 ] = = ' \\ ' ) )
lstrcpyn ( szAbsolute , szFileName , MAX_PATH ) ;
else
{
GetDirectory ( szAbsolute , wDirID ) ;
2021-05-18 11:51:36 +00:00
lstrcat ( szAbsolute , szFileName ) ; // Hack: possible buffer overflow
2020-02-09 11:36:49 +00:00
}
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Populates the list of memory pak/transfer pak files from the configured directory
2016-01-27 09:11:59 +00:00
BOOL SendFilestoList ( HWND hDlgItem , WORD wType )
{
2020-02-09 11:36:49 +00:00
HANDLE hFindFile ;
WIN32_FIND_DATA FindFile ;
TCHAR szPattern [ MAX_PATH + 10 ] ;
TCHAR * pszExtensions ;
BOOL Success ;
switch ( wType )
{
case FILIST_MEM :
GetDirectory ( szPattern , DIRECTORY_MEMPAK ) ;
lstrcat ( szPattern , _T ( " *.* " ) ) ;
pszExtensions = _T ( " .mpk \0 .n64 \0 " ) ;
break ;
case FILIST_TRANSFER :
GetDirectory ( szPattern , DIRECTORY_GBROMS ) ;
lstrcat ( szPattern , _T ( " *.gb? " ) ) ;
pszExtensions = _T ( " .gb \0 .gbc \0 " ) ;
break ;
default :
return FALSE ;
}
TCHAR * pcPoint ;
TCHAR * pszExt ;
bool bValidFile ;
hFindFile = FindFirstFile ( szPattern , & FindFile ) ;
if ( hFindFile ! = INVALID_HANDLE_VALUE )
{
do
{
pszExt = pszExtensions ;
pcPoint = _tcsrchr ( FindFile . cFileName , _T ( ' . ' ) ) ;
bValidFile = false ;
do
{
if ( ! lstrcmpi ( pcPoint , pszExt ) )
bValidFile = true ;
pszExt + = lstrlen ( pszExt ) + 1 ;
}
while ( * pszExt & & ! bValidFile ) ;
if ( bValidFile )
SendMessage ( hDlgItem , LB_ADDSTRING , 0 , ( LPARAM ) FindFile . cFileName ) ;
}
while ( FindNextFile ( hFindFile , & FindFile ) ) ;
FindClose ( hFindFile ) ;
Success = TRUE ;
}
else
Success = FALSE ;
return Success ;
2016-01-27 09:11:59 +00:00
}
bool BrowseFolders ( HWND hwndParent , TCHAR * pszHeader , TCHAR * pszDirectory )
{
2020-02-09 11:36:49 +00:00
ITEMIDLIST * piStart = NULL ;
if ( pszDirectory [ 0 ] ! = ' \0 ' )
{
IShellFolder * pDesktopFolder ;
if ( SUCCEEDED ( SHGetDesktopFolder ( & pDesktopFolder ) ) )
{
OLECHAR olePath [ MAX_PATH ] ;
ULONG chEaten ;
pDesktopFolder - > ParseDisplayName ( NULL , NULL , olePath , & chEaten , & piStart , NULL ) ;
pDesktopFolder - > Release ( ) ;
}
}
BROWSEINFO brInfo ;
brInfo . hwndOwner = hwndParent ;
brInfo . pidlRoot = piStart ;
brInfo . pszDisplayName = pszDirectory ;
brInfo . lpszTitle = pszHeader ;
brInfo . ulFlags = BIF_RETURNONLYFSDIRS ;
brInfo . lpfn = NULL ;
ITEMIDLIST * piList ;
piList = SHBrowseForFolder ( & brInfo ) ;
if ( piList )
{
SHGetPathFromIDList ( ( const LPITEMIDLIST ) piList , pszDirectory ) ;
LPMALLOC pMal ;
if ( SUCCEEDED ( SHGetMalloc ( & pMal ) ) )
{
pMal - > Free ( piList ) ;
pMal - > Release ( ) ;
}
return true ;
}
return false ;
2016-01-27 09:11:59 +00:00
}
bool GetInitialBrowseDir ( TCHAR * pszFileName , DWORD dwType )
{
2020-02-09 11:36:49 +00:00
// DIRECTORY_INVALID means there's no corresponding entry in g_aszDefFolders
const WORD wDirectory [ ] = { DIRECTORY_MEMPAK , DIRECTORY_GBROMS , DIRECTORY_GBSAVES ,
DIRECTORY_INVALID , DIRECTORY_INVALID , DIRECTORY_INVALID } ;
switch ( dwType )
{
case BF_PROFILE :
case BF_MEMPAK :
case BF_NOTE :
case BF_GBROM :
case BF_GBSAVE :
case BF_SHORTCUTS :
if ( g_aszLastBrowse [ dwType ] [ 0 ] = = 0 )
return GetDirectory ( pszFileName , wDirectory [ dwType ] ) ;
else
lstrcpyn ( pszFileName , g_aszLastBrowse [ dwType ] , MAX_PATH ) ;
return true ;
2021-05-18 11:51:36 +00:00
default : // We don't know what you're talking about
2020-02-09 11:36:49 +00:00
return GetDirectory ( pszFileName , DIRECTORY_INVALID ) ;
}
2016-01-27 09:11:59 +00:00
}
bool SaveLastBrowseDir ( TCHAR * pszFileName , DWORD dwType )
{
2020-02-09 11:36:49 +00:00
TCHAR * cSlash = _tcsrchr ( pszFileName , _T ( ' \\ ' ) ) ;
if ( cSlash )
{
switch ( dwType )
{
case BF_PROFILE :
case BF_MEMPAK :
case BF_NOTE :
case BF_GBROM :
case BF_GBSAVE :
case BF_SHORTCUTS :
* cSlash = ' \0 ' ;
lstrcpyn ( g_aszLastBrowse [ dwType ] , pszFileName , MAX_PATH ) ;
* cSlash = ' \\ ' ;
return true ;
default :
return false ;
}
}
else
return true ;
2016-01-27 09:11:59 +00:00
}
// Pop up a dialog asking for a filename from the user. Returns true if returning a valid filename, false if user cancelled.
// Used when either loading (fSave == false) or saving (fSave == true) some type of file.
// Handy, because it handles all our file type extensions for us.
bool BrowseFile ( HWND hDlg , TCHAR * pszFileName , DWORD dwType , bool fSave )
{
2020-06-10 01:48:41 +00:00
TCHAR pszFilter [ DEFAULT_BUFFER ] = { 0 } ;
TCHAR pszTitle [ DEFAULT_BUFFER ] = { 0 } ;
2020-02-09 11:36:49 +00:00
DWORD dwFlags = /*OFN_DONTADDTORECENT |*/ OFN_NOCHANGEDIR ;
dwFlags | = ( fSave ) ? OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT
: OFN_HIDEREADONLY | OFN_FILEMUSTEXIST ;
TCHAR * pszExt = NULL ;
TCHAR * pszTemp = pszFilter ;
int nFilters = 0 ;
switch ( dwType )
{
case BF_PROFILE :
LoadString ( g_hResourceDLL , IDS_DLG_CPF , pszFilter , DEFAULT_BUFFER ) ;
pszExt = _T ( " cpf " ) ;
nFilters = 1 ;
break ;
case BF_MEMPAK :
LoadString ( g_hResourceDLL , IDS_DLG_MPKN64 , pszFilter , DEFAULT_BUFFER ) ;
if ( ! fSave )
{
LoadString ( g_hResourceDLL , IDS_DLG_MPCHOOSE , pszTitle , DEFAULT_BUFFER ) ;
dwFlags = OFN_HIDEREADONLY ;
}
pszExt = _T ( " mpk " ) ;
nFilters = 2 ;
break ;
case BF_NOTE :
LoadString ( g_hResourceDLL , IDS_DLG_A64 , pszFilter , DEFAULT_BUFFER ) ;
pszExt = _T ( " a64 " ) ;
nFilters = 1 ;
break ;
case BF_GBROM :
LoadString ( g_hResourceDLL , IDS_DLG_GBGBC , pszFilter , DEFAULT_BUFFER ) ;
pszExt = _T ( " gb " ) ;
nFilters = 1 ;
break ;
case BF_GBSAVE :
LoadString ( g_hResourceDLL , IDS_DLG_SVSAV , pszFilter , DEFAULT_BUFFER ) ;
pszExt = _T ( " sv " ) ;
nFilters = 1 ;
break ;
case BF_SHORTCUTS :
LoadString ( g_hResourceDLL , IDS_DLG_SC , pszFilter , DEFAULT_BUFFER ) ;
pszExt = _T ( " sc " ) ;
nFilters = 1 ;
break ;
default :
return false ;
}
for ( ; nFilters > 0 ; nFilters - - )
{
pszTemp + = _tcslen ( pszTemp ) ;
pszTemp + = 1 ;
pszTemp + = _tcslen ( pszTemp ) ;
pszTemp + = 1 ;
}
* pszTemp = _T ( ' \0 ' ) ;
dwFlags | = OFN_NOCHANGEDIR ;
TCHAR szFileName [ MAX_PATH + 1 ] = _T ( " " ) ,
szInitialDir [ MAX_PATH + 1 ] = _T ( " " ) ,
* pcSlash ;
if ( pszFileName [ 1 ] = = _T ( ' : ' ) | | ( pszFileName [ 1 ] = = _T ( ' \\ ' ) & & pszFileName [ 0 ] = = _T ( ' \\ ' ) ) )
{
lstrcpyn ( szInitialDir , pszFileName , ARRAYSIZE ( szInitialDir ) ) ;
pcSlash = _tcsrchr ( szInitialDir , _T ( ' \\ ' ) ) ;
if ( pcSlash )
{
* pcSlash = _T ( ' \0 ' ) ;
lstrcpyn ( szFileName , & pcSlash [ 1 ] , ARRAYSIZE ( szFileName ) ) ;
}
}
else
{
if ( ! GetInitialBrowseDir ( szInitialDir , dwType ) )
GetDirectory ( szInitialDir , DIRECTORY_APPLICATION ) ;
lstrcpyn ( szFileName , pszFileName , ARRAYSIZE ( szFileName ) ) ;
}
OPENFILENAME oFile ;
oFile . lStructSize = sizeof ( OPENFILENAME ) ;
oFile . hwndOwner = hDlg ;
oFile . hInstance = NULL ;
oFile . lpstrFilter = pszFilter ;
oFile . lpstrCustomFilter = NULL ;
oFile . nMaxCustFilter = 0 ;
oFile . nFilterIndex = 0 ;
oFile . lpstrFile = szFileName ;
oFile . nMaxFile = MAX_PATH ;
oFile . lpstrFileTitle = NULL ;
2021-05-18 11:51:36 +00:00
oFile . nMaxFileTitle = MAX_PATH ; // Ignored
2020-02-09 11:36:49 +00:00
oFile . lpstrInitialDir = szInitialDir ;
oFile . lpstrTitle = pszTitle ;
oFile . Flags = dwFlags ;
oFile . nFileOffset = 0 ;
oFile . nFileExtension = 0 ;
oFile . lpstrDefExt = pszExt ;
oFile . lCustData = 0L ;
oFile . lpfnHook = NULL ;
oFile . lpTemplateName = NULL ;
if ( fSave )
{
if ( ! GetSaveFileName ( & oFile ) )
return false ;
}
else
{
if ( ! GetOpenFileName ( & oFile ) )
return false ;
}
lstrcpy ( pszFileName , szFileName ) ;
SaveLastBrowseDir ( szFileName , dwType ) ;
return true ;
2016-01-27 09:11:59 +00:00
}
bool ReadMemPakFile ( TCHAR * pszMemPakFile , BYTE * aMemPak , bool fCreate )
{
2020-02-09 11:36:49 +00:00
DWORD dwCreationDisposition = fCreate ? OPEN_ALWAYS : OPEN_EXISTING ;
HANDLE hFile = CreateFile ( pszMemPakFile , GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , dwCreationDisposition , 0 , NULL ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
{
ZeroMemory ( aMemPak , PAK_MEM_SIZE ) ;
TCHAR * pcPoint = _tcsrchr ( pszMemPakFile , ' . ' ) ;
if ( ! lstrcmpi ( pcPoint , _T ( " .n64 " ) ) )
SetFilePointer ( hFile , 0x1040 , NULL , FILE_BEGIN ) ;
else
SetFilePointer ( hFile , 0L , NULL , FILE_BEGIN ) ;
DWORD dwBytesRead ;
bool Success = ( ReadFile ( hFile , aMemPak , PAK_MEM_SIZE , & dwBytesRead , NULL ) ! = 0 ) ;
CloseHandle ( hFile ) ;
return Success ;
}
else
ErrorMessage ( IDS_ERR_MPREAD , GetLastError ( ) , false ) ;
return false ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Used by interface to create or modify memory pak files (not mapped).
// pszMemPakFile is a filename, aMemPak is the data, fCreate tells whether or not to create a new file
2016-01-27 09:11:59 +00:00
bool WriteMemPakFile ( TCHAR * pszMemPakFile , BYTE * aMemPak , bool fCreate )
{
2020-02-09 11:36:49 +00:00
DWORD dwCreationDisposition = fCreate ? OPEN_ALWAYS : OPEN_EXISTING ;
HANDLE hFile = CreateFile ( pszMemPakFile , GENERIC_WRITE , FILE_SHARE_READ , NULL , dwCreationDisposition , 0 , NULL ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
{
DWORD dwBytesWritten = 0 ;
TCHAR * pcPoint = _tcsrchr ( pszMemPakFile , _T ( ' . ' ) ) ;
if ( ! lstrcmpi ( pcPoint , _T ( " .n64 " ) ) )
{
if ( fCreate & & ! GetFileSize ( hFile , NULL ) )
{
char szHeader [ ] = " 123-456-STD " ;
SetFilePointer ( hFile , 0L , NULL , FILE_BEGIN ) ;
WriteFile ( hFile , szHeader , sizeof ( szHeader ) , & dwBytesWritten , NULL ) ;
}
SetFilePointer ( hFile , 0x1040 , NULL , FILE_BEGIN ) ;
}
else
SetFilePointer ( hFile , 0L , NULL , FILE_BEGIN ) ;
bool Success = ( WriteFile ( hFile , aMemPak , PAK_MEM_SIZE , & dwBytesWritten , NULL ) ! = 0 ) ;
if ( Success )
SetEndOfFile ( hFile ) ;
CloseHandle ( hFile ) ;
return Success ;
}
else
ErrorMessage ( IDS_ERR_MPCREATE , GetLastError ( ) , false ) ;
return false ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// This function stores the current config data to the INI file. It stores the interface's idea of configuration
// As such, it should only be called from the config window (interface). Otherwise, it will fail.
2016-01-27 09:11:59 +00:00
// Returns true if saved OK, false if there was a problem.
bool StoreConfigToINI ( )
{
2020-02-09 11:36:49 +00:00
char szANSIBuf [ DEFAULT_BUFFER ] ;
if ( ! g_ivConfig )
return false ;
TCHAR szFilename [ MAX_PATH ] ;
GetDirectory ( szFilename , DIRECTORY_CONFIG ) ;
_tcscat ( szFilename , _T ( " NRage.ini " ) ) ;
2021-05-18 11:51:36 +00:00
FILE * fFile = _tfopen ( szFilename , _T ( " wS " ) ) ; // TODO: Write, optimize for sequential
2020-02-09 11:36:49 +00:00
if ( ! fFile )
{
DebugWriteA ( " Couldn't open INI file for output! \n " ) ;
return false ;
}
2021-05-18 11:51:36 +00:00
// First write out any standard header stuff here
2020-02-09 11:36:49 +00:00
fputs ( STRING_INI_HEADER , fFile ) ;
// General
fputs ( " \n [ " STRING_INI_GENERAL " ] \n " , fFile ) ;
fprintf ( fFile , STRING_INI_LANGUAGE " =%d \n " , g_ivConfig - > Language ) ;
fprintf ( fFile , STRING_INI_SHOWMESSAGES " =%d \n " , ( int ) ( g_ivConfig - > fDisplayShortPop ) ) ;
// Folders
fputs ( " \n [ " STRING_INI_FOLDERS " ] \n " , fFile ) ;
const char szFolders [ ARRAYSIZE ( g_aszDefFolders ) ] [ DEFAULT_BUFFER ] = { STRING_INI_BRMEMPAK " =%s \n " , STRING_INI_BRGBROM " =%s \n " , STRING_INI_BRGBSAVE " =%s \n " } ;
for ( int i = 0 ; i < ARRAYSIZE ( szFolders ) ; i + + )
{
TCHAR_TO_CHAR ( szANSIBuf , g_aszDefFolders [ i ] , DEFAULT_BUFFER ) ;
fprintf ( fFile , szFolders [ i ] , szANSIBuf ) ;
}
// lastBrowserDir
fputs ( " \n [ " STRING_INI_BROWSER " ] \n " , fFile ) ;
const char szBrowser [ ARRAYSIZE ( g_aszLastBrowse ) ] [ DEFAULT_BUFFER ] = { STRING_INI_BRMEMPAK " =%s \n " , STRING_INI_BRGBROM " =%s \n " , STRING_INI_BRGBSAVE " =%s \n " ,
STRING_INI_BRPROFILE " =%s \n " , STRING_INI_BRNOTE " =%s \n " , STRING_INI_SHORTCUTS " =%s \n " } ;
for ( int i = 0 ; i < ARRAYSIZE ( szBrowser ) ; i + + )
{
TCHAR_TO_CHAR ( szANSIBuf , g_aszLastBrowse [ i ] , DEFAULT_BUFFER ) ;
fprintf ( fFile , szBrowser [ i ] , szANSIBuf ) ;
}
// Controller 1 through 4
for ( int i = 0 ; i < 4 ; i + + )
{
fprintf ( fFile , " \n [ " STRING_INI_CONTROLLER " %d] \n " , i + 1 ) ;
DumpControllerSettings ( fFile , i , true ) ;
}
// Controls
// I'm going to use STL strings here because I don't want to screw with buffer management
string strMouse ;
string strDevs [ MAX_DEVICES ] ;
string strNull ;
fputs ( " \n [ " STRING_INI_CONTROLS " ] \n " , fFile ) ;
fputs ( " # Button format: controlnum buttonID bOffset bAxisID bBtnType \n " , fFile ) ;
2021-05-18 11:51:36 +00:00
for ( int i = 0 ; i < 4 ; i + + ) // Controllers for
2020-02-09 11:36:49 +00:00
{
FormatControlsBlock ( & strMouse , strDevs , & strNull , i ) ;
2021-05-18 11:51:36 +00:00
} // End controllers for
2020-02-09 11:36:49 +00:00
DumpStreams ( fFile , strMouse , strDevs , strNull , true ) ;
strMouse . clear ( ) ;
for ( int i = 0 ; i < g_nDevices ; i + + )
strDevs [ i ] . clear ( ) ;
strNull . clear ( ) ;
// Shortcuts
fputs ( " \n [ " STRING_INI_SHORTCUTS " ] \n " , fFile ) ;
fputs ( " # Shortcuts format: controlnum buttonID bOffset bAxisID bBtnType \n " , fFile ) ;
FormatShortcutsBlock ( fFile , true ) ;
// Modifiers
fputs ( " \n [ " STRING_INI_MODIFIERS " ] \n " , fFile ) ;
fputs ( " # Modifiers format: controlnum bOffset bAxisID bBtnType bModType fToggle fStatus dwSpecific \n " , fFile ) ;
2021-05-18 11:51:36 +00:00
for ( int i = 0 ; i < 4 ; i + + ) // Controllers for
2020-02-09 11:36:49 +00:00
{
FormatModifiersBlock ( & strMouse , strDevs , & strNull , i ) ;
2021-05-18 11:51:36 +00:00
} // End controllers for
2020-02-09 11:36:49 +00:00
DumpStreams ( fFile , strMouse , strDevs , strNull , true ) ;
fclose ( fFile ) ;
DebugWriteA ( " Config stored to INI \n " ) ;
return true ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// This function loads the config data from INI into working emulator space. Does not copy into interface;
// You need to call GetCurrentConfiguration() if you want to do that.
2016-01-27 09:11:59 +00:00
// Returns true if loaded OK, false if there was a problem.
bool LoadConfigFromINI ( )
{
2020-02-09 11:36:49 +00:00
FILE * fFile = NULL ;
2021-05-18 11:51:36 +00:00
DWORD dwSection = 0 ; // This will evaluate to the bracketed "[Section]" we are currently in.
2020-02-09 11:36:49 +00:00
char szLine [ 4096 ] ;
TCHAR szFilename [ MAX_PATH ] ;
GetDirectory ( szFilename , DIRECTORY_CONFIG ) ;
_tcscat ( szFilename , _T ( " NRage.ini " ) ) ;
2021-05-18 11:51:36 +00:00
fFile = _tfopen ( szFilename , _T ( " rS " ) ) ; // Read, optimize for sequential
2020-02-09 11:36:49 +00:00
if ( ! fFile )
{
DebugWriteA ( " Couldn't open INI file for input! \n " ) ;
return false ;
}
for ( int i = 0 ; i < 4 ; i + + )
SetControllerDefaults ( & ( g_pcControllers [ i ] ) ) ;
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , false ) ;
DWORD dwCommand = PL_NOHIT ;
while ( ( fgets ( szLine , sizeof ( szLine ) - 1 , fFile ) ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
dwCommand = ParseLine ( szLine ) ;
if ( dwCommand = = PL_NOHIT )
continue ;
else if ( dwCommand = = PL_CATEGORY )
2021-05-18 11:51:36 +00:00
// Section changed to szLine
2020-02-09 11:36:49 +00:00
dwSection = djbHash ( szLine ) ;
else
ProcessKey ( dwCommand , dwSection , szLine , 0 , 0 , false ) ;
}
fclose ( fFile ) ;
return true ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Basically a stripped down version of GetConfigFromINI, called at the very beginning to get our language
2016-01-27 09:11:59 +00:00
LANGID GetLanguageFromINI ( )
{
2020-02-09 11:36:49 +00:00
FILE * fFile = NULL ;
char szLine [ 4096 ] ;
TCHAR szFilename [ MAX_PATH ] ;
GetDirectory ( szFilename , DIRECTORY_CONFIG ) ;
_tcscat ( szFilename , _T ( " NRage.ini " ) ) ;
2021-05-18 11:51:36 +00:00
fFile = _tfopen ( szFilename , _T ( " rS " ) ) ; // Read, optimize for sequential
2020-02-09 11:36:49 +00:00
if ( ! fFile )
{
DebugWriteA ( " Couldn't open INI file for input! \n " ) ;
return 0 ;
}
ProcessKey ( PL_RESET , 0 , 0 , 0 , 0 , false ) ;
DWORD dwCommand = PL_NOHIT ;
while ( ( fgets ( szLine , sizeof ( szLine ) - 1 , fFile ) ) )
{
2021-05-18 11:51:36 +00:00
szLine [ strlen ( szLine ) - 1 ] = ' \0 ' ; // Remove newline
2020-02-09 11:36:49 +00:00
dwCommand = ParseLine ( szLine ) ;
if ( dwCommand = = CHK_LANGUAGE )
{
LANGID lTemp = 0 ;
2016-01-27 09:11:59 +00:00
if ( sscanf ( szLine , " %hu " , & lTemp ) )
2020-02-09 11:36:49 +00:00
{
fclose ( fFile ) ;
return lTemp ;
}
}
}
fclose ( fFile ) ;
DebugWriteA ( " Couldn't find a Language= line in INI file... \n " ) ;
return 0 ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Both the following functions assume the buffer is big enough
2016-01-27 09:11:59 +00:00
inline void GUIDtoStringA ( char * szGUIDbuf , const GUID guid )
{
2020-02-09 11:36:49 +00:00
_snprintf ( szGUIDbuf , GUID_STRINGLENGTH + 1 , " {%08.8lX-%04.4hX-%04.4hX-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X} " , guid . Data1 , guid . Data2 , guid . Data3 , guid . Data4 [ 0 ] , guid . Data4 [ 1 ] , guid . Data4 [ 2 ] , guid . Data4 [ 3 ] , guid . Data4 [ 4 ] , guid . Data4 [ 5 ] , guid . Data4 [ 6 ] , guid . Data4 [ 7 ] ) ;
2016-01-27 09:11:59 +00:00
}
inline bool StringtoGUIDA ( LPGUID guid , const char * szGUIDbuf )
{
2020-02-09 11:36:49 +00:00
short unsigned int lastbyte ;
int blah = sscanf ( szGUIDbuf , " {%08lX-%04hX-%04hX-%02hX%02hX-%02hX%02hX%02hX%02hX%02hX%02hX} " , & guid - > Data1 , & guid - > Data2 , & guid - > Data3 , & guid - > Data4 [ 0 ] , & guid - > Data4 [ 1 ] , & guid - > Data4 [ 2 ] , & guid - > Data4 [ 3 ] , & guid - > Data4 [ 4 ] , & guid - > Data4 [ 5 ] , & guid - > Data4 [ 6 ] , & lastbyte ) ;
if ( blah = = 11 )
{
2016-01-27 09:11:59 +00:00
guid - > Data4 [ 7 ] = ( BYTE ) lastbyte ;
2020-02-09 11:36:49 +00:00
return true ;
}
else
return false ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Takes in a file to dump to, and an 'int i' telling which controller's settings to dump. Does not dump buttons or modifiers.
2016-01-27 09:11:59 +00:00
void DumpControllerSettings ( FILE * fFile , int i , bool bIsINI )
{
2020-02-09 11:36:49 +00:00
char szANSIBuf [ DEFAULT_BUFFER ] ;
fprintf ( fFile , STRING_INI_PLUGGED " =%u \n " , g_ivConfig - > Controllers [ i ] . fPlugged ) ;
fprintf ( fFile , STRING_INI_XINPUT " =%u \n " , g_ivConfig - > Controllers [ i ] . fXInput ) ;
fprintf ( fFile , STRING_INI_N64MOUSE " =%u \n " , g_ivConfig - > Controllers [ i ] . fN64Mouse ) ;
fprintf ( fFile , STRING_INI_BACKGROUNDINPUT " =%u \n " , g_ivConfig - > Controllers [ i ] . bBackgroundInput ) ;
fprintf ( fFile , STRING_INI_RAWDATA " =%u \n " , g_ivConfig - > Controllers [ i ] . fRawData ) ;
fprintf ( fFile , STRING_INI_PAKTYPE " =%u \n " , g_ivConfig - > Controllers [ i ] . PakType ) ;
fprintf ( fFile , STRING_INI_REALN64RANGE " =%u \n " , g_ivConfig - > Controllers [ i ] . fRealN64Range ) ;
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_STICKRANGE " =%u \n " , g_ivConfig - > Controllers [ i ] . bStickRange ) ;
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_AXISSET " =%u \n " , g_ivConfig - > Controllers [ i ] . bAxisSet ) ;
fprintf ( fFile , STRING_INI_KEYABSOLUTEX " =%u \n " , g_ivConfig - > Controllers [ i ] . fKeyAbsoluteX ) ;
fprintf ( fFile , STRING_INI_KEYABSOLUTEY " =%u \n " , g_ivConfig - > Controllers [ i ] . fKeyAbsoluteY ) ;
fprintf ( fFile , STRING_INI_PADDEADZONE " =%u \n " , g_ivConfig - > Controllers [ i ] . bPadDeadZone ) ;
fprintf ( fFile , STRING_INI_MOUSESENSX " =%u \n " , g_ivConfig - > Controllers [ i ] . wMouseSensitivityX ) ;
fprintf ( fFile , STRING_INI_MOUSESENSY " =%u \n " , g_ivConfig - > Controllers [ i ] . wMouseSensitivityY ) ;
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_VISUALRUMBLE " =%u \n " , g_ivConfig - > Controllers [ i ] . fVisualRumble ) ;
if ( bIsINI )
{
char szGUID [ DEFAULT_BUFFER ] ;
int iDevice = FindDeviceinList ( g_ivConfig - > FFDevices [ i ] . szProductName , g_ivConfig - > FFDevices [ i ] . bProductCounter , true ) ;
if ( iDevice = = - 1 )
{
fprintf ( fFile , STRING_INI_FFDEVICEGUID " = \n " ) ;
}
else
{
g_ivConfig - > Controllers [ i ] . guidFFDevice = g_devList [ iDevice ] . guidInstance ;
GUIDtoStringA ( szGUID , g_ivConfig - > Controllers [ i ] . guidFFDevice ) ;
fprintf ( fFile , STRING_INI_FFDEVICEGUID " =%s \n " , szGUID ) ;
}
}
else
{
TCHAR_TO_CHAR ( szANSIBuf , g_ivConfig - > FFDevices [ i ] . szProductName , DEFAULT_BUFFER ) ;
fprintf ( fFile , STRING_INI_FFDEVICENAME " =%s \n " , szANSIBuf ) ;
fprintf ( fFile , STRING_INI_FFDEVICENR " =%u \n " , g_ivConfig - > FFDevices [ i ] . bProductCounter ) ;
}
TCHAR_TO_CHAR ( szANSIBuf , g_ivConfig - > Controllers [ i ] . szMempakFile , DEFAULT_BUFFER ) ;
fprintf ( fFile , STRING_INI_MEMPAKFILE " =%s \n " , szANSIBuf ) ;
TCHAR_TO_CHAR ( szANSIBuf , g_ivConfig - > Controllers [ i ] . szTransferRom , DEFAULT_BUFFER ) ;
fprintf ( fFile , STRING_INI_GBROMFILE " =%s \n " , szANSIBuf ) ;
TCHAR_TO_CHAR ( szANSIBuf , g_ivConfig - > Controllers [ i ] . szTransferSave , DEFAULT_BUFFER ) ;
fprintf ( fFile , STRING_INI_GBROMSAVE " =%s \n " , szANSIBuf ) ;
2016-01-27 09:11:59 +00:00
}
2021-05-18 11:51:36 +00:00
// Private function, called by StoreConfigToINI to dump cached button strings to file
2016-01-27 09:11:59 +00:00
void DumpStreams ( FILE * fFile , string strMouse , string strDevs [ ] , string strNull , bool bIsINI )
{
2021-05-18 11:51:36 +00:00
// Dump all streams to file, with appropriate DInput lines and name comment
2020-02-09 11:36:49 +00:00
char szANSIBuf [ DEFAULT_BUFFER ] ;
if ( ! ( strMouse . empty ( ) ) )
{
TCHAR_TO_CHAR ( szANSIBuf , g_sysMouse . szProductName , DEFAULT_BUFFER ) ;
if ( bIsINI )
{
fprintf ( fFile , " # %s \n " , szANSIBuf ) ;
char szGUID [ DEFAULT_BUFFER ] ;
GUIDtoStringA ( szGUID , g_sysMouse . guidInstance ) ;
fprintf ( fFile , STRING_INI_DINPUTGUID " =%s \n " , szGUID ) ;
}
else
{
fprintf ( fFile , STRING_INI_DINPUTNAME " =%s \n " , szANSIBuf ) ;
fprintf ( fFile , STRING_INI_DINPUTNR " =%d \n " , 0 ) ;
}
fputs ( strMouse . c_str ( ) , fFile ) ;
}
if ( ! ( strNull . empty ( ) ) )
{
fputs ( " # NOT ASSIGNED \n " , fFile ) ;
if ( bIsINI )
{
char szGUID [ DEFAULT_BUFFER ] ;
GUIDtoStringA ( szGUID , GUID_NULL ) ;
fprintf ( fFile , STRING_INI_DINPUTGUID " =%s \n " , szGUID ) ;
}
else
{
2021-05-18 11:51:36 +00:00
fprintf ( fFile , STRING_INI_DINPUTNAME " = \n " ) ; // Leave blank
2020-02-09 11:36:49 +00:00
fprintf ( fFile , STRING_INI_DINPUTNR " = \n " ) ;
}
fputs ( strNull . c_str ( ) , fFile ) ;
}
for ( int i = 0 ; i < g_nDevices ; i + + )
{
if ( ! ( strDevs [ i ] . empty ( ) ) )
{
TCHAR_TO_CHAR ( szANSIBuf , g_devList [ i ] . szProductName , DEFAULT_BUFFER ) ;
if ( bIsINI )
{
if ( g_devList [ i ] . bProductCounter > 0 )
fprintf ( fFile , " # %s %d \n " , szANSIBuf , g_devList [ i ] . bProductCounter ) ;
else
fprintf ( fFile , " # %s \n " , szANSIBuf ) ;
char szGUID [ DEFAULT_BUFFER ] ;
GUIDtoStringA ( szGUID , g_devList [ i ] . guidInstance ) ;
fprintf ( fFile , STRING_INI_DINPUTGUID " =%s \n " , szGUID ) ;
}
else
{
fprintf ( fFile , STRING_INI_DINPUTNAME " =%s \n " , szANSIBuf ) ;
fprintf ( fFile , STRING_INI_DINPUTNR " =%d \n " , g_devList [ i ] . bProductCounter ) ;
}
fputs ( strDevs [ i ] . c_str ( ) , fFile ) ;
}
}
2016-01-27 09:11:59 +00:00
}
void FormatControlsBlock ( string * strMouse , string strDevs [ ] , string * strNull , int i )
{
2021-05-18 11:51:36 +00:00
for ( int j = 0 ; j < ARRAYSIZE ( g_ivConfig - > Controllers [ i ] . aButton ) ; j + + ) // Buttons for
2020-02-09 11:36:49 +00:00
{
2021-05-18 11:51:36 +00:00
if ( g_ivConfig - > Controllers [ i ] . aButton [ j ] . parentDevice ) // Possibly unbound
2020-02-09 11:36:49 +00:00
{
if ( IsEqualGUID ( g_sysMouse . guidInstance , g_ivConfig - > Controllers [ i ] . aButton [ j ] . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , i , j , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bOffset , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bAxisID , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bBtnType ) ;
strMouse - > append ( szBuf ) ;
}
else
{
for ( int match = 0 ; match < g_nDevices ; match + + )
{
if ( IsEqualGUID ( g_devList [ match ] . guidInstance , g_ivConfig - > Controllers [ i ] . aButton [ j ] . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the appropriate device stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_BUTTON " =%d %d %02X %d %d \n " , i , j , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bOffset , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bAxisID , g_ivConfig - > Controllers [ i ] . aButton [ j ] . bBtnType ) ;
strDevs [ match ] . append ( szBuf ) ;
break ;
}
}
}
}
else if ( g_ivConfig - > Controllers [ i ] . aButton [ j ] . bBtnType ! = DT_UNASSIGNED )
{
int k = g_ivConfig - > Controllers [ i ] . aButton [ j ] . bBtnType ;
DebugWriteA ( " Controller %d button %d is of bBtnType %d but has no parentDevice! \n " , i , j , k ) ;
}
2021-05-18 11:51:36 +00:00
} // End buttons for
2016-01-27 09:11:59 +00:00
}
void FormatModifiersBlock ( string * strMouse , string strDevs [ ] , string * strNull , int i )
{
2020-02-09 11:36:49 +00:00
for ( int j = 0 ; j < g_ivConfig - > Controllers [ i ] . nModifiers ; j + + )
{
2021-05-18 11:51:36 +00:00
if ( g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . parentDevice ) // Is it assigned to a key?
2020-02-09 11:36:49 +00:00
{
if ( IsEqualGUID ( g_sysMouse . guidInstance , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_MODIFIER " =%d %02X %d %d %d %d %d %08X \n " , i , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bOffset ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bAxisID , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bBtnType ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . bModType , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fToggle ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fStatus , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . dwSpecific ) ;
strMouse - > append ( szBuf ) ;
}
else
for ( int match = 0 ; match < g_nDevices ; match + + )
if ( IsEqualGUID ( g_devList [ match ] . guidInstance , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . parentDevice - > guidInstance ) )
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_MODIFIER " =%d %02X %d %d %d %d %d %08X \n " , i , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bOffset ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bAxisID , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bBtnType ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . bModType , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fToggle ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fStatus , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . dwSpecific ) ;
strDevs [ match ] . append ( szBuf ) ;
break ;
}
}
2021-05-18 11:51:36 +00:00
else // Save modifiers without a keybind
2020-02-09 11:36:49 +00:00
{
char szBuf [ DEFAULT_BUFFER ] ;
2021-05-18 11:51:36 +00:00
// Add to the mouse stream
2020-02-09 11:36:49 +00:00
sprintf ( szBuf , STRING_INI_MODIFIER " =%d %02X %d %d %d %d %d %08X \n " , i , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bOffset ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bAxisID , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . btnButton . bBtnType ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . bModType , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fToggle ,
g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . fStatus , g_ivConfig - > Controllers [ i ] . pModifiers [ j ] . dwSpecific ) ;
strNull - > append ( szBuf ) ;
}
}
2016-01-27 09:11:59 +00:00
}
unsigned long djbHash ( const char * str )
{
unsigned long hash = 5381 ;
int c ;
while ( ( c = * str + + ) )
2021-05-18 11:51:36 +00:00
hash = ( ( hash < < 5 ) + hash ) + c ; // hash * 33 + c
2016-01-27 09:11:59 +00:00
return hash ;
}