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. pvip->dwId = idJoy; /* Internal joystick ID */
  233. pvip->dwFirmwareRevision = dc.dwFirmwareRevision;
  234. pvip->dwHardwareRevision = dc.dwHardwareRevision;
  235. pvip->dwFFDriverVersion = dc.dwFFDriverVersion;
  236. pvip->dwFilenameLengths = lstrlen(phdi->pdidd->DevicePath);
  237. pvip->pFilenameBuffer = phdi->pdidd->DevicePath;
  238. //pvip->Usages[6];
  239. //pvip->dwPOV1usage = 0x0;
  240. pvip->dwPOV2usage = 0x0;
  241. pvip->dwPOV3usage = 0x0;
  242. /* Fill all fields of cfg */
  243. if( pcfg != NULL ) {
  244. AssertF(pcfg->dwSize == cbX(*pcfg) );
  245. pcfg->guidInstance = phdi->guid;
  246. pcfg->hwc.hws.dwNumButtons = dc.dwButtons;
  247. pcfg->hwc.hws.dwFlags = pvip->dwFlags;
  248. //pcfg.hwc.hwv.jrvHardware
  249. //pcfg.hwc.hwv.dwPOVValues
  250. pcfg->hwc.hwv.dwCalFlags = 0x0;
  251. if( ( LOWORD(phdi->guidProduct.Data1) == MSFT_SYSTEM_VID )
  252. &&( ( HIWORD(phdi->guidProduct.Data1) >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN)
  253. &&( HIWORD(phdi->guidProduct.Data1) < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) )
  254. {
  255. pcfg->hwc.dwType = HIWORD(phdi->guidProduct.Data1) - MSFT_SYSTEM_PID;
  256. pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE;
  257. }
  258. else
  259. {
  260. /*
  261. * This value really does not matter much but ideally
  262. * should be greater than or equal to JOY_HW_PREDEFMAX
  263. * Add idJoy for best compatiblity with the old CPLs.
  264. */
  265. pcfg->hwc.dwType = idJoy + JOY_HW_PREDEFMAX;
  266. pcfg->hwc.dwUsageSettings = JOY_US_PRESENT | JOY_US_VOLATILE | JOY_US_ISOEM;
  267. }
  268. if(pcfg && pvip->Usages[ecRz]) {
  269. pcfg->hwc.dwUsageSettings |= JOY_US_HASRUDDER;
  270. }
  271. pcfg->hwc.dwReserved = 0x0;
  272. /*
  273. * Default gain to nominal max so it does not get written
  274. * to the registry unless it has some other value.
  275. */
  276. pcfg->dwGain = DI_FFNOMINALMAX;
  277. propi.pguid = DIPROP_FFGAIN;
  278. propi.dwDevType = DIPH_DEVICE;
  279. propi.iobj = 0xFFFFFFFF;
  280. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dipd.diph);
  281. if( SUCCEEDED(hres) )
  282. {
  283. pcfg->dwGain = dipd.dwData;
  284. } else
  285. {
  286. // Failure to get gain is not crutial
  287. hres = S_OK;
  288. }
  289. if( pcfg->hwc.dwType >= JOY_HW_PREDEFMAX )
  290. {
  291. #ifndef UNICODE
  292. char szType[20];
  293. #endif
  294. /*
  295. * This should work, but it doesn't in Win98, bug!
  296. *
  297. * wsprintfW(pcfg->wszType, L"VID_%04X&PID_%04X",
  298. * LOWORD(didi.guidProduct.Data1), HIWORD(didi.guidProduct.Data1));
  299. */
  300. #ifdef UNICODE
  301. wsprintf(pcfg->wszType, VID_PID_TEMPLATE,
  302. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  303. #else
  304. wsprintf(szType, VID_PID_TEMPLATE,
  305. LOWORD(phdi->guidProduct.Data1), HIWORD(phdi->guidProduct.Data1));
  306. AToU(pcfg->wszType, cA(pcfg->wszType), szType);
  307. #endif
  308. }
  309. else
  310. {
  311. /*
  312. * Predefined types do not have type strings for the
  313. * uses the callers of this function need.
  314. */
  315. ZeroX(pcfg->wszType);
  316. }
  317. if( fWinnt ) {
  318. // No callout on NT
  319. ZeroX(pcfg->wszCallout);
  320. } else {
  321. lstrcpyW( pcfg->wszCallout, L"joyhid.vxd" );
  322. }
  323. } // end of filling pcfg's fields
  324. pdijti->dwSize = cbX(*pdijti);
  325. pdijti->hws.dwNumButtons = dc.dwButtons;
  326. pdijti->hws.dwFlags = pvip->dwFlags;
  327. ZeroX(pdijti->clsidConfig);
  328. propi.pguid = DIPROP_INSTANCENAME;
  329. propi.dwDevType = DIPH_DEVICE;
  330. propi.iobj = 0xFFFFFFFF;
  331. hres = pdcb->lpVtbl->GetProperty(pdcb, &propi, &dips.diph);
  332. if( hres != S_OK && lstrlenW(pdijti->wszDisplayName) != 0x0 )
  333. {
  334. // Failure to get friendly name
  335. // We will try and use the OEM name from the registry
  336. lstrcpyW(dips.wsz, pdijti->wszDisplayName);
  337. //pdcb->lpVtbl->SetProperty(pdcb, &propi, &dips.diph);
  338. }else if( SUCCEEDED(hres) )
  339. {
  340. // Use friendly name in the registry
  341. lstrcpyW(pdijti->wszDisplayName, dips.wsz);
  342. hres = S_OK;
  343. }
  344. } // GetDeviceInfo FAILED
  345. } // GetCapabilities FAILED
  346. Invoke_Release(&pdcb);
  347. }
  348. } else // No HID device for JoyID
  349. {
  350. hres = E_FAIL;
  351. }
  352. if( fBadCalData ) {
  353. hres = E_FAIL;
  354. }
  355. ExitProcX(hres);
  356. return hres;
  357. }
  358. /*****************************************************************************
  359. *
  360. * @doc INTERNAL
  361. *
  362. * @func HRESULT | JoyReg_JoyIdToDeviceInterface |
  363. *
  364. * Given a joystick ID number, obtain the device interface
  365. * corresponding to it.
  366. *
  367. * @parm UINT | idJoy |
  368. *
  369. * Joystick ID number, zero-based.
  370. *
  371. * @parm PVXDINITPARMS | pvip |
  372. *
  373. * Receives init parameters from the driver.
  374. *
  375. * @parm LPTSTR | ptszBuf |
  376. *
  377. * A buffer of size <c MAX_PATH> in which the device interface
  378. * path is built.
  379. *
  380. * @returns
  381. * A pointer to the part of the <p ptszBuf> buffer that
  382. * contains the actual device interface path.
  383. *
  384. *****************************************************************************/
  385. LPTSTR EXTERNAL
  386. JoyReg_JoyIdToDeviceInterface_NT
  387. (
  388. IN UINT idJoy,
  389. OUT PVXDINITPARMS pvip,
  390. OUT LPTSTR ptszBuf
  391. )
  392. {
  393. HRESULT hres;
  394. DIJOYCONFIG cfg;
  395. DIJOYTYPEINFO dijti;
  396. DllEnterCrit();
  397. ZeroX(cfg);
  398. ZeroX(dijti);
  399. cfg.dwSize = cbX(cfg);
  400. dijti.dwSize = cbX(dijti);
  401. hres = DIWdm_JoyHidMapping(idJoy, pvip, &cfg, &dijti );
  402. if( SUCCEEDED(hres ) )
  403. {
  404. AssertF( lstrlen(pvip->pFilenameBuffer) < MAX_PATH );
  405. lstrcpy(ptszBuf, pvip->pFilenameBuffer);
  406. }
  407. DllLeaveCrit();
  408. return ptszBuf;
  409. }