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.

480 lines
18 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHid.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * WINNT implementation of JOYHID.
  10. *
  11. * Contents:
  12. *
  13. * DIWdm_JoyHidMapping
  14. * JoyReg_JoyIdToDeviceInterface
  15. *
  16. *****************************************************************************/
  17. #include "dinputpr.h"
  18. #undef sqfl
  19. #define sqfl sqflWDM
  20. #include "dijoyhid.h"
  21. /*****************************************************************************
  22. *
  23. * @doc INTERNAL
  24. *
  25. * @func HRESULT EXTERNAL | DIWdm_JoyHidMapping |
  26. *
  27. * Does the work done by JoyHid on Win9x. This function
  28. * maps the Joystick ID to a HID device and talks to the
  29. * HID device to obtain its capabilities.
  30. *
  31. * @parm IN int | idJoy |
  32. *
  33. * The Id of the joystick to be located.
  34. *
  35. * @parm OUT PVXDINITPARAMS | pvip | OPTIONAL
  36. * Address of a VXDINITPARAMS structure that is filled out
  37. * by this function. This is an optional parameter
  38. * and can be NULL
  39. *
  40. * @parm OUT LPDIJOYCONFIG | pcfg |
  41. * Address of a DIJOYCONFIG structure that is filled out
  42. * by this function. This is an optional parameter.
  43. *
  44. * @parm IN OUT LPDIJOYTYPEINFO | pdijti |
  45. * Address of a DIJOYTYPEINFO structure that is filled out
  46. * by this function. This is an optional parameter.
  47. * If passed in, the hws.dwFlags is used to initialize the
  48. * same flags in the DIJOYCONFIG structure.
  49. *
  50. * @returns HRESULT
  51. * Returns a COM error code
  52. *
  53. *****************************************************************************/
  54. /*
  55. * ISSUE-2001/03/29-timgill function uses too much stack space
  56. * This function uses over 4K of stack space!
  57. * This causes the Win9x build to choke looking for _chkstk.
  58. * Hack by forcing caller to pass pcfg and pdijti
  59. */
  60. HRESULT EXTERNAL
  61. DIWdm_JoyHidMapping
  62. (
  63. IN int idJoy,
  64. OUT PVXDINITPARMS pvip, OPTIONAL
  65. OUT LPDIJOYCONFIG pcfg, OPTIONAL
  66. IN OUT LPDIJOYTYPEINFO pdijti
  67. )
  68. {
  69. HRESULT hres;
  70. PHIDDEVICEINFO phdi;
  71. VXDINITPARMS vip;
  72. // DIJOYCONFIG cfg;
  73. // DIJOYTYPEINFO dijti;
  74. DWORD wCaps = 0;
  75. DIPROPINFO propi;
  76. DIPROPSTRING dips;
  77. DIPROPDWORD dipd;
  78. BOOL fBadCalData = FALSE;
  79. EnterProc(DIWdm_JoyHidMapping, (_ "uxx", idJoy, pvip, pcfg));
  80. // AssertF(InCrit());
  81. if( pvip == NULL )
  82. {
  83. ZeroX(vip);
  84. vip.dwSize = cbX(vip);
  85. pvip = &vip;
  86. }
  87. // AssertF(pcfg != NULL );
  88. // if( pcfg == NULL )
  89. // {
  90. // ZeroX(cfg);
  91. // cfg.dwSize = cbX(cfg);
  92. // pcfg = & cfg;
  93. // }
  94. AssertF(pdijti != NULL );
  95. // if(pdijti == NULL )
  96. // {
  97. // ZeroX(dijti);
  98. // dijti.dwSize = cbX(dijti);
  99. // pdijti = &dijti;
  100. // }
  101. /*
  102. * Copy the type info because JOY_HWS_ISYOKE, JOY_HWS_ISCARCTRL and
  103. * JOY_HWS_ISHEADTRACKER have no simple equivalents in HID so would
  104. * otherwise get lost. No harm done if it's zero.
  105. * Note, the dwFlags is built in pvip then copied elsewhere.
  106. */
  107. pvip->dwFlags = pdijti->hws.dwFlags;
  108. phdi = phdiFindJoyId(idJoy);
  109. if( phdi != NULL )
  110. {
  111. IDirectInputDeviceCallback *pdcb;
  112. hres = CHid_New(0, &phdi->guid,
  113. &IID_IDirectInputDeviceCallback,
  114. (PPV)&pdcb);
  115. if( SUCCEEDED(hres) )
  116. {
  117. DIDEVCAPS dc;
  118. hres = pdcb->lpVtbl->GetCapabilities(pdcb, &dc );
  119. if( SUCCEEDED(hres) )
  120. {
  121. DIDEVICEINSTANCEW didi;
  122. didi.dwSize = cbX(didi);
  123. hres = pdcb->lpVtbl->GetDeviceInfo(pdcb, &didi);
  124. if( SUCCEEDED(hres) )
  125. {
  126. LPDIDATAFORMAT pdf;
  127. hres = pdcb->lpVtbl->GetDataFormat(pdcb, &pdf);
  128. if( SUCCEEDED(hres) )
  129. {
  130. DIPROPCAL dipc;
  131. DWORD axis, pov = 0;
  132. ZeroBuf(pvip->Usages, 6 * cbX(pvip->Usages[0]));
  133. hres = pdcb->lpVtbl->MapUsage(pdcb, CheckHatswitch->dwUsage, &propi.iobj);
  134. if(SUCCEEDED(hres) )
  135. {
  136. pvip->dwPOV1usage = CheckHatswitch->dwUsage;
  137. pvip->dwFlags |= CheckHatswitch->dwFlags;
  138. wCaps |= CheckHatswitch->dwCaps;
  139. propi.pguid = DIPROP_GRANULARITY;
  140. propi.dwDevType = pdf->rgodf[propi.iobj].dwType;
  141. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipd.diph);
  142. if( SUCCEEDED( hres ) )
  143. {
  144. if( dipd.dwData >= 9000 ) // 4 directional POV
  145. {
  146. wCaps |= JOYCAPS_POV4DIR;
  147. if( pcfg != NULL ) {
  148. pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_FORWARD] = JOY_POVFORWARD;
  149. pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_BACKWARD] = JOY_POVBACKWARD;
  150. pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_LEFT] = JOY_POVLEFT;
  151. pcfg->hwc.hwv.dwPOVValues[JOY_POVVAL_RIGHT] = JOY_POVRIGHT;
  152. }
  153. } else // Continuous POV
  154. {
  155. wCaps |= JOYCAPS_POVCTS;
  156. }
  157. }
  158. }
  159. for( axis = 0; axis < cA(AxesUsages)-1; axis++ )
  160. {
  161. USAGES *pUse = &AxesUsages[axis];
  162. DWORD dwCurAxisPos = pUse->dwAxisPos;
  163. if( pvip->Usages[dwCurAxisPos] != 0) {
  164. continue;
  165. } else {
  166. int i;
  167. BOOL bHasUsed = FALSE;
  168. for( i = 0; i < (int)dwCurAxisPos; i++ ) {
  169. if( pvip->Usages[i] == pUse->dwUsage ) {
  170. bHasUsed = TRUE;
  171. break;
  172. }
  173. }
  174. if( bHasUsed ) {
  175. continue;
  176. }
  177. }
  178. hres = pdcb->lpVtbl->MapUsage(pdcb, pUse->dwUsage, &propi.iobj);
  179. if(SUCCEEDED(hres) )
  180. {
  181. pvip->Usages[dwCurAxisPos] = pUse->dwUsage;
  182. pvip->dwFlags |= pUse->dwFlags;
  183. wCaps |= pUse->dwCaps;
  184. propi.pguid = DIPROP_CALIBRATION;
  185. propi.dwDevType = pdf->rgodf[propi.iobj].dwType;
  186. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipc.diph);
  187. if( SUCCEEDED(hres) && pcfg != NULL )
  188. {
  189. #ifdef WINNT
  190. (&pcfg->hwc.hwv.jrvHardware.jpMin.dwX)[dwCurAxisPos]
  191. = dipc.lMin;
  192. (&pcfg->hwc.hwv.jrvHardware.jpMax.dwX)[dwCurAxisPos]
  193. = dipc.lMax;
  194. (&pcfg->hwc.hwv.jrvHardware.jpCenter.dwX)[dwCurAxisPos]
  195. = CCal_Midpoint(dipc.lMin, dipc.lMax);
  196. #else
  197. DIPROPRANGE diprp;
  198. DIPROPRANGE diprl;
  199. propi.pguid = DIPROP_PHYSICALRANGE;
  200. propi.dwDevType = pdf->rgodf[propi.iobj].dwType;
  201. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &diprp.diph);
  202. if( SUCCEEDED( hres ) )
  203. {
  204. propi.pguid = DIPROP_LOGICALRANGE;
  205. propi.dwDevType = pdf->rgodf[propi.iobj].dwType;
  206. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &diprl.diph);
  207. if( SUCCEEDED( hres ) )
  208. {
  209. LONG lMin, lMax;
  210. lMin = (&pcfg->hwc.hwv.jrvHardware.jpMin.dwX)[dwCurAxisPos]
  211. = CHid_CoordinateTransform( (PLMINMAX)&diprp.lMin, (PLMINMAX)&diprl.lMin, dipc.lMin );
  212. lMax = (&pcfg->hwc.hwv.jrvHardware.jpMax.dwX)[dwCurAxisPos]
  213. = CHid_CoordinateTransform( (PLMINMAX)&diprp.lMin, (PLMINMAX)&diprl.lMin, dipc.lMax );
  214. (&pcfg->hwc.hwv.jrvHardware.jpCenter.dwX)[dwCurAxisPos]
  215. = CCal_Midpoint(lMin, lMax);
  216. if( lMin >= lMax ) {
  217. fBadCalData = TRUE;
  218. break;
  219. }
  220. }
  221. }
  222. #endif
  223. }
  224. }
  225. } //for (axis=0...
  226. } //GetDataFormat
  227. pvip->hres = S_OK;
  228. pvip->dwSize = cbX(*pvip); /* Which version of VJOYD are we? */
  229. pvip->dwFlags |= JOY_HWS_AUTOLOAD; /* Describes the device */
  230. if(didi.wUsage == HID_USAGE_GENERIC_GAMEPAD) {
  231. pvip->dwFlags |= JOY_HWS_ISGAMEPAD;
  232. }
  233. pvip->dwId = idJoy; /* Internal joystick ID */
  234. pvip->dwFirmwareRevision = dc.dwFirmwareRevision;
  235. pvip->dwHardwareRevision = dc.dwHardwareRevision;
  236. pvip->dwFFDriverVersion = dc.dwFFDriverVersion;
  237. pvip->dwFilenameLengths = lstrlen(phdi->pdidd->DevicePath);
  238. pvip->pFilenameBuffer = phdi->pdidd->DevicePath;
  239. //pvip->Usages[6];
  240. //pvip->dwPOV1usage = 0x0;
  241. pvip->dwPOV2usage = 0x0;
  242. pvip->dwPOV3usage = 0x0;
  243. /* Fill all fields of cfg */
  244. if( pcfg != NULL ) {
  245. AssertF(pcfg->dwSize == cbX(*pcfg) );
  246. pcfg->guidInstance = phdi->guid;
  247. pcfg->hwc.hws.dwNumButtons = dc.dwButtons;
  248. pcfg->hwc.hws.dwFlags = pvip->dwFlags;
  249. //pcfg.hwc.hwv.jrvHardware
  250. //pcfg.hwc.hwv.dwPOVValues
  251. pcfg->hwc.hwv.dwCalFlags = 0x0;
  252. if( ( LOWORD(phdi->guidProduct.Data1) == MSFT_SYSTEM_VID )
  253. &&( ( HIWORD(phdi->guidProduct.Data1) >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN)
  254. &&( HIWORD(phdi->guidProduct.Data1) < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) )
  255. {
  256. pcfg->hwc.dwType = HIWORD(phdi->guidProduct.Data1) - MSFT_SYSTEM_PID;
  257. pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE;
  258. }
  259. else
  260. {
  261. /*
  262. * This value really does not matter much but ideally
  263. * should be greater than or equal to JOY_HW_PREDEFMAX
  264. * Add idJoy for best compatiblity with the old CPLs.
  265. */
  266. pcfg->hwc.dwType = idJoy + JOY_HW_PREDEFMAX;
  267. pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE | JOY_US_ISOEM;
  268. }
  269. if(pcfg && pvip->Usages[ecRz]) {
  270. pcfg->hwc.dwUsageSettings |= JOY_US_HASRUDDER;
  271. }
  272. pcfg->hwc.dwReserved = 0x0;
  273. /*
  274. * Default gain to nominal max so it does not get written
  275. * to the registry unless it has some other value.
  276. */
  277. pcfg->dwGain = DI_FFNOMINALMAX;
  278. propi.pguid = DIPROP_FFGAIN;
  279. propi.dwDevType = DIPH_DEVICE;
  280. propi.iobj = 0xFFFFFFFF;
  281. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipd.diph);
  282. if( SUCCEEDED(hres) )
  283. {
  284. pcfg->dwGain = dipd.dwData;
  285. } else
  286. {
  287. // Failure to get gain is not crutial
  288. hres = S_OK;
  289. }
  290. if( pcfg->hwc.dwType >= JOY_HW_PREDEFMAX )
  291. {
  292. #ifndef UNICODE
  293. char szType[20];
  294. #endif
  295. /*
  296. * This should work, but it doesn't in Win98, bug!
  297. *
  298. * wsprintfW(pcfg->wszType, L"VID_%04X&PID_%04X",
  299. * LOWORD(didi.guidProduct.Data1), HIWORD(didi.guidProduct.Data1));
  300. */
  301. #ifdef UNICODE
  302. wsprintf(pcfg->wszType, VID_PID_TEMPLATE,
  303. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  304. #else
  305. wsprintf(szType, VID_PID_TEMPLATE,
  306. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  307. AToU(pcfg->wszType, cA(pcfg->wszType), szType);
  308. #endif
  309. }
  310. else
  311. {
  312. /*
  313. * Predefined types do not have type strings for the
  314. * uses the callers of this function need.
  315. */
  316. ZeroX(pcfg->wszType);
  317. }
  318. #ifdef WINNT
  319. // No callout on NT
  320. ZeroX(pcfg->wszCallout);
  321. #else
  322. lstrcpyW( pcfg->wszCallout, L"joyhid.vxd" );
  323. #endif
  324. } // end of filling pcfg's fields
  325. pdijti->dwSize = cbX(*pdijti);
  326. pdijti->hws.dwNumButtons = dc.dwButtons;
  327. pdijti->hws.dwFlags = pvip->dwFlags;
  328. ZeroX(pdijti->clsidConfig);
  329. propi.pguid = DIPROP_INSTANCENAME;
  330. propi.dwDevType = DIPH_DEVICE;
  331. propi.iobj = 0xFFFFFFFF;
  332. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dips.diph);
  333. if( hres != S_OK && lstrlenW(pdijti->wszDisplayName) != 0x0 )
  334. {
  335. // Failure to get friendly name
  336. // We will try and use the OEM name from the registry
  337. lstrcpyW(dips.wsz, pdijti->wszDisplayName);
  338. //pdcb->lpVtbl->SetProperty(pdcb, &propi, &dips.diph);
  339. }else if( SUCCEEDED(hres) )
  340. {
  341. // Use friendly name in the registry
  342. lstrcpyW(pdijti->wszDisplayName, dips.wsz);
  343. hres = S_OK;
  344. }
  345. } // GetDeviceInfo FAILED
  346. } // GetCapabilities FAILED
  347. Invoke_Release(&pdcb);
  348. }
  349. } else // No HID device for JoyID
  350. {
  351. hres = E_FAIL;
  352. }
  353. if( fBadCalData ) {
  354. hres = E_FAIL;
  355. }
  356. ExitProcX(hres);
  357. return hres;
  358. }
  359. /*****************************************************************************
  360. *
  361. * @doc INTERNAL
  362. *
  363. * @func HRESULT | JoyReg_JoyIdToDeviceInterface |
  364. *
  365. * Given a joystick ID number, obtain the device interface
  366. * corresponding to it.
  367. *
  368. * @parm UINT | idJoy |
  369. *
  370. * Joystick ID number, zero-based.
  371. *
  372. * @parm PVXDINITPARMS | pvip |
  373. *
  374. * Receives init parameters from the driver.
  375. *
  376. * @parm LPTSTR | ptszBuf |
  377. *
  378. * A buffer of size <c MAX_PATH> in which the device interface
  379. * path is built.
  380. *
  381. * @returns
  382. * A pointer to the part of the <p ptszBuf> buffer that
  383. * contains the actual device interface path.
  384. *
  385. *****************************************************************************/
  386. LPTSTR EXTERNAL
  387. JoyReg_JoyIdToDeviceInterface_NT
  388. (
  389. IN UINT idJoy,
  390. OUT PVXDINITPARMS pvip,
  391. OUT LPTSTR ptszBuf
  392. )
  393. {
  394. HRESULT hres;
  395. DIJOYCONFIG cfg;
  396. DIJOYTYPEINFO dijti;
  397. DllEnterCrit();
  398. ZeroX(cfg);
  399. ZeroX(dijti);
  400. cfg.dwSize = cbX(cfg);
  401. dijti.dwSize = cbX(dijti);
  402. hres = DIWdm_JoyHidMapping(idJoy, pvip, &cfg, &dijti );
  403. if( SUCCEEDED(hres ) )
  404. {
  405. AssertF( lstrlen(pvip->pFilenameBuffer) < MAX_PATH );
  406. lstrcpy(ptszBuf, pvip->pFilenameBuffer);
  407. }
  408. DllLeaveCrit();
  409. return ptszBuf;
  410. }