|
|
/*****************************************************************************
* * DIJoyReg.c * * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Registry access services for joystick configuration. * * Contents: * * JoyReg_GetConfig * *****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
* * The sqiffle for this file. * *****************************************************************************/
#define sqfl sqflJoyReg
#pragma BEGIN_CONST_DATA
/*****************************************************************************
* * @doc INTERNAL * * @global JOYREGHWSETTINGS | c_rghwsPredef[] | * * Array of predefined hardware settings. * *****************************************************************************/
JOYREGHWSETTINGS c_rghwsPredef[] = { /* dwFlags dwNumButtons */ { 0, 2}, /* JOY_HW_2A_2B_GENERIC */ { 0, 4}, /* JOY_HW_2A_4B_GENERIC */ { JOY_HWS_ISGAMEPAD, 2}, /* JOY_HW_2B_GAMEPAD */ { JOY_HWS_ISYOKE, 2}, /* JOY_HW_2B_FLIGHTYOKE */ { JOY_HWS_HASZ | JOY_HWS_ISYOKE, 2}, /* JOY_HW_2B_FLIGHTYOKETHROTTLE */ { JOY_HWS_HASZ, 2}, /* JOY_HW_3A_2B_GENERIC */ { JOY_HWS_HASZ, 4}, /* JOY_HW_3A_4B_GENERIC */ { JOY_HWS_ISGAMEPAD, 4}, /* JOY_HW_4B_GAMEPAD */ { JOY_HWS_ISYOKE, 4}, /* JOY_HW_4B_FLIGHTYOKE */ { JOY_HWS_HASZ | JOY_HWS_ISYOKE, 4}, /* JOY_HW_4B_FLIGHTYOKETHROTTLE */ { JOY_HWS_HASR , 2}, /* JOY_HW_TWO_2A_2B_WITH_Y */ /* To prevent the CPL from allowing
a user to add a rudder to to JOY_HWS_TWO_2A_2B_WITH_Y case, we will pretend that it already has a rudder. This should not be a problem as this struct is internal to DInput */ };
/* Hardware IDs for Predefined Joystick types */ LPCWSTR c_rghwIdPredef[] = { L"GAMEPORT\\VID_045E&PID_0102", // L"GAMEPORT\\Generic2A2B",
L"GAMEPORT\\VID_045E&PID_0103", // L"GAMEPORT\\Generic2A4B",
L"GAMEPORT\\VID_045E&PID_0104", // L"GAMEPORT\\Gamepad2B",
L"GAMEPORT\\VID_045E&PID_0105", // L"GAMEPORT\\FlightYoke2B",
L"GAMEPORT\\VID_045E&PID_0106", // L"GAMEPORT\\FlightYokeThrottle2B",
L"GAMEPORT\\VID_045E&PID_0107", // L"GAMEPORT\\Generic3A2B",
L"GAMEPORT\\VID_045E&PID_0108", // L"GAMEPORT\\Generic3A4B",
L"GAMEPORT\\VID_045E&PID_0109", // L"GAMEPORT\\Gamepad4B",
L"GAMEPORT\\VID_045E&PID_010A", // L"GAMEPORT\\FlightYoke4B",
L"GAMEPORT\\VID_045E&PID_010B", // L"GAMEPORT\\FlightYokeThrottle4B",
L"GAMEPORT\\VID_045E&PID_010C", // L"GAMEPORT\\YConnectTwo2A2B",
};
WCHAR c_hwIdPrefix[] = L"GAMEPORT\\"; // Prefix for custom devices
/*****************************************************************************
* * The default global port driver. * *****************************************************************************/
WCHAR c_wszDefPortDriver[] = L"MSANALOG.VXD";
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetValue | * * Retrieve registry information. If the data is short, and * the type is <c REG_BINARY>, then the extra is zero-filled. * * @parm HKEY | hk | * * Registry key containing fun values. * * @parm LPCTSTR | ptszValue | * * Registry value name. * * @parm DWORD | reg | * * Registry data type expected. * * @parm LPVOID | pvBuf | * * Buffer to receive information from registry. * * @parm DWORD | cb | * * Size of recipient buffer, in bytes. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c S_FALSE>: The binary read was short. The remainder of the * buffer is zero-filled. * * <c E_FAIL>: Error reading value from registry. * *****************************************************************************/
STDMETHODIMP JoyReg_GetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PV pvBuf, DWORD cb) { HRESULT hres; DWORD cbOut; LONG lRc;
/*
* Strings must be handled differently from binaries. * * Strings are retrieved in UNICODE and may be short. * * Binaries are retrieved as binary (duh) and may be long. * */
cbOut = cb;
if(reg == REG_SZ) { lRc = RegQueryStringValueW(hk, ptszValue, pvBuf, &cbOut); if(lRc == ERROR_SUCCESS) { hres = S_OK; } else { hres = hresLe(lRc); /* Else, something bad happened */ }
} else {
AssertF(reg == REG_BINARY);
lRc = RegQueryValueEx(hk, ptszValue, 0, NULL, pvBuf, &cbOut); if(lRc == ERROR_SUCCESS) { if(cb == cbOut) { hres = S_OK; } else {
/*
* Zero out the extra. */ ZeroBuf(pvAddPvCb(pvBuf, cbOut), cb - cbOut); hres = S_FALSE; }
} else if(lRc == ERROR_MORE_DATA) {
/*
* Need to double-buffer the call and throw away * the extra... */ LPVOID pv;
hres = AllocCbPpv(cbOut, &pv); // prefix 29344, odd chance that cbOut is 0x0
if(SUCCEEDED(hres) && ( pv != NULL) ) { lRc = RegQueryValueEx(hk, ptszValue, 0, NULL, pv, &cbOut); if(lRc == ERROR_SUCCESS) { CopyMemory(pvBuf, pv, cb); hres = S_OK; } else { ZeroBuf(pvBuf, cb); hres = hresLe(lRc); /* Else, something bad happened */ } FreePv(pv); }
} else { if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY) { lRc = ERROR_FILE_NOT_FOUND; } hres = hresLe(lRc); ZeroBuf(pvBuf, cb); } }
#ifdef DEBUG
/*
* Don't whine if the key we couldn't find was * REGSTR_VAL_JOYUSERVALUES, because almost no one has it. */ if(FAILED(hres) && lstrcmpi(ptszValue, REGSTR_VAL_JOYUSERVALUES) ) {
SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("Unable to read %s from registry"), ptszValue); } #endif
return hres;
}
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_IsWdmGameport | * * To test whether the joy type is WDM device or not. * * @parm HKEY | hk | * * Registry key containing fun values. * * @returns * * S_OK: if it uses WDM driver * * E_FAIL>: Not uses WDM driver * *****************************************************************************/
STDMETHODIMP JoyReg_IsWdmGameport( HKEY hk ) { HRESULT hres = E_FAIL;
if( hk ) { WCHAR wsz[MAX_JOYSTRING]; // Whistler PREFIX Bug # 45075, 45076
// Wsz is not initialized
ZeroX(wsz);
if( ( SUCCEEDED( JoyReg_GetValue( hk, REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ, &wsz, cbX(wsz) ) ) ) &&( wsz[0] ) ) { hres = S_OK; } else if( SUCCEEDED( JoyReg_GetValue( hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ, &wsz, cbX(wsz) ) ) ) { static WCHAR wszJoyhid[] = L"joyhid.vxd"; int Idx; #define WLOWER 0x0020
CAssertF( cbX(wszJoyhid) <= cbX(wsz) );
/*
* Since neither CharUpperW nor lstrcmpiW are really * implemented on 9x, do it by hand. */
for( Idx=cA(wszJoyhid)-2; Idx>=0; Idx-- ) { if( ( wsz[Idx] | WLOWER ) != wszJoyhid[Idx] ) { break; } }
if( ( Idx < 0 ) && ( wsz[cA(wszJoyhid)-1] == 0 ) ) { hres = S_OK; }
#undef WLOWER
}
}
return hres; }
#if 0
/*
* This function should be in diutil.c Putting here is just to keep it together with * JoyReg_IsWdmGameport(); */ STDMETHODIMP JoyReg_IsWdmGameportFromDeviceInstance( LPTSTR ptszDeviceInst ) { /*
* ptszDeviceInst's format is like this: * HID\VID_045E&PID_0102\0000GAMEPORT&PVID_.... */
WCHAR wszDeviceInst[MAX_PATH]; HRESULT hres = E_FAIL;
if( ptszDeviceInst ) { memset( wszDeviceInst, 0, cbX(wszDeviceInst) ); TToU( wszDeviceInst, MAX_PATH, ptszDeviceInst ); wszDeviceInst[34] = 0;
if( memcmp( &wszDeviceInst[26], c_hwIdPrefix, 16 ) == 0 ) { hres = S_OK; } }
return hres; } #endif
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_SetValue | * * Write registry information. * * @parm HKEY | hk | * * Registry key containing fun values. * * @parm LPCTSTR | ptszValue | * * Registry value name. * * @parm DWORD | reg | * * Registry data type to set. * * @parm LPCVOID | pvBuf | * * Buffer containing information to write to registry. * * @parm DWORD | cb | * * Size of buffer, in bytes. Ignored if writing a string. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c E_FAIL>: Error writing value to registry. * *****************************************************************************/
STDMETHODIMP JoyReg_SetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PCV pvBuf, DWORD cb) { HRESULT hres; LONG lRc;
/*
* Strings must be handled differently from binaries. * * A null string translates into deleting the key. */
if(reg == REG_SZ) { lRc = RegSetStringValueW(hk, ptszValue, pvBuf); } else { lRc = RegSetValueEx(hk, ptszValue, 0, reg, pvBuf, cb); }
if(lRc == ERROR_SUCCESS) { hres = S_OK; } else { RPF("Unable to write %s to registry", ptszValue); hres = E_FAIL; /* Else, something bad happened */ }
return hres;
}
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_OpenTypeKey | * * Open the joystick registry key that corresponds to a * joystick type. * * @parm LPCWSTR | pwszTypeName | * * The name of the type. * * @parm DWORD | sam | * * Desired security access mask. * * @parm OUT PHKEY | phk | * * Receives the opened registry key on success. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: The joystick type was not found. * *****************************************************************************/
STDMETHODIMP JoyReg_OpenTypeKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk) { HRESULT hres; HKEY hkTypes; EnterProc(JoyReg_OpenTypeKey, (_ "W", pwszType));
/*
* Note that it is not safe to cache the registry key. * If somebody deletes the registry key, our handle * goes stale and becomes useless. */
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, sam, REG_OPTION_NON_VOLATILE, &hkTypes);
if( SUCCEEDED(hres) ) { #ifndef UNICODE
TCHAR tszType[MAX_PATH]; UToA( tszType, cA(tszType), pwszType );
hres = hresMumbleKeyEx(hkTypes, tszType, sam, dwOptions, phk); #else
hres = hresMumbleKeyEx(hkTypes, pwszType, sam, dwOptions, phk); #endif
RegCloseKey(hkTypes); }
if(FAILED(hres)) { *phk = 0; }
ExitBenignOleProcPpv(phk); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_OpenPropKey | * * Open the Dinput properties registry key that corresponds to a * device type. This key contains the OEMMapFile and dwFlags2 information * Nominally the location HKLM/REGSTR_PATH_PRIVATEPROPERTIES/DirectInput. * * @parm LPCWSTR | pwszTypeName | * * The name of the type. * * @parm DWORD | sam | * * Desired security access mask. * * @parm OUT PHKEY | phk | * * Receives the opened registry key on success. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: The type was not found. * *****************************************************************************/
STDMETHODIMP JoyReg_OpenPropKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk) { HRESULT hres; HKEY hkTypes; EnterProc(JoyReg_OpenTypeKey, (_ "W", pwszType));
/*
* Note that it is not safe to cache the registry key. * If somebody deletes the registry key, our handle * goes stale and becomes useless. */
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DITYPEPROP, sam, REG_OPTION_NON_VOLATILE, &hkTypes);
if ( SUCCEEDED(hres) ) { #ifndef UNICODE
TCHAR tszType[MAX_PATH]; UToA( tszType, cA(tszType), pwszType );
hres = hresMumbleKeyEx(hkTypes, tszType, sam, dwOptions, phk); #else
hres = hresMumbleKeyEx(hkTypes, pwszType, sam, dwOptions, phk); #endif
RegCloseKey(hkTypes); }
if (FAILED(hres)) { *phk = 0; }
ExitBenignOleProcPpv(phk); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetTypeInfo | * * Obtain information about a non-predefined joystick type. * * @parm LPCWSTR | pwszTypeName | * * The name of the type. * * @parm OUT LPDIJOYTYPEINFO | pjti | * * Receives information about the joystick type. * The caller is assumed to have validated the * <e DIJOYCONFIG.dwSize> field. * * @parm DWORD | fl | * * Zero or more <c DITC_*> flags * which specify which parts of the structure pointed * to by <p pjti> are to be filled in. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: The joystick type was not found. * *****************************************************************************/
STDMETHODIMP JoyReg_GetTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl) { HRESULT hres; HKEY hk; EnterProc(JoyReg_GetTypeInfo, (_ "Wx", pwszType, fl));
ZeroX(pjti->clsidConfig); hres = JoyReg_OpenTypeKey(pwszType, KEY_QUERY_VALUE, REG_OPTION_NON_VOLATILE, &hk);
if(SUCCEEDED(hres)) {
if(fl & DITC_REGHWSETTINGS) { hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMDATA, REG_BINARY, &pjti->hws, cbX(pjti->hws)); if(FAILED(hres)) { goto closedone; } }
/*
* Note that this never fails. */ if(fl & DITC_CLSIDCONFIG) { TCHAR tszGuid[ctchGuid]; LONG lRc;
lRc = RegQueryString(hk, REGSTR_VAL_CPLCLSID, tszGuid, cA(tszGuid));
if(lRc == ERROR_SUCCESS && ParseGUID(&pjti->clsidConfig, tszGuid)) { /* Guid is good */ } else { ZeroX(pjti->clsidConfig); } } if(fl & DITC_DISPLAYNAME) { hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMNAME, REG_SZ, pjti->wszDisplayName, cbX(pjti->wszDisplayName)); if(FAILED(hres)) { goto closedone; } }
if(fl & DITC_CALLOUT) { hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ, pjti->wszCallout, cbX(pjti->wszCallout)); if(FAILED(hres)) { ZeroX(pjti->wszCallout); hres = S_FALSE; goto closedone; } }
if( fl & DITC_HARDWAREID ) { hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ, pjti->wszHardwareId, cbX(pjti->wszHardwareId)); if( FAILED(hres)) { ZeroX(pjti->wszHardwareId); hres = S_FALSE; goto closedone; } }
if( fl & DITC_FLAGS1 ) { hres = JoyReg_GetValue(hk, REGSTR_VAL_FLAGS1, REG_BINARY, &pjti->dwFlags1, cbX(pjti->dwFlags1) ); if( FAILED(hres) ) { pjti->dwFlags1 = 0x0; hres = S_FALSE; goto closedone; } pjti->dwFlags1 &= JOYTYPE_FLAGS1_GETVALID; }
hres = S_OK;
closedone:; RegCloseKey(hk);
} else { // ISSUE-2001/03/29-timgill debug string code should be higher
// (MarcAnd) this really should be at least sqflError but
// this happens a lot, probably due to not filtering out predefs
SquirtSqflPtszV(sqfl | sqflBenign, TEXT( "IDirectInputJoyConfig::GetTypeInfo: Nonexistent type %lS" ), pwszType); hres = DIERR_NOTFOUND; }
ExitOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_SetTypeInfo | * * Store information about a non-predefined joystick type * into the registry. * * @parm HKEY | hkTypeW | * * Registry key to the types branch with write access. * * @parm LPCWSTR | pwszTypeName | * * The name of the type. * * @parm IN LPCDIJOYTYPEINFO | pjti | * * Contains information about the joystick type. * * @parm DWORD | fl | * * Zero or more <c DITC_*> flags * which specify which parts of the structure pointed * to by <p pjti> contain values which are to be set. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: The joystick type was not found. * *****************************************************************************/
STDMETHODIMP JoyReg_SetTypeInfo(HKEY hkTypesW, LPCWSTR pwszType, LPCDIJOYTYPEINFO pjti, DWORD fl) { HRESULT hres; ULONG lRc; EnterProc(JoyRegSetTypeInfo, (_ "Wx", pwszType, fl));
if(fl & DITC_INREGISTRY) { HKEY hk; DWORD dwOptions = 0;
if( fl & DITC_VOLATILEREGKEY ) { dwOptions = REG_OPTION_VOLATILE; }else { dwOptions = REG_OPTION_NON_VOLATILE; }
#ifndef UNICODE
{ TCHAR tszType[MAX_PATH];
UToA(tszType, cA(tszType), pwszType);
hres = hresMumbleKeyEx(hkTypesW, tszType, DI_KEY_ALL_ACCESS, dwOptions, &hk);
} #else
hres = hresMumbleKeyEx(hkTypesW, pwszType, DI_KEY_ALL_ACCESS, dwOptions, &hk); #endif
if( SUCCEEDED(hres) ) {
if(fl & DITC_REGHWSETTINGS) { hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMDATA, REG_BINARY, (PV)&pjti->hws, cbX(pjti->hws)); if(FAILED(hres)) { goto closedone; } }
if(fl & DITC_CLSIDCONFIG) { if(IsEqualGUID(&pjti->clsidConfig, &GUID_Null)) { lRc = RegDeleteValue(hk, REGSTR_VAL_CPLCLSID);
/*
* It is not an error if the key does not already exist. */ if(lRc == ERROR_FILE_NOT_FOUND) { lRc = ERROR_SUCCESS; } } else { TCHAR tszGuid[ctchNameGuid]; NameFromGUID(tszGuid, &pjti->clsidConfig); lRc = RegSetValueEx(hk, REGSTR_VAL_CPLCLSID, 0, REG_SZ, (PV)&tszGuid[ctchNamePrefix], ctchGuid * cbX(tszGuid[0]) ); } if(lRc == ERROR_SUCCESS) { } else { hres = E_FAIL; goto closedone; } }
/* ISSUE-2001/03/29-timgill Needs more data checking
Should make sure string is terminated properly */ if(fl & DITC_DISPLAYNAME) { hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMNAME, REG_SZ, pjti->wszDisplayName, cbX(pjti->wszDisplayName)); if(FAILED(hres)) { goto closedone; } }
/* ISSUE-2001/03/29-timgill Needs more data checking
Should make sure string is terminated properly */ if(fl & DITC_CALLOUT) { hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ, pjti->wszCallout, cbX(pjti->wszCallout)); if(FAILED(hres)) { hres = S_FALSE; //continue to go
} }
if( fl & DITC_HARDWAREID ) { hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ, pjti->wszHardwareId, cbX(pjti->wszHardwareId) ); if( FAILED(hres) ) { hres = S_FALSE; goto closedone; } }
if( fl & DITC_FLAGS1 ) { AssertF( (pjti->dwFlags1 & ~JOYTYPE_FLAGS1_SETVALID) == 0x0 ); hres = JoyReg_SetValue(hk, REGSTR_VAL_FLAGS1, REG_BINARY, (PV)&pjti->dwFlags1, cbX(pjti->dwFlags1) ); if( FAILED(hres) ) { hres = S_FALSE; goto closedone; } } hres = S_OK;
closedone:; RegCloseKey(hk);
} else { hres = E_FAIL; /* Registry problem */ } } else { hres = S_OK; /* Vacuous success */ }
ExitOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_OpenConfigKey | * * Open the registry key that accesses joystick configuration data. * * Warning! Do not cache this regkey. * * If the user deletes the key and then re-creates it, * the opened key will go stale and will become useless. * You have to close the key and reopen it. * To avoid worrying about that case, merely open it every time. * * @parm UINT | idJoy | * * Joystick number. * * @parm DWORD | sam | * * Access level desired. * * @parm IN PJOYCAPS | pcaps | * * Receives joystick capabilities information. * If this parameter is <c NULL>, then joystick * capabilities information is not returned. * * @parm IN DWORD | dwOptions | * Option flags to RegCreateEx * * @parm PHKEY | phk | * * Receives created registry key. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * hresLe(ERROR_FILE_NOT_FOUND): The key does not exist. * *****************************************************************************/
STDMETHODIMP JoyReg_OpenConfigKey(UINT idJoy, DWORD sam, PJOYCAPS pcaps, DWORD dwOptions, PHKEY phk) { HRESULT hres; MMRESULT mmrc = MMSYSERR_ERROR; JOYCAPS caps; EnterProc(JoyReg_OpenConfigKey, (_ "uxp", idJoy, sam, pcaps));
/*
* If caller doesn't care, then just dump the caps into our * private buffer. */ if(pcaps == NULL) { pcaps = ∩︀ }
/*
* If we can't get the dev caps for the specified joystick, * then use the magic joystick id "-1" to get non-specific * caps. */ if( fWinnt ) { ZeroX(*pcaps); lstrcpy(pcaps->szRegKey, REGSTR_SZREGKEY ); mmrc = JOYERR_NOERROR; } else { mmrc = joyGetDevCaps(idJoy, pcaps, cbX(*pcaps)); if( mmrc != JOYERR_NOERROR ) { mmrc = joyGetDevCaps((DWORD)-1, pcaps, cbX(*pcaps)); } }
if(mmrc == JOYERR_NOERROR) {
TCHAR tsz[cA(REGSTR_PATH_JOYCONFIG) + 1 + /* backslash */ cA(pcaps->szRegKey) + 1 + /* backslash */ cA(REGSTR_KEY_JOYCURR) + 1];
/* tsz = MediaResources\Joystick\<drv>\CurrentJoystickSettings */ wsprintf(tsz, TEXT("%s\\%s\\") REGSTR_KEY_JOYCURR, REGSTR_PATH_JOYCONFIG, pcaps->szRegKey);
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tsz, sam, REG_OPTION_VOLATILE, phk);
} else { hres = E_FAIL; }
ExitBenignOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_OpenSaveKey | * * Open the registry key that accesses joystick saved configurations * * Warning! Do not cache this regkey. * * If the user deletes the key and then re-creates it, * the opened key will go stale and will become useless. * You have to close the key and reopen it. * To avoid worrying about that case, merely open it every time. * * @parm DWORD | dwType | * * Joystick type. * * This is either one of the standard ones in the range * * @parm IN LPCDIJOYCONFIG | pcfg | * * If the dwType represents an OEM type, this should point to a * configuration data structure containing a valid wszType. * * @parm DWORD | sam | * * Access level desired. * * @parm PHKEY | phk | * * Receives created registry key. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * hresLe(ERROR_FILE_NOT_FOUND): The key does not exist. * *****************************************************************************/
STDMETHODIMP JoyReg_OpenSaveKey(DWORD dwType, LPCDIJOYCONFIG pcfg, DWORD sam, PHKEY phk) { HRESULT hres; MMRESULT mmrc = MMSYSERR_ERROR; JOYCAPS caps; DWORD dwOptions = 0; EnterProc(JoyReg_OpenSaveKey, (_ "upx", dwType, pcfg, sam));
/*
* use the magic joystick id "-1" to get non-specific caps. */
if( fWinnt ) { ZeroX(caps); lstrcpy(caps.szRegKey, REGSTR_SZREGKEY ); mmrc = JOYERR_NOERROR; } else { mmrc = joyGetDevCaps((DWORD)-1, &caps, cbX(caps)); }
if(mmrc == JOYERR_NOERROR) { TCHAR tsz[cA(REGSTR_PATH_JOYCONFIG) + 1 + /* backslash */ cA(caps.szRegKey) + 1 + /* backslash */ cA(REGSTR_KEY_JOYSETTINGS) + 1 + /* backslash */ max( cA(REGSTR_KEY_JOYPREDEFN), cA(pcfg->wszType) ) + 1 ];
/* tsz = MediaResources\Joystick\<drv>\JoystickSettings\<Type> */ if( dwType >= JOY_HW_PREDEFMAX ) { wsprintf(tsz, TEXT("%s\\%s\\%s\\%ls"), REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYSETTINGS, pcfg->wszType); } else { /*
* We will probably never have more than the current 11 predefined * joysticks. Assume no more than 99 so %d is as many characters. */ wsprintf(tsz, TEXT("%s\\%s\\%s\\" REGSTR_KEY_JOYPREDEFN), REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYSETTINGS, dwType ); }
if( pcfg->hwc.dwUsageSettings & JOY_US_VOLATILE ) dwOptions = REG_OPTION_VOLATILE; else dwOptions = REG_OPTION_NON_VOLATILE;
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tsz, sam, dwOptions, phk);
} else { hres = E_FAIL; }
ExitOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetSetConfigValue | * * Retrieve or update configuration information about a joystick, * as stored in the registry instance key. * * @parm HKEY | hk | * * Registry key containing fun values. * * @parm LPCTSTR | ptszNValue | * * Registry value name, with "%d" where a joystick number * should be. * * @parm UINT | idJoy | * * Zero-based joystick number. * * @parm DWORD | reg | * * Registry data type expected. * * @parm LPVOID | pvBuf | * * Buffer to receive information from registry (if getting) * or containing value to set. * * @parm DWORD | cb | * * Size of buffer, in bytes. * * @parm BOOL | fSet | * * Nonzer if the value should be set; otherwise, it will be * retrieved. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c E_FAIL>: Error reading/writing value to/from registry. * *****************************************************************************/
STDMETHODIMP JoyReg_GetSetConfigValue(HKEY hk, LPCTSTR ptszNValue, UINT idJoy, DWORD reg, PV pvBuf, DWORD cb, BOOL fSet) { HRESULT hres; int ctch;
/* Extra +12 because a UINT can be as big as 4 billion */ TCHAR tsz[max( max( max(cA(REGSTR_VAL_JOYNCONFIG), cA(REGSTR_VAL_JOYNOEMNAME)), cA(REGSTR_VAL_JOYNOEMCALLOUT)), cA(REGSTR_VAL_JOYNFFCONFIG)) + 12 + 1];
ctch = wsprintf(tsz, ptszNValue, idJoy + 1); AssertF(ctch < cA(tsz));
if(fSet) { hres = JoyReg_SetValue(hk, tsz, reg, pvBuf, cb); } else { hres = JoyReg_GetValue(hk, tsz, reg, pvBuf, cb); }
return hres;
}
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | hresIdJoypInstanceGUID | * * Given a joystick ID obtain the corresponding GUID. * This routine differs in implementation on WINNT and WIN9x * On WINNT there are no predefined GUID for Joystick IDs. * * @parm IN UINT | idJoy | * * Joystick identification number. * * @parm OUT LPGUID | lpguid | * * Receives the joystick GUID. If no mapping exists, * GUID_NULL is passed back * * On Windows NT all joysticks are HID devices. The corresponding function * for WINNT is defined in diWinnt.c * *****************************************************************************/
HRESULT EXTERNAL hResIdJoypInstanceGUID_95 ( UINT idJoy, LPGUID lpguid ) { HRESULT hRes;
hRes = S_OK; if( idJoy < cA(rgGUID_Joystick) ) { *lpguid = rgGUID_Joystick[idJoy]; } else { hRes = DIERR_NOTFOUND; ZeroX(*lpguid); } return hRes; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetConfigInternal | * * Obtain information about a joystick's configuration. * * @parm UINT | uiJoy | * * Joystick identification number. * * @parm PJOYCAPS | pcaps | * * Receives information about the joystick capabilities. * If this parameter is <c NULL>, then joystick * capabilities information is not returned. * * @parm OUT LPDIJOYCONFIG | pcfg | * * Receives information about the joystick configuration. * The caller is assumed to have validated the * <e DIJOYCONFIG.dwSize> field. * * @parm DWORD | fl | * * Zero or more <c DIJC_*> flags * which specify which parts of the structure pointed * to by <p pjc> are to be filled in. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOMOREITEMS>: No more joysticks. * *****************************************************************************/
STDMETHODIMP JoyReg_GetConfigInternal(UINT idJoy, PJOYCAPS pcaps, LPDIJOYCONFIG pcfg, DWORD fl) { HRESULT hres = E_FAIL;
EnterProc(JoyReg_GetConfigInternal, (_ "upx", idJoy, pcaps, pcfg, fl));
AssertF((fl & ~DIJC_GETVALID) == 0);
/* We only support (0/16) joysticks */ if( idJoy < cJoyMax ) {
/* Force a rescan of all HID device list
* Some device may have been attached * since we last looked */ DIHid_BuildHidList(FALSE);
if(fl & DIJC_GUIDINSTANCE) { hres = hResIdJoypInstanceGUID_WDM(idJoy, &pcfg->guidInstance);
if( (hres != S_OK) && !fWinnt) { hres = hResIdJoypInstanceGUID_95(idJoy, &pcfg->guidInstance); } if( FAILED(hres) ) { goto done; } }
if( fl & DIJC_INREGISTRY ) { HKEY hk; /* Does the registry entry exist ? */ hres = JoyReg_OpenConfigKey(idJoy, KEY_QUERY_VALUE, pcaps,REG_OPTION_NON_VOLATILE , &hk); if(SUCCEEDED(hres)) { if(fl & DIJC_REGHWCONFIGTYPE) { hres = JoyReg_GetConfigValue( hk, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY, &pcfg->hwc, cbX(pcfg->hwc)); if(FAILED(hres)) { goto closedone; }
pcfg->wszType[0] = TEXT('\0'); if( (pcfg->hwc.dwUsageSettings & JOY_US_ISOEM) || ( !fWinnt && (pcfg->hwc.dwType >= JOY_HW_PREDEFMIN) && (pcfg->hwc.dwType < JOY_HW_PREDEFMAX) ) ) { hres = JoyReg_GetConfigValue( hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ, pcfg->wszType, cbX(pcfg->wszType)); if(FAILED(hres)) { goto closedone; } } }
if(fl & DIJC_CALLOUT) { pcfg->wszCallout[0] = TEXT('\0'); hres = JoyReg_GetConfigValue( hk, REGSTR_VAL_JOYNOEMCALLOUT, idJoy, REG_SZ, pcfg->wszCallout, cbX(pcfg->wszCallout)); if(FAILED(hres)) { ZeroX(pcfg->wszCallout); hres = S_FALSE; /* Note that we fall through and let hres = S_OK */ } }
if(fl & DIJC_GAIN) { /*
* If there is no FF configuration, then * default to DI_FFNOMINALMAX gain. */ hres = JoyReg_GetConfigValue(hk, REGSTR_VAL_JOYNFFCONFIG, idJoy, REG_BINARY, &pcfg->dwGain, cbX(pcfg->dwGain));
if(SUCCEEDED(hres) && ISVALIDGAIN(pcfg->dwGain)) { /* Leave it alone; it's good */ } else { hres = S_FALSE; pcfg->dwGain = DI_FFNOMINALMAX; /* Note that we fall through and let hres = S_OK */ } }
if( fl & DIJC_WDMGAMEPORT ) { PBUSDEVICEINFO pbdi; /*
* If there is no Gameport Associated with this device * then it must be a USB device */
DllEnterCrit(); if( pbdi = pbdiFromJoyId(idJoy) ) { pcfg->guidGameport = pbdi->guid; //lstrcpyW(pcfg->wszGameport, pbdi->wszDisplayName);
} else { ZeroX(pcfg->guidGameport); //pcfg->wszGameport[0] = TEXT('\0');
}
DllLeaveCrit(); }
}
closedone: RegCloseKey(hk); } } else { hres = DIERR_NOMOREITEMS; }
done: ExitBenignOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetConfig | * * Obtain information about a joystick's configuration, * taking the MSGAME.VXD driver into account. * * @parm UINT | uiJoy | * * Joystick identification number. * * @parm PJOYCAPS | pcaps | * * Receives information about the joystick capabilities. * If this parameter is <c NULL>, then joystick * capabilities information is not returned. * * @parm OUT LPDIJOYCONFIG | pcfg | * * Receives information about the joystick configuration. * The caller is assumed to have validated the * <e DIJOYCONFIG.dwSize> field. * * @parm DWORD | fl | * * Zero or more <c DIJC_*> flags * which specify which parts of the structure pointed * to by <p pjc> are to be filled in. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOMOREITEMS>: No more joysticks. * *****************************************************************************/
STDMETHODIMP JoyReg_GetConfig(UINT idJoy, PJOYCAPS pcaps, LPDIJOYCONFIG pcfg, DWORD fl) { HRESULT hres; GUID guid;
EnterProc(JoyReg_GetConfig, (_ "upx", idJoy, pcaps, pcfg, fl));
AssertF((fl & ~DIJC_GETVALID) == 0);
/*
* First determine if the joystick exits * On NT, we use WDM driver. * On Win9x, if WDM fails, use static guids. */ hres = hResIdJoypInstanceGUID_WDM(idJoy, &guid);
if( (hres != S_OK) && !fWinnt ) { hres = hResIdJoypInstanceGUID_95(idJoy, &guid); }
if( SUCCEEDED( hres) ) {
hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl);
#ifndef WINNT
/***************************************************
* * Beginning of hack for Sidewinder Gamepad. * * The gamepad needs to be polled six times before * it realizes what is going on. * ***************************************************/
if(SUCCEEDED(hres) && (fl & DIJC_CALLOUT)) {
static WCHAR s_wszMSGAME[] = L"MSGAME.VXD";
if(memcmp(pcfg->wszCallout, s_wszMSGAME, cbX(s_wszMSGAME)) == 0) { JOYINFOEX ji; int i; DWORD dwWait;
SquirtSqflPtszV(sqfl, TEXT("Making bonus polls for Sidewinder"));
/*
* It's a Sidewinder. Make six * bonus polls to shake the stick into submission. * * Actually, we make 16 bonus polls. The Sidewinder * guys said that five or six would be enough. * They're wrong. * * I also sleep 10ms between each poll because that * seems to help a bit. */ ji.dwSize = cbX(ji); ji.dwFlags = JOY_RETURNALL; for(i = 0; i < 16; i++) { MMRESULT mmrc = joyGetPosEx(idJoy, &ji); SquirtSqflPtszV(sqfl, TEXT("joyGetPosEx(%d) = %d"), idJoy, mmrc); Sleep(10); }
/*
* Now sleep for some time. They forgot to tell us * this. * * Bonus hack! The amount of time we need to sleep * is CPU-speed dependent, so we'll grab the sleep * time from the registry to allow us to tweak it * later. * * What a bunch of lamers. */ dwWait = RegQueryDIDword(NULL, REGSTR_VAL_GAMEPADDELAY, 100); if(dwWait > 10 * 1000) { dwWait = 10 * 1000; }
Sleep(dwWait);
/*
* And then check again. */ hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl); } }
/***************************************************
* * End of hack for Sidewinder Gamepad. * ***************************************************/ #endif //#ifndef WINNT
}
return hres; }
/* This never happens on NT */
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_JoyIdToDeviceInterface_95 | * * Given a joystick ID number, obtain the device interface * corresponding to it. * * @parm UINT | idJoy | * * Joystick ID number, zero-based. * * @parm PVXDINITPARMS | pvip | * * Receives init parameters from the driver. * * @parm LPTSTR | ptszBuf | * * A buffer of size <c MAX_PATH> in which the device interface * path is built. Note that we can get away with a buffer of * this size, since the code path exists only on Windows 95, * and Windows 95 does not support paths longer than <c MAX_PATH>. * (I.e., there ain't no \\?\ support in Win95.) * * @returns * * A pointer to the part of the <p ptszBuf> buffer that * contains the actual device interface path. * *****************************************************************************/
LPSTR EXTERNAL JoyReg_JoyIdToDeviceInterface_95(UINT idJoy, PVXDINITPARMS pvip, LPSTR ptszBuf) { UINT cwch; HRESULT hres; LPSTR ptszRc;
if( fWinnt ) return NULL;
hres = Hel_Joy_GetInitParms(idJoy, pvip); if(SUCCEEDED(hres)) {
/*
* The length counter includes the terminating null. */ cwch = LOWORD(pvip->dwFilenameLengths);
/*
* The name that comes from HID is "\DosDevices\blah" * but we want to use "\\.\blah". So check if it indeed * of the form "\DosDevices\blah" and if so, convert it. * If not, then give up. * * For the string to possibly be a "\DosDevices\", it * needs to be of length 12 or longer. */
if(cwch >= 12 && cwch < MAX_PATH) {
/*
* WideCharToMultiByte does parameter validation so we * don't have to. */ WideCharToMultiByte(CP_ACP, 0, pvip->pFilenameBuffer, cwch, ptszBuf, MAX_PATH, 0, 0);
/*
* The 11th (zero-based) character must be a backslash. * And the value of cwch had better be right. */ if(ptszBuf[cwch-1] == ('\0') && ptszBuf[11] == ('\\')) {
/*
* Wipe out the backslash and make sure the lead-in * is "\DosDevices". */ ptszBuf[11] = ('\0'); if(lstrcmpiA(ptszBuf, ("\\DosDevices")) == 0) { /*
* Create a "\\.\" at the start of the string. * Note! This code never runs on Alphas so we * can do evil unaligned data accesses. * * (Actually, 8 is a multiple of 4, so everything * is aligned after all.) */ *(LPDWORD)&ptszBuf[8] = 0x5C2E5C5C;
ptszRc = &ptszBuf[8]; } else { ptszRc = NULL; } } else { ptszRc = NULL; } } else { ptszRc = NULL; } } else { ptszRc = NULL; }
return ptszRc; }
/*****************************************************************************
* * @doc INTERNAL * * @func void | JoyReg_SetCalibration | * * Store information about a joystick's configuration, * shadowing the information back into the HID side of * things as well. * * @parm UINT | uiJoy | * * Joystick identification number. * * @parm LPJOYREGHWCONFIG | phwc | * * Contains information about the joystick capabilities. * This value supercedes the value in the <p pcfg>. * * @parm LPCDIJOYCONFIG | pcfg | * * Contains information about the joystick configuration. * The caller is assumed to have validated all fields. * *****************************************************************************/
STDMETHODIMP TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid, LPCTSTR ptszName, LPGUID pguidOut);
void EXTERNAL JoyReg_SetCalibration(UINT idJoy, LPJOYREGHWCONFIG phwc) { HRESULT hres; VXDINITPARMS vip; GUID guid; CHAR tsz[MAX_PATH]; LPSTR pszPath; TCHAR ptszPath[MAX_PATH]; EnterProc(JoyReg_SetCalibration, (_ "up", idJoy, phwc));
pszPath = JoyReg_JoyIdToDeviceInterface_95(idJoy, &vip, tsz);
if( pszPath ) #ifdef UNICODE
AToU( ptszPath, MAX_PATH, pszPath ); #else
lstrcpy( (LPSTR)ptszPath, pszPath ); #endif
if(pszPath && SUCCEEDED(CDIObj_FindDeviceInternal(ptszPath, &guid))) { IDirectInputDeviceCallback *pdcb; #ifdef DEBUG
CREATEDCB CreateDcb; #endif
#ifdef DEBUG
/*
* If the associated HID device got unplugged, then * the instance GUID is no more. So don't get upset * if we can't find it. But if we do find it, then * it had better be a HID device. * * CHid_New will properly fail if the associated * device is not around. */ hres = hresFindInstanceGUID(&guid, &CreateDcb, 1); AssertF(fLimpFF(SUCCEEDED(hres), CreateDcb == CHid_New)); #endif
if(SUCCEEDED(hres = CHid_New(0, &guid, &IID_IDirectInputDeviceCallback, (PPV)&pdcb))) { LPDIDATAFORMAT pdf;
/*
* The VXDINITPARAMS structure tells us where JOYHID * decided to place each of the axes. Follow that * table to put them into their corresponding location * in the HID side. */ hres = pdcb->lpVtbl->GetDataFormat(pdcb, &pdf); if(SUCCEEDED(hres)) { UINT uiAxis; DIPROPINFO propi;
propi.pguid = DIPROP_SPECIFICCALIBRATION;
/*
* For each axis... */ for(uiAxis = 0; uiAxis < 6; uiAxis++) { DWORD dwUsage = vip.Usages[uiAxis]; /*
* If the axis is mapped to a usage... */ if(dwUsage) { /*
* Convert the usage into an object index. */ hres = pdcb->lpVtbl->MapUsage(pdcb, dwUsage, &propi.iobj); if(SUCCEEDED(hres)) { DIPROPCAL cal;
/*
* Convert the old-style calibration into * a new-style calibration. */ #define CopyCalibration(f, ui) \
cal.l##f = (&phwc->hwv.jrvHardware.jp##f.dwX)[ui]
CopyCalibration(Min, uiAxis); CopyCalibration(Max, uiAxis); CopyCalibration(Center, uiAxis);
#undef CopyCalibration
/*
* Set the calibration property on the object. */ propi.dwDevType = pdf->rgodf[propi.iobj].dwType; hres = pdcb->lpVtbl->SetProperty(pdcb, &propi, &cal.diph); } } } }
Invoke_Release(&pdcb); } }
ExitProc(); }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_SetHWConfig | * * Store information about a joystick's <t JOYREGHWCONFIG>. * * @parm UINT | uiJoy | * * Joystick identification number. * * @parm LPJOYREGHWCONFIG | phwc | * * Contains information about the joystick capabilities. * This value supercedes the value in the <p pcfg>. * * @parm LPCDIJOYCONFIG | pcfg | * * Contains information about the joystick configuration. * The caller is assumed to have validated all fields. * * @parm HKEY | hk | * * The type key we are munging. * * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * *****************************************************************************/
HRESULT INTERNAL JoyReg_SetHWConfig(UINT idJoy, LPJOYREGHWCONFIG phwc, LPCDIJOYCONFIG pcfg, HKEY hk) { HRESULT hres; HKEY hkSave; DWORD dwSam;
/*
* The caller has set phwc->dwType, so use it to determine * where the data comes from or goes to. */ if( phwc->dwType == JOY_HW_NONE ) { /*
* Nothing to do */ } else if( phwc->dwType == JOY_HW_CUSTOM ) { /* ISSUE-2001/03/29-timgill Custom HWConfig not handled correctly
* We don't know the type name and the only time we can look * it up is when were modifying an existing config so although we * could store the config, we'd never be able to get it back. * Should return no better than S_FALSE. This will have to wait. */ } else { /*
* Try to access saved values */
// ISSUE-2001/03/29-timgill Dangerous type cast
PDWORD pdw = (PDWORD)&phwc->hwv;
dwSam = KEY_QUERY_VALUE;
while( pdw < &phwc->dwType ) { if( *pdw ) { /*
* Real config data so write it */ dwSam = KEY_SET_VALUE; break; } pdw++; }
/*
* If the device is autoloaded and yet the user is manually assigning it * to an ID, set the volatile flag. The flag will be set to the driver * defined value if a driver ever gets hotplug assigned to this ID but if * not, this makes sure that the settings are removed on next reboot. */ if(phwc->hws.dwFlags & JOY_HWS_AUTOLOAD) { phwc->dwUsageSettings |= JOY_US_VOLATILE; }
hres = JoyReg_OpenSaveKey( phwc->dwType, pcfg, dwSam, &hkSave );
if( SUCCEEDED(hres) ) { if( dwSam == KEY_SET_VALUE ) { hres = JoyReg_SetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY, phwc, cbX(*phwc)); if( FAILED(hres) ) { // Report the error but live with it
RPF("JoyReg_SetConfig: failed to set saved config %08x", hres ); } } else { JOYREGHWCONFIG hwc;
/*
* Read it into an extra buffer because we only want it * if it's complete. */ hres = JoyReg_GetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY, &hwc, cbX(hwc)); if( hres == S_OK ) { // Assert hws is first and no gap before dwUsageSettings
CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, hws ) == 0 ); CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, dwUsageSettings ) == sizeof( hwc.hws ) );
// Copy the whole structure except the hws
memcpy( &phwc->dwUsageSettings, &hwc.dwUsageSettings, sizeof( hwc ) - sizeof( hwc.hws ) ); } }
RegCloseKey( hkSave ); } /*
* If we failed to read, there's probably nothing there and the * structure is set up already for a blank config. * If we failed to write there probably not much we can do */ }
hres = JoyReg_SetConfigValue(hk, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY, phwc, cbX(*phwc)); if(FAILED(hres)) { goto done; }
if(phwc->dwUsageSettings & JOY_US_ISOEM) {
hres = JoyReg_SetConfigValue( hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ, pcfg->wszType, cbX(pcfg->wszType));
} else { hres = JoyReg_SetConfigValue( hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ, 0, 0); }
done:;
return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_SetConfig | * * Store information about a joystick's configuration. * * @parm UINT | uiJoy | * * Joystick identification number. * * @parm JOYREGHWCONFIG | phwc | * * Contains information about the joystick capabilities. * This value supercedes the value in the <p pcfg>. * It may be modified if we needed to load the config * info from the saved settings. * * @parm LPCDIJOYCONFIG | pcfg | * * Contains information about the joystick configuration. * The caller is assumed to have validated all fields. * * @parm DWORD | fl | * * Zero or more <c DIJC_*> flags * which specify which parts of the structures pointed * to by <p phwc> and <p pjc> are to be written out. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * *****************************************************************************/
JOYREGHWVALUES null_hwv = { 0};
STDMETHODIMP JoyReg_SetConfig(UINT idJoy, LPJOYREGHWCONFIG phwc, LPCDIJOYCONFIG pcfg, DWORD fl) { HRESULT hres; EnterProc(JoyReg_SetConfig, (_ "uppx", idJoy, phwc, pcfg, fl));
AssertF((fl & ~DIJC_INTERNALSETVALID) == 0);
if(idJoy < cJoyMax ) {
if(fl & DIJC_INREGISTRY) { HKEY hk; DWORD dwOptions = 0;
hres = JoyReg_OpenConfigKey(idJoy, KEY_SET_VALUE, NULL, dwOptions, &hk);
if(SUCCEEDED(hres)) {
if(fl & DIJC_REGHWCONFIGTYPE) { hres = JoyReg_SetHWConfig(idJoy, phwc, pcfg, hk);
if(FAILED(hres)) { goto closedone; }
if(fl & DIJC_UPDATEALIAS) { JoyReg_SetCalibration(idJoy, phwc); }
}
if(fl & DIJC_CALLOUT) { hres = JoyReg_SetConfigValue( hk, REGSTR_VAL_JOYNOEMCALLOUT, idJoy, REG_SZ, pcfg->wszCallout, cbX(pcfg->wszCallout)); if(FAILED(hres)) { hres = S_FALSE; //continue to go
} }
if(fl & DIJC_GAIN) { if(ISVALIDGAIN(pcfg->dwGain)) {
/*
* If restoring to nominal, then the key * can be deleted; the default value will * be assumed subsequently. */ if(pcfg->dwGain == DI_FFNOMINALMAX) { hres = JoyReg_SetConfigValue(hk, TEXT("Joystick%dFFConfiguration"), idJoy, REG_SZ, 0, 0); } else { hres = JoyReg_SetConfigValue(hk, TEXT("Joystick%dFFConfiguration"), idJoy, REG_BINARY, &pcfg->dwGain, cbX(pcfg->dwGain)); }
if(FAILED(hres)) { hres = S_FALSE; goto closedone; } } else { RPF("ERROR: SetConfig: Invalid dwGain"); hres = E_INVALIDARG; goto closedone; } }
hres = S_OK;
closedone:; RegCloseKey(hk); } } else { hres = S_OK; }
} else { hres = E_FAIL; }
ExitOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func int | ibJoyPosAxis | * * Returns the offset of the <p iAxis>'th joystick axis * in the <t JOYPOS> structure. * * @parm int | iAxis | * * The index of the requested axis. X, Y, Z, R, U and V are * respctively zero through five. * * @returns * * The offset relative to the structure. * *****************************************************************************/
#define ibJoyPosAxis(iAxis) \
(FIELD_OFFSET(JOYPOS, dwX) + cbX(DWORD) * (iAxis)) \
#define pJoyValue(jp, i) \
(LPDWORD)pvAddPvCb(&(jp), ibJoyPosAxis(i)) \
/*
* The following doesn't do anything at runtime. It is a compile-time * check that everything is okay. */ void INLINE JoyReg_CheckJoyPosAxis(void) { #define CheckAxis(x) \
CAssertF(ibJoyPosAxis(iJoyPosAxis##x) == FIELD_OFFSET(JOYPOS, dw##x))
CheckAxis(X); CheckAxis(Y); CheckAxis(Z); CheckAxis(R); CheckAxis(U); CheckAxis(V);
#undef CheckAxis
}
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_IsValidUserValues | * * Retermine whether the values are ostensibly valid. * * @parm IN LPCDIJOYUSERVALUES | pjuv | * * Contains information about the user joystick configuration. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: * Something looks bad. * *****************************************************************************/
STDMETHODIMP JoyReg_IsValidUserValues(LPCDIJOYUSERVALUES pjuv) { HRESULT hres; int iAxis;
/*
* First set up the values to values that are out of range so * that we will fall back to defaults. */ for(iAxis = 0; iAxis < cJoyPosAxisMax; iAxis++) { if((int)*pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis) < 0) { RPF("JOYUSERVALUES: Negative jpMax not a good idea"); goto bad; } if(*pJoyValue(pjuv->ruv.jrvRanges.jpMin, iAxis) > *pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis)) { RPF("JOYUSERVALUES: Min > Max not a good idea"); goto bad; }
if(!fInOrder(0, *pJoyValue(pjuv->ruv.jpDeadZone, iAxis), 100)) { RPF("JOYUSERVALUES: DeadZone > 100 not a good idea"); goto bad; } }
hres = S_OK;
return hres;
bad:; hres = E_INVALIDARG; return hres;
}
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_GetUserValues | * * Obtain information about user settings for the joystick. * * * @parm IN OUT LPDIJOYUSERVALUES | pjuv | * * Receives information about the user joystick configuration. * The caller is assumed to have validated the * <e DIJOYUSERVALUES.dwSize> field. * * @parm DWORD | fl | * * Zero or more <c DIJU_*> flags specifying which parts * of the <t DIJOYUSERVALUES> structure contain values * which are to be retrieved. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more * parameters was invalid. * *****************************************************************************/
STDMETHODIMP JoyReg_GetUserValues(LPDIJOYUSERVALUES pjuv, DWORD fl) { HRESULT hres; HKEY hk; LONG lRc; EnterProc(JoyReg_GetUserValues, (_ "px", pjuv, fl));
hres = S_OK; /* If nothing happens, then success */
if(fl & DIJU_USERVALUES) {
/*
* Okay, now get the user settings. * * If anything goes wrong, then just limp with the default values. */ lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, 0, KEY_QUERY_VALUE, &hk); if(lRc == ERROR_SUCCESS) {
hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYUSERVALUES, REG_BINARY, &pjuv->ruv, cbX(pjuv->ruv)); if(SUCCEEDED(hres)) { /*
* Sanity-check the values. If anything is screwy, * then fall back to the defaults. */ hres = JoyReg_IsValidUserValues(pjuv);
}
if(FAILED(hres)) { /*
* Oh well. Just use the default values, then. * * Stolen from ibmjoy\msjstick.c. */ ZeroMemory(&pjuv->ruv, cbX(pjuv->ruv));
#define DEFAULT_RANGE_MAX 65535
#define DEFAULT_TIMEOUT 5000
#define DEFAULT_DEADZONE 5
pjuv->ruv.jrvRanges.jpMax.dwX = DEFAULT_RANGE_MAX; pjuv->ruv.jrvRanges.jpMax.dwY = DEFAULT_RANGE_MAX; pjuv->ruv.jrvRanges.jpMax.dwZ = DEFAULT_RANGE_MAX; pjuv->ruv.jrvRanges.jpMax.dwR = DEFAULT_RANGE_MAX; pjuv->ruv.jrvRanges.jpMax.dwU = DEFAULT_RANGE_MAX; pjuv->ruv.jrvRanges.jpMax.dwV = DEFAULT_RANGE_MAX; pjuv->ruv.jpDeadZone.dwX = DEFAULT_DEADZONE; pjuv->ruv.jpDeadZone.dwY = DEFAULT_DEADZONE; pjuv->ruv.dwTimeOut = DEFAULT_TIMEOUT; }
RegCloseKey(hk); } }
if(fl & DIJU_INDRIVERREGISTRY) { hres = JoyReg_OpenConfigKey((UINT)-1, KEY_QUERY_VALUE, NULL, FALSE, &hk);
if(SUCCEEDED(hres)) {
if(fl & DIJU_GLOBALDRIVER) {
LONG lRc;
/*
* If it doesn't work, then return the default value * of "MSANALOG.VXD". We can't blindly use * JoyReg_GetValue, because that treats a nonexistent * value as having a default of the null string. */ lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT, 0, 0, 0, 0); if((lRc == ERROR_SUCCESS || lRc == ERROR_MORE_DATA) && SUCCEEDED( hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ, pjuv->wszGlobalDriver, cbX(pjuv->wszGlobalDriver)))) { /* Yay, it worked */ } else { CopyMemory(pjuv->wszGlobalDriver, c_wszDefPortDriver, cbX(c_wszDefPortDriver)); }
}
if(fl & DIJU_GAMEPORTEMULATOR) {
/*
* If it doesn't work, then just return a null string. */ hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR, REG_SZ, pjuv->wszGameportEmulator, cbX(pjuv->wszGameportEmulator)); if(FAILED(hres)) { pjuv->wszGameportEmulator[0] = TEXT('\0'); }
}
RegCloseKey(hk); }
}
/*
* Warning! CJoy_InitRanges() assumes this never fails. */ hres = S_OK;
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_SetUserValues | * * Store information about user settings for the joystick. * * * @parm IN LPCDIJOYUSERVALUES | pjuv | * * Contains information about the user joystick configuration. * The caller is assumed to have validated the * <e DIJOYUSERVALUES.dwSize> field. * * @parm DWORD | fl | * * Zero or more <c DIJU_*> flags specifying which parts * of the <t DIJOYUSERVALUES> structure contain values * which are to be set. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more * parameters was invalid. * *****************************************************************************/
STDMETHODIMP JoyReg_SetUserValues(LPCDIJOYUSERVALUES pjuv, DWORD fl) { HRESULT hres = E_FAIL; HKEY hk; EnterProc(JoyReg_SetUserValues, (_ "px", pjuv, fl));
if(fl & DIJU_USERVALUES) {
/*
* See if the values are sane. */ if(fl & DIJU_USERVALUES) { hres = JoyReg_IsValidUserValues(pjuv); if(FAILED(hres)) { goto done; } }
/*
* Off to the registry we go. */
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, DI_KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hk);
if(SUCCEEDED(hres)) {
hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYUSERVALUES, REG_BINARY, &pjuv->ruv, cbX(pjuv->ruv)); RegCloseKey(hk);
if(FAILED(hres)) { goto done; } } else { goto done; } }
if(fl & DIJU_INDRIVERREGISTRY) {
hres = JoyReg_OpenConfigKey((UINT)-1, KEY_SET_VALUE, NULL, FALSE, &hk);
if(SUCCEEDED(hres)) {
if(fl & DIJU_GLOBALDRIVER) { /*
* This is a weird key. The default value is * "MSANALOG.VXD", so if we get a null string, we * can't use JoyReg_SetValue, because that will * delete the key. */ if(pjuv->wszGlobalDriver[0]) { hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ, pjuv->wszGlobalDriver, cbX(pjuv->wszGlobalDriver)); } else { LONG lRc; lRc = RegSetValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT, 0, REG_SZ, (PV)TEXT(""), cbCtch(1)); if(lRc == ERROR_SUCCESS) { hres = S_OK; } else { RPF("Unable to write %s to registry", REGSTR_VAL_JOYOEMCALLOUT); hres = E_FAIL; /* Else, something bad happened */ } } if(FAILED(hres)) { goto regdone; } }
if(fl & DIJU_GAMEPORTEMULATOR) {
hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR, REG_SZ, pjuv->wszGameportEmulator, cbX(pjuv->wszGameportEmulator)); if(FAILED(hres)) { goto regdone; } }
regdone:; RegCloseKey(hk);
} else { goto done; } }
done:; ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyReg_OpenFFKey | * * Given a type key, move to its force feedback subkey. * * @parm HKEY | hkType | * * The parent type key. * * @parm REGSAM | sam | * * Access level desired. * * @parm PHKEY | phk | * * Receives created registry key. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: Couldn't open the key. * *****************************************************************************/
STDMETHODIMP JoyReg_OpenFFKey(HKEY hkType, REGSAM sam, PHKEY phk) { HRESULT hres; EnterProc(JoyReg_OpenFFKey, (_ "xx", hkType, sam));
*phk = 0;
if(hkType) { if(RegOpenKeyEx(hkType, TEXT("OEMForceFeedback"), 0, sam, phk) == 0) { hres = S_OK; } else { hres = E_FAIL; } } else { hres = DIERR_NOTFOUND; }
ExitBenignOleProc(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @func TCHAR | CJoyCfg_CharFromType | * * Convert a predefined type number to a character. * * @func UINT | CJoyCfg_TypeFromChar | * * Convert a character back to a predefined type number. * *****************************************************************************/
#define JoyCfg_CharFromType(t) ((TCHAR)(L'0' + t))
#define JoyCfg_TypeFromChar(tch) ((tch) - L'0')
/*****************************************************************************
* * @doc EXTERNAL * * @func HRESULT | JoyReg_GetPredefTypeInfo | * * Obtain information about a predefined joystick type. * * @parm LPCWSTR | pwszType | * * Points to the name of the type. It is known to begin * with a "#". The remainder has not yet been parsed. * * @parm IN OUT LPDIJOYTYPEINFO | pjti | * * Receives information about the joystick type, * already validated. * * @parm DWORD | dwFlags | * * Zero or more <c DITC_*> flags * which specify which parts of the structure pointed * to by <p pjti> are to be filled in. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_NOTFOUND>: The joystick type was not found. * *****************************************************************************/
HRESULT EXTERNAL JoyReg_GetPredefTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl) { HRESULT hres; UINT itype; EnterProcI(JoyReg_GetPredefTypeInfo, (_ "Wpx", pwszType, pjti, fl));
//(MarcAnd) These TEXT('blah') things should be L'blah' as the string is always wide
AssertF(pwszType[0] == TEXT('#'));
itype = JoyCfg_TypeFromChar(pwszType[1]);
if(fInOrder(JOY_HW_PREDEFMIN, itype, JOY_HW_PREDEFMAX) && pwszType[2] == TEXT('\0')) { /*
* No real point in checking the bits in fl, since * setting it up is so easy. */ pjti->hws = c_rghwsPredef[itype - JOY_HW_PREDEFMIN]; LoadStringW(g_hinst, IDS_PREDEFJOYTYPE + itype, pjti->wszDisplayName, cA(pjti->wszDisplayName)); pjti->wszCallout[0] = TEXT('\0'); ZeroX(pjti->clsidConfig);
if(fl & DITC_FLAGS1 ) { pjti->dwFlags1 = 0x0; }
if( fl & DITC_HARDWAREID ) { lstrcpyW(pjti->wszHardwareId, c_rghwIdPredef[itype-JOY_HW_PREDEFMIN] ); }
hres = S_OK; } else { hres = DIERR_NOTFOUND; }
ExitOleProc(); return hres; }
#if 0 //don't delete it now.
/*****************************************************************************
* * @doc INTERNAL * * @func HRESULT | JoyCfg_GetIDByOemName | * * Get the Id by OEMNAME * * @parm IN LPTSTR | szOEMNAME | * * String used to find the ID. * * @parm IN LPUNIT | lpID | * * The ID to get. * * @returns * * A COM success code unless the current configuration key could not * be opened, or could not find the OEMNAME. * *****************************************************************************/
HRESULT EXTERNAL JoyReg_GetIDByOemName( LPTSTR szOemName, PUINT pId ) { HRESULT hres = E_FAIL; LONG lRc; HKEY hkCurrCfg; UINT JoyId; TCHAR szTestName[MAX_JOYSTRING]; TCHAR szOemNameKey[MAX_JOYSTRING]; DWORD cb;
EnterProcI(JoyReg_GetIDByOemName, (_ "sp", szOemName, pId ));
hres = JoyReg_OpenConfigKey( (UINT)(-1), KEY_WRITE, NULL, REG_OPTION_NON_VOLATILE, &hkCurrCfg );
if( SUCCEEDED( hres ) ) { for( JoyId = 0; (JoyId < 16) || ( lRc == ERROR_SUCCESS ); JoyId++ ) { wsprintf( szOemNameKey, REGSTR_VAL_JOYNOEMNAME, JoyId+1 ); cb = sizeof( szTestName ); lRc = RegQueryValueEx( hkCurrCfg, szOemNameKey, 0, NULL, (PBYTE)szTestName, &cb ); if( lRc == ERROR_SUCCESS ) { if( !lstrcmpi( szOemName, szTestName ) ) { *pId = JoyId; pId ++; hres = S_OK; break; } } }
} else { SquirtSqflPtszV(sqfl | sqflError, TEXT("JoyReg_OpenConfigKey failed code 0x%08x"), hres ); }
ExitOleProc();
return hres;
} /* JoyReg_GetIDByOemName */ #endif
|