Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1418 lines
38 KiB

  1. /*****************************************************************************
  2. *
  3. * DIGenM.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Practice generic IDirectInputDevice callback for mouse.
  10. *
  11. * Contents:
  12. *
  13. * CMouse_New
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflMouse
  23. /*****************************************************************************
  24. *
  25. * Declare the interfaces we will be providing.
  26. *
  27. *****************************************************************************/
  28. Primary_Interface(CMouse, IDirectInputDeviceCallback);
  29. Interface_Template_Begin(CMouse)
  30. Primary_Interface_Template(CMouse, IDirectInputDeviceCallback)
  31. Interface_Template_End(CMouse)
  32. /*****************************************************************************
  33. *
  34. * @doc INTERNAL
  35. *
  36. * @global DIOBJECTDATAFORMAT | c_rgodfMouse[] |
  37. *
  38. * Device object data formats for the generic mouse device.
  39. * The axes come first, then the buttons.
  40. *
  41. *****************************************************************************/
  42. #pragma BEGIN_CONST_DATA
  43. #define MAKEODF(guid, f, type, inst, aspect) \
  44. { &GUID_##guid, \
  45. FIELD_OFFSET(DIMOUSESTATE_INT, f), \
  46. DIDFT_##type | DIDFT_MAKEINSTANCE(inst), \
  47. DIDOI_ASPECT##aspect, \
  48. } \
  49. /*
  50. * Warning! If you change this table, you must adjust the IDS_MOUSEOBJECT
  51. * table in dinput.rc to match!
  52. */
  53. DIOBJECTDATAFORMAT c_rgodfMouse[] = {
  54. MAKEODF( XAxis, lX, RELAXIS, 0, POSITION),
  55. MAKEODF( YAxis, lY, RELAXIS, 1, POSITION),
  56. MAKEODF( ZAxis, lZ, RELAXIS, 2, POSITION),
  57. MAKEODF(Button, rgbButtons[0], PSHBUTTON, 3, UNKNOWN),
  58. MAKEODF(Button, rgbButtons[1], PSHBUTTON, 4, UNKNOWN),
  59. MAKEODF(Button, rgbButtons[2], PSHBUTTON, 5, UNKNOWN),
  60. MAKEODF(Button, rgbButtons[3], PSHBUTTON, 6, UNKNOWN),
  61. #if (DIRECTINPUT_VERSION == 0x0700)
  62. MAKEODF(Button, rgbButtons[4], PSHBUTTON, 7, UNKNOWN),
  63. MAKEODF(Button, rgbButtons[5], PSHBUTTON, 8, UNKNOWN),
  64. MAKEODF(Button, rgbButtons[6], PSHBUTTON, 9, UNKNOWN),
  65. MAKEODF(Button, rgbButtons[7], PSHBUTTON,10, UNKNOWN),
  66. #endif
  67. };
  68. #define c_podfMouseAxes (&c_rgodfMouse[0])
  69. #define c_podfMouseButtons (&c_rgodfMouse[3])
  70. #pragma END_CONST_DATA
  71. /*****************************************************************************
  72. *
  73. * @doc INTERNAL
  74. *
  75. * @struct CMouse |
  76. *
  77. * The <i IDirectInputDeviceCallback> object for the generic mouse.
  78. *
  79. * @field IDirectInputDeviceCalllback | didc |
  80. *
  81. * The object (containing vtbl).
  82. *
  83. * @field LPDIMOUSESTATE_INT | pdmsPhys |
  84. *
  85. * Pointer to physical mouse status information kept down in the
  86. * VxD.
  87. *
  88. * @field POINT | ptPrev |
  89. *
  90. * Location of the mouse at the time we stole it exclusively.
  91. *
  92. * @field HWND | hwndCaptured |
  93. *
  94. * The window that captured the mouse.
  95. *
  96. * @field VXDINSTANCE * | pvi |
  97. *
  98. * The DirectInput instance handle. Even though we manipulate
  99. * the flags field, we do not need to mark it volatile because
  100. * we modify the flags only when unacquired, whereas the device
  101. * driver modifies the flags only when acquired.
  102. *
  103. * @field UINT | dwAxes |
  104. *
  105. * Number of axes on the mouse.
  106. *
  107. * @field UINT | dwButtons |
  108. *
  109. * Number of buttons on the mouse.
  110. *
  111. * @field DWORD | flEmulation |
  112. *
  113. * The emulation flags forced by the application. If any of
  114. * these flags is set (actually, at most one will be set), then
  115. * we are an alias device.
  116. *
  117. * @field DIDATAFORMAT | df |
  118. *
  119. * The dynamically-generated data format based on the
  120. * mouse type.
  121. *
  122. * @field DIOBJECTDATAFORMAT | rgodf[] |
  123. *
  124. * Object data format table generated as part of the
  125. * <e CMouse.df>.
  126. *
  127. * @comm
  128. *
  129. * It is the caller's responsibility to serialize access as
  130. * necessary.
  131. *
  132. *****************************************************************************/
  133. typedef struct CMouse {
  134. /* Supported interfaces */
  135. IDirectInputDeviceCallback dcb;
  136. LPDIMOUSESTATE_INT pdmsPhys; /* Physical mouse state */
  137. POINT ptPrev;
  138. HWND hwndCapture;
  139. VXDINSTANCE *pvi;
  140. UINT dwAxes;
  141. UINT dwButtons;
  142. DWORD flEmulation;
  143. DIDATAFORMAT df;
  144. DIOBJECTDATAFORMAT rgodf[cA(c_rgodfMouse)];
  145. } CMouse, DM, *PDM;
  146. #define ThisClass CMouse
  147. #define ThisInterface IDirectInputDeviceCallback
  148. #define riidExpected &IID_IDirectInputDeviceCallback
  149. /*****************************************************************************
  150. *
  151. * CMouse::QueryInterface (from IUnknown)
  152. * CMouse::AddRef (from IUnknown)
  153. * CMouse::Release (from IUnknown)
  154. *
  155. *****************************************************************************/
  156. /*****************************************************************************
  157. *
  158. * @doc INTERNAL
  159. *
  160. * @method HRESULT | CMouse | QueryInterface |
  161. *
  162. * Gives a client access to other interfaces on an object.
  163. *
  164. * @cwrap LPDIRECTINPUT | lpDirectInput
  165. *
  166. * @parm IN REFIID | riid |
  167. *
  168. * The requested interface's IID.
  169. *
  170. * @parm OUT LPVOID * | ppvObj |
  171. *
  172. * Receives a pointer to the obtained interface.
  173. *
  174. * @returns
  175. *
  176. * Returns a COM error code.
  177. *
  178. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  179. *
  180. *****************************************************************************
  181. *
  182. * @doc INTERNAL
  183. *
  184. * @method HRESULT | CMouse | AddRef |
  185. *
  186. * Increments the reference count for the interface.
  187. *
  188. * @cwrap LPDIRECTINPUT | lpDirectInput
  189. *
  190. * @returns
  191. *
  192. * Returns the object reference count.
  193. *
  194. * @xref OLE documentation for <mf IUnknown::AddRef>.
  195. *
  196. *****************************************************************************
  197. *
  198. * @doc INTERNAL
  199. *
  200. * @method HRESULT | CMouse | Release |
  201. *
  202. * Decrements the reference count for the interface.
  203. * If the reference count on the object falls to zero,
  204. * the object is freed from memory.
  205. *
  206. * @cwrap LPDIRECTINPUT | lpDirectInput
  207. *
  208. * @returns
  209. *
  210. * Returns the object reference count.
  211. *
  212. * @xref OLE documentation for <mf IUnknown::Release>.
  213. *
  214. *****************************************************************************
  215. *
  216. * @doc INTERNAL
  217. *
  218. * @method HRESULT | CMouse | QIHelper |
  219. *
  220. * We don't have any dynamic interfaces and simply forward
  221. * to <f Common_QIHelper>.
  222. *
  223. * @parm IN REFIID | riid |
  224. *
  225. * The requested interface's IID.
  226. *
  227. * @parm OUT LPVOID * | ppvObj |
  228. *
  229. * Receives a pointer to the obtained interface.
  230. *
  231. *****************************************************************************
  232. *
  233. * @doc INTERNAL
  234. *
  235. * @method HRESULT | CMouse | AppFinalize |
  236. *
  237. * We don't have any weak pointers, so we can just
  238. * forward to <f Common_Finalize>.
  239. *
  240. * @parm PV | pvObj |
  241. *
  242. * Object being released from the application's perspective.
  243. *
  244. *****************************************************************************/
  245. #ifdef DEBUG
  246. Default_QueryInterface(CMouse)
  247. Default_AddRef(CMouse)
  248. Default_Release(CMouse)
  249. #else
  250. #define CMouse_QueryInterface Common_QueryInterface
  251. #define CMouse_AddRef Common_AddRef
  252. #define CMouse_Release Common_Release
  253. #endif
  254. #define CMouse_QIHelper Common_QIHelper
  255. #define CMouse_AppFinalize Common_AppFinalize
  256. /*****************************************************************************
  257. *
  258. * @doc INTERNAL
  259. *
  260. * @func void | CMouse_Finalize |
  261. *
  262. * Releases the resources of the device.
  263. *
  264. * @parm PV | pvObj |
  265. *
  266. * Object being released. Note that it may not have been
  267. * completely initialized, so everything should be done
  268. * carefully.
  269. *
  270. *****************************************************************************/
  271. void INTERNAL
  272. CMouse_Finalize(PV pvObj)
  273. {
  274. PDM this = pvObj;
  275. if (this->pvi) {
  276. HRESULT hres;
  277. hres = Hel_DestroyInstance(this->pvi);
  278. AssertF(SUCCEEDED(hres));
  279. }
  280. }
  281. /*****************************************************************************
  282. *
  283. * @doc INTERNAL
  284. *
  285. * @method void | CMouse | GetPhysicalPosition |
  286. *
  287. * Read the physical mouse position into <p pmstOut>.
  288. *
  289. * Note that it doesn't matter if this is not atomic.
  290. * If a mouse motion occurs while we are reading it,
  291. * we will get a mix of old and new data. No big deal.
  292. *
  293. * @parm PDM | this |
  294. *
  295. * The object in question.
  296. *
  297. * @parm LPDIMOUSESTATE_INT | pdmsOut |
  298. *
  299. * Where to put the mouse position.
  300. * @returns
  301. * None.
  302. *
  303. *****************************************************************************/
  304. void INLINE
  305. CMouse_GetPhysicalPosition(PDM this, LPDIMOUSESTATE_INT pdmsOut)
  306. {
  307. AssertF(this->pdmsPhys);
  308. *pdmsOut = *this->pdmsPhys;
  309. }
  310. /*****************************************************************************
  311. *
  312. * @doc INTERNAL
  313. *
  314. * @method HRESULT | CMouse | Acquire |
  315. *
  316. * Tell the device driver to begin data acquisition.
  317. * Give the device driver the current mouse button states
  318. * in case it needs them.
  319. *
  320. * It is the caller's responsibility to have set the
  321. * data format before obtaining acquisition.
  322. *
  323. * @returns
  324. *
  325. * Returns a COM error code. The following error codes are
  326. * intended to be illustrative and not necessarily comprehensive.
  327. *
  328. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  329. *
  330. * <c S_FALSE>: The operation was begun and should be completed
  331. * by the caller by communicating with the <t VXDINSTANCE>.
  332. *
  333. *****************************************************************************/
  334. STDMETHODIMP
  335. CMouse_Acquire(PDICB pdcb)
  336. {
  337. HRESULT hres;
  338. PDM this;
  339. VXDDWORDDATA vdd;
  340. DWORD mef;
  341. EnterProcI(IDirectInputDeviceCallback::Mouse::Acquire,
  342. (_ "p", pdcb));
  343. /*
  344. * This is an internal interface, so we can skimp on validation.
  345. */
  346. this = _thisPvNm(pdcb, dcb);
  347. AssertF(this->pvi);
  348. vdd.pvi = this->pvi;
  349. vdd.dw = 0;
  350. /*
  351. * Collect information about which buttons are down.
  352. */
  353. mef = 0;
  354. if (GetAsyncKeyState(VK_LBUTTON) < 0) {
  355. mef |= MOUSEEVENTF_LEFTUP;
  356. vdd.dw |= 0x80;
  357. }
  358. if (GetAsyncKeyState(VK_RBUTTON) < 0) {
  359. mef |= MOUSEEVENTF_RIGHTUP;
  360. vdd.dw |= 0x8000;
  361. }
  362. if (GetAsyncKeyState(VK_MBUTTON) < 0) {
  363. mef |= MOUSEEVENTF_MIDDLEUP;
  364. vdd.dw |= 0x800000;
  365. }
  366. /*
  367. * HACKHACK - This, strictly speaking, belongs in dihel.c,
  368. * but we need to maintain some state, and it's easier to
  369. * put the state in our own object.
  370. */
  371. /*
  372. * A bit of work needs to be done at ring 3 now.
  373. */
  374. if (this->pvi->fl & VIFL_CAPTURED) {
  375. RECT rc;
  376. /*
  377. * Hide the mouse cursor (for compatibility with NT emulation)
  378. */
  379. GetCursorPos(&this->ptPrev);
  380. GetWindowRect(this->hwndCapture, &rc);
  381. SetCursorPos((rc.left + rc.right) >> 1,
  382. (rc.top + rc.bottom) >> 1);
  383. ShowCursor(0);
  384. if (!(this->pvi->fl & VIFL_EMULATED)) {
  385. /*
  386. * Force all mouse buttons up from USER's point of view
  387. * to avoid "stuck mouse button" problems. However, don't
  388. * force a button up unless it is actually down.
  389. */
  390. if (mef) {
  391. mouse_event(mef, 0, 0, 0, 0);
  392. }
  393. }
  394. }
  395. if (!(this->pvi->fl & VIFL_EMULATED)) {
  396. hres = IoctlHw(IOCTL_MOUSE_INITBUTTONS, &vdd.dw, cbX(vdd.dw), 0, 0);
  397. } else {
  398. #ifdef USE_WM_INPUT
  399. if( g_fRawInput ) {
  400. hres = CDIRaw_Mouse_InitButtons();
  401. }
  402. #endif
  403. hres = CEm_Mouse_InitButtons(&vdd);
  404. }
  405. AssertF(SUCCEEDED(hres));
  406. hres = S_FALSE; /* Please finish for me */
  407. ExitOleProcR();
  408. return hres;
  409. }
  410. /*****************************************************************************
  411. *
  412. * @doc INTERNAL
  413. *
  414. * @method HRESULT | CMouse | Unacquire |
  415. *
  416. * Tell the device driver to stop data acquisition.
  417. *
  418. * It is the caller's responsibility to call this only
  419. * when the device has been acquired.
  420. *
  421. * @returns
  422. *
  423. * Returns a COM error code. The following error codes are
  424. * intended to be illustrative and not necessarily comprehensive.
  425. *
  426. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  427. *
  428. * <c S_FALSE>: The operation was begun and should be completed
  429. * by the caller by communicating with the <t VXDINSTANCE>.
  430. *
  431. *****************************************************************************/
  432. STDMETHODIMP
  433. CMouse_Unacquire(PDICB pdcb)
  434. {
  435. HRESULT hres;
  436. PDM this;
  437. #ifdef WANT_TO_FIX_MANBUG43879
  438. DWORD mef;
  439. #endif
  440. EnterProcI(IDirectInputDeviceCallback::Mouse::Unacquire,
  441. (_ "p", pdcb));
  442. /*
  443. * This is an internal interface, so we can skimp on validation.
  444. */
  445. this = _thisPvNm(pdcb, dcb);
  446. AssertF(this->pvi);
  447. #ifdef WANT_TO_FIX_MANBUG43879
  448. /*
  449. * Collect information about which buttons are down.
  450. */
  451. mef = 0;
  452. if (GetAsyncKeyState(VK_LBUTTON) < 0) {
  453. mef |= MOUSEEVENTF_LEFTUP;
  454. }
  455. if (GetAsyncKeyState(VK_RBUTTON) < 0) {
  456. mef |= MOUSEEVENTF_RIGHTUP;
  457. }
  458. if (GetAsyncKeyState(VK_MBUTTON) < 0) {
  459. mef |= MOUSEEVENTF_MIDDLEUP;
  460. }
  461. if (this->pvi->fl & VIFL_FOREGROUND) {
  462. /*
  463. * Force all mouse buttons up from USER's point of view
  464. * to avoid "stuck mouse button" problems. However, don't
  465. * force a button up unless it is actually down.
  466. * This could happen if DInput loses UP events due to slow
  467. * low-level hook. See bug: 43879.
  468. */
  469. if (mef) {
  470. mouse_event(mef, 0, 0, 0, 0);
  471. }
  472. }
  473. #endif
  474. /*
  475. * HACKHACK - This is the corresponding half of the HACKHACK
  476. * in CMouse_Acquire.
  477. */
  478. /*
  479. * A bit of work needs to be done at ring 3 now.
  480. */
  481. if (this->pvi->fl & VIFL_CAPTURED) {
  482. RECT rcDesk;
  483. RECT rcApp;
  484. /*
  485. * Reposition and restore the mouse cursor
  486. * (for compatibility with NT emulation)
  487. *
  488. * Do not reposition the mouse cursor if we lost to a
  489. * window that covers the screen. Otherwise, our
  490. * repositioning will nuke the screen saver.
  491. */
  492. GetWindowRect(GetDesktopWindow(), &rcDesk);
  493. GetWindowRect(GetForegroundWindow(), &rcApp);
  494. SubtractRect(&rcDesk, &rcDesk, &rcApp);
  495. if (!IsRectEmpty(&rcDesk)) {
  496. SetCursorPos(this->ptPrev.x, this->ptPrev.y);
  497. }
  498. ShowCursor(1);
  499. }
  500. hres = S_FALSE;
  501. ExitOleProcR();
  502. return hres;
  503. }
  504. /*****************************************************************************
  505. *
  506. * @doc INTERNAL
  507. *
  508. * @method HRESULT | CMouse | GetInstance |
  509. *
  510. * Obtains the DirectInput instance handle.
  511. *
  512. * @parm OUT PPV | ppvi |
  513. *
  514. * Receives the instance handle.
  515. *
  516. *****************************************************************************/
  517. STDMETHODIMP
  518. CMouse_GetInstance(PDICB pdcb, PPV ppvi)
  519. {
  520. HRESULT hres;
  521. PDM this;
  522. EnterProcI(IDirectInputDeviceCallback::Mouse::GetInstance, (_ "p", pdcb));
  523. /*
  524. * This is an internal interface, so we can skimp on validation.
  525. */
  526. this = _thisPvNm(pdcb, dcb);
  527. AssertF(this->pvi);
  528. *ppvi = (PV)this->pvi;
  529. hres = S_OK;
  530. ExitOleProcPpvR(ppvi);
  531. return hres;
  532. }
  533. /*****************************************************************************
  534. *
  535. * @doc INTERNAL
  536. *
  537. * @method HRESULT | CMouse | GetDataFormat |
  538. *
  539. * Obtains the device's preferred data format.
  540. *
  541. * @parm OUT LPDIDEVICEFORMAT * | ppdf |
  542. *
  543. * <t LPDIDEVICEFORMAT> to receive pointer to device format.
  544. *
  545. * @returns
  546. *
  547. * Returns a COM error code. The following error codes are
  548. * intended to be illustrative and not necessarily comprehensive.
  549. *
  550. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  551. *
  552. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  553. * <p lpmdr> parameter is not a valid pointer.
  554. *
  555. *****************************************************************************/
  556. STDMETHODIMP
  557. CMouse_GetDataFormat(PDICB pdcb, LPDIDATAFORMAT *ppdf)
  558. {
  559. HRESULT hres;
  560. PDM this;
  561. EnterProcI(IDirectInputDeviceCallback::Mouse::GetDataFormat,
  562. (_ "p", pdcb));
  563. /*
  564. * This is an internal interface, so we can skimp on validation.
  565. */
  566. this = _thisPvNm(pdcb, dcb);
  567. *ppdf = &this->df;
  568. hres = S_OK;
  569. ExitOleProcPpvR(ppdf);
  570. return hres;
  571. }
  572. /*****************************************************************************
  573. *
  574. * @doc INTERNAL
  575. *
  576. * @method HRESULT | CMouse | GetDeviceInfo |
  577. *
  578. * Obtain general information about the device.
  579. *
  580. * @parm OUT LPDIDEVICEINSTANCEW | pdiW |
  581. *
  582. * <t DEVICEINSTANCE> to be filled in. The
  583. * <e DEVICEINSTANCE.dwSize> and <e DEVICEINSTANCE.guidInstance>
  584. * have already been filled in.
  585. *
  586. * Secret convenience: <e DEVICEINSTANCE.guidProduct> is equal
  587. * to <e DEVICEINSTANCE.guidInstance>.
  588. *
  589. *****************************************************************************/
  590. STDMETHODIMP
  591. CMouse_GetDeviceInfo(PDICB pdcb, LPDIDEVICEINSTANCEW pdiW)
  592. {
  593. HRESULT hres;
  594. PDM this;
  595. EnterProcI(IDirectInputDeviceCallback::Mouse::GetDeviceInfo,
  596. (_ "pp", pdcb, pdiW));
  597. /*
  598. * This is an internal interface, so we can skimp on validation.
  599. */
  600. this = _thisPvNm(pdcb, dcb);
  601. AssertF(IsValidSizeDIDEVICEINSTANCEW(pdiW->dwSize));
  602. AssertF(IsEqualGUID(&GUID_SysMouse , &pdiW->guidInstance) ||
  603. IsEqualGUID(&GUID_SysMouseEm , &pdiW->guidInstance) ||
  604. IsEqualGUID(&GUID_SysMouseEm2, &pdiW->guidInstance));
  605. pdiW->guidProduct = GUID_SysMouse;
  606. pdiW->dwDevType = MAKE_DIDEVICE_TYPE(DIDEVTYPE_MOUSE,
  607. DIDEVTYPEMOUSE_UNKNOWN);
  608. LoadStringW(g_hinst, IDS_STDMOUSE, pdiW->tszProductName, cA(pdiW->tszProductName));
  609. LoadStringW(g_hinst, IDS_STDMOUSE, pdiW->tszInstanceName, cA(pdiW->tszInstanceName));
  610. hres = S_OK;
  611. ExitOleProcR();
  612. return hres;
  613. }
  614. /*****************************************************************************
  615. *
  616. * @doc INTERNAL
  617. *
  618. * @method void | CMouse | GetProperty |
  619. *
  620. * Get a mouse device property.
  621. *
  622. * @parm IN LPCDIPROPINFO | ppropi |
  623. *
  624. * Information describing the property being retrieved.
  625. *
  626. * @parm LPDIPROPHEADER | pdiph |
  627. *
  628. * Structure to receive property value.
  629. *
  630. * @returns
  631. *
  632. * <c E_NOTIMPL> nothing happened. The caller will do
  633. * the default thing in response to <c E_NOTIMPL>.
  634. *
  635. *****************************************************************************/
  636. STDMETHODIMP
  637. CMouse_GetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph)
  638. {
  639. HRESULT hres;
  640. PDM this;
  641. EnterProcI(IDirectInputDeviceCallback::Mouse::GetProperty,
  642. (_ "pxxp", pdcb, ppropi->pguid, ppropi->iobj, pdiph));
  643. /*
  644. * This is an internal interface, so we can skimp on validation.
  645. */
  646. this = _thisPvNm(pdcb, dcb);
  647. /*
  648. * Granularity is only supported for wheels and then only if the value
  649. * could be determined (if not g_lWheelGranularity is zero).
  650. */
  651. if( ppropi->pguid == DIPROP_GRANULARITY &&
  652. ppropi->dwDevType == (DIDFT_RELAXIS | DIDFT_MAKEINSTANCE(2)) )
  653. {
  654. LPDIPROPDWORD pdipdw = (PV)pdiph;
  655. pdipdw->dwData = g_lWheelGranularity? (DWORD)g_lWheelGranularity : 120;
  656. hres = S_OK;
  657. } else {
  658. hres = E_NOTIMPL;
  659. }
  660. ExitOleProcR();
  661. return hres;
  662. }
  663. /*****************************************************************************
  664. *
  665. * @doc INTERNAL
  666. *
  667. * @method void | CMouse | GetCapabilities |
  668. *
  669. * Get mouse device capabilities.
  670. *
  671. * @parm LPDIDEVCAPS | pdc |
  672. *
  673. * Device capabilities structure to receive result.
  674. *
  675. * @returns
  676. * <c S_OK> on success.
  677. *
  678. *****************************************************************************/
  679. STDMETHODIMP
  680. CMouse_GetCapabilities(PDICB pdcb, LPDIDEVCAPS pdc)
  681. {
  682. HRESULT hres;
  683. PDM this;
  684. EnterProcI(IDirectInputDeviceCallback::Mouse::GetCapabilities,
  685. (_ "pp", pdcb, pdc));
  686. /*
  687. * This is an internal interface, so we can skimp on validation.
  688. */
  689. this = _thisPvNm(pdcb, dcb);
  690. pdc->dwDevType = MAKE_DIDEVICE_TYPE(DIDEVTYPE_MOUSE,
  691. DIDEVTYPEMOUSE_UNKNOWN);
  692. pdc->dwFlags = DIDC_ATTACHED;
  693. if (this->flEmulation) {
  694. pdc->dwFlags |= DIDC_ALIAS;
  695. }
  696. pdc->dwAxes = this->dwAxes;
  697. pdc->dwButtons = this->dwButtons;
  698. // Remove this assertion for 32650
  699. // AssertF(pdc->dwPOVs == 0);
  700. hres = S_OK;
  701. ExitOleProcR();
  702. return hres;
  703. }
  704. /*****************************************************************************
  705. *
  706. * @doc INTERNAL
  707. *
  708. * @method HRESULT | CMouse | GetDeviceState |
  709. *
  710. * Obtains the state of the mouse device.
  711. *
  712. * It is the caller's responsibility to have validated all the
  713. * parameters and ensure that the device has been acquired.
  714. *
  715. * @parm OUT LPVOID | lpvData |
  716. *
  717. * Mouse data in the preferred data format.
  718. *
  719. * @returns
  720. *
  721. * Returns a COM error code. The following error codes are
  722. * intended to be illustrative and not necessarily comprehensive.
  723. *
  724. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  725. *
  726. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  727. * <p lpmdr> parameter is not a valid pointer.
  728. *
  729. *****************************************************************************/
  730. STDMETHODIMP
  731. CMouse_GetDeviceState(PDICB pdcb, LPVOID pvData)
  732. {
  733. HRESULT hres;
  734. PDM this;
  735. EnterProcI(IDirectInputDeviceCallback::Mouse::GetDeviceState,
  736. (_ "pp", pdcb, pvData));
  737. /*
  738. * This is an internal interface, so we can skimp on validation.
  739. */
  740. this = _thisPvNm(pdcb, dcb);
  741. AssertF(this->pvi);
  742. AssertF(this->pdmsPhys);
  743. if (this->pvi->fl & VIFL_ACQUIRED) {
  744. CMouse_GetPhysicalPosition(this, pvData);
  745. hres = S_OK;
  746. } else {
  747. hres = DIERR_INPUTLOST;
  748. }
  749. ExitOleProcR();
  750. return hres;
  751. }
  752. /*****************************************************************************
  753. *
  754. * @doc INTERNAL
  755. *
  756. * @method HRESULT | CMouse | GetObjectInfo |
  757. *
  758. * Obtain the friendly name of an object, passwed by index
  759. * into the preferred data format.
  760. *
  761. * @parm IN LPCDIPROPINFO | ppropi |
  762. *
  763. * Information describing the object being accessed.
  764. *
  765. * @parm IN OUT LPDIDEVICEOBJECTINSTANCEW | pdidioiW |
  766. *
  767. * Structure to receive information. The
  768. * <e DIDEVICEOBJECTINSTANCE.guidType>,
  769. * <e DIDEVICEOBJECTINSTANCE.dwOfs>,
  770. * and
  771. * <e DIDEVICEOBJECTINSTANCE.dwType>
  772. * fields have already been filled in.
  773. *
  774. * @returns
  775. *
  776. * Returns a COM error code.
  777. *
  778. *****************************************************************************/
  779. STDMETHODIMP
  780. CMouse_GetObjectInfo(PDICB pdcb, LPCDIPROPINFO ppropi,
  781. LPDIDEVICEOBJECTINSTANCEW pdidoiW)
  782. {
  783. HRESULT hres;
  784. PDM this;
  785. EnterProcI(IDirectInputDeviceCallback::Mouse::GetObjectInfo,
  786. (_ "pxp", pdcb, ppropi->iobj, pdidoiW));
  787. /*
  788. * This is an internal interface, so we can skimp on validation.
  789. */
  790. this = _thisPvNm(pdcb, dcb);
  791. #ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
  792. AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEW(pdidoiW->dwSize));
  793. #endif
  794. if (ppropi->iobj < this->df.dwNumObjs) {
  795. AssertF(this->rgodf == this->df.rgodf);
  796. AssertF(ppropi->dwDevType == this->rgodf[ppropi->iobj].dwType);
  797. AssertF(DIDFT_GETTYPE(ppropi->dwDevType) == DIDFT_RELAXIS ||
  798. DIDFT_GETTYPE(ppropi->dwDevType) == DIDFT_PSHBUTTON);
  799. LoadStringW(g_hinst, IDS_MOUSEOBJECT +
  800. DIDFT_GETINSTANCE(ppropi->dwDevType),
  801. pdidoiW->tszName, cA(pdidoiW->tszName));
  802. /*
  803. * We do not support force feedback on mice, so
  804. * there are no FF flags to report.
  805. */
  806. hres = S_OK;
  807. } else {
  808. hres = E_INVALIDARG;
  809. }
  810. ExitOleProcR();
  811. return hres;
  812. }
  813. /*****************************************************************************
  814. *
  815. * @doc INTERNAL
  816. *
  817. * @method HRESULT | CMouse | SetCooperativeLevel |
  818. *
  819. * Notify the device of the cooperative level.
  820. *
  821. * @parm IN HWND | hwnd |
  822. *
  823. * The window handle.
  824. *
  825. * @parm IN DWORD | dwFlags |
  826. *
  827. * The cooperativity level.
  828. *
  829. * @returns
  830. *
  831. * Returns a COM error code.
  832. *
  833. *****************************************************************************/
  834. STDMETHODIMP
  835. CMouse_SetCooperativeLevel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
  836. {
  837. HRESULT hres;
  838. PDM this;
  839. EnterProcI(IDirectInputDeviceCallback::Mouse::SetCooperativityLevel,
  840. (_ "pxx", pdcb, hwnd, dwFlags));
  841. /*
  842. * This is an internal interface, so we can skimp on validation.
  843. */
  844. this = _thisPvNm(pdcb, dcb);
  845. AssertF(this->pvi);
  846. #ifdef USE_SLOW_LL_HOOKS
  847. AssertF(DIGETEMFL(this->pvi->fl) == 0 ||
  848. DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE ||
  849. DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE2);
  850. #else
  851. AssertF(DIGETEMFL(this->pvi->fl) == 0 ||
  852. DIGETEMFL(this->pvi->fl) == DIEMFL_MOUSE2);
  853. #endif
  854. /*
  855. * Even though we can do it, we don't let the app
  856. * get background exclusive access. As with the keyboard,
  857. * there is nothing that technically prevents us from
  858. * supporting it; we just don't feel like it because it's
  859. * too dangerous.
  860. */
  861. /*
  862. * VxD and LL (emulation 1) behave the same, so we check
  863. * if it's "not emulation 2".
  864. */
  865. if (!(this->pvi->fl & DIMAKEEMFL(DIEMFL_MOUSE2))) {
  866. if (dwFlags & DISCL_EXCLUSIVE) {
  867. if (dwFlags & DISCL_FOREGROUND) {
  868. #ifdef WANT_TO_FIX_MANBUG43879
  869. this->pvi->fl |= VIFL_FOREGROUND;
  870. #endif
  871. this->pvi->fl |= VIFL_CAPTURED;
  872. hres = S_OK;
  873. } else { /* Disallow exclusive background */
  874. SquirtSqflPtszV(sqfl | sqflError,
  875. TEXT("Exclusive background mouse access disallowed"));
  876. hres = E_NOTIMPL;
  877. }
  878. } else {
  879. #ifdef WANT_TO_FIX_MANBUG43879
  880. if (dwFlags & DISCL_FOREGROUND) {
  881. this->pvi->fl |= VIFL_FOREGROUND;
  882. }
  883. #endif
  884. this->pvi->fl &= ~VIFL_CAPTURED;
  885. hres = S_OK;
  886. }
  887. } else {
  888. /*
  889. * Emulation 2 supports only exclusive foreground.
  890. */
  891. if ((dwFlags & (DISCL_EXCLUSIVE | DISCL_FOREGROUND)) ==
  892. (DISCL_EXCLUSIVE | DISCL_FOREGROUND)) {
  893. #ifdef WANT_TO_FIX_MANBUG43879
  894. this->pvi->fl |= VIFL_FOREGROUND;
  895. #endif
  896. this->pvi->fl |= VIFL_CAPTURED;
  897. hres = S_OK;
  898. } else {
  899. SquirtSqflPtszV(sqfl | sqflError,
  900. TEXT("Mouse access must be exclusive foreground in Emulation 2."));
  901. hres = E_NOTIMPL;
  902. }
  903. }
  904. if (SUCCEEDED(hres)) {
  905. this->hwndCapture = hwnd;
  906. }
  907. ExitOleProcR();
  908. return hres;
  909. }
  910. /*****************************************************************************
  911. *
  912. * @doc INTERNAL
  913. *
  914. * @method HRESULT | CMouse | RunControlPanel |
  915. *
  916. * Run the mouse control panel.
  917. *
  918. * @parm IN HWND | hwndOwner |
  919. *
  920. * The owner window.
  921. *
  922. * @parm DWORD | dwFlags |
  923. *
  924. * Flags.
  925. *
  926. *****************************************************************************/
  927. #pragma BEGIN_CONST_DATA
  928. TCHAR c_tszMouse[] = TEXT("mouse");
  929. #pragma END_CONST_DATA
  930. STDMETHODIMP
  931. CMouse_RunControlPanel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
  932. {
  933. HRESULT hres;
  934. EnterProcI(IDirectInputDeviceCallback::Mouse::RunControlPanel,
  935. (_ "pxx", pdcb, hwnd, dwFlags));
  936. hres = hresRunControlPanel(c_tszMouse);
  937. ExitOleProcR();
  938. return hres;
  939. }
  940. /*****************************************************************************
  941. *
  942. * @doc INTERNAL
  943. *
  944. * @method UINT | CMouse | NumAxes |
  945. *
  946. * Determine the number of mouse axes.
  947. *
  948. * On Windows NT, we can use the new <c SM_MOUSEWHEELPRESENT>
  949. * system metric. On Windows 95, we have to hunt for the
  950. * Magellan window (using the mechanism documented in the
  951. * Magellan SDK).
  952. *
  953. *****************************************************************************/
  954. #pragma BEGIN_CONST_DATA
  955. TCHAR c_tszMouseZClass[] = TEXT("MouseZ");
  956. TCHAR c_tszMouseZTitle[] = TEXT("Magellan MSWHEEL");
  957. TCHAR c_tszMouseZActive[] = TEXT("MSH_WHEELSUPPORT_MSG");
  958. #pragma END_CONST_DATA
  959. BOOL INLINE
  960. CMouse_IsMagellanWheel(void)
  961. {
  962. if( fWinnt )
  963. return FALSE;
  964. else {
  965. HWND hwnd = FindWindow(c_tszMouseZClass, c_tszMouseZTitle);
  966. return hwnd && SendMessage(hwnd, RegisterWindowMessage(c_tszMouseZActive), 0, 0);
  967. }
  968. }
  969. #ifndef SM_MOUSEWHEELPRESENT
  970. #define SM_MOUSEWHEELPRESENT 75
  971. #endif
  972. UINT INLINE
  973. CMouse_NumAxes(void)
  974. {
  975. UINT dwAxes;
  976. if (GetSystemMetrics(SM_MOUSEWHEELPRESENT) || CMouse_IsMagellanWheel()) {
  977. dwAxes = 3;
  978. } else {
  979. dwAxes = 2;
  980. }
  981. if (dwAxes == 2) {
  982. //Should avoid rebuilding too frequently.
  983. DIHid_BuildHidList(FALSE);
  984. DllEnterCrit();
  985. if (g_phdl) {
  986. int ihdi;
  987. for (ihdi = 0; ihdi < g_phdl->chdi; ihdi++) {
  988. if (dwAxes < g_phdl->rghdi[ihdi].osd.uiAxes) {
  989. dwAxes = g_phdl->rghdi[ihdi].osd.uiAxes;
  990. }
  991. }
  992. }
  993. DllLeaveCrit();
  994. }
  995. return dwAxes;
  996. }
  997. UINT INLINE
  998. CMouse_NumButtons(DWORD dwAxes)
  999. {
  1000. UINT dwButtons;
  1001. dwButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
  1002. #ifndef WINNT
  1003. #ifdef HID_SUPPORT
  1004. {
  1005. /*
  1006. * ISSUE-2001/03/29-timgill Should try to avoid rebuilding Hid List too frequently.
  1007. */
  1008. DIHid_BuildHidList(FALSE);
  1009. DllEnterCrit();
  1010. if (g_phdl) {
  1011. int ihdi;
  1012. for (ihdi = 0; ihdi < g_phdl->chdi; ihdi++) {
  1013. if (dwButtons < g_phdl->rghdi[ihdi].osd.uiButtons) {
  1014. dwButtons = g_phdl->rghdi[ihdi].osd.uiButtons;
  1015. }
  1016. }
  1017. }
  1018. DllLeaveCrit();
  1019. }
  1020. #endif
  1021. #endif
  1022. #if (DIRECTINPUT_VERSION >= 0x0700)
  1023. if( dwButtons >= 8 ) {
  1024. dwButtons = 8;
  1025. #else
  1026. if( dwButtons >= 4 ) {
  1027. dwButtons = 4;
  1028. #endif
  1029. }
  1030. else if (dwAxes == 3 && dwButtons < 3) {
  1031. /*
  1032. * HACK FOR MAGELLAN!
  1033. *
  1034. * They return 2 from GetSystemMetrics(SM_CMOUSEBUTTONS).
  1035. * So if we see a Z-axis, then assume that
  1036. * there is also a third button.
  1037. */
  1038. dwButtons = 3;
  1039. }
  1040. return dwButtons;
  1041. }
  1042. /*****************************************************************************
  1043. *
  1044. * @doc INTERNAL
  1045. *
  1046. * @method void | CMouse | AddObjects |
  1047. *
  1048. * Add a number of objects to the device format.
  1049. *
  1050. * @parm LPCDIOBJECTDATAFORMAT | rgodf |
  1051. *
  1052. * Array of objects to be added.
  1053. *
  1054. * @parm UINT | cObj |
  1055. *
  1056. * Number of objects to add.
  1057. *
  1058. *****************************************************************************/
  1059. void INTERNAL
  1060. CMouse_AddObjects(PDM this, LPCDIOBJECTDATAFORMAT rgodf, UINT cObj)
  1061. {
  1062. UINT iodf;
  1063. EnterProc(CMouse_AddObjects, (_ "pxx", this, rgodf, cObj));
  1064. for (iodf = 0; iodf < cObj; iodf++) {
  1065. this->rgodf[this->df.dwNumObjs++] = rgodf[iodf];
  1066. }
  1067. AssertF(this->df.dwNumObjs <= cA(this->rgodf));
  1068. }
  1069. /*****************************************************************************
  1070. *
  1071. * @doc INTERNAL
  1072. *
  1073. * @method void | CMouse | Init |
  1074. *
  1075. * Initialize the object by establishing the data format
  1076. * based on the mouse type.
  1077. *
  1078. * Code for detecting the IntelliMouse (formerly known as
  1079. * Magellan) pointing device is swiped from zmouse.h.
  1080. *
  1081. * @parm REFGUID | rguid |
  1082. *
  1083. * The instance GUID we are being asked to create.
  1084. *
  1085. *****************************************************************************/
  1086. HRESULT INTERNAL
  1087. CMouse_Init(PDM this, REFGUID rguid)
  1088. {
  1089. HRESULT hres;
  1090. VXDDEVICEFORMAT devf;
  1091. EnterProc(CMouse_Init, (_ "pG", this, rguid));
  1092. this->df.dwSize = cbX(DIDATAFORMAT);
  1093. this->df.dwObjSize = cbX(DIOBJECTDATAFORMAT);
  1094. this->df.dwDataSize = cbX(DIMOUSESTATE_INT);
  1095. this->df.rgodf = this->rgodf;
  1096. AssertF(this->df.dwFlags == 0);
  1097. AssertF(this->df.dwNumObjs == 0);
  1098. /*
  1099. * Need to know early if we have a Z-axis, so we can disable
  1100. * the Z-wheel if it doesn't exist.
  1101. *
  1102. * Note that this disabling needs to be done only on Win95.
  1103. * Win98 and NT4 have native Z-axis support, so there is
  1104. * nothing bogus that needs to be hacked.
  1105. */
  1106. this->dwAxes = CMouse_NumAxes();
  1107. devf.dwExtra = this->dwAxes;
  1108. if (this->dwAxes < 3) {
  1109. DWORD dwVer = GetVersion();
  1110. if ((LONG)dwVer >= 0 ||
  1111. MAKEWORD(HIBYTE(LOWORD(dwVer)), LOBYTE(dwVer)) >= 0x040A) {
  1112. devf.dwExtra = 3;
  1113. }
  1114. }
  1115. CMouse_AddObjects(this, c_podfMouseAxes, this->dwAxes);
  1116. /*
  1117. * Create the object with the most optimistic data format.
  1118. * This is important, because DINPUT.VXD builds the
  1119. * data format only once, and we need to protect ourselves against
  1120. * the user going into Control Panel and enabling the Z-Wheel
  1121. * after DINPUT.VXD has already initialized.
  1122. */
  1123. devf.cbData = cbX(DIMOUSESTATE_INT);
  1124. devf.cObj = cA(c_rgodfMouse);
  1125. devf.rgodf = c_rgodfMouse;
  1126. /*
  1127. * But first a word from our other sponsor: Figure out the
  1128. * emulation flags based on the GUID.
  1129. */
  1130. AssertF(GUID_SysMouse .Data1 == 0x6F1D2B60);
  1131. AssertF(GUID_SysMouseEm .Data1 == 0x6F1D2B80);
  1132. AssertF(GUID_SysMouseEm2.Data1 == 0x6F1D2B81);
  1133. switch (rguid->Data1) {
  1134. default:
  1135. case 0x6F1D2B60:
  1136. AssertF(IsEqualGUID(rguid, &GUID_SysMouse));
  1137. AssertF(this->flEmulation == 0);
  1138. break;
  1139. case 0x6F1D2B80:
  1140. AssertF(IsEqualGUID(rguid, &GUID_SysMouseEm));
  1141. this->flEmulation = DIEMFL_MOUSE;
  1142. break;
  1143. case 0x6F1D2B81:
  1144. AssertF(IsEqualGUID(rguid, &GUID_SysMouseEm2));
  1145. this->flEmulation = DIEMFL_MOUSE2;
  1146. break;
  1147. }
  1148. devf.dwEmulation = this->flEmulation;
  1149. hres = Hel_Mouse_CreateInstance(&devf, &this->pvi);
  1150. if (SUCCEEDED(hres)) {
  1151. AssertF(this->pvi);
  1152. this->pdmsPhys = this->pvi->pState;
  1153. this->dwButtons = CMouse_NumButtons( this->dwAxes );
  1154. CMouse_AddObjects(this, c_podfMouseButtons, this->dwButtons);
  1155. hres = S_OK;
  1156. } else {
  1157. SquirtSqflPtszV(sqfl | sqflError,
  1158. TEXT("Mismatched version of dinput.vxd"));
  1159. hres = E_FAIL;
  1160. }
  1161. ExitOleProc();
  1162. return hres;
  1163. }
  1164. /*****************************************************************************
  1165. *
  1166. * CMouse_New (constructor)
  1167. *
  1168. * Fail the create if the machine has no mouse.
  1169. *
  1170. *****************************************************************************/
  1171. STDMETHODIMP
  1172. CMouse_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvObj)
  1173. {
  1174. HRESULT hres;
  1175. EnterProcI(IDirectInputDeviceCallback::Mouse::<constructor>,
  1176. (_ "Gp", riid, ppvObj));
  1177. AssertF(IsEqualGUID(rguid, &GUID_SysMouse) ||
  1178. IsEqualGUID(rguid, &GUID_SysMouseEm) ||
  1179. IsEqualGUID(rguid, &GUID_SysMouseEm2));
  1180. if (GetSystemMetrics(SM_MOUSEPRESENT)) {
  1181. hres = Common_NewRiid(CMouse, punkOuter, riid, ppvObj);
  1182. if (SUCCEEDED(hres)) {
  1183. /* Must use _thisPv in case of aggregation */
  1184. PDM this = _thisPv(*ppvObj);
  1185. if (SUCCEEDED(hres = CMouse_Init(this, rguid))) {
  1186. } else {
  1187. Invoke_Release(ppvObj);
  1188. }
  1189. }
  1190. } else {
  1191. RPF("Warning: System does not have a mouse");
  1192. /*
  1193. * Since we by-passed the parameter checks and we failed to create
  1194. * the new interface, try to zero the pointer now.
  1195. */
  1196. if (!IsBadWritePtr(ppvObj, sizeof(UINT_PTR) ))
  1197. {
  1198. *(PUINT_PTR)ppvObj = 0;
  1199. }
  1200. hres = DIERR_DEVICENOTREG;
  1201. }
  1202. ExitOleProcPpvR(ppvObj);
  1203. return hres;
  1204. }
  1205. /*****************************************************************************
  1206. *
  1207. * The long-awaited vtbls and templates
  1208. *
  1209. *****************************************************************************/
  1210. #pragma BEGIN_CONST_DATA
  1211. #define CMouse_Signature 0x53554F4D /* "MOUS" */
  1212. Primary_Interface_Begin(CMouse, IDirectInputDeviceCallback)
  1213. CMouse_GetInstance,
  1214. CDefDcb_GetVersions,
  1215. CMouse_GetDataFormat,
  1216. CMouse_GetObjectInfo,
  1217. CMouse_GetCapabilities,
  1218. CMouse_Acquire,
  1219. CMouse_Unacquire,
  1220. CMouse_GetDeviceState,
  1221. CMouse_GetDeviceInfo,
  1222. CMouse_GetProperty,
  1223. CDefDcb_SetProperty,
  1224. CDefDcb_SetEventNotification,
  1225. CMouse_SetCooperativeLevel,
  1226. CMouse_RunControlPanel,
  1227. CDefDcb_CookDeviceData,
  1228. CDefDcb_CreateEffect,
  1229. CDefDcb_GetFFConfigKey,
  1230. CDefDcb_SendDeviceData,
  1231. CDefDcb_Poll,
  1232. CDefDcb_GetUsage,
  1233. CDefDcb_MapUsage,
  1234. CDefDcb_SetDIData,
  1235. Primary_Interface_End(CMouse, IDirectInputDeviceCallback)