admin
base
com
developer
drivers
ds
enduser
inetcore
inetsrv
loc
mergedcomponents
multimedia
danim
ddk
directx
applicationmanager
ddraw
ddrawex
deliveryimages
dinput
dicfgddk
diconfig
dimapcfg
diquick
dx7
diquick
dll
daytona
dilib
win9x
winnt
assert.c
common.c
debug.h
default.mk
diaddhw.c
diaphack.c
dical.c
dicf.c
didenum.c
didev.c
didev.h
didevdf.c
didevef.c
dieff.c
dieffj.c
dieffv.c
diem.c
diem.h
diemh.c
diemk.c
diemm.c
dieshep.c
diexcl.c
diextdll.c
digendef.c
digenj.c
digenk.c
digenm.c
digenx.c
diguid.c
dihel.c
dihel.h
dihid.c
dihid.h
dihiddat.c
dihidenm.c
dihidini.c
dihidusg.c
dijoycfg.c
dijoyhid.c
dijoyhid.h
dijoyreg.c
dijoyreg.h
dijoytyp.c
dilib1.c
dilib2.c
dilib3.c
dilib4.c
dilib5.c
dilist.c
dimem.c
dinput.c
dinput.def
dinput.fmt
dinput.inc
dinput.inf
dinput.txt
dinputi.h
dinputpr.h
dinputrc.h
dinputrc.w
dinputv.h
diobj.c
dioledup.c
diport.c
diport.h
diraw.c
direg.c
diregutl.c
diriff.c
diriff.h
dirs
disubcls.c
dithunk.c
dithunk.h
diutil.c
diwinnt.c
diwinnt.h
ffdummy.reg
guids.c
makefil0
makefile
makefile.inc
mkhdr.pl
valid.c
dirs
dx8
dxff
ihvmap
pid
sys
dirs
readme.txt
dmusic
dplay
dsound
dxcrt
dxdiag
dxg
dxvb
gamectrl
inc
loc
misc
dirs
project.mk
dshow
embedded
inc
lib
media
netshow
opengl
private
published
reality
resmgr
dirs
multimedia.mk
project.mk
net
printscan
public
published
sdktools
shell
termsrv
tools
windows
dirs
makefil0
1109 lines
34 KiB
C
1109 lines
34 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;
|
|
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 = S_FALSE;
|
|
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));
|
|
|
|
ZeroX(dijti);
|
|
dijti.dwSize = cbX(dijti);
|
|
|
|
if( idJoy == -1 )
|
|
{
|
|
// Dx7Gold Patch:
|
|
// ID == -1 implies this device is not joystick.
|
|
// Do not write any entries to the registry
|
|
return E_FAIL;
|
|
}
|
|
|
|
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, NULL, 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 thDIWdm_SetJoyIdis 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,
|
|
NULL, REG_OPTION_VOLATILE, &hk)))
|
|
{
|
|
TCHAR tsz[MAX_JOYSTRING];
|
|
|
|
wsprintf(tsz, TEXT("%u"), idJoy + 1);
|
|
if( fWinnt )
|
|
DIWinnt_RegDeleteKey(hk, tsz);
|
|
else
|
|
RegDeleteKey(hk, tsz);
|
|
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 fDIWdm_SetJoyIdind 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 JOYSTICK devices */
|
|
if( fHasAllBitsFlFl( phdi->osd.dwDevType, DIDEVTYPE_JOYSTICK | 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 JOYSTICK devices */
|
|
if( fHasAllBitsFlFl( phdi->osd.dwDevType, DIDEVTYPE_JOYSTICK | 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;
|
|
}
|
|
|
|
|