|
|
/*****************************************************************************
* * DIDev.h * * Copyright (c) 1996-1997 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Common header file for IDirectInputDevice implementation. * * The original didev.c file was getting too big, so the * stuff that supports IDirectInputEffect has been split out * into didevef.c. Since both files need to access the * internal structure of an IDirectInputDevice, we need this * common header file. * *****************************************************************************/
/*****************************************************************************
* * The sqiffle for this file. * *****************************************************************************/
#define sqfl sqflDev
/*****************************************************************************
* * Declare the interfaces we will be providing. * *****************************************************************************/
#define ThisClass CDIDev
#ifdef IDirectInputDevice7Vtbl
#define ThisInterface TFORM(IDirectInputDevice7)
#define ThisInterfaceA IDirectInputDevice7A
#define ThisInterfaceW IDirectInputDevice7W
#define ThisInterfaceT IDirectInputDevice7
#else
#ifdef IDirectInputDevice2Vtbl
#define ThisInterface TFORM(IDirectInputDevice2)
#define ThisInterfaceA IDirectInputDevice2A
#define ThisInterfaceW IDirectInputDevice2W
#define ThisInterfaceT IDirectInputDevice2
#else
#define ThisInterface TFORM(IDirectInputDevice)
#define ThisInterfaceA IDirectInputDeviceA
#define ThisInterfaceW IDirectInputDeviceW
#define ThisInterfaceT IDirectInputDevice
#endif
#endif
Primary_Interface(CDIDev, TFORM(ThisInterfaceT)); Secondary_Interface(CDIDev, SFORM(ThisInterfaceT));
/*****************************************************************************
* * @doc INTERNAL * * @enum DIOPT | * * Device data format optimization levels. * * @emem dioptNone | * * Device data format is not optimized at all. We must read * the device data into a private buffer and copy each field * into the application buffer. * * @emem dioptMatch | * * Application data format matches the device data format * in the places where the application requests data at all. * We can read the device data into a private buffer, then * block copy the data into the application buffer. * * * @emem dioptDirect | * * <e DIOPT.dioptMatch>, plus the entire device data * format fits inside the application format. * We can read the device data directly into the application * buffer. * * @emem dioptEqual | * * <e DIOPT.dioptDirect>, plus the device data format * and application data formats are completely equal * (except for fields that the app doesn't explicitly * ask for). * We can issue buffered reads directly into the application * buffer. * *****************************************************************************/
typedef enum DIOPT { dioptNone = 0, dioptMatch = 1, dioptDirect = 2, dioptEqual = 3, } DIOPT;
#undef BUGGY_DX7_WINNT
#ifdef WINNT
#define BUGGY_DX7_WINNT 1
#endif //WINNT
/*****************************************************************************
* * @doc INTERNAL * * @struct CDIDev | * * The generic <i IDirectInputDevice> object. * * The A and W versions are simply alternate interfaces on the same * underlying object. * * @field IDirectInputDeviceA | ddA | * * ANSI DirectInputDevice object (containing vtbl). * * @field IDirectInputDeviceW | ddW | * * UNICODE DirectInputDevice object (containing vtbl). * #ifdef IDirectInputDevice2Vtbl
* @field IDirectInputDevice2A | dd2A | * * ANSI DirectInputDevice2 object (containing vtbl). * * @field IDirectInputDevice2W | dd2W | * * UNICODE DirectInputDevice2 object (containing vtbl). #endif
* * @field IDirectInputDeviceCallback * | pdcb | * * Callback object which handles the low-level device access. * * @field BOOL | fAcquired:1 | * * Set if the device has been acquired. Before the device * can be acquired, the <e CDIDev.pdix> must be set. * * @field BOOL | fAcquiredInstance:1 | * * Set if the device instance has been acquired by us. * This lets us know how much needs to be done on the * unacquire. * * @field BOOL | fCritInited:1 | * * Set if the critical section has been initialized. * #if DIRECTINPUT_VERSION > 0x0300
* @field BOOL | fCook:1 | * * Set if the device requires that data be cooked. * * @field BOOL | fPolledDataFormat:1 | * * Set if the device's data format requires explicit polling. * * @field BOOL | fOnceAcquired:1 | * * Set once the device is acquired. * * @field BOOL | fOnceForcedUnacquired:1 | * * Set once the device is forced unacquired. * * @field BOOL | fUnacqiredWhenIconic:1 | * * Set once the device is unacquired (in CDIDev_CallWndProc) when the app is minimized. * #endif
* @field HWND | hwnd | * * Window that has requested exclusive access when acquired. * * @field DWORD | discl | * * Current value of * <mf IDirectInputDevice::SetCooperativeLevel> flags. * #ifdef BUGGY_DX3_SP3
* @field int | cInstCwp | * * Instance of the CallWndProc hook we installed with. * #endif
* @field HANDLE | hNotify | * * The notification handle that should be set when the * state of the device changes. Note that this is actually * a copy of the original handle supplied by the application, * so the handle should be closed when no longer needed. * * @field FARPROC | GetState | * * Function that transfers the device data in response * to <mf IDirectInputDevice::GetDeviceState>. This field * is computed when the data format is set. * * @field PDIXLAT | pdix | * * Pointer to table used for data format translation. * It is indexed by device object; the value is the * location in the application data format where the * data should be stored. * * For example, if the object described by * <e CDIDev.df.rgodf[3]> * should be placed at offset 8 in the application * data format, then * <e CDIDev.pdix[3]> = 8. * * @field PING | rgiobj | * * The inverse of <e CDIDev.pdix>. Given an offset, * converts it to the device object index. * * For example, if the object described by * <e CDIDev.df.rgodf[3]> * should be placed at offset 8 in the application * data format, then * <e CDIDev.rgiobj[8]> = 3. * * Entries for invalid offsets are -1. * * @field DWORD | dwDataSize | * * Size of the data, as requested by the application. * #ifdef BUGGY_DX7_WINNT
* * @field PDIXLAT | pdix2 | * * Pointer to table used for data format (c_rgodfDIJoy) translation. * It is indexed by device object; the value is the * location in the application data format where the * data should be stored. * * For example, if the object described by * <e CDIDev.df.rgodf[3]> * should be placed at offset 8 in the application * data format, then * <e CDIDev.pdix2[3]> = 8. * * See @devnotes on CDIDev_ParseDataFormatInternal for detail. * * @field PING | rgiobj2 | * * The inverse of <e CDIDev.pdix2>. Given an offset, * converts it to the device object index. * * For example, if the object described by * <e CDIDev.df.rgodf[3]> * should be placed at offset 8 in the application * data format, then * <e CDIDev.rgiobj2[8]> = 3. * * Entries for invalid offsets are -1. * * @field DWORD | dwDataSize2 | * * Size of the data, as requested by the application (connected to rgiobj2). * #endif
* * @field DIDATAFORMAT | df | * * Device data format. * * @field DIOPT | diopt | * * Device optimization level. * * @field int | ibDelta | * * If <e CDIDev.diopt> is at least <e DIOPT.dioptMatch>, * contains the shift necessary in order to align the * application data format with the device data format. * * @field int | ibMin | * * If <e CDIDev.diopt> is at least <e DIOPT.dioptMatch>, * contains the offset of the first field in the device * format which is valid in both the application and * device data formats. * * @field DWORD | cbMatch | * * If <e CDIDev.diopt> is at least <e DIOPT.dioptMatch>, * contains the number of bytes which matched. This is the * number of bytes that can be block-copied. * * @field PV | pvBuffer | * * if <e CDIDev.diopt> is <e DIOPT.dioptMatch> or less, * then contains a scratch buffer equal in size to the * device data format which is used when an unoptimized * data format has been selected. * * @field PV | pvLastBuffer | * * Last instantaneous device state received. This is used * to emulate relative axes. Only the axis fields of the * structure are valid. * * @field PVXDINSTANCE | pvi | * * Instance handle for talking to the VxD. * * @field DWORD | cAxes | * * Number of axes on the device. This in turn yields the * size of the axis offset table. * * @field LPDWORD | rgdwAxesOfs | * * Axis offset table. This is used during relative axis * acquisition mode to convert the absolute numbers into * relative numbers. * * @field HRESULT | hresPolled | * * <c S_OK> if the device is interrupt-driven. * <c DI_POLLEDDEVICE> if the device is polled. * * @field HRESULT | hresNotAcquired | * * <c DIERR_INPUTLOST> if the device was unacquired without * the application's consent. <c DIERR_NOTACQUIRED> if * the application should have known better. * * @field DWORD | celtBuf | * * Size of the device buffer. * * @field DWORD | celtBufMax | * * The largest buffer size we will permit. There is * a secret property that lets you increase the value, * in case an ISV comes up with a good reason for having * a larger buffer. * * @field LPDWORD | rgdwPOV | * * An array of DWORDs listing the locations (data offsets) * of all the optional POVs that were in the app's requested * data format and which we were unable to satisfy. We * need this so we can set them to -1 in the device state * because most apps are lazy and don't check if the object * actually exists before reading from it. To keep them safe, * we normally return zeros in nonexistent objects, but for * POVs, the "safe" value is -1, not zero. * * @field DWORD | cdwPOV | * * Number of failed optional POVs in the <e CDIDev.rgdwPOV> array. * #ifdef IDirectInputDevice2Vtbl
* * @field LPDIRECTINPUTEFFECTSHEPHERD | pes | * * The <i IDirectInputEffectShepherd> * object which does the * low-level goo related to the force feedback part of the device. * * @field SHEPHANDLE | sh | * * The joystick "tag" which is used by dieshep.c * to determine who owns the joystick. * The <e SHEPHANDLE.dwEffect> field is permanently * zero, so that we can pass it to * <mf IDirectInputEffectShepherd::Escape> * to perform a device escape. * * @field DWORD | dwVersion | * * Version number of DirectInput we are emulating. * * @field GPA | gpaEff | * * Pointer array of (held) <i IDirectInputEffect> objects * that have been created for this device. * * @field PEFFECTMAPINFO | rgemi | * * Array of <t EFFECTMAPINFO> structures, one for each * effect supported by the device. * * @field UINT | cemi | * * Number of elements in the <e CDIDev.rgemi> array. * * @field DWORD | didcFF | * * Cached device capability flags related to force-feedback. * * @field DIFFDEVICEATTRIBUTES | ffattr | * * Contains force feedback device attributes. * * @field DWORD | dwGain | * * The gain setting for the device. * * @field DWORD | dwAutoCenter | * * The autocenter setting for the device. #endif
#if DIRECTINPUT_VERSION >= 0x04F0
* * @field DWORD | didftInstance | * * The instance mask to use for the client. For * DX 3.0 clients, the value is 0x0000FF00, whereas * DX 5.0 clients have 0x00FFFF00. The larger * mask is to accomodate HID devices with huge numbers * of controls. * * #endif
* * @field BOOL | fNotifiedNotBuffered:1 | * * Used only in XDEBUG to remember whether we * notified the caller that the device isn't buffered. * * @field LONG | cCrit | * * Number of times the critical section has been taken. * Used only in XDEBUG to check whether the caller is * releasing the object while another method is using it. * * @field DWORD | thidCrit | * * The thread that is currently in the critical section. * Used only in DEBUG for internal consistency checking. * * @field CRITICAL_SECTION | crst | * * Object critical section. Must be taken when accessing * volatile member variables. * * @field GUID | guid | * * The instance GUID of the device we are. * *****************************************************************************/
typedef struct DIXLAT { DWORD dwOfs; } DIXLAT, *PDIXLAT;
typedef struct CDIDev {
/* Supported interfaces */ TFORM(IDirectInputDevice) TFORM(dd); SFORM(IDirectInputDevice) SFORM(dd); #ifdef IDirectInputDevice2Vtbl
TFORM(IDirectInputDevice2) TFORM(dd2); SFORM(IDirectInputDevice2) SFORM(dd2); #endif
IDirectInputDeviceCallback *pdcb;
BOOL fAcquired:1; BOOL fAcquiredInstance:1; BOOL fCritInited:1; #if DIRECTINPUT_VERSION > 0x0300
BOOL fCook:1; BOOL fPolledDataFormat:1; BOOL fOnceAcquired:1; BOOL fOnceForcedUnacquired:1; #ifdef WINNT
BOOL fUnacquiredWhenIconic:1; #endif
#endif
/* WARNING! EVERYTHING AFTER THIS LINE IS ZERO'd ON A RESET */
HWND hwnd; DWORD discl; #ifdef BUGGY_DX3_SP3
int cInstCwp; #endif
HANDLE hNotify;
STDMETHOD(GetState)(struct CDIDev *, PV); STDMETHOD(GetDeviceState)(struct CDIDev *, PV); PDIXLAT pdix; PINT rgiobj; DWORD dwDataSize; #ifdef BUGGY_DX7_WINNT
PDIXLAT pdix2; PINT rgiobj2; DWORD dwDataSize2; #endif //BUGGY_DX7_WINNT
DIDATAFORMAT df; DIOPT diopt; int ibDelta; int ibMin; DWORD cbMatch; PV pvBuffer; PV pvLastBuffer;
PVXDINSTANCE pvi; PV pvData; DWORD cAxes; LPDWORD rgdwAxesOfs; HRESULT hresPolled; HRESULT hresNotAcquired; DWORD celtBuf; LPDWORD rgdwPOV; DWORD cdwPOV;
#ifdef IDirectInputDevice2Vtbl
PEFFECTMAPINFO rgemi; UINT cemi; DWORD didcFF; SHEPHANDLE sh; DIFFDEVICEATTRIBUTES ffattr; #endif
/* WARNING! EVERYTHING ABOVE THIS LINE IS ZERO'd ON A RESET */ DWORD celtBufMax; /* Must be first field after zero'd region */
#ifdef IDirectInputDevice2Vtbl
LPDIRECTINPUTEFFECTSHEPHERD pes; DWORD dwVersion; GPA gpaEff; DWORD dwGain; DWORD dwAutoCenter; #endif
#if DIRECTINPUT_VERSION >= 0x04F0
DWORD didftInstance; #endif
RD(BOOL fNotifiedNotBuffered:1;) long cCrit; DWORD thidCrit; CRITICAL_SECTION crst;
GUID guid; /* This is also zero'd on a reset */
#if (DIRECTINPUT_VERSION > 0x061A)
DIAPPHACKS diHacks; #endif
} CDIDev, DD, *PDD;
typedef IDirectInputDeviceA DDA, *PDDA; typedef IDirectInputDeviceW DDW, *PDDW; typedef DIDEVICEOBJECTDATA DOD, *PDOD; typedef LPCDIDEVICEOBJECTDATA PCDOD;
/*****************************************************************************
* * Methods that live outside didev.c * *****************************************************************************/ #ifdef BUGGY_DX7_WINNT
HRESULT CDIDev_ParseDataFormatInternal(PDD this, const DIDATAFORMAT *lpdf); #endif //BUGGY_DX7_WINNT
/*****************************************************************************
* * IDirectInputDevice::SetDataFormat * *****************************************************************************/
STDMETHODIMP CDIDev_SetDataFormat(PV pdd, LPCDIDATAFORMAT lpdf _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(SetDataFormat, (PV pdd, LPCDIDATAFORMAT lpdf), (pdd, lpdf THAT_))
#else
#define CDIDev_SetDataFormatA CDIDev_SetDataFormat
#define CDIDev_SetDataFormatW CDIDev_SetDataFormat
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice::GetDeviceState * *****************************************************************************/
STDMETHODIMP CDIDev_GetDeviceState(PV pdd, DWORD cbDataSize, LPVOID pvData _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(GetDeviceState, (PV pdd, DWORD cbDataSize, LPVOID pvData), (pdd, cbDataSize, pvData THAT_))
#else
#define CDIDev_GetDeviceStateA CDIDev_GetDeviceState
#define CDIDev_GetDeviceStateW CDIDev_GetDeviceState
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice::GetDeviceData * *****************************************************************************/
STDMETHODIMP CDIDev_GetDeviceData(PV pdd, DWORD cbdod, PDOD rgdod, LPDWORD pdwInOut, DWORD fl _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(GetDeviceData, (PV pdd, DWORD cbdod, PDOD rgdod, LPDWORD pdwInOut, DWORD fl), (pdd, cbdod, rgdod, pdwInOut, fl THAT_))
#else
#define CDIDev_GetDeviceDataA CDIDev_GetDeviceData
#define CDIDev_GetDeviceDataW CDIDev_GetDeviceData
#endif
#endif
#ifdef IDirectInputDevice2Vtbl
/*****************************************************************************
* * IDirectInputDevice2::CreateEffect * *****************************************************************************/
STDMETHODIMP CDIDev_CreateEffect(PV pdd, REFGUID rguid, LPCDIEFFECT peff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(CreateEffect, (PV pdd, REFGUID rguid, LPCDIEFFECT peff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter), (pdd, rguid, peff, ppdeff, punkOuter THAT_))
#else
#define CDIDev_CreateEffectA CDIDev_CreateEffect
#define CDIDev_CreateEffectW CDIDev_CreateEffect
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::EnumEffects * *****************************************************************************/
STDMETHODIMP CDIDev_EnumEffectsW(PV pdd, LPDIENUMEFFECTSCALLBACKW pecW, PV pvRef, DWORD fl);
STDMETHODIMP CDIDev_EnumEffectsA(PV pdd, LPDIENUMEFFECTSCALLBACKA pecA, PV pvRef, DWORD fl);
/*****************************************************************************
* * IDirectInputDevice2::GetEffectInfo * *****************************************************************************/
STDMETHODIMP CDIDev_GetEffectInfoW(PV pddW, LPDIEFFECTINFOW peiW, REFGUID rguid);
STDMETHODIMP CDIDev_GetEffectInfoA(PV pddA, LPDIEFFECTINFOA peiA, REFGUID rguid);
/*****************************************************************************
* * IDirectInputDevice2::GetForceFeedbackState * *****************************************************************************/
STDMETHODIMP CDIDev_GetForceFeedbackState(PV pdd, LPDWORD pdwOut _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(GetForceFeedbackState, (PV pdd, LPDWORD pdwOut), (pdd, pdwOut THAT_))
#else
#define CDIDev_GetForceFeedbackStateA CDIDev_GetForceFeedbackState
#define CDIDev_GetForceFeedbackStateW CDIDev_GetForceFeedbackState
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::SendForceFeedbackCommand * *****************************************************************************/
STDMETHODIMP CDIDev_SendForceFeedbackCommand(PV pdd, DWORD dwCmd _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(SendForceFeedbackCommand, (PV pdd, DWORD dwCmd), (pdd, dwCmd THAT_))
#else
#define CDIDev_SendForceFeedbackCommandA CDIDev_SendForceFeedbackCommand
#define CDIDev_SendForceFeedbackCommandW CDIDev_SendForceFeedbackCommand
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::EnumCreatedEffects * *****************************************************************************/
STDMETHODIMP CDIDev_EnumCreatedEffectObjects(PV pdd, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK pec, LPVOID pvRef, DWORD dwFlags _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(EnumCreatedEffectObjects, (PV pdd, LPDIENUMCREATEDEFFECTOBJECTSCALLBACK pec, LPVOID pvRef, DWORD dwFlags), (pdd, pec, pvRef, dwFlags THAT_))
#else
#define CDIDev_EnumCreatedEffectObjectsA CDIDev_EnumCreatedEffectObjects
#define CDIDev_EnumCreatedEffectObjectsW CDIDev_EnumCreatedEffectObjects
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::Escape * *****************************************************************************/
STDMETHODIMP CDIDev_Escape(PV pdd, LPDIEFFESCAPE pesc _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(Escape, (PV pdd, LPDIEFFESCAPE pesc), (pdd, pesc THAT_))
#else
#define CDIDev_EscapeA CDIDev_Escape
#define CDIDev_EscapeW CDIDev_Escape
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::Poll * *****************************************************************************/
STDMETHODIMP CDIDev_Poll(PV pdd _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(Poll, (PV pdd), (pdd THAT_))
#else
#define CDIDev_PollA CDIDev_Poll
#define CDIDev_PollW CDIDev_Poll
#endif
#endif
/*****************************************************************************
* * IDirectInputDevice2::SendDeviceData * *****************************************************************************/
STDMETHODIMP CDIDev_SendDeviceData(PV pdd, DWORD cbdod, PCDOD rgdod, LPDWORD pdwInOut, DWORD fl _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(SendDeviceData, (PV pdd, DWORD cbdod, PCDOD rgdod, LPDWORD pdwInOut, DWORD fl), (pdd, cbdod, rgdod, pdwInOut, fl THAT_))
#else
#define CDIDev_SendDeviceDataA CDIDev_SendDeviceData
#define CDIDev_SendDeviceDataW CDIDev_SendDeviceData
#endif
#endif
#endif /* IDirectInputDevice2Vtbl */
/*****************************************************************************
* * More internal worker functions. * * IsConsists is used for assertion checking. * * Finalize calls Unacquire to clean up in the case where the * caller forgot. * * Similarly, Reset needs to reset the GetDeviceState pointer. * * SetDataFormat needs to set the axis mode property. * * CDIDev_InitFF is used by CDIDev_Initialize to initialize * the force-feedback portion of the device. * *****************************************************************************/
#ifdef DEBUG
BOOL INTERNAL CDIDev_IsConsistent(PDD this); #endif
STDMETHODIMP CDIDev_InternalUnacquire(PV pdd);
STDMETHODIMP CDIDev_GetAbsDeviceState(PDD this, LPVOID pvData); STDMETHODIMP CDIDev_GetRelDeviceState(PDD this, LPVOID pvData);
STDMETHODIMP CDIDev_RealSetProperty(PDD this, REFGUID rguid, LPCDIPROPHEADER pdiph);
#ifdef IDirectInputDevice2Vtbl
STDMETHODIMP CDIDev_FFAcquire(PDD this); STDMETHODIMP CDIDev_InitFF(PDD this); STDMETHODIMP CDIDev_GetLoad(PDD this, LPDWORD pdw); STDMETHODIMP CDIDev_RefreshGain(PDD this); HRESULT INTERNAL CDIDev_CreateEffectDriver(PDD this); #endif
|