/*************************************************************************** * * Copyright (C) 1996 - 2000 Microsoft Corporation. All Rights Reserved. * * File: dinputi.h * Content: DirectInput internal include file *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 1996.05.07 raymondc Lost a bet * *@@END_MSINTERNAL * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif /*************************************************************************** * * Debug / RDebug / Retail * * If either DEBUG or RDEBUG, set XDEBUG. * * Retail defines nothing. * ***************************************************************************/ #if defined(DEBUG) || defined(RDEBUG) #define XDEBUG #endif /*************************************************************************** * * Turning off stuff... * * Turn off these things, because they confuse the bilingualism macros. * Instead, we call then IMumbleT. * ***************************************************************************/ #undef IDirectInput #undef IDirectInput2 #undef IDirectInput7 #undef IDirectInput8 #undef IDirectInputDevice #undef IDirectInputDevice2 #undef IDirectInputDevice7 #undef IDirectInputDevice8 /* * And defines JOY_POVCENTERED incorrectly... */ #undef JOY_POVCENTERED #define JOY_POVCENTERED 0xFFFFFFFF /* * And older versions of windows.h don't have this definition. */ #ifndef HasOverlappedIoCompleted #define HasOverlappedIoCompleted(lpOverlapped) \ ((lpOverlapped)->Internal != STATUS_PENDING) #endif /*************************************************************************** * * Abbreviations.... * * Give shorter names to things we talk about frequently. * ***************************************************************************/ typedef LPDIRECTINPUT8 PDI , *PPDI ; typedef LPDIRECTINPUT8A PDIA, *PPDIA; typedef LPDIRECTINPUT8W PDIW, *PPDIW; typedef LPDIRECTINPUTDEVICE8 PDID , *PPDID ; typedef LPDIRECTINPUTDEVICE8A PDIDA, *PPDIDA; typedef LPDIRECTINPUTDEVICE8W PDIDW, *PPDIDW; typedef LPDIRECTINPUTEFFECT PDIE , *PPDIE ; typedef DIOBJECTDATAFORMAT ODF, *PODF; typedef const ODF *PCODF; typedef LPUNKNOWN PUNK; typedef LPVOID PV, *PPV; typedef CONST VOID *PCV; typedef REFIID RIID; typedef CONST GUID *PCGUID; /*************************************************************************** * * GetProcAddress'd KERNEL32 and USER32 functions. * ***************************************************************************/ typedef DWORD (WINAPI *OPENVXDHANDLE)(HANDLE); typedef BOOL (WINAPI *CANCELIO)(HANDLE); typedef DWORD (WINAPI *MSGWAITFORMULTIPLEOBJECTSEX) (DWORD, LPHANDLE, DWORD, DWORD, DWORD); typedef BOOL (WINAPI *TRYENTERCRITICALSECTION)(LPCRITICAL_SECTION); extern OPENVXDHANDLE _OpenVxDHandle; extern CANCELIO _CancelIO; extern MSGWAITFORMULTIPLEOBJECTSEX _MsgWaitForMultipleObjectsEx; #ifdef XDEBUG extern TRYENTERCRITICALSECTION _TryEnterCritSec; BOOL WINAPI FakeTryEnterCriticalSection(LPCRITICAL_SECTION lpCrit_sec); #endif DWORD WINAPI FakeMsgWaitForMultipleObjectsEx(DWORD, LPHANDLE, DWORD, DWORD, DWORD); BOOL WINAPI FakeCancelIO(HANDLE h); /*************************************************************************** * * Our global variables - see dinput.c for documentation * ***************************************************************************/ extern HINSTANCE g_hinst; #ifndef WINNT extern HANDLE g_hVxD; extern HANDLE g_hVjoyd; extern DWORD g_dwLastBonusPoll; #endif extern DWORD g_flEmulation; extern LPDWORD g_pdwSequence; #ifdef USE_SLOW_LL_HOOKS extern HHOOK g_hhkLLHookCheck; #define g_fUseLLHooks ((BOOL)(UINT_PTR)g_hhkLLHookCheck) #endif extern HANDLE g_hmtxGlobal; extern HANDLE g_hfm; extern struct SHAREDOBJECTPAGE *g_psop; extern UINT g_wmJoyChanged; extern HANDLE g_hmtxJoy; extern HINSTANCE g_hinstSetupapi; extern LONG g_lWheelGranularity; extern int g_cdtoMax; extern int g_cdto; extern struct _DEVICETOUSER *g_pdto; extern BOOL g_fRawInput; #ifdef USE_WM_INPUT extern HWND g_hwndThread; extern HANDLE g_hEventAcquire; extern HANDLE g_hEventThread; extern HANDLE g_hEventHid; #endif extern PDWORD g_rgdwCRCTable; typedef struct _DIAPPHACKS { BOOL fReacquire; BOOL fNoSubClass; int nMaxDeviceNameLength; } DIAPPHACKS, *LPDIAPPHACKS; extern DIAPPHACKS g_AppHacks; extern DWORD g_dwAppDate; extern DWORD g_dwAppFileLen; extern DWORD g_dwLastMsgSent; extern UINT g_wmDInputNotify; /***************************************************************************** * * Baggage * * Stuff I carry everywhere. * *****************************************************************************/ #define INTERNAL NTAPI /* Called only within a translation unit */ #define EXTERNAL NTAPI /* Called from other translation units */ #define INLINE static __inline #define BEGIN_CONST_DATA data_seg(".text", "CODE") #define END_CONST_DATA data_seg(".data", "DATA") /* * Arithmetic on pointers. */ #define pvSubPvCb(pv, cb) ((PV)((PBYTE)pv - (cb))) #define pvAddPvCb(pv, cb) ((PV)((PBYTE)pv + (cb))) #define cbSubPvPv(p1, p2) ((PBYTE)(p1) - (PBYTE)(p2)) /* * Convert an object (X) to a count of bytes (cb). */ #define cbX(X) sizeof(X) /* * Convert an array name (A) to a generic count (c). */ #define cA(a) (cbX(a)/cbX(a[0])) /* * Convert a count of X's (cx) into a count of bytes * and vice versa. */ #define cbCxX(cx, X) ((cx) * cbX(X)) #define cxCbX(cb, X) ((cb) / cbX(X)) /* * Convert a count of chars (cch), tchars (ctch), wchars (cwch), * or dwords (cdw) into a count of bytes, and vice versa. */ #define cbCch(cch) cbCxX( cch, CHAR) #define cbCwch(cwch) cbCxX(cwch, WCHAR) #define cbCtch(ctch) cbCxX(ctch, TCHAR) #define cbCdw(cdw) cbCxX( cdw, DWORD) #define cchCb(cb) cxCbX(cb, CHAR) #define cwchCb(cb) cxCbX(cb, WCHAR) #define ctchCb(cb) cxCbX(cb, TCHAR) #define cdwCb(cb) cxCbX(cb, DWORD) /* * Zero an arbitrary buffer. It is a common error to get the second * and third parameters to memset backwards. */ #define ZeroBuf(pv, cb) memset(pv, 0, cb) /* * Zero an arbitrary object. */ #define ZeroX(x) ZeroBuf(&(x), cbX(x)) /* * land -- Logical and. Evaluate the first. If the first is zero, * then return zero. Otherwise, return the second. */ #define fLandFF(f1, f2) ((f1) ? (f2) : 0) /* * lor -- Logical or. Evaluate the first. If the first is nonzero, * return it. Otherwise, return the second. * * Unfortunately, due to the *nature* of the C language, this can * be implemented only with a GNU extension. In the non-GNU case, * we return 1 if the first is nonzero. */ #if defined(__GNUC__) #define fLorFF(f1, f2) ((f1) ?: (f2)) #else #define fLorFF(f1, f2) ((f1) ? 1 : (f2)) #endif /* * limp - logical implication. True unless the first is nonzero and * the second is zero. */ #define fLimpFF(f1, f2) (!(f1) || (f2)) /* * leqv - logical equivalence. True if both are zero or both are nonzero. */ #define fLeqvFF(f1, f2) (!(f1) == !(f2)) /* * fInOrder - checks that i1 <= i2 < i3. */ #define fInOrder(i1, i2, i3) ((unsigned)((i2)-(i1)) < (unsigned)((i3)-(i1))) /* * fHasAllBitsFlFl - checks that all bits in fl2 are set in fl1. */ BOOL INLINE fHasAllBitsFlFl(DWORD fl1, DWORD fl2) { return (fl1 & fl2) == fl2; } /* * fEqualMask - checks that all masked bits are equal */ BOOL INLINE fEqualMaskFlFl(DWORD flMask, DWORD fl1, DWORD fl2) { return ((fl1 ^ fl2) & flMask) == 0; } /* * Words to keep preprocessor happy. */ #define comma , #define empty /* * Atomically exchange one value for another. */ #if defined(_M_IA64) || defined(_M_AMD64) #define InterlockedExchange64 _InterlockedExchange64 #ifndef RC_INVOKED #pragma intrinsic(_InterlockedExchange64) #endif /*RC_INVOKED*/ #define pvExchangePpvPv(ppv, pv) \ InterlockedExchange((ppv), (pv)) #define pvExchangePpvPv64(ppv, pv) \ InterlockedExchange64((ppv), (pv)) #else /*_M_IA64*/ #define pvExchangePpvPv(ppv, pv) \ (PV)InterlockedExchange((PLONG)(ppv), (LONG)(pv)) #define pvExchangePpvPv64(ppv, pv) \ (PV)InterlockedExchange((PLONG)(ppv), (LONG)(pv)) #endif /*_M_IA64*/ /* * Creating HRESULTs from a USHORT or from a LASTERROR. */ #define hresUs(us) MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(us)) #define hresLe(le) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, (USHORT)(le)) /* * or a registry function return code */ HRESULT INLINE hresReg( LONG lRc ) { return( (lRc) ? MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, (USHORT)(lRc)) : S_OK ); } /*************************************************************************** * * Debugging macros needed by inline functions * * The build of debugging goo is in debug.h * ***************************************************************************/ int EXTERNAL AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine); #ifdef DEBUG #define AssertFPtsz(c, ptsz) \ ((c) ? 0 : AssertPtszPtszLn(ptsz, TEXT(__FILE__), __LINE__)) #define ValidateF(c, arg) \ ((c) ? 0 : (RPF arg, ValidationException(), 0)) #define ConfirmF(c) \ ((c) ? 0 : AssertPtszPtszLn(TEXT(#c), TEXT(__FILE__), __LINE__)) #else /* !DEBUG */ #define AssertFPtsz(c, ptsz) #define ValidateF(c, arg) #define ConfirmF(c) (c) #endif /* * CAssertF - compile-time assertion. */ #define CAssertF(c) switch(0) case c: case 0: #define AssertF(c) AssertFPtsz(c, TEXT(#c)) /*************************************************************************** * * Validation Code.... * * "If it crashes in retail, it must crash in debug." * * What we don't want is an app that works fine under debug, but crashes * under retail. * * So if we find an invalid parameter in debug that would not have been * detected by retail, let it pass through after a warning. That way, * the invalid parameter continues onward through the system and creates * as much (or more) havoc in debug as it would under retail. * * There used to be _fFastValidXxx functions, but the decision was made * to do full validation always, except in inner-loop methods. * * The hresFullValidXxx functions return HRESULTs instead of BOOLs. * * Values for Xxx: * * Hwnd - hwnd = window handle * Pdw - pdw = pointer to a dword * PdwOut - pdw = pointer to a dword that will be set initially to 0 * Pfn - pfn = function pointer * riid - riid = pointer to IID * guid - pguid = pointer to GUID * Esc - pesc = pointer to DIEFFESCAPE * * ReadPx - p -> structure for reading, X = structure name * WritePx - p -> structure for writing, X = structure name * * ReadPxCb - p -> structure for reading, X = structure name * first field of structure is dwSize which must be * equal to cbX(X). * * WritePxCb - p -> structure for writing, X = structure name * first field of structure is dwSize which must be * equal to cbX(X). * * WritePxCb2 - p -> structure for writing, X = structure name * first field of structure is dwSize which must be * equal to cbX(X) or cbX(X2). * * ReadPvCb - p -> buffer, cb = size of buffer * WritePvCb - p -> buffer, cb = size of buffer * * Pobj - p -> internal interface * * fl - fl = incoming flags, flV = valid flags * ***************************************************************************/ #ifndef XDEBUG /* * Wrappers that throw away the szProc and iarg info. */ #define hresFullValidHwnd_(hwnd, z, i) \ _hresFullValidHwnd_(hwnd) \ #define hresFullValidPcbOut_(pdw, cb, z, i) \ _hresFullValidPcbOut_(pdw, cb) \ #define hresFullValidReadPxCb_(pv, cb, pszProc, iarg) \ _hresFullValidReadPxCb_(pv, cb) \ #define hresFullValidReadPvCb_(pv, cb, pszProc, iarg) \ _hresFullValidReadPvCb_(pv, cb) \ #define hresFullValidReadPxCb3_(pv, cb, cb2, cb3, pszProc, iarg) \ _hresFullValidReadPxCb3_(pv, cb, cb2, cb3) \ #define hresFullValidWritePxCb_(pv, cb, pszProc, iarg) \ _hresFullValidWritePxCb_(pv, cb) \ #define hresFullValidWritePxCb3_(pv, cb, cb2, cb3, pszProc, iarg) \ _hresFullValidWritePxCb3_(pv, cb, cb2, cb3) \ #define hresFullValidWriteNoScramblePxCb_(pv, cb, pszProc, iarg)\ _hresFullValidWriteNoScramblePxCb_(pv, cb) \ #define hresFullValidWritePvCb_(pv, cb, pszProc, iarg) \ _hresFullValidWritePvCb_(pv, cb) \ #define hresFullValidFl_(fl, flV, pszProc, iarg) \ _hresFullValidFl_(fl, flV) \ #define hresFullValidPfn_(pfn, pszProc, iarg) \ _hresFullValidPfn_(pfn) \ #define hresFullValidPitf_(punk, pszProc, iarg) \ _hresFullValidPitf_(punk) \ #define hresFullValidReadStrA_(psz, cch, pszProc, iarg) \ _hresFullValidReadStrA_(psz, cch) \ #define hresFullValidReadStrW_(pwsz, cwch, pszProc, iarg) \ _hresFullValidReadStrW_(pwsz, cwch) \ #define hresFullValidHwnd0_(hwnd, pszProc, iarg) \ _hresFullValidHwnd0_(hwnd) \ #define hresFullValidPitf0_(punk, pszProc, iarg) \ _hresFullValidPitf0_(punk) \ #define hresFullValidPesc_(pesc, pszProc, iarg) \ _hresFullValidPesc_(pesc) \ #define hresFullValidWriteLargePvCb_(pv, cb, pszProc, iarg) \ _hresFullValidWriteLargePvCb_(pv, cb) \ #endif /* * The actual functions. */ STDMETHODIMP hresFullValidHwnd_(HWND hwnd, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidPcbOut_(PV pdw, UINT cb, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidReadPxCb_(PCV pv, UINT cb, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidReadPvCb_(PCV pv, UINT cb, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidReadPxCb3_(PV pv, UINT cb, UINT cb2, UINT cb3, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidWritePxCb_(PV pv, UINT cb, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidWritePxCb3_(PV pv, UINT cb, UINT cb2, UINT cb3, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidWritePvCb_(PV pv, UINT cb, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidFl_(DWORD fl, DWORD flV, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidPfn_(FARPROC pfn, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidPitf_(PUNK punk, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidReadStrA_(LPCSTR psz, UINT cch, LPCSTR s_szProc, int iarg); STDMETHODIMP hresFullValidReadStrW_(LPCWSTR pwsz, UINT cwch, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidPesc_(LPDIEFFESCAPE pesc, LPCSTR pszProc, int iarg); STDMETHODIMP hresFullValidWriteLargePvCb_(PV pv, UINT cb, LPCSTR pszProc, int iarg); #ifdef XDEBUG STDMETHODIMP hresFullValidWriteNoScramblePxCb_(PV pv, UINT cb, LPCSTR s_szProc, int iarg); #define hresFullValidWriteNoScramblePvCb_(pv, cb, pszProc, iarg) \ hresFullValidWritePvCb_(pv, cb, pszProc, MAKELONG(iarg, 1)) \ #else /* * Retail doesn't scramble. */ #define _hresFullValidWriteNoScramblePxCb_ \ _hresFullValidWritePxCb_ \ #define _hresFullValidWriteNoScramblePxCb3_ \ _hresFullValidWritePxCb3_ \ #define hresFullValidWriteNoScramblePvCb_ \ hresFullValidWritePvCb_ \ #endif HRESULT INLINE hresFullValidHwnd0_(HWND hwnd, LPCSTR pszProc, int iarg) { HRESULT hres; if(hwnd) { hres = hresFullValidHwnd_(hwnd, pszProc, iarg); } else { hres = S_OK; } return hres; } HRESULT INLINE hresFullValidPitf0_(PUNK punk, LPCSTR pszProc, int iarg) { HRESULT hres; if(punk) { hres = hresFullValidPitf_(punk, pszProc, iarg); } else { hres = S_OK; } return hres; } /* * Wrappers for derived types. */ #define hresFullValidRiid_(riid, s_szProc, iarg) \ hresFullValidReadPvCb_(riid, cbX(IID), s_szProc, iarg) \ /* * Wrapers that add the szProc and iarg info. */ #define hresFullValidHwnd(hwnd, iarg) \ hresFullValidHwnd_(hwnd, s_szProc, iarg) \ #define hresFullValidPcbOut(pdw, cb, i) \ hresFullValidPcbOut_(pdw, cb, s_szProc, i) \ #define hresFullValidReadPdw_(pdw, z, i) \ hresFullValidReadPvCb_(pdw, cbX(DWORD), z, i) \ #define hresFullValidRiid(riid, iarg) \ hresFullValidRiid_(riid, s_szProc, iarg) \ #define hresFullValidGuid(pguid, iarg) \ hresFullValidReadPvCb_(pguid, cbX(GUID), s_szProc, iarg) \ #define hresFullValidReadPxCb(pv, X, iarg) \ hresFullValidReadPxCb_(pv, cbX(X), s_szProc, iarg) \ #define hresFullValidReadPxCb2(pv, X, X2, iarg) \ hresFullValidReadPxCb_(pv, MAKELONG(cbX(X), cbX(X2)), \ s_szProc, iarg) \ #define hresFullValidReadPvCb(pv, cb, iarg) \ hresFullValidReadPvCb_(pv, cb, s_szProc, iarg) \ #define hresFullValidReadPx(pv, X, iarg) \ hresFullValidReadPvCb_(pv, cbX(X), s_szProc, iarg) \ #define hresFullValidReadPxCb3(pv, X, X2, X3, iarg) \ hresFullValidReadPxCb3_(pv, cbX(X), cbX(X2), cbX(X3), \ s_szProc, iarg) \ #define hresFullValidWritePxCb(pv, X, iarg) \ hresFullValidWritePxCb_(pv, cbX(X), s_szProc, iarg) \ #define hresFullValidWritePxCb2(pv, X, X2, iarg) \ hresFullValidWritePxCb_(pv, MAKELONG(cbX(X), cbX(X2)), \ s_szProc, iarg) \ #define hresFullValidWritePxCb3(pv, X, X2, X3, iarg) \ hresFullValidWritePxCb3_(pv, cbX(X), cbX(X2), cbX(X3), \ s_szProc, iarg) \ #define hresFullValidWriteNoScramblePxCb(pv, X, iarg) \ hresFullValidWriteNoScramblePxCb_(pv, cbX(X), s_szProc, iarg)\ #define hresFullValidWriteNoScramblePxCb2(pv, X, X2, iarg) \ hresFullValidWriteNoScramblePxCb_(pv, MAKELONG(cbX(X), cbX(X2)),\ s_szProc, iarg)\ #define hresFullValidWritePvCb(pv, cb, iarg) \ hresFullValidWritePvCb_(pv, cb, s_szProc, iarg) \ #define hresFullValidWriteNoScramblePvCb(pv, cb, iarg) \ hresFullValidWriteNoScramblePvCb_(pv, cb, s_szProc, iarg) \ #define hresFullValidWritePx(pv, X, iarg) \ hresFullValidWritePvCb_(pv, cbX(X), s_szProc, iarg) \ #define hresFullValidReadPdw(pdw, iarg) \ hresFullValidReadPdw_(pdw, s_szProc, iarg) \ #define hresFullValidWritePguid(pguid, iarg) \ hresFullValidWritePx(pguid, GUID, iarg) \ #define hresFullValidFl(fl, flV, iarg) \ hresFullValidFl_(fl, flV, s_szProc, iarg) \ #define hresFullValidPfn(pfn, iarg) \ hresFullValidPfn_((FARPROC)(pfn), s_szProc, iarg) \ #define hresFullValidPitf(pitf, iarg) \ hresFullValidPitf_((PUNK)(pitf), s_szProc, iarg) \ #define hresFullValidReadStrA(psz, cch, iarg) \ hresFullValidReadStrA_(psz, cch, s_szProc, iarg) \ #define hresFullValidReadStrW(pwsz, cwch, iarg) \ hresFullValidReadStrW_(pwsz, cwch, s_szProc, iarg) \ #define hresFullValidHwnd0(hwnd, iarg) \ hresFullValidHwnd0_(hwnd, s_szProc, iarg) \ #define hresFullValidPitf0(pitf, iarg) \ hresFullValidPitf0_((PUNK)(pitf), s_szProc, iarg) \ #define hresFullValidPesc(pesc, iarg) \ hresFullValidPesc_(pesc, s_szProc, iarg) \ #define hresFullValidWriteLargePvCb(pv, cb, iarg) \ hresFullValidWriteLargePvCb_(pv, cb, s_szProc, iarg) \ /***************************************************************************** * * @doc INTERNAL * * @func void | ValidationException | * * Raises a parameter validation exception in XDEBUG. * *****************************************************************************/ #define ecValidation (ERROR_SEVERITY_ERROR | hresLe(ERROR_INVALID_PARAMETER)) #ifdef XDEBUG #define ValidationException() RaiseException(ecValidation, 0, 0, 0) #else #define ValidationException() #endif /***************************************************************************** * * Bilingualism * * Special macros that help writing ANSI and UNICODE versions of * the same underlying interface. * *****************************************************************************/ /* * _THAT is something you tack onto the end of a "bilingual" interface. * In debug, it expands to the magic third argument which represents * the vtbl the object should have. In retail, it expands to nothing. */ #ifdef XDEBUG #define _THAT , PV vtblExpected #define THAT_ , vtblExpected #else #define _THAT #define THAT_ #endif /* * CSET_STUBS creates stubs for ANSI and UNICODE versions of the * same procedure that is not character set-sensitive. * * mf - method function name * arg1 - argument list in prototype form * arg2 - argument list for calling (with _riid appended). * * It is assumed that the caller has already defined the symbols * ThisClass and ThisInterface[AWT]. * * This macro should be used only in DEBUG. In retail, the common * procedure handles both character sets directly. */ #ifdef XDEBUG #define CSET_STUBS(mf, arg1, arg2) \ CSET_STUB(TFORM, mf, arg1, arg2) \ CSET_STUB(SFORM, mf, arg1, arg2) \ #define CSET_STUB(FORM, mf, arg1, arg2) \ _CSET_STUB(FORM, mf, arg1, arg2, ThisClass, ThisInterface) \ #define _CSET_STUB(FORM, mf, arg1, arg2, cls, itf) \ __CSET_STUB(FORM, mf, arg1, arg2, cls, itf) \ #define __CSET_STUB(FORM, mf, arg1, arg2, cls, itf) \ STDMETHODIMP \ FORM(cls##_##mf) arg1 \ { \ PV vtblExpected = Class_Vtbl(ThisClass, FORM(ThisInterfaceT)); \ return cls##_##mf arg2; \ } \ #endif /* * TFORM(x) expands to x##A if ANSI or x##W if UNICODE. * This T-izes a symbol, in the sense of TCHAR or PTSTR. * * SFORM(x) expands to x##W if ANSI or x##A if UNICODE. * This anti-T-izes a symbol. */ #ifdef UNICODE #define _TFORM(x) x##W #define _SFORM(x) x##A #else #define _TFORM(x) x##A #define _SFORM(x) x##W #endif #define TFORM(x) _TFORM(x) #define SFORM(x) _SFORM(x) #ifdef UNICODE typedef CHAR SCHAR; #else typedef WCHAR SCHAR; #endif typedef SCHAR * LPSSTR; typedef const SCHAR * LPCSSTR; /* * SToT(dst, cchDst, src) - convert S to T * TToS(dst, cchDst, src) - convert T to S * * Remember, "T" means "ANSI if ANSI, or UNICODE if UNICODE", * and "S" is the anti-T. * * So SToT converts to the preferred character set, and TToS converts * to the alternate character set. * */ #define AToU(dst, cchDst, src) \ MultiByteToWideChar(CP_ACP, 0, src, -1, dst, cchDst) #define UToA(dst, cchDst, src) \ WideCharToMultiByte(CP_ACP, 0, src, -1, dst, cchDst, 0, 0) #ifdef UNICODE #define SToT AToU #define TToS UToA #define AToT AToU #define TToU(dst, cchDst, src) lstrcpyn(dst, src, cchDst) #define UToT(dst, cchDst, src) lstrcpyn(dst, src, cchDst) #else #define SToT UToA #define TToS AToU #define AToT(dst, cchDst, src) lstrcpyn(dst, src, cchDst) #define TToU AToU #define UToT UToA #endif /***************************************************************************** * * Unicode wrappers for Win95 * *****************************************************************************/ #ifndef UNICODE #define LoadStringW _LoadStringW int EXTERNAL LoadStringW(HINSTANCE hinst, UINT ids, LPWSTR pwsz, int cwch); #define RegDeleteKeyW _RegDeleteKeyW LONG EXTERNAL RegDeleteKeyW(HKEY hk, LPCWSTR pwsz); #endif /***************************************************************************** * * Registry access functions * *****************************************************************************/ //our own version of KEY_ALL_ACCESS, that does not use WRITE_DAC and WRITE_OWNER (see Whistler bug 318865) #define DI_DAC_OWNER (WRITE_DAC | WRITE_OWNER) #define DI_KEY_ALL_ACCESS (KEY_ALL_ACCESS & ~DI_DAC_OWNER) LONG EXTERNAL RegQueryString(HKEY hk, LPCTSTR ptszValue, LPTSTR ptszBuf, DWORD ctchBuf); LONG EXTERNAL RegQueryStringValueW(HKEY hk, LPCTSTR ptszValue, LPWSTR pwszBuf, LPDWORD pcbBuf); LONG EXTERNAL RegSetStringValueW(HKEY hk, LPCTSTR ptszValue, LPCWSTR pwszBuf); DWORD EXTERNAL RegQueryDIDword(LPCTSTR ptszPath, LPCTSTR ptszValue, DWORD dwDefault); STDMETHODIMP hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk); STDMETHODIMP hresRegCopyValues( HKEY hkSrc, HKEY hkDest ); STDMETHODIMP hresRegCopyKey( HKEY hkSrcRoot, PTCHAR szSrcName, PTCHAR szClass, HKEY hkDestRoot, PTCHAR szDestName, HKEY *phkSub ); STDMETHODIMP hresRegCopyKeys( HKEY hkSrc, HKEY hkRoot, PDWORD OPTIONAL pMaxNameLen ); STDMETHODIMP hresRegCopyBranch( HKEY hkSrc, HKEY hkDest ); /***************************************************************************** * * Common Object Managers for the Component Object Model * * OLE wrapper macros and structures. For more information, see * the beginning of common.c * *****************************************************************************/ /***************************************************************************** * * Pre-vtbl structures * * Careful! If you change these structures, you must also adjust * common.c accordingly. * *****************************************************************************/ typedef struct PREVTBL { /* Shared vtbl prefix */ RIID riid; /* Type of this object */ LONG lib; /* offset from start of object */ } PREVTBL, *PPREVTBL; typedef struct PREVTBLP { /* Prefix for primary vtbl */ #ifdef DEBUG LPCTSTR tszClass; /* Class name (for squirties) */ #endif PPV rgvtbl; /* Array of standard vtbls */ UINT cbvtbl; /* Size of vtbl array in bytes */ STDMETHOD(QIHelper)(PV pv, RIID riid, PPV ppvOut); /* QI helper */ STDMETHOD_(void,AppFinalizeProc)(PV pv);/* App finalization procedure */ STDMETHOD_(void,FinalizeProc)(PV pv);/* Finalization procedure */ PREVTBL prevtbl; /* lib must be zero */ } PREVTBLP, *PPREVTBLP; /* * A fuller implementation is in common.c. Out here, we need only * concern ourselves with getting to the primary interface. */ #define _thisPv(pitf) \ pvSubPvCb(pitf, (*(PPREVTBL*)(pitf))[-1].lib) #define _thisPvNm(pitf, nm) \ pvSubPvCb(pitf, FIELD_OFFSET(ThisClass, nm)) \ #ifndef XDEBUG #define hresPvVtbl_(pv, vtbl, pszProc) \ _hresPvVtbl_(pv, vtbl) \ #endif HRESULT EXTERNAL hresPvVtbl_(PV pv, PV vtbl, LPCSTR pszProc); #define hresPvVtbl(pv, vtbl) \ hresPvVtbl_(pv, vtbl, s_szProc) \ #define hresPvI(pv, I) \ hresPvVtbl(pv, Class_Vtbl(ThisClass, I)) \ #define hresPv(pv) \ hresPvI(pv, ThisInterface) \ #define hresPvA(pv) \ hresPvI(pv, ThisInterfaceA) \ #define hresPvW(pv) \ hresPvI(pv, ThisInterfaceW) \ #ifdef XDEBUG #define hresPvT(pv) \ hresPvVtbl(pv, vtblExpected) \ #else #define hresPvT(pv) \ hresPv(pv) \ #endif /***************************************************************************** * * Declaring interfaces * * The extra level of indirection on _Primary_Interface et al * allow the interface name to be a macro which expands to the * *real* name of the interface. * *****************************************************************************/ #define __Class_Vtbl(C, I) &c_##I##_##C##VI.vtbl #define _Class_Vtbl(C, I) __Class_Vtbl(C, I) #define Class_Vtbl(C, I) _Class_Vtbl(C, I) #define Num_Interfaces(C) cA(c_rgpv##C##Vtbl) #ifdef DEBUG #define Simple_Interface(C) Primary_Interface(C, IUnknown); \ Default_QueryInterface(C) \ Default_AddRef(C) \ Default_Release(C) #define Simple_Vtbl(C) Class_Vtbl(C) #define Simple_Interface_Begin(C) Primary_Interface_Begin(C, IUnknown) #define Simple_Interface_End(C) Primary_Interface_End(C, IUnknown) #else #define Simple_Interface(C) Primary_Interface(C, IUnknown) #define Simple_Vtbl(C) Class_Vtbl(C) #define Simple_Interface_Begin(C) \ struct S_##C##Vtbl c_##I##_##C##VI = { { \ c_rgpv##C##Vtbl, \ cbX(c_rgpv##C##Vtbl), \ C##_QIHelper, \ C##_AppFinalize, \ C##_Finalize, \ { &IID_##IUnknown, 0 }, \ }, { \ Common##_QueryInterface, \ Common##_AddRef, \ Common##_Release, \ #define Simple_Interface_End(C) \ } }; \ #endif #define _Primary_Interface(C, I) \ extern struct S_##C##Vtbl { \ PREVTBLP prevtbl; \ I##Vtbl vtbl; \ } c_##I##_##C##VI \ #define Primary_Interface(C, I) \ _Primary_Interface(C, I) \ #ifdef DEBUG #define _Primary_Interface_Begin(C, I) \ struct S_##C##Vtbl c_##I##_##C##VI = { { \ TEXT(#C), \ c_rgpv##C##Vtbl, \ cbX(c_rgpv##C##Vtbl), \ C##_QIHelper, \ C##_AppFinalize, \ C##_Finalize, \ { &IID_##I, 0, }, \ }, { \ C##_QueryInterface, \ C##_AddRef, \ C##_Release, \ #else #define _Primary_Interface_Begin(C, I) \ struct S_##C##Vtbl c_##I##_##C##VI = { { \ c_rgpv##C##Vtbl, \ cbX(c_rgpv##C##Vtbl), \ C##_QIHelper, \ C##_AppFinalize, \ C##_Finalize, \ { &IID_##I, 0, }, \ }, { \ C##_QueryInterface, \ C##_AddRef, \ C##_Release, \ #endif #define Primary_Interface_Begin(C, I) \ _Primary_Interface_Begin(C, I) \ #define Primary_Interface_End(C, I) \ } }; \ #define _Secondary_Interface(C, I) \ extern struct S_##I##_##C##Vtbl { \ PREVTBL prevtbl; \ I##Vtbl vtbl; \ } c_##I##_##C##VI \ #define Secondary_Interface(C, I) \ _Secondary_Interface(C, I) \ /* * Secret backdoor for the "private" IUnknown in common.c */ #define _Secondary_Interface_Begin(C, I, ofs, Pfx) \ struct S_##I##_##C##Vtbl c_##I##_##C##VI = { { \ &IID_##I, \ ofs, \ }, { \ Pfx##QueryInterface, \ Pfx##AddRef, \ Pfx##Release, \ #define Secondary_Interface_Begin(C, I, nm) \ _Secondary_Interface_Begin(C, I, FIELD_OFFSET(C, nm), Common_) \ #define _Secondary_Interface_End(C, I) \ } }; \ #define Secondary_Interface_End(C, I, nm) \ _Secondary_Interface_End(C, I) \ #define Interface_Template_Begin(C) \ PV c_rgpv##C##Vtbl[] = { \ #define Primary_Interface_Template(C, I) \ Class_Vtbl(C, I), \ #define Secondary_Interface_Template(C, I) \ Class_Vtbl(C, I), \ #define Interface_Template_End(C) \ }; \ STDMETHODIMP Common_QueryInterface(PV, RIID, PPV); STDMETHODIMP_(ULONG) Common_AddRef(PV pv); STDMETHODIMP_(ULONG) Common_Release(PV pv); STDMETHODIMP_(void) Common_Hold(PV pv); STDMETHODIMP_(void) Common_Unhold(PV pv); STDMETHODIMP Common_QIHelper(PV, RIID, PPV); void EXTERNAL Common_Finalize(PV); #define Common_AppFinalize Common_Finalize #ifndef XDEBUG #define _Common_New_(cb, punkOuter, vtbl, pvpObj, z) \ __Common_New_(cb, punkOuter, vtbl, pvpObj) \ #define _Common_NewRiid_(cb, vtbl, punkOuter, riid, pvpObj, z) \ __Common_NewRiid_(cb, vtbl, punkOuter, riid, pvpObj) \ #endif STDMETHODIMP _Common_New_(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj, LPCSTR s_szProc); STDMETHODIMP _Common_NewRiid_(ULONG cb, PV vtbl, PUNK punkOuter, RIID riid, PPV pvpObj, LPCSTR s_szProc); #define Common_NewCb(cb, C, punkOuter, ppvObj) \ _Common_New_(cb, punkOuter, Class_Vtbl(C, ThisInterface), ppvObj, s_szProc) #define Common_New(C, punkOuter, ppvObj) \ Common_NewCb(cbX(C), C, punkOuter, ppvObj) \ #define Common_NewCbRiid(cb, C, punkOuter, riid, ppvObj) \ _Common_NewRiid_(cb, Class_Vtbl(C, ThisInterface), punkOuter, riid, ppvObj, s_szProc) #define Common_NewRiid(C, punkOuter, riid, ppvObj) \ _Common_NewRiid_(cbX(C), Class_Vtbl(C, ThisInterface), punkOuter, riid, ppvObj, s_szProc) #ifdef DEBUG PV EXTERNAL Common_IsType(PV pv); #else #define Common_IsType #endif #define Assert_CommonType Common_IsType STDMETHODIMP Forward_QueryInterface(PV pv, RIID riid, PPV ppvObj); STDMETHODIMP_(ULONG) Forward_AddRef(PV pv); STDMETHODIMP_(ULONG) Forward_Release(PV pv); void EXTERNAL Invoke_Release(PV pv); #define Common_DumpObjects() /***************************************************************************** * * OLE wrappers * * These basically do the same as IUnknown_Mumble, except that they * avoid side-effects in evaluation by being inline functions. * *****************************************************************************/ HRESULT INLINE OLE_QueryInterface(PV pv, RIID riid, PPV ppvObj) { PUNK punk = pv; return punk->lpVtbl->QueryInterface(punk, riid, ppvObj); } ULONG INLINE OLE_AddRef(PV pv) { PUNK punk = pv; return punk->lpVtbl->AddRef(punk); } ULONG INLINE OLE_Release(PV pv) { PUNK punk = pv; return punk->lpVtbl->Release(punk); } /***************************************************************************** * * Macros that forward to the common handlers after squirting. * Use these only in DEBUG. * * It is assumed that sqfl has been #define'd to the appropriate sqfl. * *****************************************************************************/ #ifdef DEBUG #define Default_QueryInterface(Class) \ STDMETHODIMP \ Class##_QueryInterface(PV pv, RIID riid, PPV ppvObj) \ { \ SquirtSqflPtszV(sqfl, TEXT(#Class) TEXT("_QueryInterface()")); \ return Common_QueryInterface(pv, riid, ppvObj); \ } \ // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers. #define Default_AddRef(Class) \ STDMETHODIMP_(ULONG) \ Class##_AddRef(PV pv) \ { \ ULONG ulRc = Common_AddRef(pv); \ SquirtSqflPtszV(sqfl, TEXT(#Class) TEXT("_AddRef(%p) -> %d"), pv, ulRc); \ return ulRc; \ } \ // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers. #define Default_Release(Class) \ STDMETHODIMP_(ULONG) \ Class##_Release(PV pv) \ { \ ULONG ulRc = Common_Release(pv); \ SquirtSqflPtszV(sqfl, TEXT(#Class) TEXT("_Release(%p) -> %d"), pv, ulRc); \ return ulRc; \ } \ #endif /***************************************************************************** * * Paranoid callbacks * * Callback() performs a callback. The callback must accept exactly * two parameters, both pointers. (All our callbacks are like this.) * And it must return a BOOL. * *****************************************************************************/ typedef BOOL (FAR PASCAL * DICALLBACKPROC)(LPVOID, LPVOID); #ifdef XDEBUG BOOL EXTERNAL Callback(DICALLBACKPROC, PVOID, PVOID); #else #define Callback(pec, pv1, pv2) pec(pv1, pv2) #endif #if 0 /***************************************************************************** * * Groveling into a CONTEXT structure. * * This is used to check that a callback procedure is properly * prototyped. We save the stack register before calling the * procedure and compare it with the stack register on the way back. * If they are different, explode! * * ctxEsp is the name of the stack pointer register. * *****************************************************************************/ typedef struct STACKINFO { CONTEXT ctxPre; /* Thread context before call */ CONTEXT ctxPost; /* Thread context after call */ } STACKINFO, *PSTACKINFO; #ifdef XDEBUG #if defined(_X86_) #define ctxEsp Esp #elif defined(_ALPHA_) #define ctxEsp IntSp #elif defined(_MIPS_) #define ctxEsp IntSp #elif defined(_PPC_) #define ctxEsp Gpr1 #else #pragma message("I don't know what the stack register is called on this platform") #endif #endif #ifdef ctxEsp #define DECLARE_STACKINFO() \ STACKINFO si \ #define PRE_CALLBACK() \ si.ctxPre.ContextFlags = CONTEXT_CONTROL; \ GetThreadContext(GetCurrentThread(), &si.ctxPre) \ #define POST_CALLBACK() \ si.ctxPost.ContextFlags = CONTEXT_CONTROL; \ if (GetThreadContext(GetCurrentThread(), &si.ctxPost) && \ si.ctxPre.ctxEsp != si.ctxPost.ctxEsp) { \ RPF("DINPUT: Incorrectly prototyped callback! Crash soon!"); \ ValidationException(); \ } \ #else #define DECLARE_STACKINFO() #define PRE_CALLBACK() #define POST_CALLBACK() #endif #endif /***************************************************************************** * * Alternative message cracker macros * * Basically the same as HANDLE_MSG, except that it stashes the * answer into hres. * *****************************************************************************/ #define HRES_MSG(this, msg, fn) \ case msg: hres = HANDLE_##msg(this, wParam, lParam, fn); break /***************************************************************************** * * Registry keys and value names * *****************************************************************************/ #define REGSTR_PATH_DINPUT TEXT("Software\\Microsoft\\DirectInput") #define REGSTR_KEY_APPHACK TEXT("Compatibility") #define REGSTR_KEY_TEST TEXT("Test") #define REGSTR_KEY_KEYBTYPE REGSTR_KEY_TEST TEXT("\\KeyboardType") #define REGSTR_VAL_EMULATION TEXT("Emulation") #define REGSTR_VAL_GAMEPADDELAY TEXT("GamepadDelay") #define REGSTR_VAL_JOYNFFCONFIG TEXT("Joystick%dFFConfiguration") #define REGSTR_VAL_JOYGAMEPORTEMULATOR TEXT("OEMEmulator") #define REGSTR_VAL_CPLCLSID TEXT("ConfigCLSID") #define REGSTR_KEY_JOYPREDEFN TEXT("predef%d") #define REGSTR_VAL_JOYOEMCALLOUT TEXT("OEMCallout") #define REGSTR_VAL_JOYOEMHARDWAREID TEXT("OEMHardwareID") #define REGSTR_VAL_FLAGS1 TEXT("Flags1") #define REGSTR_VAL_FLAGS2 TEXT("Flags2") #define REGSTR_PATH_DITYPEPROP REGSTR_PATH_PRIVATEPROPERTIES TEXT("\\DirectInput") #define REGSTR_VAL_JOYOEMMAPFILE TEXT("OEMMapFile") /***************************************************************************** * * Registered window messages * *****************************************************************************/ #define MSGSTR_JOYCHANGED TEXT("MSJSTICK_VJOYD_MSGSTR") /***************************************************************************** * * mem.c - Memory management * * Be extremely careful with FreePv, because it doesn't work if * the pointer is null. * *****************************************************************************/ #define NEED_REALLOC STDMETHODIMP EXTERNAL ReallocCbPpv(UINT cb, PV ppvObj); STDMETHODIMP EXTERNAL AllocCbPpv(UINT cb, PV ppvObj); #ifdef NEED_REALLOC #define FreePpv(ppv) (void)ReallocCbPpv(0, ppv) #else void EXTERNAL FreePpv(PV ppv); #define FreePpv(ppv) FreePpv(ppv) #endif #define FreePv(pv) LocalFree((HLOCAL)(pv)) /***************************************************************************** * * diutil.c - Misc utilities * *****************************************************************************/ extern GUID GUID_Null; #define ctchGuid (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1) BOOL EXTERNAL ParseGUID(LPGUID pGUID, LPCTSTR ptsz); BOOL EXTERNAL ParseVIDPID(PUSHORT puVID, PUSHORT puPID , LPCWSTR ptsz); #define ctchNamePrefix 12 /* 12 = strlen("DirectInput.") */ #define ctchNameGuid (ctchNamePrefix + ctchGuid) void EXTERNAL NameFromGUID(LPTSTR ptszBuf, PCGUID pGUID); typedef STDMETHOD(CREATEDCB)(PUNK, REFGUID, RIID, PPV); typedef struct DIOBJECTSTATICDATA { union { PCGUID rguidInstance; /* If a static device */ UINT uiButtons; /* If a HID mouse */ }; DWORD dwDevType; union { CREATEDCB CreateDcb; /* If a static device */ UINT uiAxes; /* If a HID mouse */ }; } DIOBJECTSTATICDATA, *PDIOBJECTSTATICDATA, **PPDIOBJECTSTATICDATA; HRESULT EXTERNAL hresRunControlPanel(LPCTSTR ptszCpl); HRESULT EXTERNAL DiActionFormatAtoW(const LPDIACTIONFORMATA lpDiAfA, LPDIACTIONFORMATW* lplpDiAfW); HRESULT EXTERNAL DiActionFormatWtoW(const LPDIACTIONFORMATW lpDiAfW0, LPDIACTIONFORMATW* lplpDiAfW); void FreeDiActionFormatW(LPDIACTIONFORMATW* lplpDiAfW ); void EXTERNAL ObjectInfoWToA(LPDIDEVICEOBJECTINSTANCEA pdoiA, LPCDIDEVICEOBJECTINSTANCEW pdoiW); void EXTERNAL EffectInfoWToA(LPDIEFFECTINFOA pdeiA, LPCDIEFFECTINFOW pdeiW); #ifndef XDEBUG #define hresFindInstanceGUID_(pGUID, pcdcb, z, i) \ _hresFindInstanceGUID_(pGUID, pcdcb) \ #define hresValidInstanceVer_(hinst, dwVer, z) \ _hresValidInstanceVer_(hinst, dwVer) \ #endif HRESULT EXTERNAL hresFindInstanceGUID_(PCGUID pGUID, CREATEDCB *pcdcb, LPCSTR s_szProc, int iarg); HRESULT EXTERNAL hresValidInstanceVer_(HINSTANCE hinst, DWORD dwVersion, LPCSTR s_szProc); #define hresFindInstanceGUID(pGuid, pcdcb, iarg) \ hresFindInstanceGUID_(pGuid, pcdcb, s_szProc, iarg) \ #define hresValidInstanceVer(hinst, dwVer) \ hresValidInstanceVer_(hinst, dwVer, s_szProc) \ HRESULT EXTERNAL DupEventHandle(HANDLE h, LPHANDLE phOut); DWORD EXTERNAL GetWindowPid(HWND hwnd); PV EXTERNAL pvFindResource(HINSTANCE hinst, DWORD id, LPCTSTR rt); void EXTERNAL GetNthString(LPWSTR pwsz, UINT ids, UINT ui); #define GetNthButtonString(pwsz, ui) \ GetNthString(pwsz, IDS_BUTTONTEMPLATE, ui) #define GetNthAxisString(pwsz, ui) \ GetNthString(pwsz, IDS_AXISTEMPLATE, ui) #define GetNthPOVString(pwsz, ui) \ GetNthString(pwsz, IDS_POVTEMPLATE, ui) HRESULT EXTERNAL hresDupPtszPptsz(LPCTSTR ptszSrc, LPTSTR *pptszDst); BOOL EXTERNAL fInitializeCriticalSection(LPCRITICAL_SECTION pCritSec); void EXTERNAL DiCharUpperW(LPWSTR pwsz); typedef int ( __stdcall * COMP_FUNC )( PV, PV ); void ptrPartialQSort( PPV ppL, PPV ppR, COMP_FUNC fpCompare ); void ptrInsertSort( PPV ppBase, PPV ppLast, COMP_FUNC fpCompare ); void __cdecl shortsort (char *lo,char *hi,unsigned width,int (__cdecl *comp)(const void *, const void *)); STDMETHODIMP GetWideUserName ( LPCSTR lpszUserName, LPCWSTR lpwszUserName, LPWSTR *ppwszGoodUserName ); DWORD EXTERNAL GetValidDI8DevType ( DWORD dwDevType, DWORD dwNumButtons, DWORD dwFlags ); HRESULT DIGetKeyNameText( UINT index, DWORD dwDevType, LPWSTR lpwszName, int nSize ); #define WIN_UNKNOWN_OS 0 #define WIN95_OS 1 #define WIN98_OS 2 #define WINME_OS 3 #define WINNT_OS 4 #define WINWH_OS 5 DWORD INTERNAL DIGetOSVersion(); /***************************************************************************** * * dilist.c * *****************************************************************************/ /***************************************************************************** * * @doc INTERNAL * * @struct GPA | * * Growable pointer array. * * @field PPV | rgpv | * * The base of the array of pointers. * * @field int | cpv | * * The number of pointers in use in the array. * * @field int | cpvAlloc | * * The number of pointers allocated in the array. * *****************************************************************************/ typedef struct GPA { PPV rgpv; int cpv; int cpvAlloc; } GPA, *HGPA; void EXTERNAL GPA_Init(HGPA hgpa); void EXTERNAL GPA_Term(HGPA hgpa); STDMETHODIMP GPA_Append(HGPA hgpa, PV pv); BOOL EXTERNAL GPA_FindPtr(HGPA hgpa, PV pv); STDMETHODIMP GPA_DeletePtr(HGPA hgpa, PV pv); STDMETHODIMP GPA_Clone(HGPA hgpaDst, HGPA hgpaSrc); /***************************************************************************** * * @doc INTERNAL * * @func void | GPA_InitFromZero | * * Initialize a GPA structure that is already zero-initialized. * * @parm HGPA | hgpa | * * Handle to pointer array. * *****************************************************************************/ /* * Nothing needs to be done; zero-init is just fine. * * Note: didev.c also has a global GPA, and it assumes that zero-init * is just fine. */ #define GPA_InitFromZero(hgpa) /***************************************************************************** * * dioledup.c * *****************************************************************************/ STDMETHODIMP DICoCreateInstance(LPTSTR ptszClsid, LPUNKNOWN punkOuter, RIID riid, PPV ppvOut, HINSTANCE *phinst); /***************************************************************************** * * diexcl.c - Exclusive access management * * We also keep GUID uniqueness goo up here, because it is * diexcl.c that manages shared memory. * *****************************************************************************/ STDMETHODIMP Excl_Acquire(PCGUID pguid, HWND hwnd, DWORD discl); void EXTERNAL Excl_Unacquire(PCGUID pguid, HWND hwnd, DWORD discl); STDMETHODIMP Excl_Init(void); LONG EXTERNAL Excl_UniqueGuidInteger(void); DWORD EXTERNAL Excl_GetConfigChangedTime(); void EXTERNAL Excl_SetConfigChangedTime(DWORD tm); /***************************************************************************** * * @doc INTERNAL * * @struct GLOBALJOYSTATE | * * Structure that records global joystick state information. * * @field DWORD | dwTag | * * Counter used to keep track of how many times each joystick's * force feedback driver has been reset. This is used to make * sure that nobody messes with a joystick that he doesn't own. * * Each time the joystick is reset, the corresponding counter * is incremented. Before we do anything to a device, we check * if the reset counter matches the value stored in the * object. If not, then it means that the device has been * reset in the meantime and no longer belongs to the caller. * * @field DWORD | dwCplGain | * * Control panel (global) gain setting for the joystick. * * @field DWORD | dwDevGain | * * Most recent device (local) gain applied to the joystick. * * This is cached so that when the global gain changes, * we know what physical gain to apply as a result. * *****************************************************************************/ typedef struct GLOBALJOYSTATE { DWORD dwTag; DWORD dwCplGain; DWORD dwDevGain; } GLOBALJOYSTATE, *PGLOBALJOYSTATE; /***************************************************************************** * * @doc INTERNAL * * @struct SHAREDOBJECTHEADER | * * A simple header comes in front of the array of objects. * * WARNING! This structure may not change between DEBUG and * RETAIL. Otherwise, you have problems if one DirectInput * app is using DEBUG and another is using RETAIL. * * The global variable points to one of these things, * suitably cast. * * @field int | cso | * * Number of s currently in use. The array * is kept packed for simplicity. * * @field DWORD | dwSequence | * * Global sequence number used during data collection. * (Not used if we have a VxD to manage a "really global" * sequence number.) * * @field int | cguid | * * Unique integer for GUID generation. * * @field DWORD | rgdwJoy[cMaxJoy] | * * Counter used to keep track of how many times each joystick's * force feedback driver has been reset. This is used to make * sure that nobody messes with a joystick that they don't own. * * Each time the joystick is reset, the corresponding counter * is incremented. Before we do anything to a device, we check * if the reset counter matches the value stored in the * object. If not, then it means that the device has been * reset in the meantime and no longer belongs to the caller. * * Note! We support up to 16 joysticks. Hope that'll be enough * for a while. * * @field GLOBALJOYSTATE | rggjs[cMaxJoy] | * * Global settings for each joystick. * * @field DWORD | tmConfigChanged * * The tick count of last config changed. * *****************************************************************************/ #define cJoyMax 16 /* Up to 16 joysticks */ typedef struct SHAREDOBJECTHEADER { int cso; DWORD dwSequence; int cguid; GLOBALJOYSTATE rggjs[cJoyMax]; DWORD tmConfigChanged; } SHAREDOBJECTHEADER, *PSHAREDOBJECTHEADER; #define g_psoh ((PSHAREDOBJECTHEADER)g_psop) /***************************************************************************** * * @doc INTERNAL * * @topic The Worker Thread | * * Some emulation behaviors (low-level hooks, HID) require * a worker thread to do the data collection. We multiplex * all such work onto a single worker thread (known as * simple "the" worker thread). * * The thread is spun up when the first client needs it * and is taken down when the last client has been released. * * To prevent race conditions from crashing us, we addref * our DLL when the thread exists and have the thread * perform a FreeLibrary as its final act. * *****************************************************************************/ #define WORKER_THREAD /***************************************************************************** * * diem.c - Emulation * *****************************************************************************/ HRESULT EXTERNAL CEm_AcquireInstance(PVXDINSTANCE *ppvi); HRESULT EXTERNAL CEm_UnacquireInstance(PVXDINSTANCE *ppvi); HRESULT EXTERNAL CEm_SetBufferSize(PVXDDWORDDATA pvdd); HRESULT EXTERNAL CEm_DestroyInstance(PVXDINSTANCE *ppvi); HRESULT EXTERNAL CEm_SetDataFormat(PVXDDATAFORMAT pvdf); HRESULT EXTERNAL CEm_Mouse_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut); HRESULT EXTERNAL CEm_Mouse_InitButtons(PVXDDWORDDATA pvdd); HRESULT EXTERNAL CEm_Kbd_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut); HRESULT EXTERNAL CEm_Kbd_InitKeys(PVXDDWORDDATA pvdd); HRESULT EXTERNAL CEm_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut); HRESULT EXTERNAL CEm_Joy_Ping(PVXDINSTANCE *ppvi); HRESULT EXTERNAL CEm_HID_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut); /***************************************************************************** * * diemm.c - Mouse Emulation * *****************************************************************************/ void EXTERNAL CEm_Mouse_AddState(LPDIMOUSESTATE_INT pms, DWORD tm); /***************************************************************************** * * dinput.c - Basic DLL stuff * *****************************************************************************/ void EXTERNAL DllEnterCrit_(LPCTSTR lptszFile, UINT line); void EXTERNAL DllLeaveCrit_(LPCTSTR lptszFile, UINT line); #ifdef DEBUG BOOL EXTERNAL DllInCrit(void); #define DllEnterCrit() DllEnterCrit_(TEXT(__FILE__), __LINE__) #define DllLeaveCrit() DllLeaveCrit_(TEXT(__FILE__), __LINE__) #else #define DllEnterCrit() DllEnterCrit_(NULL, 0x0) #define DllLeaveCrit() DllLeaveCrit_(NULL, 0x0) #endif void EXTERNAL DllAddRef(void); void EXTERNAL DllRelease(void); BOOL EXTERNAL DllLoadLibrary(void); void EXTERNAL DllFreeLibrary(void); #ifdef DEBUG extern UINT g_thidCrit; #define InCrit() (g_thidCrit == GetCurrentThreadId()) #endif /* * Describes the CLSIDs we provide to OLE. */ typedef STDMETHOD(CREATEFUNC)(PUNK punkOuter, RIID riid, PPV ppvOut); typedef struct CLSIDMAP { REFCLSID rclsid; /* The clsid */ CREATEFUNC pfnCreate; /* How to create it */ UINT ids; /* String that describes it */ } CLSIDMAP, *PCLSIDMAP; #ifdef DEBUG #define DEMONSTRATION_FFDRIVER #ifdef DOWNLEVEL_COM #define cclsidmap 5 /* DirectInput, DirectInputDevice, DirectInput8, DirectInputDevice8, DIEffectDiver */ #else #define cclsidmap 3 /* DirectInput8, DirectInputDevice8, DIEffectDiver */ #endif #else #ifdef DOWNLEVEL_COM #define cclsidmap 4 /* CLSID_DirectInput, CLSID_DirectInputDevice, CLSID_DirectInput8, CLSID_DirectInputDevice8 */ #else #define cclsidmap 2 /* CLSID_DirectInput8, CLSID_DirectInputDevice8 */ #endif #endif extern CLSIDMAP c_rgclsidmap[cclsidmap]; /***************************************************************************** * * dicf.c - IClassFactory implementation * *****************************************************************************/ STDMETHODIMP CDIFactory_New(CREATEFUNC pfnCreate, RIID riid, PPV ppvObj); /***************************************************************************** * * didenum.c - IDirectInput device enumeration * *****************************************************************************/ typedef struct _CDIDEnum CDIDEnum; extern GUID rgGUID_Joystick[cJoyMax]; #define GUID_Joystick (rgGUID_Joystick[0]) void EXTERNAL CDIDEnum_Release(CDIDEnum *pde); STDMETHODIMP CDIDEnum_Next(CDIDEnum *pde, LPDIDEVICEINSTANCEW pddiW); STDMETHODIMP CDIDEnum_InternalNext(CDIDEnum *pde, LPDIDEVICEINSTANCEW pddiW, LPDIRECTINPUTDEVICE8W *ppdid8W); STDMETHODIMP CDIDEnum_New(PDIW pdiW, DWORD dwDevType, DWORD edfl, DWORD dwVer, CDIDEnum **); /***************************************************************************** * * diobj.c - IDirectInput implementation * *****************************************************************************/ HRESULT EXTERNAL CDIObj_TestDeviceFlags(PDIDW pdidW, DWORD diedfl); HRESULT EXTERNAL CDIObj_TestDeviceFlagsInternal(PDIDW pdidW, DWORD diedfl); HRESULT EXTERNAL CDIObj_FindDeviceInternal(LPCTSTR ptszName, LPGUID pguidOut); STDMETHODIMP CDIObj_New(PUNK punkOuter, RIID riid, PPV ppvOut); typedef struct _DIMAPPER { LPCWSTR lpszUserName; LPDIACTIONFORMATW pDiActionFormat; LPDIENUMDEVICESBYSEMANTICSCBW pecW; LPVOID pvRef; DWORD dwFlags; } DIMAPPER, *LPDIMAPPER; typedef struct _DIORDERDEV { DWORD dwOrder; DWORD dwFlags; LPDIRECTINPUTDEVICE8W pdid8W; DIDEVICEINSTANCEW ddiW; FILETIME ftTimeStamp; } DIORDERDEV, *LPDIORDERDEV; /***************************************************************************** * * diaddhw.c - AddNewHardware * *****************************************************************************/ HRESULT EXTERNAL AddNewHardware(HWND hwnd, REFGUID rguid); /***************************************************************************** * * dijoycfg.c - IDirectInputJoyConfig implementation * *****************************************************************************/ STDMETHODIMP CJoyCfg_New(PUNK punkOuter, RIID riid, PPV ppvOut); /***************************************************************************** * * @doc INLINE * * @method BOOL | IsWriteSam | * * Nonzero if the registry security access mask will * obtain (or attempt to obtain) write access. * * @parm REGSAM | regsam | * * Registry security access mask. * *****************************************************************************/ BOOL INLINE IsWriteSam(REGSAM sam) { return sam & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | MAXIMUM_ALLOWED); } /***************************************************************************** * * dijoyreg.c - Joystick registry services * *****************************************************************************/ extern LPCWSTR c_rghwIdPredef[]; STDMETHODIMP JoyReg_OpenTypeKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk); STDMETHODIMP JoyReg_OpenPropKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk); STDMETHODIMP JoyReg_OpenFFKey(HKEY hkType, REGSAM sam, PHKEY phk); STDMETHODIMP JoyReg_OpenConfigKey(UINT idJoy, DWORD sam, DWORD dwOptions, PHKEY phk); STDMETHODIMP JoyReg_GetTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl); STDMETHODIMP JoyReg_SetTypeInfo(HKEY hkTypesW, LPCWSTR pwszType, LPCDIJOYTYPEINFO pjti, DWORD fl); STDMETHODIMP JoyReg_GetConfig(UINT idJoy, LPDIJOYCONFIG pcfg, DWORD fl); STDMETHODIMP JoyReg_SetConfig(UINT idJoy, LPJOYREGHWCONFIG phwc, LPCDIJOYCONFIG pcfg, DWORD fl); STDMETHODIMP JoyReg_GetUserValues(LPDIJOYUSERVALUES pjuv, DWORD fl); STDMETHODIMP JoyReg_SetUserValues(LPCDIJOYUSERVALUES pjuv, DWORD fl); STDMETHODIMP JoyReg_GetSetConfigValue(HKEY hk, LPCTSTR ptszNValue, UINT idJoy, DWORD reg, PV pvBuf, DWORD cb, BOOL fSet); #define GSCV_GET 0 #define GSCV_SET 1 #define JoyReg_GetConfigValue(hk, ptsz, id, reg, pv, cb) \ JoyReg_GetSetConfigValue(hk, ptsz, id, reg, pv, cb, GSCV_GET) #define JoyReg_SetConfigValue(hk, ptsz, id, reg, pv, cb) \ JoyReg_GetSetConfigValue(hk, ptsz, id, reg, (PV)(pv), cb, GSCV_SET) STDMETHODIMP JoyReg_GetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PV pvBuf, DWORD cb); #ifndef WINNT STDMETHODIMP JoyReg_IsWdmGameport(HKEY hk); #endif #if 0 STDMETHODIMP JoyReg_IsWdmGameportFromDeviceInstance( LPTSTR ptszDeviceInst ); #endif STDMETHODIMP JoyReg_SetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PCV pvBuf, DWORD cb); #ifndef WINNT LPSTR EXTERNAL JoyReg_JoyIdToDeviceInterface_95(UINT idJoy, PVXDINITPARMS pvip, LPSTR ptszBuf); #endif HRESULT EXTERNAL JoyReg_GetPredefTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl); HRESULT EXTERNAL hResIdJoypInstanceGUID_95( UINT idJoy, LPGUID lpguid); HRESULT EXTERNAL hResIdJoypInstanceGUID_WDM( UINT idJoy, LPGUID lpguid); #ifdef WINNT #define hResIdJoypInstanceGUID(id,lpguid) hResIdJoypInstanceGUID_WDM(id, lpguid) #else #define hResIdJoypInstanceGUID(id,lpguid) hResIdJoypInstanceGUID_95(id, lpguid) #endif #if 0 HRESULT EXTERNAL JoyReg_GetIDByOemName( LPTSTR szOemName, PUINT pId ); #endif /***************************************************************************** * * didev.c - IDirectInputDevice implementation * *****************************************************************************/ void EXTERNAL DeviceInfoWToA(LPDIDEVICEINSTANCEA pdiA, LPCDIDEVICEINSTANCEW pdiW); void EXTERNAL Device8WTo8A(LPDIRECTINPUTDEVICE8A *ppdid8A, LPDIRECTINPUTDEVICE8W pdid8W); STDMETHODIMP CDIDev_New(PUNK punkOuter, RIID riid, PPV ppvObj); /***************************************************************************** * * CDIDev_Enter/LeaveCrit are secret backdoors to allow emulation * and effects * to take the device critical section when updating buffers. * * CDIDev_InCrit is used for assertion checking. * * CDIDev_IsExclAcquired is used by effects to make sure the parent * is acquired for exclusive before attempting to download. * * CDIDev_SyncShepHandle is used to get the joystick "tag" which * is used by dieshep.c to determine who owns the joystick. * *****************************************************************************/ void EXTERNAL CDIDev_EnterCrit_(struct CDIDev *this, LPCTSTR lptszFile, UINT line); void EXTERNAL CDIDev_LeaveCrit_(struct CDIDev *this, LPCTSTR lptszFile, UINT line); #ifdef DEBUG BOOL INTERNAL CDIDev_InCrit(struct CDIDev *this); #define CDIDev_EnterCrit(cdidev) CDIDev_EnterCrit_(cdidev, TEXT(__FILE__), __LINE__) #define CDIDev_LeaveCrit(cdidev) CDIDev_LeaveCrit_(cdidev, TEXT(__FILE__), __LINE__) #else #define CDIDev_EnterCrit(cdidev) CDIDev_EnterCrit_(cdidev, NULL, 0x0); #define CDIDev_LeaveCrit(cdidev) CDIDev_LeaveCrit_(cdidev, NULL, 0x0); #endif #ifndef XDEBUG #define CDIDev_IsExclAcquired_(pdd, z) \ _CDiDev_IsExclAcquired_(pdd) \ #endif STDMETHODIMP CDIDev_IsExclAcquired_(struct CDIDev *this, LPCSTR s_szProc); #define CDIDev_IsExclAcquired(pdd) \ CDIDev_IsExclAcquired_(pdd, s_szProc) \ STDMETHODIMP CDIDev_SyncShepHandle(struct CDIDev *this, PSHEPHANDLE psh); /***************************************************************************** * * CDIDev_SetNotifyEvent is used by the emulation code to * notify the application when the state of the device changes. * *****************************************************************************/ void EXTERNAL CDIDev_SetNotifyEvent(struct CDIDev *this); void EXTERNAL CDIDev_SetForcedUnacquiredFlag(struct CDIDev *this); /***************************************************************************** * * CDIDev_NotifyCreate/DestroyEvent is used by CDIEff to * let the parent know when a child effect comes or goes. * * CDIDev_FindEffectGUID is used by CDIEff to convert an * effect GUID into an effect cookie dword. * * CDIDev_ConvertObjects converts item identifiers in various ways. * *****************************************************************************/ HRESULT EXTERNAL CDIDev_NotifyCreateEffect(struct CDIDev *this, struct CDIEff *pdeff); HRESULT EXTERNAL CDIDev_NotifyDestroyEffect(struct CDIDev *this, struct CDIEff *pdeff); /***************************************************************************** * * @doc INTERNAL * * @struct EFFECTMAPINFO | * * Information about an effect, much like a * , but containing the * effect ID, too. * * @field DWORD | dwId | * * The effect ID. This comes first so we can copy * an into a * all at one go. * * @field GUID | guid | * * The effect GUID. * * @field DWORD | dwEffType | * * The effect type and flags. * * @field WCHAR | wszName[MAX_PATH] | * * The name for the effect. * *****************************************************************************/ typedef struct EFFECTMAPINFO { DIEFFECTATTRIBUTES attr; GUID guid; WCHAR wszName[MAX_PATH]; } EFFECTMAPINFO, *PEFFECTMAPINFO; typedef const EFFECTMAPINFO *PCEFFECTMAPINFO; #ifndef XDEBUG #define CDIDev_FindEffectGUID_(this, rguid, pemi, z, i) \ _CDIDev_FindEffectGUID_(this, rguid, pemi) \ #endif #define CDIDev_FindEffectGUID(this, rguid, pemi, iarg) \ CDIDev_FindEffectGUID_(this, rguid, pemi, s_szProc, iarg) \ STDMETHODIMP CDIDev_FindEffectGUID_(struct CDIDev *this, REFGUID rguid, PEFFECTMAPINFO pemi, LPCSTR s_szProc, int iarg); STDMETHODIMP CDIDev_ConvertObjects(struct CDIDev *this, UINT cdw, LPDWORD rgdw, UINT fl); /* * Note that the bonus DEVCO flags live inside the DIDFT_INSTANCEMASK. */ #define DEVCO_AXIS DIDFT_AXIS #define DEVCO_BUTTON DIDFT_BUTTON #define DEVCO_TYPEMASK DIDFT_TYPEMASK #define DEVCO_FFACTUATOR DIDFT_FFACTUATOR #define DEVCO_FFEFFECTTRIGGER DIDFT_FFEFFECTTRIGGER #define DEVCO_ATTRMASK DIDFT_ATTRMASK #define DEVCO_FROMID 0x00000100 #define DEVCO_FROMOFFSET 0x00000200 #define DEVCO_FROMMASK 0x00000300 #define DEVCO_TOID 0x00001000 #define DEVCO_TOOFFSET 0x00002000 #define DEVCO_TOMASK 0x00003000 #if ((DEVCO_FROMMASK | DEVCO_TOMASK) & DIDFT_INSTANCEMASK) != \ (DEVCO_FROMMASK | DEVCO_TOMASK) #error DEVCO_FROMMASK and DEVCI_TOMASK should not escape DIDFT_INSTANCEMASK. #endif #define DEVCO_VALID (DEVCO_TYPEMASK | \ DEVCO_ATTRMASK | \ DEVCO_FROMMASK | \ DEVCO_TOMASK) /***************************************************************************** * * dieffv.c - IDirectInputEffectDriver for VJoyD joysticks * *****************************************************************************/ STDMETHODIMP CEffVxd_New(PUNK punkOuter, RIID riid, PPV ppvOut); /***************************************************************************** * * dieshep.c - IDirectInputEffectShepherd * *****************************************************************************/ STDMETHODIMP CEShep_New(HKEY hk, PUNK punkOuter, RIID riid, PPV ppvOut); /***************************************************************************** * * digendef.c - Default IDirectInputDeviceCallback * *****************************************************************************/ /* * We can't call it a DCB because winbase.h already has one for * comm goo. */ typedef IDirectInputDeviceCallback DICB, *PDICB; STDMETHODIMP CDefDcb_Acquire(PDICB pdcb); STDMETHODIMP CDefDcb_Unacquire(PDICB pdcb); STDMETHODIMP CDefDcb_GetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph); STDMETHODIMP CDefDcb_SetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPCDIPROPHEADER pdiph); STDMETHODIMP CDefDcb_SetEventNotification(PDICB pdcb, HANDLE h); STDMETHODIMP CDefDcb_SetCooperativeLevel(PDICB pdcb, HWND hwnd, DWORD dwFlags); STDMETHODIMP CDefDcb_CookDeviceData(PDICB pdcb, DWORD cdod, LPDIDEVICEOBJECTDATA rgdod); STDMETHODIMP CDefDcb_CreateEffect(PDICB pdcb, LPDIRECTINPUTEFFECTSHEPHERD *ppes); STDMETHODIMP CDefDcb_GetFFConfigKey(PDICB pdcb, DWORD sam, PHKEY phk); STDMETHODIMP CDefDcb_SendDeviceData(PDICB pdcb, DWORD cbdod, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl); STDMETHODIMP CDefDcb_Poll(IDirectInputDeviceCallback *pdcb); STDMETHODIMP CDefDcb_GetVersions(IDirectInputDeviceCallback *pdcb, LPDIDRIVERVERSIONS pvers); STDMETHODIMP CDefDcb_MapUsage(IDirectInputDeviceCallback *pdcb, DWORD dwUsage, PINT piOut); STDMETHODIMP_(DWORD) CDefDcb_GetUsage(IDirectInputDeviceCallback *pdcb, int iobj); STDMETHODIMP CDefDcb_SetDIData(PDICB pdcb, DWORD dwVer, LPVOID lpdihacks); STDMETHODIMP CDefDcb_BuildDefaultActionMap(PDICB pdcb, LPDIACTIONFORMATW pActionFormat, DWORD dwFlags, REFGUID guidInst); /***************************************************************************** * * digenx.c - IDirectInputDeviceCallback that does nothing * *****************************************************************************/ extern IDirectInputDeviceCallback c_dcbNil; #define c_pdcbNil &c_dcbNil /***************************************************************************** * * digenm.c - IDirectInputDeviceCallback for mouse * *****************************************************************************/ STDMETHODIMP CMouse_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvOut); /***************************************************************************** * * digenk.c - IDirectInputDeviceCallback for keyboard * *****************************************************************************/ extern BYTE g_rgbKbdRMap[]; STDMETHODIMP CKbd_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvOut); /***************************************************************************** * * digenj.c - IDirectInputDeviceCallback for joystick * *****************************************************************************/ STDMETHODIMP CJoy_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvOut); /***************************************************************************** * * @doc INTERNAL * * @func UINT | ibJoyPosAxisFromPosAxis | * * Returns the offset of the

'th joystick axis * in the structure. * * @parm UINT | uiAxis | * * The index of the requested axis. X, Y, Z, R, U and V are * respctively zero through five. * * @returns * * The offset relative to the structure. * *****************************************************************************/ #define _ibJoyPosAxisFromPosAxis(uiAxis) \ (FIELD_OFFSET(JOYPOS, dwX) + cbX(DWORD) * (uiAxis)) UINT INLINE ibJoyPosAxisFromPosAxis(UINT uiPosAxis) { #define CheckAxis(x) \ CAssertF(_ibJoyPosAxisFromPosAxis(iJoyPosAxis##x) \ == FIELD_OFFSET(JOYPOS, dw##x)) \ CheckAxis(X); CheckAxis(Y); CheckAxis(Z); CheckAxis(R); CheckAxis(U); CheckAxis(V); #undef CheckAxis return _ibJoyPosAxisFromPosAxis(uiPosAxis); } /***************************************************************************** * * dieffj.c - Dummy IDirectInputEffectDriver for joystick * *****************************************************************************/ STDMETHODIMP CJoyEff_New(PUNK punkOuter, RIID riid, PPV ppvOut); /***************************************************************************** * * dihid.c - IDirectInputDeviceCallback for generic HID devices * *****************************************************************************/ STDMETHODIMP CHid_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvOut); /***************************************************************************** * * dieff.c - IDirectInputEffect implementation * *****************************************************************************/ STDMETHODIMP CDIEff_New(struct CDIDev *pdev, LPDIRECTINPUTEFFECTSHEPHERD pes, PUNK punkOuter, RIID riid, PPV ppvObj); /***************************************************************************** * * dihidusg.c - HID usage converters * *****************************************************************************/ /***************************************************************************** * * @doc INTERNAL * * @struct HIDUSAGEMAP | * * This structure maps HID usages to GUIDs * or legacy joystick axes. * * @field DWORD | dwUsage | * * Packed usage via . * * @field BYTE | bPosAxis | * * axis number, where 0 = X, 1 = Y, ..., 5 = V. * * @field BYTE | bSemFlag | * * DISEM_FLAGS_* value for axis. * * @field BYTE | bReserved1 | * * Byte reserved to improve alignment * * @field BYTE | bReserved2 | * * Byte reserved to improve alignment * * @field DWORD | dwSemHint | * * A root of a semantic generally appropriate for this axis. * * @field PCGUID | pguid | * * Corresponding . * *****************************************************************************/ typedef struct HIDUSAGEMAP { DWORD dwUsage; BYTE bPosAxis; BYTE bSemFlag; BYTE bReserved1; BYTE bReserved2; DWORD dwSemHint; PCGUID pguid; } HIDUSAGEMAP, *PHIDUSAGEMAP; PHIDUSAGEMAP EXTERNAL UsageToUsageMap(DWORD dwUsage); /* * Flags defined for dwSemHint * The names have the same suffixes as the equivalent HID usages * Values are ORed together for a summary of a device's default semantics */ #define DISEM_HINT_X 0x00000001 #define DISEM_HINT_Y 0x00000002 #define DISEM_HINT_Z 0x00000004 #define DISEM_HINT_WHEEL 0x00000004 #define DISEM_HINT_RX 0x00000008 #define DISEM_HINT_RY 0x00000010 #define DISEM_HINT_RZ 0x00000020 #define DISEM_HINT_SIXDOF 0x0000003F #define DISEM_HINT_THROTTLE 0x00000040 #define DISEM_HINT_POV 0x00000080 #define DISEM_HINT_HATSWITCH 0x00000080 #define DISEM_HINT_ACCELERATOR 0x00000100 #define DISEM_HINT_BRAKE 0x00000200 #define DISEM_HINT_CLUTCH 0x00000400 #define DISEM_HINT_SHIFTER 0x00000800 #define DISEM_HINT_STEERING 0x00001000 #define DISEM_HINT_RUDDER 0x00002000 #define DISEM_HINT_SLIDER 0x00004000 #define DISEM_HINT_DIAL 0x00004000 #define DISEM_HINT_ABSOLUTE 0x00008000 DWORD EXTERNAL GuidToUsage(PCGUID pguid); UINT EXTERNAL GetHIDString(DWORD Usage, DWORD UsagePage, LPWSTR pwszBuf, UINT cwch); void EXTERNAL InsertCollectionNumber(UINT icoll, LPWSTR pwszBuf); /***************************************************************************** * * disubcls.c - Subclassing * *****************************************************************************/ typedef LRESULT (CALLBACK *SUBCLASSPROC)(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp, UINT_PTR uId, ULONG_PTR dwRef); BOOL EXTERNAL SetWindowSubclass(HWND hwnd, SUBCLASSPROC pfnSubclass, UINT_PTR uId, ULONG_PTR dwRef); BOOL EXTERNAL GetWindowSubclass(HWND hwnd, SUBCLASSPROC pfnSubclass, UINT_PTR uId, ULONG_PTR *pdwRef); BOOL EXTERNAL RemoveWindowSubclass(HWND hwnd, SUBCLASSPROC pfnSubclass, UINT_PTR uId); LRESULT EXTERNAL DefSubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp); /***************************************************************************** * * dical.c - Axis ramps and calibration * * Structure names begin with "Joy" for historical reasons. * *****************************************************************************/ #if defined(_X86_) LONG EXTERNAL CCal_MulDiv(LONG lA, LONG lB, LONG lC); #else #define CCal_MulDiv MulDiv #endif /***************************************************************************** * * @doc INTERNAL * * @struct JOYRAMP | * * Parameters for a "ramp". A ramp looks like this: * * r ! * e dy - *--- * t ! / * u ! / * r ! / * n y ---* * e ! * d +--!---!--- * x dx * * physical position * * * y, dy = baseline and height * * x, dx = initiation level and width * * The mapping is * * * (-infty, x ] -> y * (x, x+dx ) -> (y, y+dy) * [x+dx, infty) -> y+dy * * It is very important that the middle range not be taken * if dx = 0. * * @field int | x | * * Horizontal value below which we return the baseline. * * @field DWORD | dx | * * Width of the ramp. Beyond this point, we return the * full height. * * @field int | y | * * Baseline. * * @field int | dy | * * Total height. * *****************************************************************************/ typedef struct JOYRAMP { int x; int y; DWORD dx; int dy; } JOYRAMP, *PJOYRAMP; typedef const JOYRAMP *PCJOYRAMP; /***************************************************************************** * * @doc INTERNAL * * @struct JOYRANGECONVERT | * * Parameters for range conversion. * * The conversion curve is in five sections. * * * * ! * lmax- *---- * r ! / * e ! / * t ! / * u lc- *------* * r ! / * n ! / * e ! / * d lmin-------* * ! * +-!----!---!------!----!----!-- * pmin smin dmin dmax smax pmax * * ! * pc * * * physical position * * * lmin/lmax = logical min/max - This is the smallest/largest * position the app will ever see. * * lc = logical center * * pmin/pmax = physical min/max - This is the position determined by * calibration to be the value which the hardware reports * when the device is physically at its bottom/upper limit. Note * that the hardware might report values outside this range. * * pc = physical center - This is the nominal neutral location for * the axis * * dmin/dmax = dead zone min/max - This is the zone around which * the center is artificially expanded. * * smin/smax = saturation min/max - This is the level at which * we treat the axis as being at its most extreme position. * * @field BOOL | fRaw | * * Is the axis in raw mode? If so, then no cooking is performed. * * @field JOYRAMP | rmpLow | * * The ramp for below-center. * * @field JOYRAMP | rmpHigh | * * The ramp for above-center. * * @field DWORD | dwPmin | * * Physical minimum. * * @field DWORD | dwPmax | * * Physical maximum. * * @field LONG | lMin | * * Logical minimum. * * @field LONG | lCenter | * * Logical center. * * @field LONG | lMax | * * Logical maximum. * * @field DWORD | dwPc | * * Physical center. * * @field DWORD | dwDz | * * Dead zone (in ten thousandths, 10000 = 100%). * * @field DWORD | dwSat | * * Saturation level (in ten thousands, 10000 = 100%). * * @field BOOL | fPolledPOV | * * Whether the axis is a polled POV. Usable only when the axis is a POV. * * @field LONG | lMinPOV[5] | * * Mininum ranges of POV directions. Usable only when the axis is a POV. * * @field LONG | lMaxPOV[5] | * * Maxinum ranges of POV directions. Usable only when the axis is a POV. * * *****************************************************************************/ /* * Number of range divisions. We work in ten thousandths. */ #define RANGEDIVISIONS 10000 typedef struct JOYRANGECONVERT { BOOL fRaw; JOYRAMP rmpLow; JOYRAMP rmpHigh; DWORD dwPmin; DWORD dwPmax; DWORD dwPc; LONG lMin; LONG lMax; LONG lC; DWORD dwDz; DWORD dwSat; DWORD dwCPointsNum; CPOINT cp[MAXCPOINTSNUM]; //4 is for deadzone(2) and saturation(2) #ifdef WINNT BOOL fPolledPOV; LONG lMinPOV[5]; LONG lMaxPOV[5]; #endif } JOYRANGECONVERT, *PJOYRANGECONVERT; typedef const JOYRANGECONVERT *PCJOYRANGECONVERT; /***************************************************************************** * * dical.c functions * *****************************************************************************/ void EXTERNAL CCal_CookRange(PJOYRANGECONVERT this, LONG UNALIGNED *pl); void EXTERNAL CCal_RecalcRange(PJOYRANGECONVERT this); STDMETHODIMP CCal_GetProperty(PJOYRANGECONVERT this, REFGUID rguid, LPDIPROPHEADER pdiph); STDMETHODIMP CCal_SetProperty(PJOYRANGECONVERT this, LPCDIPROPINFO ppropi, LPCDIPROPHEADER pdiph, HKEY hkType); /***************************************************************************** * * @doc INTERNAL * * @func LONG | CCal_Midpoint | * * Return the midpoint of two values. Note, however, that * we round instead of downward. This is important, * because many people set the ranges to something like * 0 .. 0xFFFF, and we want the midpoint to be 0x8000. * * Care must be taken that the intermediate sum does not overflow. * * @parm LONG | lMin | * * Lower limit. * * @parm LONG | lMax | * * Upper limit. * * @returns * * The midpoint. * *****************************************************************************/ LONG INLINE CCal_Midpoint(LONG lMin, LONG lMax) { /* * Can't do "lMax + lMin" because that might overflow. */ AssertF(lMax >= lMin); return lMin + (UINT)(lMax - lMin + 1) / 2; } /***************************************************************************** * * dijoytyp.c * *****************************************************************************/ STDMETHODIMP CType_OpenIdSubkey(HKEY, DWORD, REGSAM, PHKEY); void EXTERNAL CType_RegGetObjectInfo(HKEY hkType, DWORD dwId, LPDIDEVICEOBJECTINSTANCEW pdidoiW); void EXTERNAL CType_RegGetTypeInfo(HKEY hkType, LPDIOBJECTDATAFORMAT podf, BOOL bHid); void EXTERNAL CType_MakeGameCtrlName(PWCHAR wszOutput, DWORD dwDevType, DWORD dwAxes, DWORD dwButtons, DWORD dwPOVs ); /***************************************************************************** * * didevdf.c * *****************************************************************************/ HRESULT CDIDev_ActionMap_IsValidMapObject(LPDIACTIONFORMATW paf #ifdef XDEBUG comma LPCSTR pszProc comma UINT argnum #endif ); STDMETHODIMP CMap_ValidateActionMapSemantics( LPDIACTIONFORMATW paf, DWORD dwFlags ); STDMETHODIMP CMap_BuildDefaultSysActionMap( LPDIACTIONFORMATW paf, DWORD dwFlags, DWORD dwPhysicalGenre, REFGUID guidDevInst, LPDIDATAFORMAT dfDev, DWORD dwButtonZeroInst ); typedef struct _DIDOBJDEFSEM { DWORD dwID; /* object id of control */ DWORD dwSemantic; /* default semantic match */ } DIDOBJDEFSEM, *PDIDOBJDEFSEM; STDMETHODIMP CMap_BuildDefaultDevActionMap( LPDIACTIONFORMATW paf, DWORD dwFlags, REFGUID guidDevInst, PDIDOBJDEFSEM rgObjSem, DWORD dwNumAxes, DWORD dwNumPOVs, DWORD dwNumButtons ); STDMETHODIMP CMap_DeviceValidateActionMap( PV pdd, LPDIACTIONFORMATW paf, DWORD dwFlags, PDWORD pdwOut ); STDMETHODIMP CMap_InitializeCRCTable( void ); HRESULT CMap_GetDeviceUserName( REFGUID guidDevInst, LPWSTR wszOwner ); /***************************************************************************** * * diaphack.c * *****************************************************************************/ BOOL EXTERNAL AhGetAppHacks(LPTSTR tszAppId); HRESULT EXTERNAL AhAppRegister(DWORD dwVer, DWORD dwMapper); /***************************************************************************** * * dimapshp.c - IDirectInputMapShepherd * *****************************************************************************/ STDMETHODIMP CMapShep_New(PUNK punkOuter, RIID riid, PPV ppvObj); HRESULT INTERNAL _CreateInstance(REFCLSID rclsid, LPCTSTR ptszDll, LPUNKNOWN punkOuter, RIID riid, PPV ppvOut, HINSTANCE *phinst); /***************************************************************************** * * diraw.c * *****************************************************************************/ #ifdef USE_WM_INPUT #define DIRAW_NONEXCL 0 #define DIRAW_EXCL 1 #define DIRAW_NOHOTKEYS 2 HRESULT CDIRaw_RegisterRawInputDevice( UINT uirim, DWORD dwOrd, HWND hwnd); HRESULT CDIRaw_UnregisterRawInputDevice( UINT uirim, HWND hwnd ); BOOL CDIRaw_OnInput(MSG *pmsg); HRESULT INTERNAL CDIRaw_Mouse_InitButtons(); int EXTERNAL DIRaw_GetKeyboardType(int nTypeFlag); #endif #ifdef __cplusplus }; #endif