Windows2003-3790/multimedia/directx/dinput/dx8/dll/dijoytyp.c
2020-09-30 16:53:55 +02:00

492 lines
15 KiB
C

/*****************************************************************************
*
* DIJoyTyp.c
*
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Functions that pull data out of the joystick type key
* (wherever it is).
*
* Contents:
*
* ?
*
*****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
*
* The sqiffle for this file.
*
*****************************************************************************/
#define sqfl sqflJoyType
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | CType_OpenIdSubkey |
*
* Given an object ID, attempt to open the subkey that
* corresponds to it for reading.
*
* @parm HKEY | hkType |
*
* The joystick type key, possibly <c NULL> if we don't
* have a type key. (For example, if it was never created.)
*
* @parm DWORD | dwId |
*
* Object id.
*
* @parm REGSAM | regsam |
*
* Registry security access mask.
*
* @parm PHKEY | phk |
*
* Receives the object key on success.
*
* @returns
*
* Returns a COM error code.
*
*****************************************************************************/
STDMETHODIMP
CType_OpenIdSubkey(HKEY hkType, DWORD dwId, REGSAM sam, PHKEY phk)
{
HRESULT hres;
EnterProc(CType_OpenIdSubkey, (_ "xx", hkType, dwId));
*phk = 0;
if(hkType)
{
/*
* Worst case is "Actuators\65535" which has length 15.
*/
TCHAR tsz[32];
LPCTSTR ptszType;
if(dwId & DIDFT_AXIS)
{
ptszType = TEXT("Axes");
} else if(dwId & DIDFT_BUTTON)
{
ptszType = TEXT("Buttons");
} else if(dwId & DIDFT_POV)
{
ptszType = TEXT("POVs");
} else if(dwId & DIDFT_NODATA)
{
ptszType = TEXT("Actuators");
} else
{
hres = E_NOTIMPL;
goto done;
}
// ISSUE-2001/03/29-timgill Need to scale back for pos vs state
// MarcAnd -- I believe this means: if you're trying to
// look for the X axis, we should use the position
// instance, not the velocity one.
wsprintf(tsz, TEXT("%s\\%u"), ptszType, DIDFT_GETINSTANCE(dwId));
hres = hresMumbleKeyEx(hkType, tsz, sam, REG_OPTION_NON_VOLATILE, phk);
} else
{
hres = DIERR_NOTFOUND;
}
done:;
if(hres == DIERR_NOTFOUND)
{
ExitBenignOleProcPpv(phk);
} else
{
ExitOleProcPpv(phk);
}
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | CType_RegGetObjectInfo |
*
* Given an object ID, look into the registry subkey for the
* object and extract anything we can find.
*
* If we find nothing, then do nothing.
*
* @parm HKEY | hkType |
*
* The joystick type key, possibly <c NULL> if we don't
* have a type key. (For example, if it was never created.)
*
* @parm DWORD | dwId |
*
* Object id.
*
* @parm LPDIDEVICEOBJECTINSTANCEW | pdidoiW |
*
* Structure to receive information. The
* <e DIDEVICEOBJECTINSTANCE.guidType>,
* <e DIDEVICEOBJECTINSTANCE.dwOfs>,
* and
* <e DIDEVICEOBJECTINSTANCE.dwType>
* <e DIDEVICEOBJECTINSTANCE.dwFlags>
* fields have already been filled in so we should only not override
* these with default data.
*
*****************************************************************************/
void EXTERNAL
CType_RegGetObjectInfo(HKEY hkType, DWORD dwId,
LPDIDEVICEOBJECTINSTANCEW pdidoiW)
{
HRESULT hres;
HKEY hk;
EnterProc(CType_RegKeyObjectInfo, (_ "xx", hkType, dwId));
/*
* Extract information about this item from the registry.
*/
hres = CType_OpenIdSubkey(hkType, dwId, KEY_QUERY_VALUE, &hk);
if(SUCCEEDED(hres))
{
DIOBJECTATTRIBUTES attr;
/*
* Read the regular and HID attributes.
*/
hres = JoyReg_GetValue(hk, TEXT("Attributes"),
REG_BINARY, &attr,
cbX(attr));
if(SUCCEEDED(hres))
{
/*
* Copy the bit fields.
* PREFIX warns (333540) that attr.dwFlags is not initialized
* however JoyReg_GetValue zeroes any part of the buffer after
* the bytes read from the registry if the buffer size is larger
* than what was read.
*/
pdidoiW->dwFlags |= (attr.dwFlags & ~DIDOI_ASPECTMASK);
/*
* Don't add FF if the dwId did not have it.
* (See comment on FF attrs below for why.)
*/
if( ( dwId & ( DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR ) ) == 0 )
{
pdidoiW->dwFlags &= ~( DIDOI_FFACTUATOR | DIDOI_FFEFFECTTRIGGER );
}
/*
* Copy the aspect, but don't change
* the aspect from "known" to "unknown". If the
* registry doesn't have an aspect, then use the
* aspect we got from the caller.
*/
if((attr.dwFlags & DIDOI_ASPECTMASK) != DIDOI_ASPECTUNKNOWN)
{
pdidoiW->dwFlags = (pdidoiW->dwFlags & ~DIDOI_ASPECTMASK) |
(attr.dwFlags & DIDOI_ASPECTMASK);
}
}
/*
* If the caller wants force feedback info,
* then get it.
*/
if(pdidoiW->dwSize >= cbX(DIDEVICEOBJECTINSTANCE_DX5W))
{
/*
* Only copy the usages if they are valid.
* JoyReg_GetValue zeros any buffer beyond what is read.
*/
if(SUCCEEDED(hres) && attr.wUsagePage && attr.wUsage )
{
pdidoiW->wUsagePage = attr.wUsagePage;
pdidoiW->wUsage = attr.wUsage;
}
/*
* Only try to read the FF attributes if the object supports FF
* This may save time but is primarily to allow us to ignore FF
* attributes in the registry for objects (such as FF driving
* controller pedals) which IHVs mark incorrectly.
*/
if( dwId & ( DIDFT_FFEFFECTTRIGGER | DIDFT_FFACTUATOR ) )
{
/*
* Assert that we can read the DIFFOBJECTATTRIBUTES
* directly into the DIDEVICEOBJECTINSTANCE_DX5.
*/
CAssertF(FIELD_OFFSET(DIFFOBJECTATTRIBUTES,
dwFFMaxForce) == 0);
CAssertF(FIELD_OFFSET(DIFFOBJECTATTRIBUTES,
dwFFForceResolution) == 4);
CAssertF(FIELD_OFFSET(DIDEVICEOBJECTINSTANCE_DX5,
dwFFMaxForce) + 4 ==
FIELD_OFFSET(DIDEVICEOBJECTINSTANCE_DX5,
dwFFForceResolution));
CAssertF(cbX(DIFFOBJECTATTRIBUTES) == 8);
/*
* If this doesn't work, gee that's too bad.
* JoyReg_GetValue will zero-fill the error parts.
*/
JoyReg_GetValue(hk, TEXT("FFAttributes"),
REG_BINARY, &pdidoiW->dwFFMaxForce,
cbX(DIFFOBJECTATTRIBUTES));
}
else
{
AssertF( ( pdidoiW->dwFFMaxForce | pdidoiW->dwFFForceResolution ) == 0 );
}
}
/*
* Read the optional custom name.
*
* Note that JoyReg_GetValue(REG_SZ) uses
* RegQueryStringValueW, which sets the
* string to null on error so we don't have to.
*/
hres = JoyReg_GetValue(hk, 0, REG_SZ,
pdidoiW->tszName, cbX(pdidoiW->tszName));
if(SUCCEEDED(hres))
{
} else
{
AssertF(pdidoiW->tszName[0] == L'\0');
}
RegCloseKey(hk);
} else
{
AssertF(pdidoiW->tszName[0] == L'\0');
}
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | CType_RegGetTypeInfo |
*
* Given an object ID, look into the registry subkey for the
* object and extract attribute bits that should be OR'd
* into the object ID.
*
* This needs to be done during device initialization to
* establish the attributes in the data format so that
*
* 1. <mf IDirectInputDevice::EnumObjects> filters properly, and
*
* 2. >mf IDirectInputEffect::SetParameters> can validate properly.
*
* @parm HKEY | hkType |
*
* The joystick type key, possibly <c NULL> if we don't
* have a type key. (For example, if it was never created.)
*
* @parm LPDIOBJECTDATAFORMAT | podf |
*
* Structure to receive more information. The
* <e DIOBJECTDATAFORMAT.dwType> field identifies the object.
*
* On return the
* <e DIOBJECTDATAFORMAT.dwType>
* and
* <e DIOBJECTDATAFORMAT.dwFlags>
* fields are updated.
*
*****************************************************************************/
void EXTERNAL
CType_RegGetTypeInfo(HKEY hkType, LPDIOBJECTDATAFORMAT podf, BOOL fPidDevice)
{
HRESULT hres;
HKEY hk;
EnterProc(CType_RegKeyObjectInfo, (_ "xx", hkType, podf->dwType));
hres = CType_OpenIdSubkey(hkType, podf->dwType, KEY_QUERY_VALUE, &hk);
if(SUCCEEDED(hres))
{
DWORD dwFlags;
CAssertF(FIELD_OFFSET(DIOBJECTATTRIBUTES, dwFlags) == 0);
hres = JoyReg_GetValue(hk, TEXT("Attributes"),
REG_BINARY, &dwFlags, cbX(dwFlags));
if(SUCCEEDED(hres))
{
/*
* Propagate the attributes into the type code.
*/
CAssertF(DIDOI_FFACTUATOR == DIDFT_GETATTR(DIDFT_FFACTUATOR));
CAssertF(DIDOI_FFEFFECTTRIGGER
== DIDFT_GETATTR(DIDFT_FFEFFECTTRIGGER));
/*
* PREFIX warns (333539) that dwFlags is not initialized however
* JoyReg_GetValue zeroes any part of the buffer after the bytes
* read from the registry if the buffer size is larger than what
* was read.
*/
podf->dwType |= DIDFT_MAKEATTR(dwFlags);
podf->dwFlags |= (dwFlags & ~DIDOI_ASPECTMASK);
/*
* Copy the aspect, but don't change
* the aspect from "known" to "unknown". If the
* registry doesn't have an aspect, then use the
* aspect we got from the caller.
*/
if((dwFlags & DIDOI_ASPECTMASK) != DIDOI_ASPECTUNKNOWN)
{
podf->dwFlags = (podf->dwFlags & ~DIDOI_ASPECTMASK) |
(dwFlags & DIDOI_ASPECTMASK);
}
}
RegCloseKey(hk);
}else
{
#ifndef WINNT
// Post Dx7Gold Patch
// This is for Win9x only.
// On Win9x, a device that is being accessed through the vjoyd path
// will not get forces, as the attributes necessary for FF have not
// been appropriately marked.
// THe following code will mark the
DWORD dwFlags = DIDFT_GETATTR( podf->dwType & ~DIDFT_ATTRMASK )
| ( podf->dwFlags & ~DIDOI_ASPECTMASK);
if( dwFlags != 0x0
&& fPidDevice )
{
hres = CType_OpenIdSubkey(hkType, podf->dwType, DI_KEY_ALL_ACCESS, &hk);
if(SUCCEEDED(hres) )
{
hres = JoyReg_SetValue(hk, TEXT("Attributes"),
REG_BINARY, &dwFlags, cbX(dwFlags));
RegCloseKey(hk);
}
}
#endif // ! WINNT
}
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | CType_MakeGameCtrlName |
*
* Make a game controller name from the attributes of the controller.
* Used as a last resort when a name is needed but none is available.
*
* @parm PWCHAR | wszName |
*
* Output buffer where name will be generated.
*
* @parm DWORD | dwType |
*
* DI8DEVTYPE value for the controller.
*
* @parm DWORD | dwAxes |
*
* The number of axes the device has.
*
* @parm DWORD | dwButtons |
*
* The numer of buttons the device has.
*
* @parm DWORD | dwPOVs |
*
* The number of POVs the device has.
*
*****************************************************************************/
void EXTERNAL
CType_MakeGameCtrlName
(
PWCHAR wszOutput,
DWORD dwDevType,
DWORD dwAxes,
DWORD dwButtons,
DWORD dwPOVs
)
{
TCHAR tsz[64];
TCHAR tszPOV[64];
TCHAR tszFormat[64];
#ifndef UNICODE
TCHAR tszOut[cA(tsz)+cA(tszFormat)+cA(tszPOV)];
#endif
/* tszFormat = %d axis, %d button %s */
LoadString(g_hinst, IDS_TEXT_TEMPLATE, tszFormat, cA(tszFormat));
/* tsz = joystick, gamepad, etc. */
if( ( GET_DIDEVICE_TYPE( dwDevType ) >= DI8DEVTYPE_JOYSTICK )
&& ( GET_DIDEVICE_TYPE( dwDevType ) <= DI8DEVTYPE_FLIGHT ) )
{
LoadString(g_hinst, GET_DIDEVICE_TYPE( dwDevType ) + IDS_PLAIN_STICK - DI8DEVTYPE_JOYSTICK,
tsz, cA(tsz));
}
else if( GET_DIDEVICE_TYPEANDSUBTYPE( dwDevType )
== MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL, DI8DEVTYPESUPPLEMENTAL_HEADTRACKER ) )
{
LoadString(g_hinst, IDS_HEAD_TRACKER, tsz, cA(tsz));
}
else
{
LoadString(g_hinst, IDS_DEVICE_NAME, tsz, cA(tsz));
}
if( dwPOVs )
{
LoadString(g_hinst, IDS_WITH_POV, tszPOV, cA(tszPOV));
}
else
{
tszPOV[0] = TEXT( '\0' );
}
#ifdef UNICODE
wsprintfW(wszOutput, tszFormat, dwAxes, dwButtons, tsz, tszPOV);
#else
wsprintfA(tszOut, tszFormat, dwAxes, dwButtons, tsz, tszPOV);
TToU(wszOutput, cA(tszOut), tszOut);
#endif
}