/***************************************************************************** * * 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 | * * , plus the entire device data * format fits inside the application format. * We can read the device data directly into the application * buffer. * * @emem dioptEqual | * * , 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 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 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 * 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 . 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 * * should be placed at offset 8 in the application * data format, then * = 8. * * @field PING | rgiobj | * * The inverse of . Given an offset, * converts it to the device object index. * * For example, if the object described by * * should be placed at offset 8 in the application * data format, then * = 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 * * should be placed at offset 8 in the application * data format, then * = 8. * * See @devnotes on CDIDev_ParseDataFormatInternal for detail. * * @field PING | rgiobj2 | * * The inverse of . Given an offset, * converts it to the device object index. * * For example, if the object described by * * should be placed at offset 8 in the application * data format, then * = 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 is at least , * contains the shift necessary in order to align the * application data format with the device data format. * * @field int | ibMin | * * If is at least , * 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 is at least , * contains the number of bytes which matched. This is the * number of bytes that can be block-copied. * * @field PV | pvBuffer | * * if is 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 | * * if the device is interrupt-driven. * if the device is polled. * * @field HRESULT | hresNotAcquired | * * if the device was unacquired without * the application's consent. 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 array. * #ifdef IDirectInputDevice2Vtbl * * @field LPDIRECTINPUTEFFECTSHEPHERD | pes | * * The * 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 field is permanently * zero, so that we can pass it to * * to perform a device escape. * * @field DWORD | dwVersion | * * Version number of DirectInput we are emulating. * * @field GPA | gpaEff | * * Pointer array of (held) objects * that have been created for this device. * * @field PEFFECTMAPINFO | rgemi | * * Array of structures, one for each * effect supported by the device. * * @field UINT | cemi | * * Number of elements in the 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