3040 lines
88 KiB
C
3040 lines
88 KiB
C
/*****************************************************************************
|
|
*
|
|
* 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";
|
|
|
|
#ifdef WINNT
|
|
#define REGSTR_SZREGKEY TEXT("\\DINPUT.DLL\\")
|
|
#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @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;
|
|
|
|
}
|
|
|
|
#ifndef WINNT
|
|
/*****************************************************************************
|
|
*
|
|
* @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;
|
|
}
|
|
#endif /* ndef WINNT */
|
|
|
|
|
|
#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 S_FALSE> if some of the data was not available.
|
|
*
|
|
* <c DIERR_NOTFOUND>: The joystick type was not found.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
STDMETHODIMP
|
|
JoyReg_GetTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl)
|
|
{
|
|
HRESULT hres = S_FALSE;
|
|
HKEY hk;
|
|
BOOL fPartialData = FALSE;
|
|
EnterProc(JoyReg_GetTypeInfo, (_ "Wx", pwszType, fl));
|
|
|
|
|
|
ZeroX(pjti->clsidConfig);
|
|
|
|
if( fl & ( DITC_FLAGS2 | DITC_MAPFILE ) )
|
|
{
|
|
/*
|
|
* The new registry branch is likely to be empty for many devices
|
|
* so don't fail for anything here.
|
|
*/
|
|
|
|
hres = JoyReg_OpenPropKey(pwszType, KEY_QUERY_VALUE, REG_OPTION_NON_VOLATILE, &hk);
|
|
|
|
if( SUCCEEDED( hres ) )
|
|
{
|
|
if( fl & DITC_FLAGS2 )
|
|
{
|
|
hres = JoyReg_GetValue(hk,
|
|
REGSTR_VAL_FLAGS2, REG_BINARY,
|
|
&pjti->dwFlags2,
|
|
cbX(pjti->dwFlags2) );
|
|
|
|
pjti->dwFlags2 &= JOYTYPE_FLAGS2_GETVALID;
|
|
|
|
if( FAILED( hres ) )
|
|
{
|
|
pjti->dwFlags2 = 0x0;
|
|
fPartialData = TRUE;
|
|
}
|
|
}
|
|
|
|
if( fl & DITC_MAPFILE )
|
|
{
|
|
hres = JoyReg_GetValue(hk,
|
|
REGSTR_VAL_JOYOEMMAPFILE, REG_SZ,
|
|
pjti->wszMapFile,
|
|
cbX(pjti->wszMapFile));
|
|
if( FAILED( hres ) )
|
|
{
|
|
ZeroX(pjti->wszMapFile);
|
|
fPartialData = TRUE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hk);
|
|
}
|
|
else
|
|
{
|
|
pjti->dwFlags2 = 0x0;
|
|
ZeroX(pjti->wszMapFile);
|
|
fPartialData = TRUE;
|
|
}
|
|
|
|
hres = S_OK;
|
|
}
|
|
|
|
if( fl & DITC_INREGISTRY_DX6 )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
#ifndef WINNT
|
|
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;
|
|
fPartialData = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
fPartialData = TRUE;
|
|
}
|
|
}
|
|
|
|
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;
|
|
fPartialData = TRUE;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
if( SUCCEEDED( hres ) && fPartialData )
|
|
{
|
|
hres = S_FALSE;
|
|
}
|
|
|
|
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 = S_OK; /* Vacuous success in case of no flags set */
|
|
ULONG lRc;
|
|
EnterProc(JoyRegSetTypeInfo, (_ "Wx", pwszType, fl));
|
|
|
|
if( fl & ( DITC_FLAGS2 | DITC_MAPFILE ) )
|
|
{
|
|
HKEY hkProp;
|
|
|
|
hres = JoyReg_OpenPropKey(pwszType, DI_KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &hkProp);
|
|
|
|
if( SUCCEEDED( hres ) )
|
|
{
|
|
if( fl & DITC_FLAGS2 )
|
|
{
|
|
DWORD dwTemp;
|
|
LONG lRc;
|
|
|
|
/*
|
|
* Read and merge any current value so that bits unused in
|
|
* DX8 can be preserved. Although this is more work now it
|
|
* should save adding Flags3 support next time.
|
|
*/
|
|
AssertF( (pjti->dwFlags2 & ~JOYTYPE_FLAGS2_SETVALID) == 0x0 );
|
|
|
|
/*
|
|
* PREFIX warns (259898) that RegQueryValueEx reads the value
|
|
* of dwTemp before it is set but then it checks lpData and
|
|
* zeroes the value before it is used.
|
|
*/
|
|
lRc = RegQueryValueEx( hkProp, REGSTR_VAL_FLAGS2, 0, 0, 0, &dwTemp );
|
|
|
|
if( lRc == ERROR_FILE_NOT_FOUND )
|
|
{
|
|
lRc = ERROR_SUCCESS;
|
|
dwTemp = cbX( pjti->dwFlags2 );
|
|
}
|
|
|
|
if( lRc == ERROR_SUCCESS )
|
|
{
|
|
if( dwTemp <= cbX( pjti->dwFlags2 ) )
|
|
{
|
|
CAssertF( cbX( dwTemp ) == cbX( pjti->dwFlags2 ) );
|
|
JoyReg_GetValue( hkProp, REGSTR_VAL_FLAGS2,
|
|
REG_BINARY, &dwTemp, cbX( dwTemp ) );
|
|
|
|
dwTemp &= ~JOYTYPE_FLAGS2_SETVALID;
|
|
dwTemp |= pjti->dwFlags2;
|
|
|
|
if( dwTemp )
|
|
{
|
|
hres = JoyReg_SetValue( hkProp, REGSTR_VAL_FLAGS2,
|
|
REG_BINARY, (PV)&dwTemp, cbX( dwTemp ) );
|
|
} else
|
|
{
|
|
lRc = RegDeleteValue( hkProp, REGSTR_VAL_FLAGS2 );
|
|
if (lRc == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
lRc = ERROR_SUCCESS;
|
|
}
|
|
hres = hresLe( lRc );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Need to double buffer for the extra bytes
|
|
*/
|
|
PBYTE pbFlags2;
|
|
|
|
hres = AllocCbPpv( dwTemp, &pbFlags2 );
|
|
if( SUCCEEDED( hres ) )
|
|
{
|
|
if ( ERROR_SUCCESS == RegQueryValueEx(
|
|
hkProp, REGSTR_VAL_FLAGS2, 0, NULL, pbFlags2, &dwTemp ) )
|
|
{
|
|
CAssertF( JOYTYPE_FLAGS2_SETVALID == JOYTYPE_FLAGS2_GETVALID );
|
|
*(PDWORD)pbFlags2 &= ~JOYTYPE_FLAGS2_SETVALID;
|
|
*(PDWORD)pbFlags2 |= pjti->dwFlags2;
|
|
|
|
if ( ERROR_SUCCESS == RegSetValueEx(
|
|
hkProp, REGSTR_VAL_FLAGS2, 0, REG_BINARY, pbFlags2, dwTemp ) )
|
|
{
|
|
hres = S_OK;
|
|
} else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT( "IDIJC::SetTypeInfo: failed to write extended Flags2" ) );
|
|
hres = E_FAIL;
|
|
}
|
|
} else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT( "IDIJC::SetTypeInfo: failed to read extended Flags2" ) );
|
|
hres = E_FAIL; /* Else, something bad happened */
|
|
}
|
|
FreePv( pbFlags2 );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT( "IDIJC::SetTypeInfo: failed to read size of Flags2, error %d" ), lRc );
|
|
hres = hresLe( lRc );
|
|
}
|
|
|
|
if( FAILED( hres ) )
|
|
{
|
|
hres = S_FALSE;
|
|
goto closedoneprop;
|
|
}
|
|
}
|
|
|
|
if( fl & DITC_MAPFILE )
|
|
{
|
|
hres = JoyReg_SetValue(hkProp,
|
|
REGSTR_VAL_JOYOEMMAPFILE, REG_SZ,
|
|
pjti->wszMapFile,
|
|
cbX(pjti->wszMapFile));
|
|
if( FAILED(hres) )
|
|
{
|
|
hres = S_FALSE;
|
|
goto closedoneprop;
|
|
}
|
|
}
|
|
|
|
hres = S_OK;
|
|
closedoneprop:;
|
|
|
|
RegCloseKey(hkProp);
|
|
}
|
|
else
|
|
{
|
|
RPF( "Failed to open DirectInput type property key" );
|
|
}
|
|
}
|
|
|
|
if( hres == S_OK )
|
|
{
|
|
if( fl & DITC_INREGISTRY_DX6 )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
#ifndef WINNT
|
|
/* 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
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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 */
|
|
}
|
|
}
|
|
}
|
|
|
|
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 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, DWORD dwOptions, PHKEY phk)
|
|
{
|
|
HRESULT hres;
|
|
EnterProc(JoyReg_OpenConfigKey, (_ "uxx", idJoy, sam, dwOptions));
|
|
|
|
#ifdef WINNT
|
|
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_JOYCONFIG REGSTR_SZREGKEY REGSTR_KEY_JOYCURR,
|
|
sam, REG_OPTION_VOLATILE, phk);
|
|
#else
|
|
|
|
{
|
|
MMRESULT mmrc = MMSYSERR_ERROR;
|
|
JOYCAPS caps;
|
|
/*
|
|
* If we can't get the dev caps for the specified joystick,
|
|
* then use the magic joystick id "-1" to get non-specific
|
|
* caps.
|
|
*/
|
|
mmrc = joyGetDevCaps(idJoy, &caps, cbX(caps));
|
|
if ( mmrc != JOYERR_NOERROR )
|
|
{
|
|
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_JOYCURR) + 1];
|
|
|
|
/* tsz = MediaResources\Joystick\<drv>\CurrentJoystickSettings */
|
|
wsprintf(tsz, TEXT("%s\\%s\\") REGSTR_KEY_JOYCURR,
|
|
REGSTR_PATH_JOYCONFIG, caps.szRegKey);
|
|
|
|
|
|
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tsz, sam, REG_OPTION_VOLATILE, phk);
|
|
|
|
} else
|
|
{
|
|
hres = E_FAIL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
JOYCAPS caps;
|
|
DWORD dwOptions = 0;
|
|
EnterProc(JoyReg_OpenSaveKey, (_ "upx", dwType, pcfg, sam));
|
|
|
|
|
|
#ifdef WINNT
|
|
lstrcpy(caps.szRegKey, REGSTR_SZREGKEY );
|
|
#else
|
|
|
|
/*
|
|
* use the magic joystick id "-1" to get non-specific caps.
|
|
*/
|
|
|
|
if ( joyGetDevCaps((DWORD)-1, &caps, cbX(caps)) != JOYERR_NOERROR )
|
|
{
|
|
hres = E_FAIL;
|
|
} else
|
|
#endif
|
|
{
|
|
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);
|
|
|
|
}
|
|
|
|
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 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, LPDIJOYCONFIG pcfg, DWORD fl)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
EnterProc(JoyReg_GetConfigInternal, (_ "upx", idJoy, 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);
|
|
|
|
#ifndef WINNT
|
|
if ( FAILED(hres) )
|
|
{
|
|
hres = hResIdJoypInstanceGUID_95(idJoy, &pcfg->guidInstance);
|
|
}
|
|
#endif
|
|
|
|
if ( FAILED(hres) )
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ( fl & DIJC_INREGISTRY )
|
|
{
|
|
HKEY hk;
|
|
/* Does the registry entry exist ? */
|
|
hres = JoyReg_OpenConfigKey(idJoy, KEY_QUERY_VALUE, 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)
|
|
#ifndef WINNT
|
|
||( (pcfg->hwc.dwType >= JOY_HW_PREDEFMIN)
|
|
&&(pcfg->hwc.dwType < JOY_HW_PREDEFMAX) )
|
|
#endif
|
|
)
|
|
{
|
|
hres = JoyReg_GetConfigValue(
|
|
hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
|
|
pcfg->wszType, cbX(pcfg->wszType));
|
|
if (FAILED(hres))
|
|
{
|
|
goto closedone;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef WINNT
|
|
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 */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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 *naive* MSGAME.VXD driver into account.
|
|
*
|
|
* @parm UINT | uiJoy |
|
|
*
|
|
* Joystick identification number.
|
|
*
|
|
* @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, LPDIJOYCONFIG pcfg, DWORD fl)
|
|
{
|
|
HRESULT hres;
|
|
GUID guid;
|
|
|
|
EnterProc(JoyReg_GetConfig, (_ "upx", idJoy, 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);
|
|
|
|
#ifndef WINNT
|
|
if ( FAILED(hres) )
|
|
{
|
|
hres = hResIdJoypInstanceGUID_95(idJoy, &guid);
|
|
}
|
|
#endif
|
|
|
|
if ( SUCCEEDED( hres) )
|
|
{
|
|
|
|
hres = JoyReg_GetConfigInternal(idJoy, pcfg, fl);
|
|
|
|
#ifndef WINNT
|
|
/***************************************************
|
|
*
|
|
* Beginning of hack for *naive* Sidewinder Gamepad.
|
|
*
|
|
* The gamepad needs to be polled sixteen 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)
|
|
{
|
|
SquirtSqflPtszV(sqfl,
|
|
TEXT("Making bonus polls for Sidewinder"));
|
|
|
|
/*
|
|
* Sigh. It's a Sidewinder. Make sixteen
|
|
* bonus polls to shake the stick into submission.
|
|
*
|
|
* There's no point in doing this over and over if we're
|
|
* in some kind of loop so make sure a "reasonable"
|
|
* length of time has passed since last time we tried.
|
|
* 3 seconds is a little less than the current CPL
|
|
* background refresh rate.
|
|
*/
|
|
|
|
if ( !g_dwLastBonusPoll || ( GetTickCount() - g_dwLastBonusPoll > 3000 ) )
|
|
{
|
|
JOYINFOEX ji;
|
|
int i;
|
|
DWORD dwWait;
|
|
|
|
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 10ms between each poll because that
|
|
* seems to help a bit.
|
|
*/
|
|
Sleep(10);
|
|
}
|
|
|
|
/*
|
|
* Bonus hack! Now sleep for some time.
|
|
* 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 shame.
|
|
*/
|
|
dwWait = RegQueryDIDword(NULL, REGSTR_VAL_GAMEPADDELAY, 100);
|
|
if (dwWait > 10 * 1000)
|
|
{
|
|
dwWait = 10 * 1000;
|
|
}
|
|
|
|
Sleep(dwWait);
|
|
|
|
/*
|
|
* And then check again.
|
|
*/
|
|
hres = JoyReg_GetConfigInternal(idJoy, pcfg, fl);
|
|
|
|
g_dwLastBonusPoll = GetTickCount();
|
|
}
|
|
}
|
|
|
|
}
|
|
/***************************************************
|
|
*
|
|
* End of hack for *naive* Sidewinder Gamepad.
|
|
*
|
|
***************************************************/
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
#ifndef WINNT
|
|
/*****************************************************************************
|
|
*
|
|
* @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;
|
|
|
|
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();
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @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, dwOptions, &hk);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
|
|
if (fl & DIJC_REGHWCONFIGTYPE)
|
|
{
|
|
hres = JoyReg_SetHWConfig(idJoy, phwc, pcfg, hk);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
goto closedone;
|
|
}
|
|
|
|
#ifndef WINNT
|
|
if (fl & DIJC_UPDATEALIAS)
|
|
{
|
|
JoyReg_SetCalibration(idJoy, phwc);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef WINNT
|
|
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
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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, 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, 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));
|
|
|
|
AssertF(pwszType[0] == L'#');
|
|
|
|
itype = JoyCfg_TypeFromChar(pwszType[1]);
|
|
|
|
if (fInOrder(JOY_HW_PREDEFMIN, itype, JOY_HW_PREDEFMAX) &&
|
|
pwszType[2] == L'\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] = L'\0';
|
|
|
|
ZeroX(pjti->clsidConfig);
|
|
|
|
pjti->dwFlags1 = 0x0;
|
|
|
|
if ( fl & DITC_HARDWAREID )
|
|
{
|
|
lstrcpyW(pjti->wszHardwareId, c_rghwIdPredef[itype-JOY_HW_PREDEFMIN] );
|
|
}
|
|
|
|
pjti->dwFlags2 = 0x0;
|
|
|
|
pjti->wszMapFile[0] = L'\0';
|
|
|
|
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, 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
|
|
|