|
|
/*****************************************************************************
* * DIGenM.c * * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved. * * Abstract: * * Practice generic IDirectInputDevice callback for mouse. * * Contents: * * CMouse_New * *****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
* * The sqiffle for this file. * *****************************************************************************/
#define sqfl sqflMouse
/*****************************************************************************
* * Declare the interfaces we will be providing. * *****************************************************************************/
Primary_Interface(CMouse, IDirectInputDeviceCallback);
Interface_Template_Begin(CMouse) Primary_Interface_Template(CMouse, IDirectInputDeviceCallback) Interface_Template_End(CMouse)
/*****************************************************************************
* * @doc INTERNAL * * @global DIOBJECTDATAFORMAT | c_rgodfMouse[] | * * Device object data formats for the generic mouse device. * The axes come first, then the buttons. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
#define MAKEODF(guid, f, type, inst, aspect) \
{ &GUID_##guid, \ FIELD_OFFSET(DIMOUSESTATE_INT, f), \ DIDFT_##type | DIDFT_MAKEINSTANCE(inst), \ DIDOI_ASPECT##aspect, \ } \
/*
* Warning! If you change this table, you must adjust the IDS_MOUSEOBJECT * table in dinput.rc to match! */
DIOBJECTDATAFORMAT c_rgodfMouse[] = { MAKEODF( XAxis, lX, RELAXIS, 0, POSITION), MAKEODF( YAxis, lY, RELAXIS, 1, POSITION), MAKEODF( ZAxis, lZ, RELAXIS, 2, POSITION), MAKEODF(Button, rgbButtons[0], PSHBUTTON, 3, UNKNOWN), MAKEODF(Button, rgbButtons[1], PSHBUTTON, 4, UNKNOWN), MAKEODF(Button, rgbButtons[2], PSHBUTTON, 5, UNKNOWN), MAKEODF(Button, rgbButtons[3], PSHBUTTON, 6, UNKNOWN), MAKEODF(Button, rgbButtons[4], PSHBUTTON, 7, UNKNOWN), MAKEODF(Button, rgbButtons[5], PSHBUTTON, 8, UNKNOWN), MAKEODF(Button, rgbButtons[6], PSHBUTTON, 9, UNKNOWN), MAKEODF(Button, rgbButtons[7], PSHBUTTON,10, UNKNOWN), };
#define c_podfMouseAxes (&c_rgodfMouse[0])
#define c_podfMouseButtons (&c_rgodfMouse[3])
#pragma END_CONST_DATA
/*****************************************************************************
* * @doc INTERNAL * * @struct CMouse | * * The <i IDirectInputDeviceCallback> object for the generic mouse. * * @field IDirectInputDeviceCalllback | didc | * * The object (containing vtbl). * * @field LPDIMOUSESTATE_INT | pdmsPhys | * * Pointer to physical mouse status information kept down in the * VxD. * * @field POINT | ptPrev | * * Location of the mouse at the time we stole it exclusively. * * @field HWND | hwndCaptured | * * The window that captured the mouse. * * @field VXDINSTANCE * | pvi | * * The DirectInput instance handle. Even though we manipulate * the flags field, we do not need to mark it volatile because * we modify the flags only when unacquired, whereas the device * driver modifies the flags only when acquired. * * @field UINT | dwAxes | * * Number of axes on the mouse. * * @field UINT | dwButtons | * * Number of buttons on the mouse. * * @field DWORD | flEmulation | * * The emulation flags forced by the application. If any of * these flags is set (actually, at most one will be set), then * we are an alias device. * * @field DIDATAFORMAT | df | * * The dynamically-generated data format based on the * mouse type. * * @field DIOBJECTDATAFORMAT | rgodf[] | * * Object data format table generated as part of the * <e CMouse.df>. * * @comm * * It is the caller's responsibility to serialize access as * necessary. * *****************************************************************************/
typedef struct CMouse {
/* Supported interfaces */ IDirectInputDeviceCallback dcb;
LPDIMOUSESTATE_INT pdmsPhys; /* Physical mouse state */
POINT ptPrev; HWND hwndCapture;
VXDINSTANCE *pvi;
UINT dwAxes; UINT dwButtons; DWORD flEmulation;
DIDATAFORMAT df; DIOBJECTDATAFORMAT rgodf[cA(c_rgodfMouse)];
} CMouse, DM, *PDM;
#define ThisClass CMouse
#define ThisInterface IDirectInputDeviceCallback
#define riidExpected &IID_IDirectInputDeviceCallback
/*****************************************************************************
* * CMouse::QueryInterface (from IUnknown) * CMouse::AddRef (from IUnknown) * CMouse::Release (from IUnknown) * *****************************************************************************/
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | QueryInterface | * * Gives a client access to other interfaces on an object. * * @cwrap LPDIRECTINPUT | lpDirectInput * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * * @returns * * Returns a COM error code. * * @xref OLE documentation for <mf IUnknown::QueryInterface>. * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CMouse | AddRef | * * Increments the reference count for the interface. * * @cwrap LPDIRECTINPUT | lpDirectInput * * @returns * * Returns the object reference count. * * @xref OLE documentation for <mf IUnknown::AddRef>. * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CMouse | Release | * * Decrements the reference count for the interface. * If the reference count on the object falls to zero, * the object is freed from memory. * * @cwrap LPDIRECTINPUT | lpDirectInput * * @returns * * Returns the object reference count. * * @xref OLE documentation for <mf IUnknown::Release>. * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CMouse | QIHelper | * * We don't have any dynamic interfaces and simply forward * to <f Common_QIHelper>. * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | CMouse | AppFinalize | * * We don't have any weak pointers, so we can just * forward to <f Common_Finalize>. * * @parm PV | pvObj | * * Object being released from the application's perspective. * *****************************************************************************/
#ifdef DEBUG
Default_QueryInterface(CMouse) Default_AddRef(CMouse) Default_Release(CMouse)
#else
#define CMouse_QueryInterface Common_QueryInterface
#define CMouse_AddRef Common_AddRef
#define CMouse_Release Common_Release
#endif
#define CMouse_QIHelper Common_QIHelper
#define CMouse_AppFinalize Common_AppFinalize
/*****************************************************************************
* * @doc INTERNAL * * @func void | CMouse_Finalize | * * Releases the resources of the device. * * @parm PV | pvObj | * * Object being released. Note that it may not have been * completely initialized, so everything should be done * carefully. * *****************************************************************************/
void INTERNAL CMouse_Finalize(PV pvObj) { PDM this = pvObj;
if (this->pvi) { HRESULT hres; hres = Hel_DestroyInstance(this->pvi); AssertF(SUCCEEDED(hres)); } }
/*****************************************************************************
* * @doc INTERNAL * * @method void | CMouse | GetPhysicalPosition | * * Read the physical mouse position into <p pmstOut>. * * Note that it doesn't matter if this is not atomic. * If a mouse motion occurs while we are reading it, * we will get a mix of old and new data. No big deal. * * @parm PDM | this | * * The object in question. * * @parm LPDIMOUSESTATE_INT | pdmsOut | * * Where to put the mouse position. * @returns * None. * *****************************************************************************/
void INLINE CMouse_GetPhysicalPosition(PDM this, LPDIMOUSESTATE_INT pdmsOut) { AssertF(this->pdmsPhys); *pdmsOut = *this->pdmsPhys; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | Acquire | * * Tell the device driver to begin data acquisition. * Give the device driver the current mouse button states * in case it needs them. * * It is the caller's responsibility to have set the * data format before obtaining acquisition. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c S_FALSE>: The operation was begun and should be completed * by the caller by communicating with the <t VXDINSTANCE>. * *****************************************************************************/
STDMETHODIMP CMouse_Acquire(PDICB pdcb) { HRESULT hres; PDM this; VXDDWORDDATA vdd; DWORD mef; EnterProcI(IDirectInputDeviceCallback::Mouse::Acquire, (_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi);
vdd.pvi = this->pvi; vdd.dw = 0;
/*
* Collect information about which buttons are down. */ mef = 0; if (GetAsyncKeyState(VK_LBUTTON) < 0) { mef |= MOUSEEVENTF_LEFTUP; vdd.dw |= 0x80; } if (GetAsyncKeyState(VK_RBUTTON) < 0) { mef |= MOUSEEVENTF_RIGHTUP; vdd.dw |= 0x8000; } if (GetAsyncKeyState(VK_MBUTTON) < 0) { mef |= MOUSEEVENTF_MIDDLEUP; vdd.dw |= 0x800000; }
/*
* HACKHACK - This, strictly speaking, belongs in dihel.c, * but we need to maintain some state, and it's easier to * put the state in our own object. */
/*
* A bit of work needs to be done at ring 3 now. */ if (this->pvi->fl & VIFL_CAPTURED) { RECT rc;
/*
* Hide the mouse cursor (for compatibility with NT emulation) */ GetCursorPos(&this->ptPrev); GetWindowRect(this->hwndCapture, &rc); SetCursorPos((rc.left + rc.right) >> 1, (rc.top + rc.bottom) >> 1); ShowCursor(0);
if (!(this->pvi->fl & VIFL_EMULATED)) { /*
* Force all mouse buttons up from USER's point of view * to avoid "stuck mouse button" problems. However, don't * force a button up unless it is actually down. */ if (mef) { mouse_event(mef, 0, 0, 0, 0); } } }
if (!(this->pvi->fl & VIFL_EMULATED)) { hres = IoctlHw(IOCTL_MOUSE_INITBUTTONS, &vdd.dw, cbX(vdd.dw), 0, 0); } else { #ifdef USE_WM_INPUT
if( g_fRawInput ) { hres = CDIRaw_Mouse_InitButtons(); } #endif
hres = CEm_Mouse_InitButtons(&vdd); }
AssertF(SUCCEEDED(hres));
hres = S_FALSE; /* Please finish for me */
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | Unacquire | * * Tell the device driver to stop data acquisition. * * It is the caller's responsibility to call this only * when the device has been acquired. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c S_FALSE>: The operation was begun and should be completed * by the caller by communicating with the <t VXDINSTANCE>. * *****************************************************************************/
STDMETHODIMP CMouse_Unacquire(PDICB pdcb) { HRESULT hres; PDM this; #ifdef WANT_TO_FIX_MANBUG43879
DWORD mef; #endif
EnterProcI(IDirectInputDeviceCallback::Mouse::Unacquire, (_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi);
#ifdef WANT_TO_FIX_MANBUG43879
/*
* Collect information about which buttons are down. */ mef = 0; if (GetAsyncKeyState(VK_LBUTTON) < 0) { mef |= MOUSEEVENTF_LEFTUP; } if (GetAsyncKeyState(VK_RBUTTON) < 0) { mef |= MOUSEEVENTF_RIGHTUP; } if (GetAsyncKeyState(VK_MBUTTON) < 0) { mef |= MOUSEEVENTF_MIDDLEUP; }
if (this->pvi->fl & VIFL_FOREGROUND) { /*
* Force all mouse buttons up from USER's point of view * to avoid "stuck mouse button" problems. However, don't * force a button up unless it is actually down. * This could happen if DInput loses UP events due to slow * low-level hook. See bug: 43879. */ if (mef) { mouse_event(mef, 0, 0, 0, 0); } } #endif
/*
* HACKHACK - This is the corresponding half of the HACKHACK * in CMouse_Acquire. */
/*
* A bit of work needs to be done at ring 3 now. */ if (this->pvi->fl & VIFL_CAPTURED) { RECT rcDesk; RECT rcApp;
/*
* Reposition and restore the mouse cursor * (for compatibility with NT emulation) * * Do not reposition the mouse cursor if we lost to a * window that covers the screen. Otherwise, our * repositioning will nuke the screen saver. */ GetWindowRect(GetDesktopWindow(), &rcDesk); GetWindowRect(GetForegroundWindow(), &rcApp); SubtractRect(&rcDesk, &rcDesk, &rcApp); if (!IsRectEmpty(&rcDesk)) { SetCursorPos(this->ptPrev.x, this->ptPrev.y); } ShowCursor(1); }
hres = S_FALSE; ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | GetInstance | * * Obtains the DirectInput instance handle. * * @parm OUT PPV | ppvi | * * Receives the instance handle. * *****************************************************************************/
STDMETHODIMP CMouse_GetInstance(PDICB pdcb, PPV ppvi) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetInstance, (_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi); *ppvi = (PV)this->pvi; hres = S_OK;
ExitOleProcPpvR(ppvi); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | GetDataFormat | * * Obtains the device's preferred data format. * * @parm OUT LPDIDEVICEFORMAT * | ppdf | * * <t LPDIDEVICEFORMAT> to receive pointer to device format. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The * <p lpmdr> parameter is not a valid pointer. * *****************************************************************************/
STDMETHODIMP CMouse_GetDataFormat(PDICB pdcb, LPDIDATAFORMAT *ppdf) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetDataFormat, (_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
*ppdf = &this->df; hres = S_OK;
ExitOleProcPpvR(ppdf); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | GetDeviceInfo | * * Obtain general information about the device. * * @parm OUT LPDIDEVICEINSTANCEW | pdiW | * * <t DEVICEINSTANCE> to be filled in. The * <e DEVICEINSTANCE.dwSize> and <e DEVICEINSTANCE.guidInstance> * have already been filled in. * * Secret convenience: <e DEVICEINSTANCE.guidProduct> is equal * to <e DEVICEINSTANCE.guidInstance>. * *****************************************************************************/
STDMETHODIMP CMouse_GetDeviceInfo(PDICB pdcb, LPDIDEVICEINSTANCEW pdiW) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetDeviceInfo, (_ "pp", pdcb, pdiW));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(IsValidSizeDIDEVICEINSTANCEW(pdiW->dwSize));
AssertF(IsEqualGUID(&GUID_SysMouse , &pdiW->guidInstance) || IsEqualGUID(&GUID_SysMouseEm , &pdiW->guidInstance) || IsEqualGUID(&GUID_SysMouseEm2, &pdiW->guidInstance)); pdiW->guidProduct = GUID_SysMouse;
pdiW->dwDevType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_MOUSE, DI8DEVTYPEMOUSE_UNKNOWN);
LoadStringW(g_hinst, IDS_STDMOUSE, pdiW->tszProductName, cA(pdiW->tszProductName)); LoadStringW(g_hinst, IDS_STDMOUSE, pdiW->tszInstanceName, cA(pdiW->tszInstanceName));
hres = S_OK;
ExitOleProcR(); return hres;
}
/*****************************************************************************
* * @doc INTERNAL * * @method void | CMouse | GetProperty | * * Get a mouse device property. * * @parm IN LPCDIPROPINFO | ppropi | * * Information describing the property being retrieved. * * @parm LPDIPROPHEADER | pdiph | * * Structure to receive property value. * * @returns * * <c E_NOTIMPL> nothing happened. The caller will do * the default thing in response to <c E_NOTIMPL>. * *****************************************************************************/
STDMETHODIMP CMouse_GetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetProperty, (_ "pxxp", pdcb, ppropi->pguid, ppropi->iobj, pdiph));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
/*
* Granularity is only supported for wheels. */ if (ppropi->pguid == DIPROP_GRANULARITY && ppropi->dwDevType == (DIDFT_RELAXIS | DIDFT_MAKEINSTANCE(2)) ) { LPDIPROPDWORD pdipdw = (PV)pdiph; pdipdw->dwData = g_lWheelGranularity? (DWORD)g_lWheelGranularity : 120; hres = S_OK; } else { hres = E_NOTIMPL; }
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method void | CMouse | GetCapabilities | * * Get mouse device capabilities. * * @parm LPDIDEVCAPS | pdc | * * Device capabilities structure to receive result. * * @returns * <c S_OK> on success. * *****************************************************************************/
STDMETHODIMP CMouse_GetCapabilities(PDICB pdcb, LPDIDEVCAPS pdc) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetCapabilities, (_ "pp", pdcb, pdc));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
pdc->dwDevType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_MOUSE, DI8DEVTYPEMOUSE_UNKNOWN); pdc->dwFlags = DIDC_ATTACHED; if (this->flEmulation) { pdc->dwFlags |= DIDC_ALIAS; }
pdc->dwAxes = this->dwAxes; pdc->dwButtons = this->dwButtons; AssertF(pdc->dwPOVs == 0);
hres = S_OK; ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | GetDeviceState | * * Obtains the state of the mouse device. * * It is the caller's responsibility to have validated all the * parameters and ensure that the device has been acquired. * * @parm OUT LPVOID | lpvData | * * Mouse data in the preferred data format. * * @returns * * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * <c DI_OK> = <c S_OK>: The operation completed successfully. * * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The * <p lpmdr> parameter is not a valid pointer. * *****************************************************************************/
STDMETHODIMP CMouse_GetDeviceState(PDICB pdcb, LPVOID pvData) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetDeviceState, (_ "pp", pdcb, pvData));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi); AssertF(this->pdmsPhys);
if (this->pvi->fl & VIFL_ACQUIRED) { CMouse_GetPhysicalPosition(this, pvData); hres = S_OK; } else { hres = DIERR_INPUTLOST; }
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | GetObjectInfo | * * Obtain the friendly name of an object, passwed by index * into the preferred data format. * * @parm IN LPCDIPROPINFO | ppropi | * * Information describing the object being accessed. * * @parm IN OUT LPDIDEVICEOBJECTINSTANCEW | pdidioiW | * * Structure to receive information. The * <e DIDEVICEOBJECTINSTANCE.guidType>, * <e DIDEVICEOBJECTINSTANCE.dwOfs>, * and * <e DIDEVICEOBJECTINSTANCE.dwType> * fields have already been filled in. * * @returns * * Returns a COM error code. * *****************************************************************************/
STDMETHODIMP CMouse_GetObjectInfo(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIDEVICEOBJECTINSTANCEW pdidoiW) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::GetObjectInfo, (_ "pxp", pdcb, ppropi->iobj, pdidoiW));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEW(pdidoiW->dwSize));
if (ppropi->iobj < this->df.dwNumObjs) { AssertF(this->rgodf == this->df.rgodf); AssertF(ppropi->dwDevType == this->rgodf[ppropi->iobj].dwType);
AssertF(DIDFT_GETTYPE(ppropi->dwDevType) == DIDFT_RELAXIS || DIDFT_GETTYPE(ppropi->dwDevType) == DIDFT_PSHBUTTON);
LoadStringW(g_hinst, IDS_MOUSEOBJECT + DIDFT_GETINSTANCE(ppropi->dwDevType), pdidoiW->tszName, cA(pdidoiW->tszName));
/*
* We do not support force feedback on mice, so * there are no FF flags to report. */ hres = S_OK; } else { hres = E_INVALIDARG; }
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | SetCooperativeLevel | * * Notify the device of the cooperative level. * * @parm IN HWND | hwnd | * * The window handle. * * @parm IN DWORD | dwFlags | * * The cooperativity level. * * @returns * * Returns a COM error code. * *****************************************************************************/
STDMETHODIMP CMouse_SetCooperativeLevel(PDICB pdcb, HWND hwnd, DWORD dwFlags) { HRESULT hres; PDM this; EnterProcI(IDirectInputDeviceCallback::Mouse::SetCooperativityLevel, (_ "pxx", pdcb, hwnd, dwFlags));
/*
* This is an internal interface, so we can skimp on validation. */ this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi);
#ifdef USE_SLOW_LL_HOOKS
AssertF(DIGETEMFL(this->pvi->fl) == 0 || DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE || DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE2); #else
AssertF(DIGETEMFL(this->pvi->fl) == 0 || DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE2); #endif
/*
* Even though we can do it, we don't let the app * get background exclusive access. As with the keyboard, * there is nothing that technically prevents us from * supporting it; we just don't feel like it because it's * too dangerous. */
/*
* VxD and LL (emulation 1) behave the same, so we check * if it's "not emulation 2". */
if (!(this->pvi->fl & DIMAKEEMFL(DIEMFL_MOUSE2))) {
if (dwFlags & DISCL_EXCLUSIVE) { if (dwFlags & DISCL_FOREGROUND) { #ifdef WANT_TO_FIX_MANBUG43879
this->pvi->fl |= VIFL_FOREGROUND; #endif
this->pvi->fl |= VIFL_CAPTURED; hres = S_OK; } else { /* Disallow exclusive background */ SquirtSqflPtszV(sqfl | sqflError, TEXT("Exclusive background mouse access disallowed")); hres = E_NOTIMPL; } } else { #ifdef WANT_TO_FIX_MANBUG43879
if (dwFlags & DISCL_FOREGROUND) { this->pvi->fl |= VIFL_FOREGROUND; } #endif
this->pvi->fl &= ~VIFL_CAPTURED; hres = S_OK; }
} else { /*
* Emulation 2 supports only exclusive foreground. */ if ((dwFlags & (DISCL_EXCLUSIVE | DISCL_FOREGROUND)) == (DISCL_EXCLUSIVE | DISCL_FOREGROUND)) { #ifdef WANT_TO_FIX_MANBUG43879
this->pvi->fl |= VIFL_FOREGROUND; #endif
this->pvi->fl |= VIFL_CAPTURED; hres = S_OK; } else { SquirtSqflPtszV(sqfl | sqflError, TEXT("Mouse access must be exclusive foreground in Emulation 2.")); hres = E_NOTIMPL; } }
if (SUCCEEDED(hres)) { this->hwndCapture = hwnd; }
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | RunControlPanel | * * Run the mouse control panel. * * @parm IN HWND | hwndOwner | * * The owner window. * * @parm DWORD | dwFlags | * * Flags. * *****************************************************************************/
#pragma BEGIN_CONST_DATA
TCHAR c_tszMouse[] = TEXT("mouse");
#pragma END_CONST_DATA
STDMETHODIMP CMouse_RunControlPanel(PDICB pdcb, HWND hwnd, DWORD dwFlags) { HRESULT hres; EnterProcI(IDirectInputDeviceCallback::Mouse::RunControlPanel, (_ "pxx", pdcb, hwnd, dwFlags));
hres = hresRunControlPanel(c_tszMouse);
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method HRESULT | CMouse | BuildDefaultActionMap | * * Validate the passed action map, blanking out invalid ones. * * @parm LPDIACTIONFORMATW | pActionFormat | * * Actions to map. * * @parm DWORD | dwFlags | * * Flags used to indicate mapping preferences. * * @parm REFGUID | guidInst | * * Device instance GUID. * * @returns * * <c E_NOTIMPL> * *****************************************************************************/
STDMETHODIMP CMouse_BuildDefaultActionMap ( PDICB pdcb, LPDIACTIONFORMATW paf, DWORD dwFlags, REFGUID guidInst ) { HRESULT hres; PDM this;
/*
* This is an internal interface, so we can skimp on validation. */ EnterProcI(IDirectInputDeviceCallback::Mouse::BuildDefaultActionMap, (_ "ppxG", pdcb, paf, dwFlags, guidInst));
this = _thisPvNm(pdcb, dcb);
hres = CMap_BuildDefaultSysActionMap ( paf, dwFlags, DIPHYSICAL_MOUSE, guidInst, &this->df, 3 /* Generic mice buttons start at instnace 3 */ );
ExitOleProcR(); return hres; }
/*****************************************************************************
* * @doc INTERNAL * * @method UINT | CMouse | NumAxes | * * Determine the number of mouse axes. * * On Windows NT, we can use the new <c SM_MOUSEWHEELPRESENT> * system metric. On Windows 95, we have to hunt for the * Magellan window (using the mechanism documented in the * Magellan SDK). * *****************************************************************************/
#pragma BEGIN_CONST_DATA
TCHAR c_tszMouseZClass[] = TEXT("MouseZ"); TCHAR c_tszMouseZTitle[] = TEXT("Magellan MSWHEEL"); TCHAR c_tszMouseZActive[] = TEXT("MSH_WHEELSUPPORT_MSG");
#pragma END_CONST_DATA
#ifdef WINNT
#define CMouse_IsMagellanWheel() FALSE
#else
BOOL INLINE CMouse_IsMagellanWheel(void) { HWND hwnd = FindWindow(c_tszMouseZClass, c_tszMouseZTitle); return hwnd && SendMessage(hwnd, RegisterWindowMessage(c_tszMouseZActive), 0, 0); } #endif
#ifndef SM_MOUSEWHEELPRESENT
#define SM_MOUSEWHEELPRESENT 75
#endif
UINT INLINE CMouse_NumAxes(void) { UINT dwAxes;
if (GetSystemMetrics(SM_MOUSEWHEELPRESENT) || CMouse_IsMagellanWheel()) { dwAxes = 3; } else { dwAxes = 2; }
if (dwAxes == 2) { //Should avoid rebuilding too frequently.
DIHid_BuildHidList(FALSE);
DllEnterCrit();
if (g_phdl) { int ihdi; for (ihdi = 0; ihdi < g_phdl->chdi; ihdi++) { if (dwAxes < g_phdl->rghdi[ihdi].osd.uiAxes) { dwAxes = g_phdl->rghdi[ihdi].osd.uiAxes; } } } DllLeaveCrit(); }
return dwAxes; }
UINT INLINE CMouse_NumButtons(DWORD dwAxes) { UINT dwButtons;
dwButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
#ifndef WINNT
#ifdef HID_SUPPORT
{ /*
* ISSUE-2001/03/29-timgill Should try to avoid rebuilding Hid List too frequently. */ DIHid_BuildHidList(FALSE);
DllEnterCrit();
if (g_phdl) { int ihdi; for (ihdi = 0; ihdi < g_phdl->chdi; ihdi++) { if (dwButtons < g_phdl->rghdi[ihdi].osd.uiButtons) { dwButtons = g_phdl->rghdi[ihdi].osd.uiButtons; } } } DllLeaveCrit(); } #endif
#endif
if( dwButtons >= 8 ) { dwButtons = 8; } else if (dwAxes == 3 && dwButtons < 3) { /*
* HACK FOR MAGELLAN! * * They return 2 from GetSystemMetrics(SM_CMOUSEBUTTONS). * So if we see a Z-axis, then assume that * there is also a third button. */ dwButtons = 3; }
return dwButtons; }
/*****************************************************************************
* * @doc INTERNAL * * @method void | CMouse | AddObjects | * * Add a number of objects to the device format. * * @parm LPCDIOBJECTDATAFORMAT | rgodf | * * Array of objects to be added. * * @parm UINT | cObj | * * Number of objects to add. * *****************************************************************************/
void INTERNAL CMouse_AddObjects(PDM this, LPCDIOBJECTDATAFORMAT rgodf, UINT cObj) { UINT iodf; EnterProc(CMouse_AddObjects, (_ "pxx", this, rgodf, cObj));
for (iodf = 0; iodf < cObj; iodf++) { this->rgodf[this->df.dwNumObjs++] = rgodf[iodf]; } AssertF(this->df.dwNumObjs <= cA(this->rgodf)); }
/*****************************************************************************
* * @doc INTERNAL * * @method void | CMouse | Init | * * Initialize the object by establishing the data format * based on the mouse type. * * Code for detecting the IntelliMouse (formerly known as * Magellan) pointing device is swiped from zmouse.h. * * @parm REFGUID | rguid | * * The instance GUID we are being asked to create. * *****************************************************************************/
HRESULT INTERNAL CMouse_Init(PDM this, REFGUID rguid) { HRESULT hres; VXDDEVICEFORMAT devf; EnterProc(CMouse_Init, (_ "pG", this, rguid));
this->df.dwSize = cbX(DIDATAFORMAT); this->df.dwObjSize = cbX(DIOBJECTDATAFORMAT); this->df.dwDataSize = cbX(DIMOUSESTATE_INT); this->df.rgodf = this->rgodf; AssertF(this->df.dwFlags == 0); AssertF(this->df.dwNumObjs == 0);
/*
* Need to know early if we have a Z-axis, so we can disable * the Z-wheel if it doesn't exist. * * Note that this disabling needs to be done only on Win95. * Win98 and NT4 have native Z-axis support, so there is * nothing bogus that needs to be hacked. */ this->dwAxes = CMouse_NumAxes(); devf.dwExtra = this->dwAxes; if (this->dwAxes < 3) { DWORD dwVer = GetVersion(); if ((LONG)dwVer >= 0 || MAKEWORD(HIBYTE(LOWORD(dwVer)), LOBYTE(dwVer)) >= 0x040A) { devf.dwExtra = 3; } } CMouse_AddObjects(this, c_podfMouseAxes, this->dwAxes);
/*
* Create the object with the most optimistic data format. * This is important, because DINPUT.VXD builds the * data format only once, and we need to protect ourselves against * the user going into Control Panel and enabling the Z-Wheel * after DINPUT.VXD has already initialized. */
devf.cbData = cbX(DIMOUSESTATE_INT); devf.cObj = cA(c_rgodfMouse); devf.rgodf = c_rgodfMouse;
/*
* But first a word from our other sponsor: Figure out the * emulation flags based on the GUID. */
AssertF(GUID_SysMouse .Data1 == 0x6F1D2B60); AssertF(GUID_SysMouseEm .Data1 == 0x6F1D2B80); AssertF(GUID_SysMouseEm2.Data1 == 0x6F1D2B81);
switch (rguid->Data1) {
default: case 0x6F1D2B60: AssertF(IsEqualGUID(rguid, &GUID_SysMouse)); AssertF(this->flEmulation == 0); break;
case 0x6F1D2B80: AssertF(IsEqualGUID(rguid, &GUID_SysMouseEm)); this->flEmulation = DIEMFL_MOUSE; break;
case 0x6F1D2B81: AssertF(IsEqualGUID(rguid, &GUID_SysMouseEm2)); this->flEmulation = DIEMFL_MOUSE2; break;
}
devf.dwEmulation = this->flEmulation;
hres = Hel_Mouse_CreateInstance(&devf, &this->pvi); if (SUCCEEDED(hres)) {
AssertF(this->pvi); this->pdmsPhys = this->pvi->pState;
this->dwButtons = CMouse_NumButtons( this->dwAxes );
CMouse_AddObjects(this, c_podfMouseButtons, this->dwButtons);
hres = S_OK;
} else { SquirtSqflPtszV(sqfl | sqflError, TEXT("Mismatched version of dinput.vxd")); hres = E_FAIL; }
ExitOleProc(); return hres; }
/*****************************************************************************
* * CMouse_New (constructor) * * Fail the create if the machine has no mouse. * *****************************************************************************/
STDMETHODIMP CMouse_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvObj) { HRESULT hres; EnterProcI(IDirectInputDeviceCallback::Mouse::<constructor>, (_ "Gp", riid, ppvObj));
AssertF(IsEqualGUID(rguid, &GUID_SysMouse) || IsEqualGUID(rguid, &GUID_SysMouseEm) || IsEqualGUID(rguid, &GUID_SysMouseEm2));
if (GetSystemMetrics(SM_MOUSEPRESENT)) { hres = Common_NewRiid(CMouse, punkOuter, riid, ppvObj);
if (SUCCEEDED(hres)) { /* Must use _thisPv in case of aggregation */ PDM this = _thisPv(*ppvObj);
if (SUCCEEDED(hres = CMouse_Init(this, rguid))) { } else { Invoke_Release(ppvObj); }
} } else { RPF("Warning: System does not have a mouse"); /*
* Since we by-passed the parameter checks and we failed to create * the new interface, try to zero the pointer now. */ if (!IsBadWritePtr(ppvObj, sizeof(UINT_PTR) )) { *(PUINT_PTR)ppvObj = 0; } hres = DIERR_DEVICENOTREG; }
ExitOleProcPpvR(ppvObj); return hres; }
/*****************************************************************************
* * The long-awaited vtbls and templates * *****************************************************************************/
#pragma BEGIN_CONST_DATA
#define CMouse_Signature 0x53554F4D /* "MOUS" */
Primary_Interface_Begin(CMouse, IDirectInputDeviceCallback) CMouse_GetInstance, CDefDcb_GetVersions, CMouse_GetDataFormat, CMouse_GetObjectInfo, CMouse_GetCapabilities, CMouse_Acquire, CMouse_Unacquire, CMouse_GetDeviceState, CMouse_GetDeviceInfo, CMouse_GetProperty, CDefDcb_SetProperty, CDefDcb_SetEventNotification, CMouse_SetCooperativeLevel, CMouse_RunControlPanel, CDefDcb_CookDeviceData, CDefDcb_CreateEffect, CDefDcb_GetFFConfigKey, CDefDcb_SendDeviceData, CDefDcb_Poll, CDefDcb_GetUsage, CDefDcb_MapUsage, CDefDcb_SetDIData, CMouse_BuildDefaultActionMap, Primary_Interface_End(CMouse, IDirectInputDeviceCallback)
|