windows-nt/Source/XPSP1/NT/multimedia/directx/dinput/dx8/dll/didev.h
2020-09-26 16:20:57 +08:00

832 lines
24 KiB
C

/*****************************************************************************
*
* 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
#define ThisInterface TFORM(IDirectInputDevice8)
#define ThisInterfaceA IDirectInputDevice8A
#define ThisInterfaceW IDirectInputDevice8W
#define ThisInterfaceT IDirectInputDevice8
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;
/*****************************************************************************
*
* @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).
*
* @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.
*
* @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.
*
* @field HWND | hwnd |
*
* Window that has requested exclusive access when acquired.
*
* @field DWORD | discl |
*
* Current value of
* <mf IDirectInputDevice8::SetCooperativeLevel> flags.
*
* @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 IDirectInputDevice8::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 dwOfs value is the location
* in the application data format where the data should be stored,
* the uAppData is the application specified data associated with
* the object.
*
* 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].dwOfs> = 8.
*
*
* @field PING | rgiobj |
*
* The inverse of <e CDIDev.pdix.dwOfs>. 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.
*
* @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.
*
*
* @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.
*
* @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;
UINT_PTR uAppData;
} DIXLAT, *PDIXLAT;
typedef struct CDIDev
{
/* Supported interfaces */
TFORM(IDirectInputDevice) TFORM(dd);
SFORM(IDirectInputDevice) SFORM(dd);
/*
* All interfaces currently have vtbls that are unmodified supersets of
* all previous versions of the interface, so we use the latest interface
* for all versions and do not need to keep multiple interfaces.
*/
IDirectInputDeviceCallback *pdcb;
BOOL fAcquired:1;
BOOL fAcquiredInstance:1;
BOOL fCritInited:1;
BOOL fCook:1;
BOOL fPolledDataFormat:1;
BOOL fOnceAcquired:1;
BOOL fOnceForcedUnacquired:1;
#ifdef WINNT
BOOL fUnacquiredWhenIconic:1;
#endif
/* WARNING! EVERYTHING AFTER THIS LINE IS ZERO'd ON A RESET */
HWND hwnd;
DWORD discl;
HANDLE hNotify;
STDMETHOD(GetState)(struct CDIDev *, PV);
STDMETHOD(GetDeviceState)(struct CDIDev *, PV);
PDIXLAT pdix;
PINT rgiobj;
DWORD dwDataSize;
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;
PEFFECTMAPINFO rgemi;
UINT cemi;
DWORD didcFF;
SHEPHANDLE sh;
DIFFDEVICEATTRIBUTES ffattr;
DIDEVCAPS_DX3 dc3;
/* WARNING! EVERYTHING ABOVE THIS LINE IS ZERO'd ON A RESET */
DWORD celtBufMax; /* Must be first field after zero'd region */
LPDIRECTINPUTEFFECTSHEPHERD pes;
DWORD dwVersion;
GPA gpaEff;
DWORD dwGain;
DWORD dwAutoCenter;
RD(BOOL fNotifiedNotBuffered:1;)
LONG cCrit;
DWORD thidCrit;
CRITICAL_SECTION crst;
GUID guid; /* This is also zero'd on a reset */
DIAPPHACKS diHacks;
LPDIRECTINPUTMAPSHEPHERD pMS;
} CDIDev, DD, *PDD;
typedef IDirectInputDeviceA DDA, *PDDA;
typedef IDirectInputDeviceW DDW, *PDDW;
typedef DIDEVICEOBJECTDATA DOD, *PDOD;
typedef LPCDIDEVICEOBJECTDATA PCDOD;
/*****************************************************************************
*
* Methods that live outside didev.c
*
*****************************************************************************/
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::EnumEffects
*
*****************************************************************************/
STDMETHODIMP
CDIDev_EnumEffectsW(PV pdd, LPDIENUMEFFECTSCALLBACKW pecW, PV pvRef, DWORD fl);
STDMETHODIMP
CDIDev_EnumEffectsA(PV pdd, LPDIENUMEFFECTSCALLBACKA pecA, PV pvRef, DWORD fl);
/*****************************************************************************
*
* IDirectInputDevice8::GetEffectInfo
*
*****************************************************************************/
STDMETHODIMP
CDIDev_GetEffectInfoW(PV pddW, LPDIEFFECTINFOW peiW, REFGUID rguid);
STDMETHODIMP
CDIDev_GetEffectInfoA(PV pddA, LPDIEFFECTINFOA peiA, REFGUID rguid);
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::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
/*****************************************************************************
*
* IDirectInputDevice8::SendDeviceData
*
*****************************************************************************/
STDMETHODIMP
CDIDev_SendDeviceData(PV pdd, DWORD cbdod, LPCDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut, DWORD fl _THAT);
#ifdef INCLUDED_BY_DIDEV
#ifdef XDEBUG
CSET_STUBS(SendDeviceData,
(PV pdd, DWORD cbdod, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl),
(pdd, cbdod, rgdod, pdwInOut, fl THAT_))
#else
#define CDIDev_SendDeviceDataA CDIDev_SendDeviceData
#define CDIDev_SendDeviceDataW CDIDev_SendDeviceData
#endif
#endif
/*****************************************************************************
*
* IDirectInputDevice8::CDIDev_BuildActionMap
*
*****************************************************************************/
STDMETHODIMP
CDIDev_BuildActionMapW( PV pdd, LPDIACTIONFORMATW pAFW, LPCWSTR wszName, DWORD fl);
STDMETHODIMP
CDIDev_BuildActionMapA( PV pdd, LPDIACTIONFORMATA pAFA, LPCSTR szName, DWORD fl);
/*****************************************************************************
*
* IDirectInputDevice8::CDIDev_SetActionMap
*
*****************************************************************************/
STDMETHODIMP
CDIDev_SetActionMapW( PV pdd, LPDIACTIONFORMATW pAFW, LPCWSTR wszName, DWORD fl);
STDMETHODIMP
CDIDev_SetActionMapA( PV pdd, LPDIACTIONFORMATA pAFA, LPCSTR szName, DWORD fl);
/*****************************************************************************
*
* IDirectInputDevice8::CDIDev_GetImageInfo
*
*****************************************************************************/
STDMETHODIMP
CDIDev_GetImageInfoW( PV pdd, LPDIDEVICEIMAGEINFOHEADERW piih);
STDMETHODIMP
CDIDev_GetImageInfoA( PV pdd, LPDIDEVICEIMAGEINFOHEADERA piih);
/*****************************************************************************
*
* Methods in didev.c needed in supporting files
*
*****************************************************************************/
/*****************************************************************************
*
* IDirectInputDevice8::GetProperty
*
*****************************************************************************/
STDMETHODIMP
CDIDev_GetProperty(PV pdd, REFGUID rguid, LPDIPROPHEADER pdiph _THAT);
#ifdef XDEBUG
STDMETHODIMP
CDIDev_GetPropertyA(PV pdd, REFGUID rguid, LPDIPROPHEADER pdiph);
STDMETHODIMP
CDIDev_GetPropertyW(PV pdd, REFGUID rguid, LPDIPROPHEADER pdiph);
#else
#define CDIDev_GetPropertyA CDIDev_GetProperty
#define CDIDev_GetPropertyW CDIDev_GetProperty
#endif
/*****************************************************************************
*
* 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);
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);