1112 lines
33 KiB
C
1112 lines
33 KiB
C
/*****************************************************************************
|
|
*
|
|
* DIWdm.c
|
|
*
|
|
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* Abstract:
|
|
*
|
|
* WINNT specific functions.
|
|
*
|
|
* Contents:
|
|
*
|
|
* hResIdJoyInstanceGUID
|
|
* DIWdm_SetLegacyConfig
|
|
* DIWdm_InitJoyId
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "dinputpr.h"
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* The sqiffle for this file.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#define sqfl sqflWDM
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func HRESULT | DIWdm_SetJoyId |
|
|
* Given a guid for a HID device and a Joystick ID.
|
|
* This function will swap the old joystick ID for the device
|
|
* specified by the guid ( pcguid ) for the new ID specified in
|
|
* idJoy
|
|
*
|
|
* @parm IN UINT | idJoy |
|
|
*
|
|
* The Joyid the the HID device specified by pcguid should have.
|
|
*
|
|
* @parm OUT LPGUID | pcguid |
|
|
*
|
|
* GUID that specifies a HID device.
|
|
*
|
|
* @returns
|
|
* HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
HRESULT EXTERNAL
|
|
DIWdm_SetJoyId
|
|
(
|
|
IN PCGUID pcguid,
|
|
IN int idJoy
|
|
)
|
|
{
|
|
PHIDDEVICEINFO phdi;
|
|
HRESULT hres;
|
|
BOOL fConfigChanged = FALSE;
|
|
|
|
EnterProcI(DIWdm_SetJoyId, (_"Gu", pcguid, idJoy));
|
|
|
|
//PostDx7 patch:
|
|
// No point setting the joystick entries in the registry
|
|
// if the ID of the joystick is -1.
|
|
if( idJoy == -1 )
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
DllEnterCrit();
|
|
|
|
hres = S_OK;
|
|
|
|
/* Get pointer to HIDDEVICEINFO from the GUID */
|
|
phdi = phdiFindHIDInstanceGUID(pcguid);
|
|
if(phdi != NULL )
|
|
{
|
|
PHIDDEVICEINFO phdiSwap = NULL;
|
|
GUID guidInstanceOld;
|
|
LONG lRc;
|
|
int idJoySwap;
|
|
|
|
/* Swap the ID's */
|
|
idJoySwap = phdi->idJoy;
|
|
phdi->idJoy = idJoy;
|
|
|
|
phdiSwap = NULL;
|
|
/* Get the GUID for the old ID */
|
|
if( SUCCEEDED( hres = hResIdJoypInstanceGUID_WDM(idJoySwap, &guidInstanceOld)) )
|
|
{
|
|
/* Get pointer to HIDDEVICEINFO for old ID */
|
|
phdiSwap = phdiFindHIDInstanceGUID(&guidInstanceOld);
|
|
if( phdiSwap )
|
|
{
|
|
phdiSwap->idJoy = idJoySwap;
|
|
} else
|
|
{
|
|
// Old device disappeared !
|
|
}
|
|
|
|
} else
|
|
{
|
|
DIJOYCONFIG c_djcReset = {
|
|
cbX(c_djcReset), /* dwSize */
|
|
{ 0}, /* guidInstance */
|
|
{ 0}, /* hwc */
|
|
DI_FFNOMINALMAX, /* dwGain */
|
|
{ 0}, /* wszType */
|
|
{ 0}, /* wszCallout */
|
|
};
|
|
|
|
hres = JoyReg_SetConfig(idJoySwap, &c_djcReset.hwc,&c_djcReset, DIJC_SETVALID) ;
|
|
if( FAILED(hres) )
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: JoyReg_SetConfig to NULL FAILED "),
|
|
s_szProc );
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the new ID and LegacyConfig */
|
|
if( phdi )
|
|
{
|
|
if( lRc = RegSetValueEx(phdi->hk, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoy, cbX(idJoy)) == ERROR_SUCCESS )
|
|
{
|
|
/*
|
|
* This extra RegSetValueEx on "Joystick Id" is to keep the
|
|
* compatibility with Win2k Gold.
|
|
* See Windows bug 395416 for detail.
|
|
*/
|
|
RegSetValueEx(phdi->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoy, cbX(idJoy));
|
|
|
|
if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoy)) )
|
|
{
|
|
fConfigChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set old ID and legacy Config */
|
|
if( (phdiSwap != NULL) && (phdiSwap != phdi) )
|
|
{
|
|
if( lRc = RegSetValueEx(phdiSwap->hk, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoySwap, cbX(idJoySwap)) == ERROR_SUCCESS )
|
|
{
|
|
/*
|
|
* This extra RegSetValueEx on "Joystick Id" is to keep the
|
|
* compatibility with Win2k Gold.
|
|
* See Windows bug 395416 for detail.
|
|
*/
|
|
RegSetValueEx(phdiSwap->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoySwap, cbX(idJoySwap));
|
|
|
|
if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoySwap) ) )
|
|
{
|
|
fConfigChanged = TRUE;
|
|
}
|
|
}
|
|
} else if( phdiSwap == NULL )
|
|
{
|
|
// Old Device disappeared !
|
|
if( SUCCEEDED( hres = DIWdm_SetLegacyConfig(idJoySwap) ) )
|
|
{
|
|
fConfigChanged = TRUE;
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
hres = E_FAIL;
|
|
RPF("ERROR %s: invalid guid.", s_szProc);
|
|
}
|
|
|
|
#ifndef WINNT
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
/*
|
|
* Make sure the new Ids do not cause any collisions
|
|
*/
|
|
DIWdm_InitJoyId();
|
|
}
|
|
#endif
|
|
|
|
if( fConfigChanged ) {
|
|
#ifdef WINNT
|
|
Excl_SetConfigChangedTime( GetTickCount() );
|
|
PostMessage(HWND_BROADCAST, g_wmJoyChanged, 0, 0L);
|
|
#else
|
|
joyConfigChanged(0);
|
|
#endif
|
|
}
|
|
|
|
DllLeaveCrit();
|
|
|
|
ExitOleProc();
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func HRESULT | hResIdJoyInstanceGUID_WDM |
|
|
*
|
|
* Maps a HID JoyStick ID to a DeviceInstance GUID
|
|
*
|
|
* The parameters have already been validated.
|
|
*
|
|
*
|
|
* @parm IN UINT | idJoy |
|
|
*
|
|
* The Joyid of the HID device to be located.
|
|
*
|
|
* @parm OUT LPGUID | lpguid |
|
|
*
|
|
* The Device Instance GUID corresponding to the JoystickID
|
|
* If a mapping is not found GUID_NULL is passed back in lpguid
|
|
*
|
|
* @returns
|
|
* HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
HRESULT EXTERNAL hResIdJoypInstanceGUID_WDM
|
|
(
|
|
IN UINT idJoy,
|
|
OUT LPGUID lpguid
|
|
)
|
|
{
|
|
HRESULT hres = DIERR_NOTFOUND;
|
|
EnterProc( hResIdJoypInstanceGUID_WDM, ( _ "ux", idJoy, lpguid) );
|
|
|
|
/* Zap the guid for failure case */
|
|
ZeroBuf(lpguid, cbX(*lpguid) );
|
|
|
|
if( idJoy > cJoyMax )
|
|
{
|
|
hres = DIERR_NOMOREITEMS;
|
|
} else
|
|
{
|
|
DllEnterCrit();
|
|
|
|
/* Build the HID list if it is too old */
|
|
DIHid_BuildHidList(FALSE);
|
|
|
|
/* Make sure there is some HID device */
|
|
if(g_phdl)
|
|
{
|
|
int ihdi;
|
|
PHIDDEVICEINFO phdi;
|
|
|
|
/* Search over all HID devices */
|
|
for(ihdi = 0, phdi = g_phdl->rghdi;
|
|
ihdi < g_phdl->chdi;
|
|
ihdi++, phdi++)
|
|
{
|
|
/* Check for matching ID */
|
|
if(idJoy == (UINT)phdi->idJoy)
|
|
{
|
|
hres = S_OK;
|
|
/* Copy the GUID */
|
|
*lpguid = phdi->guid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
DllLeaveCrit();
|
|
}
|
|
|
|
ExitBenignOleProc();
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func PHIDDEVICEINFO | phdiFindJoyId |
|
|
*
|
|
* Locates information given a joystick ID for a HID device.
|
|
*
|
|
* The parameters have already been validated.
|
|
*
|
|
* The DLL critical must be held across the call; once the
|
|
* critical section is released, the returned pointer becomes
|
|
* invalid.
|
|
*
|
|
* @parm IN int | idJoy |
|
|
*
|
|
* The Id of the joystick to be located.
|
|
*
|
|
* @returns
|
|
*
|
|
* Pointer to the <t HIDDEVICEINFO> that describes
|
|
* the device.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PHIDDEVICEINFO EXTERNAL
|
|
phdiFindJoyId(int idJoy )
|
|
{
|
|
PHIDDEVICEINFO phdi;
|
|
|
|
EnterProcI(phdiFindJoyId, (_"u", idJoy));
|
|
|
|
/* We should have atleast one HID device */
|
|
if(g_phdl)
|
|
{
|
|
int ihdi;
|
|
|
|
/* Loop over all HID devices */
|
|
for(ihdi = 0, phdi = g_phdl->rghdi; ihdi < g_phdl->chdi;
|
|
ihdi++, phdi++)
|
|
{
|
|
/* Match */
|
|
if(idJoy == phdi->idJoy)
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
phdi = 0;
|
|
|
|
done:;
|
|
|
|
ExitProcX((UINT_PTR)phdi);
|
|
return phdi;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func HRESULT | DIWdm_SetLegacyConfig |
|
|
*
|
|
* Sets up the registry keys so that a joystick HID device
|
|
* can be "seen" by legacy APIs and the Control Panel.
|
|
* Primarily, this routine sets up the structs that are passed
|
|
* to JoyReg_SetConfig routine.
|
|
*
|
|
* @parm IN int | idJoy |
|
|
*
|
|
* Joystick ID.
|
|
*
|
|
* @returns HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
//ISSUE-2001/03/29-timgill Fix unicode madness
|
|
HRESULT INTERNAL DIWdm_SetLegacyConfig
|
|
(
|
|
IN int idJoy
|
|
)
|
|
{
|
|
HRESULT hres;
|
|
DIJOYCONFIG cfg;
|
|
BOOL fNeedType;
|
|
BOOL fNeedConfig;
|
|
BOOL fNeedNone;
|
|
HKEY hk;
|
|
DIJOYTYPEINFO dijti;
|
|
PHIDDEVICEINFO phdi;
|
|
WCHAR wszType[cA(VID_PID_TEMPLATE)];
|
|
#ifndef UNICODE
|
|
char szType[cbX(VID_PID_TEMPLATE)];
|
|
#endif
|
|
|
|
EnterProcI(DIWdm_SetLegacyConfig, (_ "u", idJoy));
|
|
|
|
if( idJoy == -1 )
|
|
{
|
|
// Dx7Gold Patch:
|
|
// ID == -1 implies this device is not joystick.
|
|
// Do not write any entries to the registry
|
|
return E_FAIL;
|
|
}
|
|
|
|
ZeroX(dijti);
|
|
dijti.dwSize = cbX(dijti);
|
|
|
|
fNeedType = fNeedConfig = TRUE;
|
|
fNeedNone = FALSE;
|
|
|
|
|
|
/*
|
|
* 1. Find out what the WinMM registry data is saying now
|
|
*/
|
|
CAssertF( JOY_HW_NONE == 0 );
|
|
hres = JoyReg_OpenConfigKey(idJoy, KEY_QUERY_VALUE, 0x0, &hk);
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
/* Get the type name from the registry */
|
|
JoyReg_GetConfigValue(
|
|
hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
|
|
&cfg.wszType, cbX(cfg.wszType) );
|
|
hres = JoyReg_GetConfigValue(
|
|
hk, REGSTR_VAL_JOYNCONFIG, idJoy, REG_BINARY,
|
|
&cfg.hwc, cbX(cfg.hwc) );
|
|
RegCloseKey(hk);
|
|
} else
|
|
{
|
|
cfg.wszType[0] = '\0';
|
|
}
|
|
if( FAILED( hres ) )
|
|
{
|
|
cfg.hwc.dwType = JOY_HW_NONE;
|
|
}
|
|
|
|
/*
|
|
* 2. If the config info is in sync with WDM then don't rewrite
|
|
*/
|
|
phdi = phdiFindJoyId(idJoy);
|
|
if( phdi )
|
|
{
|
|
/*
|
|
* The type key for HID devices is "VID_xxxx&PID_yyyy",
|
|
* mirroring the format used by plug and play.
|
|
*/
|
|
|
|
if( ( LOWORD(phdi->guidProduct.Data1) == MSFT_SYSTEM_VID )
|
|
&&( ( HIWORD(phdi->guidProduct.Data1) >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN )
|
|
&&( HIWORD(phdi->guidProduct.Data1) < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) )
|
|
{
|
|
/* Predefined type definitions don't go into the registry */
|
|
fNeedType = FALSE;
|
|
|
|
/*
|
|
* Predefined types are determined by the dwType value so fix
|
|
* only it if that is wrong.
|
|
*/
|
|
if( cfg.hwc.dwType + MSFT_SYSTEM_PID == HIWORD(phdi->guidProduct.Data1) )
|
|
{
|
|
fNeedConfig = FALSE;
|
|
} else
|
|
{
|
|
/*
|
|
* Get type info so that JOY_HWS_* flags start with correct values.
|
|
*/
|
|
wszType[0] = L'#';
|
|
wszType[1] = L'0' + HIWORD(phdi->guidProduct.Data1) - MSFT_SYSTEM_PID;
|
|
wszType[2] = L'\0';
|
|
JoyReg_GetPredefTypeInfo(wszType, &dijti, DITC_INREGISTRY | DITC_DISPLAYNAME);
|
|
}
|
|
} else
|
|
{
|
|
/*
|
|
* This should work, but it doesn't in Win98.
|
|
*
|
|
* ctch = wsprintfW(wszType, L"VID_%04X&PID_%04X",
|
|
* LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
|
|
*/
|
|
|
|
#ifdef UNICODE
|
|
wsprintfW(wszType, VID_PID_TEMPLATE,
|
|
LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
|
|
CharUpperW(wszType);
|
|
#else
|
|
wsprintf(szType, VID_PID_TEMPLATE,
|
|
LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
|
|
CharUpper( szType );
|
|
AToU( wszType, cA(wszType), szType );
|
|
#endif
|
|
}
|
|
} else
|
|
{
|
|
/*
|
|
* There is no WDM device so flag for deletion if the WinMM data is wrong
|
|
*/
|
|
if( ( cfg.hwc.dwType != JOY_HW_NONE ) || ( cfg.wszType[0] != L'\0' ) )
|
|
{
|
|
fNeedNone = TRUE;
|
|
fNeedType = fNeedConfig = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
if( fNeedType ) /* Not already decided against (predefined type) */
|
|
{
|
|
/* Does the registry have the correct device ? */
|
|
|
|
/*
|
|
* lstrcmpW doesn't work in Win9x, bad. We have to use our own DiChauUpperW,
|
|
* then memcmp. Also, the wsprintf template has to use 'X' not 'x'.
|
|
*/
|
|
|
|
DiCharUpperW(cfg.wszType);
|
|
if( (memcmp(cfg.wszType, wszType, cbX(wszType)) == 0x0)
|
|
&& (cfg.hwc.dwType >= JOY_HW_PREDEFMAX) )
|
|
{
|
|
fNeedConfig = FALSE;
|
|
}
|
|
|
|
/* Check the type key */
|
|
hres = JoyReg_GetTypeInfo(wszType, &dijti, DITC_INREGISTRY);
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
fNeedType = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* No failures up to this point should be returned
|
|
*/
|
|
hres = S_OK;
|
|
|
|
|
|
/*
|
|
* 3. If something is missing, find the data from WDM and set it straight
|
|
*/
|
|
if( fNeedType || fNeedConfig )
|
|
{
|
|
if( fNeedConfig ) {
|
|
ZeroX(cfg);
|
|
cfg.dwSize = cbX(cfg);
|
|
|
|
hres = DIWdm_JoyHidMapping(idJoy, NULL, &cfg, &dijti );
|
|
} else {
|
|
|
|
hres = DIWdm_JoyHidMapping(idJoy, NULL, NULL, &dijti );
|
|
}
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
if( fNeedType == TRUE)
|
|
{
|
|
hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_JOYOEM,
|
|
DI_KEY_ALL_ACCESS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&hk);
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
hres = JoyReg_SetTypeInfo(hk,
|
|
cfg.wszType,
|
|
&dijti,
|
|
DITC_REGHWSETTINGS | DITC_DISPLAYNAME | DITC_HARDWAREID );
|
|
if( SUCCEEDED(hres ) )
|
|
{
|
|
} else // SetTypeinfo FAILED
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: JoyReg_SetTypeInfo FAILED "),
|
|
s_szProc );
|
|
|
|
RegCloseKey(hk);
|
|
} else // SetTypeinfo FAILED
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: JoyReg_OpenTypeKey FAILED "),
|
|
s_szProc );
|
|
}
|
|
|
|
if( fNeedConfig )
|
|
{
|
|
hres = JoyReg_SetConfig(idJoy,
|
|
&cfg.hwc,
|
|
&cfg,
|
|
DIJC_INREGISTRY);
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
#ifdef WINNT
|
|
Excl_SetConfigChangedTime( GetTickCount() );
|
|
PostMessage (HWND_BROADCAST, g_wmJoyChanged, idJoy+1, 0L);
|
|
#else
|
|
joyConfigChanged(0);
|
|
#endif
|
|
} else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT(",JoyReg_SetConfig FAILED hres=%d"),
|
|
hres);
|
|
}
|
|
}
|
|
} else // DIWdm_GetJoyHidMapping FAILED
|
|
{
|
|
fNeedNone = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 4. If WinMM has data for a device that WDM does not, delete it
|
|
*/
|
|
if( fNeedNone )
|
|
{
|
|
ZeroX( cfg );
|
|
cfg.dwSize = cbX( cfg );
|
|
cfg.dwGain = DI_FFNOMINALMAX;
|
|
|
|
if(SUCCEEDED(hres = JoyReg_SetConfig(idJoy, &cfg.hwc,
|
|
&cfg, DIJC_SETVALID)) &&
|
|
SUCCEEDED(hres = JoyReg_OpenConfigKey(idJoy, MAXIMUM_ALLOWED,
|
|
REG_OPTION_VOLATILE, &hk)))
|
|
{
|
|
TCHAR tsz[MAX_JOYSTRING];
|
|
|
|
wsprintf(tsz, TEXT("%u"), idJoy + 1);
|
|
#ifdef WINNT
|
|
DIWinnt_RegDeleteKey(hk, tsz);
|
|
#else
|
|
RegDeleteKey(hk, tsz);
|
|
#endif
|
|
RegCloseKey(hk);
|
|
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
ExitProcX(hres);
|
|
|
|
return hres;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func void | DIWdm_InitJoyId |
|
|
*
|
|
* Initializes Joystick IDs for JoyConfig and legacy APIs
|
|
* Store the joystick IDs the registry under the %%DirectX/JOYID key.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL EXTERNAL
|
|
DIWdm_InitJoyId( void )
|
|
{
|
|
BOOL fRc;
|
|
LONG lRc;
|
|
int ihdi;
|
|
int idJoy;
|
|
BOOL fNeedId;
|
|
BOOL rfJoyId[cJoyMax]; /* Bool Array for to determine which IDs are in use */
|
|
PHIDDEVICEINFO phdi;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
EnterProcI(DIWdm_InitJoyId, (_ ""));
|
|
|
|
DllEnterCrit();
|
|
|
|
fRc = TRUE;
|
|
ZeroX(rfJoyId );
|
|
fNeedId = FALSE;
|
|
|
|
|
|
/* Iterate over all HID devices to find used IDs */
|
|
for( ihdi = 0, phdi = g_phdl->rghdi ;
|
|
(g_phdl != NULL) && (phdi != NULL) && (phdi->fAttached) && (ihdi < g_phdl->chdi) ;
|
|
ihdi++, phdi++ )
|
|
{
|
|
/* We need joyIDs only for HID game controller devices */
|
|
if( ( GET_DIDEVICE_TYPE( phdi->osd.dwDevType ) >= DI8DEVTYPE_GAMEMIN )
|
|
&& ( phdi->osd.dwDevType & DIDEVTYPE_HID ) )
|
|
{
|
|
idJoy = phdi->idJoy ;
|
|
|
|
/* Validate the ID. */
|
|
if( idJoy < cJoyMax && rfJoyId[idJoy] != TRUE )
|
|
{
|
|
rfJoyId[idJoy] = TRUE;
|
|
hres = DIWdm_SetLegacyConfig(idJoy);
|
|
if( FAILED ( hres ) )
|
|
{
|
|
fRc = FALSE;
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: DIWdm_SetLegacyConfig() FAILED ")
|
|
TEXT("idJoy=%d FAILED hres = %d"),
|
|
s_szProc, idJoy, hres );
|
|
}
|
|
} else
|
|
{
|
|
/* ID either over the limit OR is already used */
|
|
phdi->idJoy = JOY_BOGUSID;
|
|
fNeedId = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Are there devices that need an ID */
|
|
if( fNeedId )
|
|
{
|
|
/*
|
|
* We have Examined all Joystick Ids found used IDs
|
|
* and determined some device needs an Id
|
|
*/
|
|
/* Iterate to assign unused Id's */
|
|
for( ihdi = 0, phdi = g_phdl->rghdi;
|
|
ihdi < g_phdl->chdi ;
|
|
ihdi++, phdi++ )
|
|
{
|
|
/* We need joyIDs only for HID game controller devices */
|
|
if( ( GET_DIDEVICE_TYPE( phdi->osd.dwDevType ) >= DI8DEVTYPE_GAMEMIN )
|
|
&& ( phdi->osd.dwDevType & DIDEVTYPE_HID ) )
|
|
{
|
|
idJoy = phdi->idJoy;
|
|
if( idJoy == JOY_BOGUSID )
|
|
{
|
|
/* Get an Unused ID */
|
|
for(idJoy = 0x0;
|
|
idJoy < cJoyMax;
|
|
idJoy++ )
|
|
{
|
|
if( rfJoyId[idJoy] == FALSE )
|
|
break;
|
|
}
|
|
|
|
if( idJoy < cJoyMax )
|
|
{
|
|
rfJoyId[idJoy] = TRUE;
|
|
phdi->idJoy = idJoy;
|
|
if( lRc = RegSetValueEx(phdi->hk, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoy, cbX(idJoy)) == ERROR_SUCCESS )
|
|
{
|
|
/*
|
|
* This extra RegSetValueEx on "Joystick Id" is to keep the
|
|
* compatibility with Win2k Gold.
|
|
* See Windows bug 395416 for detail.
|
|
*/
|
|
RegSetValueEx(phdi->hkOld, TEXT("Joystick Id"), 0, REG_BINARY,
|
|
(PV)&idJoy, cbX(idJoy));
|
|
|
|
/* Setup Registry data for legacy API's */
|
|
hres = DIWdm_SetLegacyConfig(idJoy);
|
|
|
|
if( FAILED ( hres ) )
|
|
{
|
|
fRc = FALSE;
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: DIWdm_SetLegacyConfig() FAILED")
|
|
TEXT(" idJoy=%d hres = %d"),
|
|
s_szProc, idJoy, hres );
|
|
}
|
|
} else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: RegSetValueEx(JOYID) FAILED ")
|
|
TEXT("Error = %d"),
|
|
s_szProc, lRc);
|
|
fRc = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DllLeaveCrit();
|
|
|
|
ExitBenignProcF(fRc);
|
|
|
|
return fRc;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func HRESULT | DIWdm_SetConfig |
|
|
*
|
|
* Sets config for analog joysticks. This function is an
|
|
* extention of the JoyCfg_SetConfig function for NT.
|
|
* It associates a gameport/serialport bus with a legacy (HID) device and
|
|
* sends an IOCTL to the gameport/serialport bus to attach the device.
|
|
* The IOCLT takes the hardware ID[] which is got from
|
|
* the Joystick OEM types entry
|
|
* (HKLM\CurrentControlSet\Control\Media\PrivateProperties\Joystick\OEM)
|
|
* Some time later PnP realizes that a new device has been added, and hunts for
|
|
* an inf file that matches the HardwareId.
|
|
*
|
|
* When the new HID device finally shows up, we look for the gameport/serialport that
|
|
* the HID device is associated with and try to give it the requested idJoy.
|
|
*
|
|
*
|
|
* @parm IN UINT | idJoy |
|
|
*
|
|
* ID of Joystick
|
|
*
|
|
* @parm IN LPJOYREGHWCONFIG | pjwc |
|
|
*
|
|
* Address of JOYREGHWCONFIG structure that contains config info for the joystick
|
|
*
|
|
* @parm IN LPCDIJOYCONFIG | pcfg |
|
|
*
|
|
* Address of DIJOYCONFIG structure that contains config info for the joystick
|
|
*
|
|
* @parm IN DWORD | fl |
|
|
*
|
|
* Flags
|
|
*
|
|
* @returns
|
|
*
|
|
* DIERR_INVALIDPARAM This function needs DX6.1a functionality.
|
|
* DIERR_UNSUPPORTED Autoload devices cannot be added through this API.
|
|
* DIERR_NOTFOUND TypeInfo not found in the registry.
|
|
* E_ACCESSDENIED Gameport is configured to use another device.
|
|
* E_FAIL CreateFile on Gameport device failed.
|
|
* Could not send IOCTL to gameport device.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT EXTERNAL
|
|
DIWdm_SetConfig
|
|
(
|
|
IN UINT idJoy,
|
|
IN LPJOYREGHWCONFIG pjwc,
|
|
IN LPCDIJOYCONFIG pcfg,
|
|
IN DWORD fl
|
|
)
|
|
{
|
|
HRESULT hres;
|
|
EnterProc(DIWdm_SetConfig, (_"uppu", idJoy, pjwc, pcfg, fl));
|
|
|
|
DllEnterCrit();
|
|
|
|
hres = E_FAIL;
|
|
|
|
if( pcfg->dwSize < cbX(DIJOYCONFIG_DX6 ))
|
|
{
|
|
/* This function needs DX5B2 functionality */
|
|
hres = DIERR_INVALIDPARAM;
|
|
} else if( pjwc->hws.dwFlags & JOY_HWS_AUTOLOAD )
|
|
{
|
|
/* Device cannot be autoload */
|
|
hres = DIERR_UNSUPPORTED;
|
|
} else
|
|
{
|
|
DIJOYTYPEINFO dijti;
|
|
BUS_REGDATA RegData;
|
|
|
|
ZeroX(dijti);
|
|
dijti.dwSize = cbX(dijti);
|
|
|
|
ZeroX(RegData);
|
|
RegData.dwSize = cbX(RegData);
|
|
RegData.nJoysticks = 1;
|
|
|
|
/* Is this a predefined joystick type ? */
|
|
if(pcfg->wszType[0] == TEXT('#'))
|
|
{
|
|
#define JoyCfg_TypeFromChar(tch) ((tch) - L'0')
|
|
hres = JoyReg_GetPredefTypeInfo(pcfg->wszType,
|
|
&dijti, DITC_INREGISTRY | DITC_HARDWAREID);
|
|
|
|
RegData.uVID = MSFT_SYSTEM_VID;
|
|
RegData.uPID = MSFT_SYSTEM_PID + JoyCfg_TypeFromChar(pcfg->wszType[1]);
|
|
|
|
if(JoyCfg_TypeFromChar(pcfg->wszType[1]) == JOY_HW_TWO_2A_2B_WITH_Y )
|
|
{
|
|
RegData.nJoysticks = 2;
|
|
pjwc->hws.dwFlags = 0x0;
|
|
}
|
|
#undef JoyCfg_TypeFromChar
|
|
} else
|
|
{
|
|
hres = JoyReg_GetTypeInfo(pcfg->wszType,
|
|
&dijti, DITC_INREGISTRY | DITC_HARDWAREID | DITC_DISPLAYNAME );
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
USHORT uVID, uPID;
|
|
PWCHAR pCurrChar;
|
|
PWCHAR pLastSlash = NULL;
|
|
|
|
/* Find the last slash in the hardwareId, any VID/PID should follow directly */
|
|
for( pCurrChar = dijti.wszHardwareId; *pCurrChar != L'\0'; pCurrChar++ )
|
|
{
|
|
if( *pCurrChar == L'\\' )
|
|
{
|
|
pLastSlash = pCurrChar;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the hardware ID has no separator, treat the device as
|
|
* though JOY_HWS_AUTOLOAD were set because we cannot expose
|
|
* a non-PnP device without a hardware ID.
|
|
*/
|
|
if( pLastSlash++ )
|
|
{
|
|
/*
|
|
* If the hardwareId does contain a VIDPID, try the type
|
|
* name. Some auto-detect types require this.
|
|
*
|
|
* Prefix gets messed up in ParseVIDPID (mb:34573) and warns
|
|
* that uVID is uninitialized when ParseVIDPID returns TRUE.
|
|
*/
|
|
if( ParseVIDPID( &uVID, &uPID, pLastSlash )
|
|
|| ParseVIDPID( &uVID, &uPID, pcfg->wszType ) )
|
|
{
|
|
RegData.uVID = uVID;
|
|
RegData.uPID = uPID;
|
|
}
|
|
else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflBenign,
|
|
TEXT("%hs: cannot find VID and PID for non-PnP type %ls"),
|
|
s_szProc, pcfg->wszType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%hs: invalid hardware ID for non-PnP type %ls"),
|
|
s_szProc, pcfg->wszType);
|
|
hres = DIERR_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
PBUSDEVICEINFO pbdi;
|
|
PBUSDEVICELIST pbdl;
|
|
|
|
/* Copy over the hardwareID */
|
|
lstrcpyW(RegData.wszHardwareId, dijti.wszHardwareId);
|
|
RegData.hws = pjwc->hws;
|
|
RegData.dwFlags1 = dijti.dwFlags1;
|
|
|
|
pbdi = pbdiFromGUID(&pcfg->guidGameport);
|
|
|
|
// Attach device to the gameport
|
|
if( pbdi )
|
|
{
|
|
// Set the Joystick ID for the gameport/serialport
|
|
pbdi->idJoy = idJoy;
|
|
|
|
// We know which instance of the gameport.
|
|
hres = DIBusDevice_Expose(pbdi, &RegData);
|
|
} else if( NULL != ( pbdl = pbdlFromGUID(&pcfg->guidGameport ) ) )
|
|
{
|
|
// We don't kwow which instance of the gameport
|
|
// only which bus.
|
|
// We will expose the device on all instances of the
|
|
// gameport and later delete devices when we find they
|
|
// are not connected.
|
|
hres = DIBusDevice_ExposeEx(pbdl, &RegData);
|
|
} else
|
|
{
|
|
hres = DIERR_DEVICENOTREG;
|
|
}
|
|
|
|
|
|
if( SUCCEEDED(hres) )
|
|
{
|
|
/* Device is not present */
|
|
pjwc->dwUsageSettings &= ~JOY_US_PRESENT;
|
|
|
|
/* Definately volatile */
|
|
pjwc->dwUsageSettings |= JOY_US_VOLATILE;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitOleProc();
|
|
DllLeaveCrit();
|
|
|
|
return hres;
|
|
} /* DIWdm_SetConfig */
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc EXTERNAL
|
|
*
|
|
* @func HRESULT | DIWdm_DeleteConfig |
|
|
*
|
|
* WDM extension for JoyCfd::DeleteConfig. On WDM a legacy(HID) device will
|
|
* keep reappearing as long as the gameport bus is aware of it. So when a
|
|
* legacy(HID) device is deleted, we need to find out he associated gameport bus
|
|
* and tell him to stop attaching the device.
|
|
*
|
|
* @parm IN UINT | idJoy |
|
|
*
|
|
* ID of Joystick
|
|
*
|
|
* @returns
|
|
*
|
|
* HRESULT code
|
|
* DIERR_DEVICENOTREG: Device is not a WDM device
|
|
* DIERR_UNSUPPORTED: Device is WDM but not gameport
|
|
* S_OK: Device Persistance removed.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
HRESULT EXTERNAL
|
|
DIWdm_DeleteConfig( int idJoy )
|
|
{
|
|
HRESULT hres = S_OK;
|
|
PBUSDEVICEINFO pbdi = NULL;
|
|
PHIDDEVICEINFO phdi = NULL;
|
|
|
|
EnterProcI(DIWdm_DeleteConfig, (_"u", idJoy));
|
|
DllEnterCrit();
|
|
|
|
DIHid_BuildHidList(FALSE);
|
|
|
|
/*
|
|
* pbdi (BUSDEVICEINFO) must be obtained before we remove the device
|
|
*/
|
|
phdi = phdiFindJoyId(idJoy);
|
|
if(phdi != NULL )
|
|
{
|
|
pbdi = pbdiFromphdi(phdi);
|
|
} else
|
|
{
|
|
hres = DIERR_DEVICENOTREG;
|
|
goto _done;
|
|
}
|
|
|
|
|
|
if( SUCCEEDED(hres)
|
|
&& phdi != NULL
|
|
&& pbdi != NULL )
|
|
{
|
|
lstrcpy( g_tszIdLastRemoved, pbdi->ptszId );
|
|
g_tmLastRemoved = GetTickCount();
|
|
|
|
// If the device is a bus device ( Non USB )
|
|
// it needs some help in removal.
|
|
hres = DIBusDevice_Remove(pbdi);
|
|
|
|
//If the device has been successfully removed,
|
|
//then we need remember it in phdi list in case
|
|
//the PnP doesn't function well.
|
|
if( pbdi->fAttached == FALSE )
|
|
{
|
|
phdi->fAttached = FALSE;
|
|
}
|
|
|
|
} else
|
|
{
|
|
//HDEVINFO hdev;
|
|
|
|
// Device is USB, we do not support removing
|
|
// USB devices from the CPL. User is encouraged to
|
|
// Yank out the device or go to the device manager to
|
|
// remove it.
|
|
|
|
// This is true in Win2K. But in Win9X, since VJOYD also works with USB,
|
|
// when we swap id, we need delete it first.
|
|
|
|
hres = DIERR_UNSUPPORTED;
|
|
|
|
#if 0
|
|
// In case we wanted to support removing USB devices from
|
|
// the game cpl. Here is the code ...
|
|
|
|
/*
|
|
* Talk to SetupApi to delete the device.
|
|
* This should not be necessary, but I have
|
|
* to do this to work around a PnP bug whereby
|
|
* the device is not removed after I send a remove
|
|
* IOCTL to gameenum.
|
|
*/
|
|
hdev = SetupDiCreateDeviceInfoList(NULL, NULL);
|
|
if( phdi && hdev != INVALID_HANDLE_VALUE)
|
|
{
|
|
SP_DEVINFO_DATA dinf;
|
|
|
|
dinf.cbSize = cbX(SP_DEVINFO_DATA);
|
|
|
|
/* Get SP_DEVINFO_DATA for the HID device */
|
|
if(SetupDiOpenDeviceInfo(hdev, phdi->ptszId, NULL, 0, &dinf))
|
|
{
|
|
/* Delete the device */
|
|
if( SetupDiCallClassInstaller(DIF_REMOVE,
|
|
hdev,
|
|
&dinf) )
|
|
{
|
|
// SUCCESS
|
|
} else
|
|
{
|
|
hres = E_FAIL;
|
|
SquirtSqflPtszV(sqfl | sqflError,
|
|
TEXT("%S: SetupDiClassInstalled(DIF_REMOVE) FAILED "),
|
|
s_szProc );
|
|
}
|
|
}
|
|
SetupDiDestroyDeviceInfoList(hdev);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
_done:
|
|
|
|
/*
|
|
* Force a remake of the HID list
|
|
* Some devices may have disappered
|
|
* It helps to sleep for some time to give
|
|
* PnP and its worker threads to spin.
|
|
*/
|
|
Sleep(10);
|
|
|
|
DIHid_BuildHidList(TRUE);
|
|
DllLeaveCrit();
|
|
|
|
ExitOleProc();
|
|
|
|
return hres;
|
|
}
|
|
|
|
|