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.

666 lines
17 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHel.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Hardware emulation layer for DirectInput.
  10. *
  11. * Contents:
  12. *
  13. * Hel_AcquireInstance
  14. * Hel_UnacquireInstance
  15. * Hel_SetBufferSize
  16. * Hel_DestroyInstance
  17. *
  18. * Hel_SetDataFormat
  19. * Hel_SetNotifyHandle
  20. *
  21. * Hel_Mouse_CreateInstance
  22. * Hel_Kbd_CreateInstance
  23. * Hel_Kbd_InitKeys
  24. * Hel_Joy_CreateInstance
  25. * Hel_Joy_Ping
  26. * Hel_Joy_GetInitParms
  27. *
  28. * IoctlHw
  29. *
  30. *****************************************************************************/
  31. #include "dinputpr.h"
  32. /*****************************************************************************
  33. *
  34. * The sqiffle for this file.
  35. *
  36. *****************************************************************************/
  37. #define sqfl sqflHel
  38. /*****************************************************************************
  39. *
  40. * @doc INTERNAL
  41. *
  42. * @func HRESULT | IoctlHw |
  43. *
  44. * Send the IOCtl to the hardware device.
  45. *
  46. * @parm DWORD | ioctl |
  47. *
  48. * I/O control code.
  49. *
  50. * @parm IN LPVOID | pvIn |
  51. *
  52. * Optional input parameter.
  53. *
  54. * @parm DWORD | cbIn |
  55. *
  56. * Size of input buffer in bytes.
  57. *
  58. * @parm IN LPVOID | pvOut |
  59. *
  60. * Optional output parameter.
  61. *
  62. * @parm DWORD | cbOut |
  63. *
  64. * Size of output buffer in bytes.
  65. *
  66. * @returns
  67. *
  68. * <c S_OK> if the ioctl succeeded and returned the correct
  69. * number of bytes, else something based on the Win32 error code.
  70. *
  71. *****************************************************************************/
  72. #ifndef WINNT
  73. HRESULT EXTERNAL
  74. IoctlHw(DWORD ioctl, LPVOID pvIn, DWORD cbIn, LPVOID pvOut, DWORD cbOut)
  75. {
  76. HRESULT hres;
  77. DWORD cbRc;
  78. if (g_hVxD != INVALID_HANDLE_VALUE) {
  79. if (DeviceIoControl(g_hVxD, ioctl, pvIn, cbIn,
  80. pvOut, cbOut, &cbRc, 0)) {
  81. if (cbRc == cbOut) {
  82. hres = S_OK;
  83. } else {
  84. SquirtSqflPtszV(sqfl, TEXT("Ioctl(%08x) returned wrong cbOut"),
  85. ioctl);
  86. hres = DIERR_BADDRIVERVER;
  87. }
  88. } else {
  89. SquirtSqflPtszV(sqfl | sqflError,
  90. TEXT("Ioctl(%08x) failed, error %d"),
  91. ioctl, GetLastError());
  92. hres = hresLe(GetLastError());
  93. }
  94. } else {
  95. hres = DIERR_BADDRIVERVER;
  96. }
  97. return hres;
  98. }
  99. #endif
  100. /*****************************************************************************
  101. *
  102. * @doc INTERNAL
  103. *
  104. * @func HRESULT | Hel_IoctlChoose |
  105. *
  106. * Send the IOCtl to the hardware device if it is native,
  107. * or perform the operation through emulation if it is emulated.
  108. *
  109. * @parm PVXDINSTANCE | pvi |
  110. *
  111. * The device in question.
  112. *
  113. * @parm PFNHANDLER | pfn |
  114. *
  115. * The emulation function to call to carry out the operation.
  116. *
  117. * @parm DWORD | ioctl |
  118. *
  119. * I/O control code.
  120. *
  121. * @parm IN LPVOID | pvIn |
  122. *
  123. * Optional input parameter.
  124. *
  125. * @parm DWORD | cbIn |
  126. *
  127. * Size of input buffer in bytes.
  128. *
  129. *****************************************************************************/
  130. typedef HRESULT (EXTERNAL *PFNHANDLER)(PV pv);
  131. HRESULT INTERNAL
  132. Hel_IoctlChoose(PVXDINSTANCE pvi, PFNHANDLER pfn,
  133. DWORD ioctl, LPVOID pvIn, DWORD cbIn)
  134. {
  135. HRESULT hres;
  136. if (!(pvi->fl & VIFL_EMULATED)) {
  137. hres = IoctlHw(ioctl, pvIn, cbIn, 0, 0);
  138. } else {
  139. hres = pfn(pvIn);
  140. }
  141. return hres;
  142. }
  143. /*****************************************************************************
  144. *
  145. * @doc INTERNAL
  146. *
  147. * @func HRESULT | Hel_AcquireInstance |
  148. *
  149. * Attempt to acquire the device instance, using either the
  150. * device driver or emulation, whichever is appropriate.
  151. *
  152. * @parm PVXDINSTANCE | pvi |
  153. *
  154. * The instance to acquire.
  155. *
  156. *****************************************************************************/
  157. HRESULT EXTERNAL
  158. Hel_AcquireInstance(PVXDINSTANCE pvi)
  159. {
  160. return Hel_IoctlChoose(pvi, CEm_AcquireInstance,
  161. IOCTL_ACQUIREINSTANCE, &pvi, cbX(pvi));
  162. }
  163. /*****************************************************************************
  164. *
  165. * @doc INTERNAL
  166. *
  167. * @func HRESULT | Hel_UnacquireInstance |
  168. *
  169. * Attempt to unacquire the device instance.
  170. *
  171. * @parm PVXDINSTANCE | pvi |
  172. *
  173. * The instance to unacquire.
  174. *
  175. *****************************************************************************/
  176. HRESULT EXTERNAL
  177. Hel_UnacquireInstance(PVXDINSTANCE pvi)
  178. {
  179. return Hel_IoctlChoose(pvi, CEm_UnacquireInstance,
  180. IOCTL_UNACQUIREINSTANCE, &pvi, cbX(pvi));
  181. }
  182. /*****************************************************************************
  183. *
  184. * @doc INTERNAL
  185. *
  186. * @func HRESULT | Hel_DestroyInstance |
  187. *
  188. * Destroy the device instance in the appropriate way.
  189. *
  190. * @parm PVXDINSTANCE | pvi |
  191. *
  192. * The instance.
  193. *
  194. *****************************************************************************/
  195. HRESULT EXTERNAL
  196. Hel_DestroyInstance(PVXDINSTANCE pvi)
  197. {
  198. return Hel_IoctlChoose(pvi, CEm_DestroyInstance,
  199. IOCTL_DESTROYINSTANCE, &pvi, cbX(pvi));
  200. }
  201. /*****************************************************************************
  202. *
  203. * @doc INTERNAL
  204. *
  205. * @func HRESULT | Hel_SetDataFormat |
  206. *
  207. * Set the data format.
  208. *
  209. * @parm PVXDDATAFORMAT | pvdf |
  210. *
  211. * Information about the data format.
  212. *
  213. *****************************************************************************/
  214. HRESULT EXTERNAL
  215. Hel_SetDataFormat(PVXDDATAFORMAT pvdf)
  216. {
  217. return Hel_IoctlChoose(pvdf->pvi, CEm_SetDataFormat,
  218. IOCTL_SETDATAFORMAT, pvdf, cbX(*pvdf));
  219. }
  220. /*****************************************************************************
  221. *
  222. * @doc INTERNAL
  223. *
  224. * @func HRESULT | Hel_SetNotifyHandle |
  225. *
  226. * Set the data format.
  227. *
  228. * @parm PVXDDWORDDATA | pvdd |
  229. *
  230. * Information about the data format.
  231. *
  232. *****************************************************************************/
  233. HRESULT EXTERNAL
  234. Hel_SetNotifyHandle(PVXDDWORDDATA pvdd)
  235. {
  236. HRESULT hres = S_OK;
  237. #ifndef WINNT
  238. if (!(pvdd->pvi->fl & VIFL_EMULATED)) {
  239. AssertF(_OpenVxDHandle);
  240. if (pvdd->dw) {
  241. pvdd->dw = _OpenVxDHandle((HANDLE)pvdd->dw);
  242. }
  243. hres = IoctlHw(IOCTL_SETNOTIFYHANDLE, pvdd, cbX(*pvdd), 0, 0);
  244. }
  245. #endif
  246. return hres;
  247. }
  248. /*****************************************************************************
  249. *
  250. * @doc INTERNAL
  251. *
  252. * @func HRESULT | Hel_SetBufferSize |
  253. *
  254. * Set the buffer size.
  255. *
  256. * @parm PVXDDWORDDATA | pvdd |
  257. *
  258. * Information about the buffer size.
  259. *
  260. *****************************************************************************/
  261. HRESULT EXTERNAL
  262. Hel_SetBufferSize(PVXDDWORDDATA pvdd)
  263. {
  264. HRESULT hres;
  265. EnterProc(Hel_SetBufferSize, (_ "pxx", pvdd->pvi, pvdd->dw, pvdd->pvi->fl));
  266. hres = Hel_IoctlChoose(pvdd->pvi, CEm_SetBufferSize,
  267. IOCTL_SETBUFFERSIZE, pvdd, cbX(*pvdd));
  268. ExitOleProc();
  269. return hres;
  270. }
  271. /*****************************************************************************
  272. *
  273. * @doc INTERNAL
  274. *
  275. * @struct CREATEDEVICEINFO |
  276. *
  277. * Describes how to create the device either via the driver or
  278. * via emulation.
  279. *
  280. * @parm DWORD | dwIoctl |
  281. *
  282. * IOCtl code to try.
  283. *
  284. * @parm DWORD | flEmulation |
  285. *
  286. * Flag in registry that forces emulation.
  287. *
  288. * @parm EMULATIONCREATEPROC | pfnCreate |
  289. *
  290. * Function that creates emulation object.
  291. *
  292. *****************************************************************************/
  293. #pragma BEGIN_CONST_DATA
  294. typedef HRESULT (EXTERNAL *EMULATIONCREATEPROC)
  295. (PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut);
  296. typedef struct CREATEDEVICEINFO {
  297. DWORD dwIoctl;
  298. DWORD flEmulation;
  299. EMULATIONCREATEPROC pfnCreate;
  300. } CREATEDEVICEINFO, *PCREATEDEVICEINFO;
  301. CREATEDEVICEINFO c_cdiMouse = {
  302. IOCTL_MOUSE_CREATEINSTANCE,
  303. DIEMFL_MOUSE,
  304. CEm_Mouse_CreateInstance,
  305. };
  306. CREATEDEVICEINFO c_cdiKbd = {
  307. IOCTL_KBD_CREATEINSTANCE,
  308. DIEMFL_KBD | DIEMFL_KBD2,
  309. CEm_Kbd_CreateInstance,
  310. };
  311. CREATEDEVICEINFO c_cdiJoy = {
  312. IOCTL_JOY_CREATEINSTANCE,
  313. DIEMFL_JOYSTICK,
  314. CEm_Joy_CreateInstance,
  315. };
  316. #pragma END_CONST_DATA
  317. /*****************************************************************************
  318. *
  319. * @doc INTERNAL
  320. *
  321. * @func HRESULT | Hel_CreateInstance |
  322. *
  323. * Attempt to create the device instance through the driver
  324. * with the specified IOCtl.
  325. *
  326. * If that is not possible, then use the emulation callback.
  327. *
  328. * @parm PCREATEDEVICEINFO | pcdi |
  329. *
  330. * Describes how to create the device.
  331. *
  332. * @parm PVXDDEVICEFORMAT | pdevf |
  333. *
  334. * Describes the device being created.
  335. *
  336. * @parm PVXDINSTANCE * | ppviOut |
  337. *
  338. * Receives created instance.
  339. *
  340. *****************************************************************************/
  341. HRESULT EXTERNAL
  342. Hel_CreateInstance(PCREATEDEVICEINFO pcdi,
  343. PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  344. {
  345. HRESULT hres;
  346. pdevf->dwEmulation |= g_flEmulation;
  347. pdevf->dwEmulation &= pcdi->flEmulation;
  348. if (pdevf->dwEmulation ||
  349. (FAILED(hres = IoctlHw(pcdi->dwIoctl, pdevf, cbX(*pdevf),
  350. ppviOut, cbX(*ppviOut))))) {
  351. hres = pcdi->pfnCreate(pdevf, ppviOut);
  352. }
  353. return hres;
  354. }
  355. /*****************************************************************************
  356. *
  357. * @doc INTERNAL
  358. *
  359. * @func HRESULT | Hel_Mouse_CreateInstance |
  360. *
  361. * Attempt to create the device instance through the driver.
  362. * If that is not possible, then use the emulation layer.
  363. *
  364. * @parm PVXDDEVICEFORMAT | pdevf |
  365. *
  366. * Describes the device being created.
  367. *
  368. * @parm PVXDINSTANCE * | ppviOut |
  369. *
  370. * Receives created instance.
  371. *
  372. *****************************************************************************/
  373. HRESULT EXTERNAL
  374. Hel_Mouse_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  375. {
  376. return Hel_CreateInstance(&c_cdiMouse, pdevf, ppviOut);
  377. }
  378. /*****************************************************************************
  379. *
  380. * @doc INTERNAL
  381. *
  382. * @func HRESULT | Hel_Kbd_CreateInstance |
  383. *
  384. * Attempt to create the device instance through the driver.
  385. * If that is not possible, then use the emulation layer.
  386. *
  387. * @parm PVXDDEVICEFORMAT | pdevf |
  388. *
  389. * Describes the device being created.
  390. *
  391. * @parm PVXDINSTANCE * | ppviOut |
  392. *
  393. * Receives created instance.
  394. *
  395. *****************************************************************************/
  396. HRESULT EXTERNAL
  397. Hel_Kbd_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  398. {
  399. return Hel_CreateInstance(&c_cdiKbd, pdevf, ppviOut);
  400. }
  401. /*****************************************************************************
  402. *
  403. * @doc INTERNAL
  404. *
  405. * @func HRESULT | Hel_Kbd_InitKeys |
  406. *
  407. * Tell the device driver (or emulation) about the key state.
  408. *
  409. * @parm PVXDDWORDDATA | pvdd |
  410. *
  411. * The instance and the key state.
  412. *
  413. *****************************************************************************/
  414. HRESULT EXTERNAL
  415. Hel_Kbd_InitKeys(PVXDDWORDDATA pvdd)
  416. {
  417. return Hel_IoctlChoose(pvdd->pvi, CEm_Kbd_InitKeys,
  418. IOCTL_KBD_INITKEYS, pvdd, cbX(*pvdd));
  419. }
  420. /*****************************************************************************
  421. *
  422. * @doc INTERNAL
  423. *
  424. * @func HRESULT | Hel_Joy_CreateInstance |
  425. *
  426. * Attempt to create the device instance through the driver.
  427. * If that is not possible, then use the emulation layer.
  428. *
  429. * @parm PVXDDEVICEFORMAT | pdevf |
  430. *
  431. * Describes the device being created.
  432. *
  433. * @parm PVXDINSTANCE * | ppviOut |
  434. *
  435. * Receives created instance.
  436. *
  437. *****************************************************************************/
  438. HRESULT EXTERNAL
  439. Hel_Joy_CreateInstance(PVXDDEVICEFORMAT pdevf, PVXDINSTANCE *ppviOut)
  440. {
  441. return Hel_CreateInstance(&c_cdiJoy, pdevf, ppviOut);
  442. }
  443. /*****************************************************************************
  444. *
  445. * @doc INTERNAL
  446. *
  447. * @func HRESULT | Hel_Joy_Ping |
  448. *
  449. * Ask the device driver (or emulation) to get the joystick info.
  450. * If the poll fails, the device will be forced unacquired.
  451. *
  452. * @parm PVXDDWORDDATA | pvdd |
  453. *
  454. * The instance and the key state.
  455. *
  456. *****************************************************************************/
  457. HRESULT EXTERNAL
  458. Hel_Joy_Ping(PVXDINSTANCE pvi)
  459. {
  460. return Hel_IoctlChoose(pvi, CEm_Joy_Ping,
  461. IOCTL_JOY_PING, &pvi, cbX(pvi));
  462. }
  463. /*****************************************************************************
  464. *
  465. * @doc INTERNAL
  466. *
  467. * @func HRESULT | Hel_Joy_Ping8 |
  468. *
  469. * Ask the device driver (or emulation) to get the joystick info.
  470. * If the poll fails, the device will NOT be forced unacquired.
  471. *
  472. * @parm PVXDDWORDDATA | pvdd |
  473. *
  474. * The instance and the key state.
  475. *
  476. *****************************************************************************/
  477. HRESULT EXTERNAL
  478. Hel_Joy_Ping8(PVXDINSTANCE pvi)
  479. {
  480. return Hel_IoctlChoose(pvi, CEm_Joy_Ping,
  481. IOCTL_JOY_PING8, &pvi, cbX(pvi));
  482. }
  483. #ifdef IDirectInputDevice2Vtbl
  484. /*****************************************************************************
  485. *
  486. * @doc INTERNAL
  487. *
  488. * @func HRESULT | Hel_Joy_GetInitParms |
  489. *
  490. * Ask the device driver (or emulation) for
  491. * VJOYD initialization parameters.
  492. *
  493. * In emulation, we assume the internal and external
  494. * IDs are equal (because they may as well be),
  495. * that no flags are set, and there are no versions.
  496. *
  497. * @parm DWORD | dwExternalID |
  498. *
  499. * The external joystick number.
  500. *
  501. * @parm PVXDINITPARMS | pvip |
  502. *
  503. * Receives assorted information.
  504. *
  505. *****************************************************************************/
  506. HRESULT EXTERNAL
  507. Hel_Joy_GetInitParms(DWORD dwExternalID, PVXDINITPARMS pvip)
  508. {
  509. HRESULT hres;
  510. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  511. FAILED(hres = IoctlHw(IOCTL_JOY_GETINITPARMS,
  512. &dwExternalID, cbX(dwExternalID),
  513. pvip, cbX(*pvip))) ||
  514. FAILED(hres = pvip->hres)) {
  515. /*
  516. * Do it the emulation way.
  517. */
  518. ZeroX(*pvip);
  519. pvip->dwId = dwExternalID;
  520. hres = S_OK;
  521. }
  522. return hres;
  523. }
  524. /*****************************************************************************
  525. *
  526. * @doc INTERNAL
  527. *
  528. * @func HRESULT | Hel_Joy_GetAxisCaps |
  529. *
  530. * Obtain a bitmask of the axes supported by the joystick.
  531. * If VJOYD won't tell us, then we figure it out from the
  532. * registry structure passed in.
  533. *
  534. * @parm DWORD | dwExternalID |
  535. *
  536. * The external joystick number.
  537. *
  538. * @parm PVXDAXISCAPS | pvac |
  539. *
  540. * Structure to receive the axis capabilities.
  541. *
  542. * @parm PJOYCAPS | pjc |
  543. *
  544. * The joystick capabilities as reported by the registry.
  545. *
  546. *****************************************************************************/
  547. HRESULT EXTERNAL
  548. Hel_Joy_GetAxisCaps(DWORD dwExternalID, PVXDAXISCAPS pvac, PJOYCAPS pjc)
  549. {
  550. HRESULT hres;
  551. if ((g_flEmulation & DIEMFL_JOYSTICK) ||
  552. FAILED(hres = IoctlHw(IOCTL_JOY_GETAXES,
  553. &dwExternalID, cbX(dwExternalID),
  554. pvac, cbX(*pvac)))) {
  555. /*
  556. * If that didn't work, then get the axis information
  557. * from the registry.
  558. */
  559. /*
  560. * Every joystick has an X and Y (no way to tell)
  561. */
  562. pvac->dwPos = JOYPF_X | JOYPF_Y;
  563. if (pjc->wCaps & JOYCAPS_HASZ) {
  564. pvac->dwPos |= JOYPF_Z;
  565. }
  566. if (pjc->wCaps & JOYCAPS_HASR) {
  567. pvac->dwPos |= JOYPF_R;
  568. }
  569. if (pjc->wCaps & JOYCAPS_HASU) {
  570. pvac->dwPos |= JOYPF_U;
  571. }
  572. if (pjc->wCaps & JOYCAPS_HASV) {
  573. pvac->dwPos |= JOYPF_V;
  574. }
  575. if (pjc->wCaps & JOYCAPS_HASPOV) {
  576. pvac->dwPos |= JOYPF_POV0;
  577. }
  578. /*
  579. * Old VJOYD clients do not support velocity or any of the
  580. * other stuff.
  581. */
  582. pvac->dwVel = 0;
  583. pvac->dwAccel = 0;
  584. pvac->dwForce = 0;
  585. hres = S_OK;
  586. }
  587. /*
  588. * CJoy_InitRing3 assumes that this never fails.
  589. */
  590. AssertF(SUCCEEDED(hres));
  591. return hres;
  592. }
  593. #endif