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.

2845 lines
81 KiB

  1. /*****************************************************************************
  2. *
  3. * DIJoyReg.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Registry access services for joystick configuration.
  10. *
  11. * Contents:
  12. *
  13. * JoyReg_GetConfig
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflJoyReg
  23. #pragma BEGIN_CONST_DATA
  24. /*****************************************************************************
  25. *
  26. * @doc INTERNAL
  27. *
  28. * @global JOYREGHWSETTINGS | c_rghwsPredef[] |
  29. *
  30. * Array of predefined hardware settings.
  31. *
  32. *****************************************************************************/
  33. JOYREGHWSETTINGS c_rghwsPredef[] = {
  34. /* dwFlags dwNumButtons */
  35. { 0, 2}, /* JOY_HW_2A_2B_GENERIC */
  36. { 0, 4}, /* JOY_HW_2A_4B_GENERIC */
  37. { JOY_HWS_ISGAMEPAD, 2}, /* JOY_HW_2B_GAMEPAD */
  38. { JOY_HWS_ISYOKE, 2}, /* JOY_HW_2B_FLIGHTYOKE */
  39. { JOY_HWS_HASZ | JOY_HWS_ISYOKE, 2}, /* JOY_HW_2B_FLIGHTYOKETHROTTLE */
  40. { JOY_HWS_HASZ, 2}, /* JOY_HW_3A_2B_GENERIC */
  41. { JOY_HWS_HASZ, 4}, /* JOY_HW_3A_4B_GENERIC */
  42. { JOY_HWS_ISGAMEPAD, 4}, /* JOY_HW_4B_GAMEPAD */
  43. { JOY_HWS_ISYOKE, 4}, /* JOY_HW_4B_FLIGHTYOKE */
  44. { JOY_HWS_HASZ | JOY_HWS_ISYOKE, 4}, /* JOY_HW_4B_FLIGHTYOKETHROTTLE */
  45. { JOY_HWS_HASR , 2}, /* JOY_HW_TWO_2A_2B_WITH_Y */
  46. /* To prevent the CPL from allowing
  47. a user to add a rudder to to JOY_HWS_TWO_2A_2B_WITH_Y case, we
  48. will pretend that it already has a rudder. This should not be a problem
  49. as this struct is internal to DInput
  50. */
  51. };
  52. /* Hardware IDs for Predefined Joystick types */
  53. LPCWSTR c_rghwIdPredef[] =
  54. {
  55. L"GAMEPORT\\VID_045E&PID_0102", // L"GAMEPORT\\Generic2A2B",
  56. L"GAMEPORT\\VID_045E&PID_0103", // L"GAMEPORT\\Generic2A4B",
  57. L"GAMEPORT\\VID_045E&PID_0104", // L"GAMEPORT\\Gamepad2B",
  58. L"GAMEPORT\\VID_045E&PID_0105", // L"GAMEPORT\\FlightYoke2B",
  59. L"GAMEPORT\\VID_045E&PID_0106", // L"GAMEPORT\\FlightYokeThrottle2B",
  60. L"GAMEPORT\\VID_045E&PID_0107", // L"GAMEPORT\\Generic3A2B",
  61. L"GAMEPORT\\VID_045E&PID_0108", // L"GAMEPORT\\Generic3A4B",
  62. L"GAMEPORT\\VID_045E&PID_0109", // L"GAMEPORT\\Gamepad4B",
  63. L"GAMEPORT\\VID_045E&PID_010A", // L"GAMEPORT\\FlightYoke4B",
  64. L"GAMEPORT\\VID_045E&PID_010B", // L"GAMEPORT\\FlightYokeThrottle4B",
  65. L"GAMEPORT\\VID_045E&PID_010C", // L"GAMEPORT\\YConnectTwo2A2B",
  66. };
  67. WCHAR c_hwIdPrefix[] = L"GAMEPORT\\"; // Prefix for custom devices
  68. /*****************************************************************************
  69. *
  70. * The default global port driver.
  71. *
  72. *****************************************************************************/
  73. WCHAR c_wszDefPortDriver[] = L"MSANALOG.VXD";
  74. /*****************************************************************************
  75. *
  76. * @doc INTERNAL
  77. *
  78. * @func HRESULT | JoyReg_GetValue |
  79. *
  80. * Retrieve registry information. If the data is short, and
  81. * the type is <c REG_BINARY>, then the extra is zero-filled.
  82. *
  83. * @parm HKEY | hk |
  84. *
  85. * Registry key containing fun values.
  86. *
  87. * @parm LPCTSTR | ptszValue |
  88. *
  89. * Registry value name.
  90. *
  91. * @parm DWORD | reg |
  92. *
  93. * Registry data type expected.
  94. *
  95. * @parm LPVOID | pvBuf |
  96. *
  97. * Buffer to receive information from registry.
  98. *
  99. * @parm DWORD | cb |
  100. *
  101. * Size of recipient buffer, in bytes.
  102. *
  103. * @returns
  104. *
  105. * Returns a COM error code. The following error codes are
  106. * intended to be illustrative and not necessarily comprehensive.
  107. *
  108. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  109. *
  110. * <c S_FALSE>: The binary read was short. The remainder of the
  111. * buffer is zero-filled.
  112. *
  113. * <c E_FAIL>: Error reading value from registry.
  114. *
  115. *****************************************************************************/
  116. STDMETHODIMP
  117. JoyReg_GetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PV pvBuf, DWORD cb)
  118. {
  119. HRESULT hres;
  120. DWORD cbOut;
  121. LONG lRc;
  122. /*
  123. * Strings must be handled differently from binaries.
  124. *
  125. * Strings are retrieved in UNICODE and may be short.
  126. *
  127. * Binaries are retrieved as binary (duh) and may be long.
  128. *
  129. */
  130. cbOut = cb;
  131. if(reg == REG_SZ)
  132. {
  133. lRc = RegQueryStringValueW(hk, ptszValue, pvBuf, &cbOut);
  134. if(lRc == ERROR_SUCCESS)
  135. {
  136. hres = S_OK;
  137. } else
  138. {
  139. hres = hresLe(lRc); /* Else, something bad happened */
  140. }
  141. } else
  142. {
  143. AssertF(reg == REG_BINARY);
  144. lRc = RegQueryValueEx(hk, ptszValue, 0, NULL, pvBuf, &cbOut);
  145. if(lRc == ERROR_SUCCESS)
  146. {
  147. if(cb == cbOut)
  148. {
  149. hres = S_OK;
  150. } else
  151. {
  152. /*
  153. * Zero out the extra.
  154. */
  155. ZeroBuf(pvAddPvCb(pvBuf, cbOut), cb - cbOut);
  156. hres = S_FALSE;
  157. }
  158. } else if(lRc == ERROR_MORE_DATA)
  159. {
  160. /*
  161. * Need to double-buffer the call and throw away
  162. * the extra...
  163. */
  164. LPVOID pv;
  165. hres = AllocCbPpv(cbOut, &pv);
  166. // prefix 29344, odd chance that cbOut is 0x0
  167. if(SUCCEEDED(hres) && ( pv != NULL) )
  168. {
  169. lRc = RegQueryValueEx(hk, ptszValue, 0, NULL, pv, &cbOut);
  170. if(lRc == ERROR_SUCCESS)
  171. {
  172. CopyMemory(pvBuf, pv, cb);
  173. hres = S_OK;
  174. } else
  175. {
  176. ZeroBuf(pvBuf, cb);
  177. hres = hresLe(lRc); /* Else, something bad happened */
  178. }
  179. FreePv(pv);
  180. }
  181. } else
  182. {
  183. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  184. {
  185. lRc = ERROR_FILE_NOT_FOUND;
  186. }
  187. hres = hresLe(lRc);
  188. ZeroBuf(pvBuf, cb);
  189. }
  190. }
  191. #ifdef DEBUG
  192. /*
  193. * Don't whine if the key we couldn't find was
  194. * REGSTR_VAL_JOYUSERVALUES, because almost no one has it.
  195. */
  196. if(FAILED(hres) && lstrcmpi(ptszValue, REGSTR_VAL_JOYUSERVALUES) )
  197. {
  198. SquirtSqflPtszV(sqfl | sqflVerbose,
  199. TEXT("Unable to read %s from registry"),
  200. ptszValue);
  201. }
  202. #endif
  203. return hres;
  204. }
  205. /*****************************************************************************
  206. *
  207. * @doc INTERNAL
  208. *
  209. * @func HRESULT | JoyReg_IsWdmGameport |
  210. *
  211. * To test whether the joy type is WDM device or not.
  212. *
  213. * @parm HKEY | hk |
  214. *
  215. * Registry key containing fun values.
  216. *
  217. * @returns
  218. *
  219. * S_OK: if it uses WDM driver
  220. *
  221. * E_FAIL>: Not uses WDM driver
  222. *
  223. *****************************************************************************/
  224. STDMETHODIMP
  225. JoyReg_IsWdmGameport( HKEY hk )
  226. {
  227. HRESULT hres = E_FAIL;
  228. if( hk )
  229. {
  230. WCHAR wsz[MAX_JOYSTRING];
  231. // Whistler PREFIX Bug # 45075, 45076
  232. // Wsz is not initialized
  233. ZeroX(wsz);
  234. if( ( SUCCEEDED( JoyReg_GetValue( hk, REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ,
  235. &wsz, cbX(wsz) ) ) )
  236. &&( wsz[0] ) )
  237. {
  238. hres = S_OK;
  239. }
  240. else if( SUCCEEDED( JoyReg_GetValue( hk, REGSTR_VAL_JOYOEMCALLOUT, REG_SZ,
  241. &wsz, cbX(wsz) ) ) )
  242. {
  243. static WCHAR wszJoyhid[] = L"joyhid.vxd";
  244. int Idx;
  245. #define WLOWER 0x0020
  246. CAssertF( cbX(wszJoyhid) <= cbX(wsz) );
  247. /*
  248. * Since neither CharUpperW nor lstrcmpiW are really
  249. * implemented on 9x, do it by hand.
  250. */
  251. for( Idx=cA(wszJoyhid)-2; Idx>=0; Idx-- )
  252. {
  253. if( ( wsz[Idx] | WLOWER ) != wszJoyhid[Idx] )
  254. {
  255. break;
  256. }
  257. }
  258. if( ( Idx < 0 ) && ( wsz[cA(wszJoyhid)-1] == 0 ) )
  259. {
  260. hres = S_OK;
  261. }
  262. #undef WLOWER
  263. }
  264. }
  265. return hres;
  266. }
  267. #if 0
  268. /*
  269. * This function should be in diutil.c Putting here is just to keep it together with
  270. * JoyReg_IsWdmGameport();
  271. */
  272. STDMETHODIMP
  273. JoyReg_IsWdmGameportFromDeviceInstance( LPTSTR ptszDeviceInst )
  274. {
  275. /*
  276. * ptszDeviceInst's format is like this:
  277. * HID\VID_045E&PID_0102\0000GAMEPORT&PVID_....
  278. */
  279. WCHAR wszDeviceInst[MAX_PATH];
  280. HRESULT hres = E_FAIL;
  281. if( ptszDeviceInst )
  282. {
  283. memset( wszDeviceInst, 0, cbX(wszDeviceInst) );
  284. TToU( wszDeviceInst, MAX_PATH, ptszDeviceInst );
  285. wszDeviceInst[34] = 0;
  286. if( memcmp( &wszDeviceInst[26], c_hwIdPrefix, 16 ) == 0 )
  287. {
  288. hres = S_OK;
  289. }
  290. }
  291. return hres;
  292. }
  293. #endif
  294. /*****************************************************************************
  295. *
  296. * @doc INTERNAL
  297. *
  298. * @func HRESULT | JoyReg_SetValue |
  299. *
  300. * Write registry information.
  301. *
  302. * @parm HKEY | hk |
  303. *
  304. * Registry key containing fun values.
  305. *
  306. * @parm LPCTSTR | ptszValue |
  307. *
  308. * Registry value name.
  309. *
  310. * @parm DWORD | reg |
  311. *
  312. * Registry data type to set.
  313. *
  314. * @parm LPCVOID | pvBuf |
  315. *
  316. * Buffer containing information to write to registry.
  317. *
  318. * @parm DWORD | cb |
  319. *
  320. * Size of buffer, in bytes. Ignored if writing a string.
  321. *
  322. * @returns
  323. *
  324. * Returns a COM error code. The following error codes are
  325. * intended to be illustrative and not necessarily comprehensive.
  326. *
  327. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  328. *
  329. * <c E_FAIL>: Error writing value to registry.
  330. *
  331. *****************************************************************************/
  332. STDMETHODIMP
  333. JoyReg_SetValue(HKEY hk, LPCTSTR ptszValue, DWORD reg, PCV pvBuf, DWORD cb)
  334. {
  335. HRESULT hres;
  336. LONG lRc;
  337. /*
  338. * Strings must be handled differently from binaries.
  339. *
  340. * A null string translates into deleting the key.
  341. */
  342. if(reg == REG_SZ)
  343. {
  344. lRc = RegSetStringValueW(hk, ptszValue, pvBuf);
  345. } else
  346. {
  347. lRc = RegSetValueEx(hk, ptszValue, 0, reg, pvBuf, cb);
  348. }
  349. if(lRc == ERROR_SUCCESS)
  350. {
  351. hres = S_OK;
  352. } else
  353. {
  354. RPF("Unable to write %s to registry", ptszValue);
  355. hres = E_FAIL; /* Else, something bad happened */
  356. }
  357. return hres;
  358. }
  359. /*****************************************************************************
  360. *
  361. * @doc INTERNAL
  362. *
  363. * @func HRESULT | JoyReg_OpenTypeKey |
  364. *
  365. * Open the joystick registry key that corresponds to a
  366. * joystick type.
  367. *
  368. * @parm LPCWSTR | pwszTypeName |
  369. *
  370. * The name of the type.
  371. *
  372. * @parm DWORD | sam |
  373. *
  374. * Desired security access mask.
  375. *
  376. * @parm OUT PHKEY | phk |
  377. *
  378. * Receives the opened registry key on success.
  379. *
  380. * @returns
  381. *
  382. * Returns a COM error code. The following error codes are
  383. * intended to be illustrative and not necessarily comprehensive.
  384. *
  385. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  386. *
  387. * <c DIERR_NOTFOUND>: The joystick type was not found.
  388. *
  389. *****************************************************************************/
  390. STDMETHODIMP
  391. JoyReg_OpenTypeKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk)
  392. {
  393. HRESULT hres;
  394. HKEY hkTypes;
  395. EnterProc(JoyReg_OpenTypeKey, (_ "W", pwszType));
  396. /*
  397. * Note that it is not safe to cache the registry key.
  398. * If somebody deletes the registry key, our handle
  399. * goes stale and becomes useless.
  400. */
  401. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  402. REGSTR_PATH_JOYOEM,
  403. sam,
  404. REG_OPTION_NON_VOLATILE,
  405. &hkTypes);
  406. if( SUCCEEDED(hres) )
  407. {
  408. #ifndef UNICODE
  409. TCHAR tszType[MAX_PATH];
  410. UToA( tszType, cA(tszType), pwszType );
  411. hres = hresMumbleKeyEx(hkTypes,
  412. tszType,
  413. sam,
  414. dwOptions,
  415. phk);
  416. #else
  417. hres = hresMumbleKeyEx(hkTypes,
  418. pwszType,
  419. sam,
  420. dwOptions,
  421. phk);
  422. #endif
  423. RegCloseKey(hkTypes);
  424. }
  425. if(FAILED(hres))
  426. {
  427. *phk = 0;
  428. }
  429. ExitBenignOleProcPpv(phk);
  430. return hres;
  431. }
  432. /*****************************************************************************
  433. *
  434. * @doc INTERNAL
  435. *
  436. * @func HRESULT | JoyReg_OpenPropKey |
  437. *
  438. * Open the Dinput properties registry key that corresponds to a
  439. * device type. This key contains the OEMMapFile and dwFlags2 information
  440. * Nominally the location HKLM/REGSTR_PATH_PRIVATEPROPERTIES/DirectInput.
  441. *
  442. * @parm LPCWSTR | pwszTypeName |
  443. *
  444. * The name of the type.
  445. *
  446. * @parm DWORD | sam |
  447. *
  448. * Desired security access mask.
  449. *
  450. * @parm OUT PHKEY | phk |
  451. *
  452. * Receives the opened registry key on success.
  453. *
  454. * @returns
  455. *
  456. * Returns a COM error code. The following error codes are
  457. * intended to be illustrative and not necessarily comprehensive.
  458. *
  459. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  460. *
  461. * <c DIERR_NOTFOUND>: The type was not found.
  462. *
  463. *****************************************************************************/
  464. STDMETHODIMP
  465. JoyReg_OpenPropKey(LPCWSTR pwszType, DWORD sam, DWORD dwOptions, PHKEY phk)
  466. {
  467. HRESULT hres;
  468. HKEY hkTypes;
  469. EnterProc(JoyReg_OpenTypeKey, (_ "W", pwszType));
  470. /*
  471. * Note that it is not safe to cache the registry key.
  472. * If somebody deletes the registry key, our handle
  473. * goes stale and becomes useless.
  474. */
  475. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  476. REGSTR_PATH_DITYPEPROP,
  477. sam,
  478. REG_OPTION_NON_VOLATILE,
  479. &hkTypes);
  480. if ( SUCCEEDED(hres) )
  481. {
  482. #ifndef UNICODE
  483. TCHAR tszType[MAX_PATH];
  484. UToA( tszType, cA(tszType), pwszType );
  485. hres = hresMumbleKeyEx(hkTypes,
  486. tszType,
  487. sam,
  488. dwOptions,
  489. phk);
  490. #else
  491. hres = hresMumbleKeyEx(hkTypes,
  492. pwszType,
  493. sam,
  494. dwOptions,
  495. phk);
  496. #endif
  497. RegCloseKey(hkTypes);
  498. }
  499. if (FAILED(hres))
  500. {
  501. *phk = 0;
  502. }
  503. ExitBenignOleProcPpv(phk);
  504. return hres;
  505. }
  506. /*****************************************************************************
  507. *
  508. * @doc INTERNAL
  509. *
  510. * @func HRESULT | JoyReg_GetTypeInfo |
  511. *
  512. * Obtain information about a non-predefined joystick type.
  513. *
  514. * @parm LPCWSTR | pwszTypeName |
  515. *
  516. * The name of the type.
  517. *
  518. * @parm OUT LPDIJOYTYPEINFO | pjti |
  519. *
  520. * Receives information about the joystick type.
  521. * The caller is assumed to have validated the
  522. * <e DIJOYCONFIG.dwSize> field.
  523. *
  524. * @parm DWORD | fl |
  525. *
  526. * Zero or more <c DITC_*> flags
  527. * which specify which parts of the structure pointed
  528. * to by <p pjti> are to be filled in.
  529. *
  530. * @returns
  531. *
  532. * Returns a COM error code. The following error codes are
  533. * intended to be illustrative and not necessarily comprehensive.
  534. *
  535. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  536. *
  537. * <c DIERR_NOTFOUND>: The joystick type was not found.
  538. *
  539. *****************************************************************************/
  540. STDMETHODIMP
  541. JoyReg_GetTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl)
  542. {
  543. HRESULT hres;
  544. HKEY hk;
  545. EnterProc(JoyReg_GetTypeInfo, (_ "Wx", pwszType, fl));
  546. ZeroX(pjti->clsidConfig);
  547. hres = JoyReg_OpenTypeKey(pwszType, KEY_QUERY_VALUE, REG_OPTION_NON_VOLATILE, &hk);
  548. if(SUCCEEDED(hres))
  549. {
  550. if(fl & DITC_REGHWSETTINGS)
  551. {
  552. hres = JoyReg_GetValue(hk,
  553. REGSTR_VAL_JOYOEMDATA, REG_BINARY,
  554. &pjti->hws, cbX(pjti->hws));
  555. if(FAILED(hres))
  556. {
  557. goto closedone;
  558. }
  559. }
  560. /*
  561. * Note that this never fails.
  562. */
  563. if(fl & DITC_CLSIDCONFIG)
  564. {
  565. TCHAR tszGuid[ctchGuid];
  566. LONG lRc;
  567. lRc = RegQueryString(hk, REGSTR_VAL_CPLCLSID, tszGuid, cA(tszGuid));
  568. if(lRc == ERROR_SUCCESS &&
  569. ParseGUID(&pjti->clsidConfig, tszGuid))
  570. {
  571. /* Guid is good */
  572. } else
  573. {
  574. ZeroX(pjti->clsidConfig);
  575. }
  576. }
  577. if(fl & DITC_DISPLAYNAME)
  578. {
  579. hres = JoyReg_GetValue(hk,
  580. REGSTR_VAL_JOYOEMNAME, REG_SZ,
  581. pjti->wszDisplayName,
  582. cbX(pjti->wszDisplayName));
  583. if(FAILED(hres))
  584. {
  585. goto closedone;
  586. }
  587. }
  588. if(fl & DITC_CALLOUT)
  589. {
  590. hres = JoyReg_GetValue(hk,
  591. REGSTR_VAL_JOYOEMCALLOUT, REG_SZ,
  592. pjti->wszCallout,
  593. cbX(pjti->wszCallout));
  594. if(FAILED(hres))
  595. {
  596. ZeroX(pjti->wszCallout);
  597. hres = S_FALSE;
  598. goto closedone;
  599. }
  600. }
  601. if( fl & DITC_HARDWAREID )
  602. {
  603. hres = JoyReg_GetValue(hk,
  604. REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ,
  605. pjti->wszHardwareId,
  606. cbX(pjti->wszHardwareId));
  607. if( FAILED(hres))
  608. {
  609. ZeroX(pjti->wszHardwareId);
  610. hres = S_FALSE;
  611. goto closedone;
  612. }
  613. }
  614. if( fl & DITC_FLAGS1 )
  615. {
  616. hres = JoyReg_GetValue(hk,
  617. REGSTR_VAL_FLAGS1, REG_BINARY,
  618. &pjti->dwFlags1,
  619. cbX(pjti->dwFlags1) );
  620. if( FAILED(hres) )
  621. {
  622. pjti->dwFlags1 = 0x0;
  623. hres = S_FALSE;
  624. goto closedone;
  625. }
  626. pjti->dwFlags1 &= JOYTYPE_FLAGS1_GETVALID;
  627. }
  628. hres = S_OK;
  629. closedone:;
  630. RegCloseKey(hk);
  631. } else
  632. {
  633. // ISSUE-2001/03/29-timgill debug string code should be higher
  634. // (MarcAnd) this really should be at least sqflError but
  635. // this happens a lot, probably due to not filtering out predefs
  636. SquirtSqflPtszV(sqfl | sqflBenign,
  637. TEXT( "IDirectInputJoyConfig::GetTypeInfo: Nonexistent type %lS" ),
  638. pwszType);
  639. hres = DIERR_NOTFOUND;
  640. }
  641. ExitOleProc();
  642. return hres;
  643. }
  644. /*****************************************************************************
  645. *
  646. * @doc INTERNAL
  647. *
  648. * @func HRESULT | JoyReg_SetTypeInfo |
  649. *
  650. * Store information about a non-predefined joystick type
  651. * into the registry.
  652. *
  653. * @parm HKEY | hkTypeW |
  654. *
  655. * Registry key to the types branch with write access.
  656. *
  657. * @parm LPCWSTR | pwszTypeName |
  658. *
  659. * The name of the type.
  660. *
  661. * @parm IN LPCDIJOYTYPEINFO | pjti |
  662. *
  663. * Contains information about the joystick type.
  664. *
  665. * @parm DWORD | fl |
  666. *
  667. * Zero or more <c DITC_*> flags
  668. * which specify which parts of the structure pointed
  669. * to by <p pjti> contain values which are to be set.
  670. *
  671. * @returns
  672. *
  673. * Returns a COM error code. The following error codes are
  674. * intended to be illustrative and not necessarily comprehensive.
  675. *
  676. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  677. *
  678. * <c DIERR_NOTFOUND>: The joystick type was not found.
  679. *
  680. *****************************************************************************/
  681. STDMETHODIMP
  682. JoyReg_SetTypeInfo(HKEY hkTypesW,
  683. LPCWSTR pwszType, LPCDIJOYTYPEINFO pjti, DWORD fl)
  684. {
  685. HRESULT hres;
  686. ULONG lRc;
  687. EnterProc(JoyRegSetTypeInfo, (_ "Wx", pwszType, fl));
  688. if(fl & DITC_INREGISTRY)
  689. {
  690. HKEY hk;
  691. DWORD dwOptions = 0;
  692. if( fl & DITC_VOLATILEREGKEY )
  693. {
  694. dwOptions = REG_OPTION_VOLATILE;
  695. }else
  696. {
  697. dwOptions = REG_OPTION_NON_VOLATILE;
  698. }
  699. #ifndef UNICODE
  700. {
  701. TCHAR tszType[MAX_PATH];
  702. UToA(tszType, cA(tszType), pwszType);
  703. hres = hresMumbleKeyEx(hkTypesW,
  704. tszType,
  705. DI_KEY_ALL_ACCESS,
  706. dwOptions,
  707. &hk);
  708. }
  709. #else
  710. hres = hresMumbleKeyEx(hkTypesW,
  711. pwszType,
  712. DI_KEY_ALL_ACCESS,
  713. dwOptions,
  714. &hk);
  715. #endif
  716. if( SUCCEEDED(hres) )
  717. {
  718. if(fl & DITC_REGHWSETTINGS)
  719. {
  720. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMDATA, REG_BINARY,
  721. (PV)&pjti->hws, cbX(pjti->hws));
  722. if(FAILED(hres))
  723. {
  724. goto closedone;
  725. }
  726. }
  727. if(fl & DITC_CLSIDCONFIG)
  728. {
  729. if(IsEqualGUID(&pjti->clsidConfig, &GUID_Null))
  730. {
  731. lRc = RegDeleteValue(hk, REGSTR_VAL_CPLCLSID);
  732. /*
  733. * It is not an error if the key does not already exist.
  734. */
  735. if(lRc == ERROR_FILE_NOT_FOUND)
  736. {
  737. lRc = ERROR_SUCCESS;
  738. }
  739. } else
  740. {
  741. TCHAR tszGuid[ctchNameGuid];
  742. NameFromGUID(tszGuid, &pjti->clsidConfig);
  743. lRc = RegSetValueEx(hk, REGSTR_VAL_CPLCLSID, 0, REG_SZ,
  744. (PV)&tszGuid[ctchNamePrefix], ctchGuid * cbX(tszGuid[0]) );
  745. }
  746. if(lRc == ERROR_SUCCESS)
  747. {
  748. } else
  749. {
  750. hres = E_FAIL;
  751. goto closedone;
  752. }
  753. }
  754. /* ISSUE-2001/03/29-timgill Needs more data checking
  755. Should make sure string is terminated properly */
  756. if(fl & DITC_DISPLAYNAME)
  757. {
  758. hres = JoyReg_SetValue(hk,
  759. REGSTR_VAL_JOYOEMNAME, REG_SZ,
  760. pjti->wszDisplayName,
  761. cbX(pjti->wszDisplayName));
  762. if(FAILED(hres))
  763. {
  764. goto closedone;
  765. }
  766. }
  767. /* ISSUE-2001/03/29-timgill Needs more data checking
  768. Should make sure string is terminated properly */
  769. if(fl & DITC_CALLOUT)
  770. {
  771. hres = JoyReg_SetValue(hk,
  772. REGSTR_VAL_JOYOEMCALLOUT, REG_SZ,
  773. pjti->wszCallout,
  774. cbX(pjti->wszCallout));
  775. if(FAILED(hres))
  776. {
  777. hres = S_FALSE;
  778. //continue to go
  779. }
  780. }
  781. if( fl & DITC_HARDWAREID )
  782. {
  783. hres = JoyReg_SetValue(hk,
  784. REGSTR_VAL_JOYOEMHARDWAREID, REG_SZ,
  785. pjti->wszHardwareId,
  786. cbX(pjti->wszHardwareId) );
  787. if( FAILED(hres) )
  788. {
  789. hres = S_FALSE;
  790. goto closedone;
  791. }
  792. }
  793. if( fl & DITC_FLAGS1 )
  794. {
  795. AssertF( (pjti->dwFlags1 & ~JOYTYPE_FLAGS1_SETVALID) == 0x0 );
  796. hres = JoyReg_SetValue(hk,
  797. REGSTR_VAL_FLAGS1, REG_BINARY,
  798. (PV)&pjti->dwFlags1,
  799. cbX(pjti->dwFlags1) );
  800. if( FAILED(hres) )
  801. {
  802. hres = S_FALSE;
  803. goto closedone;
  804. }
  805. }
  806. hres = S_OK;
  807. closedone:;
  808. RegCloseKey(hk);
  809. } else
  810. {
  811. hres = E_FAIL; /* Registry problem */
  812. }
  813. } else
  814. {
  815. hres = S_OK; /* Vacuous success */
  816. }
  817. ExitOleProc();
  818. return hres;
  819. }
  820. /*****************************************************************************
  821. *
  822. * @doc INTERNAL
  823. *
  824. * @func HRESULT | JoyReg_OpenConfigKey |
  825. *
  826. * Open the registry key that accesses joystick configuration data.
  827. *
  828. * Warning! Do not cache this regkey.
  829. *
  830. * If the user deletes the key and then re-creates it,
  831. * the opened key will go stale and will become useless.
  832. * You have to close the key and reopen it.
  833. * To avoid worrying about that case, merely open it every time.
  834. *
  835. * @parm UINT | idJoy |
  836. *
  837. * Joystick number.
  838. *
  839. * @parm DWORD | sam |
  840. *
  841. * Access level desired.
  842. *
  843. * @parm IN PJOYCAPS | pcaps |
  844. *
  845. * Receives joystick capabilities information.
  846. * If this parameter is <c NULL>, then joystick
  847. * capabilities information is not returned.
  848. *
  849. * @parm IN DWORD | dwOptions |
  850. * Option flags to RegCreateEx
  851. *
  852. * @parm PHKEY | phk |
  853. *
  854. * Receives created registry key.
  855. *
  856. * @returns
  857. *
  858. * Returns a COM error code. The following error codes are
  859. * intended to be illustrative and not necessarily comprehensive.
  860. *
  861. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  862. *
  863. * hresLe(ERROR_FILE_NOT_FOUND): The key does not exist.
  864. *
  865. *****************************************************************************/
  866. STDMETHODIMP
  867. JoyReg_OpenConfigKey(UINT idJoy, DWORD sam, PJOYCAPS pcaps, DWORD dwOptions, PHKEY phk)
  868. {
  869. HRESULT hres;
  870. MMRESULT mmrc = MMSYSERR_ERROR;
  871. JOYCAPS caps;
  872. EnterProc(JoyReg_OpenConfigKey, (_ "uxp", idJoy, sam, pcaps));
  873. /*
  874. * If caller doesn't care, then just dump the caps into our
  875. * private buffer.
  876. */
  877. if(pcaps == NULL)
  878. {
  879. pcaps = &caps;
  880. }
  881. /*
  882. * If we can't get the dev caps for the specified joystick,
  883. * then use the magic joystick id "-1" to get non-specific
  884. * caps.
  885. */
  886. if( fWinnt )
  887. {
  888. ZeroX(*pcaps);
  889. lstrcpy(pcaps->szRegKey, REGSTR_SZREGKEY );
  890. mmrc = JOYERR_NOERROR;
  891. } else
  892. {
  893. mmrc = joyGetDevCaps(idJoy, pcaps, cbX(*pcaps));
  894. if( mmrc != JOYERR_NOERROR ) {
  895. mmrc = joyGetDevCaps((DWORD)-1, pcaps, cbX(*pcaps));
  896. }
  897. }
  898. if(mmrc == JOYERR_NOERROR)
  899. {
  900. TCHAR tsz[cA(REGSTR_PATH_JOYCONFIG) +
  901. 1 + /* backslash */
  902. cA(pcaps->szRegKey) +
  903. 1 + /* backslash */
  904. cA(REGSTR_KEY_JOYCURR) + 1];
  905. /* tsz = MediaResources\Joystick\<drv>\CurrentJoystickSettings */
  906. wsprintf(tsz, TEXT("%s\\%s\\") REGSTR_KEY_JOYCURR,
  907. REGSTR_PATH_JOYCONFIG, pcaps->szRegKey);
  908. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tsz, sam, REG_OPTION_VOLATILE, phk);
  909. } else
  910. {
  911. hres = E_FAIL;
  912. }
  913. ExitBenignOleProc();
  914. return hres;
  915. }
  916. /*****************************************************************************
  917. *
  918. * @doc INTERNAL
  919. *
  920. * @func HRESULT | JoyReg_OpenSaveKey |
  921. *
  922. * Open the registry key that accesses joystick saved configurations
  923. *
  924. * Warning! Do not cache this regkey.
  925. *
  926. * If the user deletes the key and then re-creates it,
  927. * the opened key will go stale and will become useless.
  928. * You have to close the key and reopen it.
  929. * To avoid worrying about that case, merely open it every time.
  930. *
  931. * @parm DWORD | dwType |
  932. *
  933. * Joystick type.
  934. *
  935. * This is either one of the standard ones in the range
  936. *
  937. * @parm IN LPCDIJOYCONFIG | pcfg |
  938. *
  939. * If the dwType represents an OEM type, this should point to a
  940. * configuration data structure containing a valid wszType.
  941. *
  942. * @parm DWORD | sam |
  943. *
  944. * Access level desired.
  945. *
  946. * @parm PHKEY | phk |
  947. *
  948. * Receives created registry key.
  949. *
  950. * @returns
  951. *
  952. * Returns a COM error code. The following error codes are
  953. * intended to be illustrative and not necessarily comprehensive.
  954. *
  955. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  956. *
  957. * hresLe(ERROR_FILE_NOT_FOUND): The key does not exist.
  958. *
  959. *****************************************************************************/
  960. STDMETHODIMP
  961. JoyReg_OpenSaveKey(DWORD dwType, LPCDIJOYCONFIG pcfg, DWORD sam, PHKEY phk)
  962. {
  963. HRESULT hres;
  964. MMRESULT mmrc = MMSYSERR_ERROR;
  965. JOYCAPS caps;
  966. DWORD dwOptions = 0;
  967. EnterProc(JoyReg_OpenSaveKey, (_ "upx", dwType, pcfg, sam));
  968. /*
  969. * use the magic joystick id "-1" to get non-specific caps.
  970. */
  971. if( fWinnt )
  972. {
  973. ZeroX(caps);
  974. lstrcpy(caps.szRegKey, REGSTR_SZREGKEY );
  975. mmrc = JOYERR_NOERROR;
  976. } else
  977. {
  978. mmrc = joyGetDevCaps((DWORD)-1, &caps, cbX(caps));
  979. }
  980. if(mmrc == JOYERR_NOERROR)
  981. {
  982. TCHAR tsz[cA(REGSTR_PATH_JOYCONFIG) +
  983. 1 + /* backslash */
  984. cA(caps.szRegKey) +
  985. 1 + /* backslash */
  986. cA(REGSTR_KEY_JOYSETTINGS) +
  987. 1 + /* backslash */
  988. max( cA(REGSTR_KEY_JOYPREDEFN), cA(pcfg->wszType) ) + 1 ];
  989. /* tsz = MediaResources\Joystick\<drv>\JoystickSettings\<Type> */
  990. if( dwType >= JOY_HW_PREDEFMAX )
  991. {
  992. wsprintf(tsz, TEXT("%s\\%s\\%s\\%ls"),
  993. REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYSETTINGS, pcfg->wszType);
  994. } else
  995. {
  996. /*
  997. * We will probably never have more than the current 11 predefined
  998. * joysticks. Assume no more than 99 so %d is as many characters.
  999. */
  1000. wsprintf(tsz, TEXT("%s\\%s\\%s\\" REGSTR_KEY_JOYPREDEFN),
  1001. REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYSETTINGS, dwType );
  1002. }
  1003. if( pcfg->hwc.dwUsageSettings & JOY_US_VOLATILE )
  1004. dwOptions = REG_OPTION_VOLATILE;
  1005. else
  1006. dwOptions = REG_OPTION_NON_VOLATILE;
  1007. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE, tsz, sam, dwOptions, phk);
  1008. } else
  1009. {
  1010. hres = E_FAIL;
  1011. }
  1012. ExitOleProc();
  1013. return hres;
  1014. }
  1015. /*****************************************************************************
  1016. *
  1017. * @doc INTERNAL
  1018. *
  1019. * @func HRESULT | JoyReg_GetSetConfigValue |
  1020. *
  1021. * Retrieve or update configuration information about a joystick,
  1022. * as stored in the registry instance key.
  1023. *
  1024. * @parm HKEY | hk |
  1025. *
  1026. * Registry key containing fun values.
  1027. *
  1028. * @parm LPCTSTR | ptszNValue |
  1029. *
  1030. * Registry value name, with "%d" where a joystick number
  1031. * should be.
  1032. *
  1033. * @parm UINT | idJoy |
  1034. *
  1035. * Zero-based joystick number.
  1036. *
  1037. * @parm DWORD | reg |
  1038. *
  1039. * Registry data type expected.
  1040. *
  1041. * @parm LPVOID | pvBuf |
  1042. *
  1043. * Buffer to receive information from registry (if getting)
  1044. * or containing value to set.
  1045. *
  1046. * @parm DWORD | cb |
  1047. *
  1048. * Size of buffer, in bytes.
  1049. *
  1050. * @parm BOOL | fSet |
  1051. *
  1052. * Nonzer if the value should be set; otherwise, it will be
  1053. * retrieved.
  1054. *
  1055. * @returns
  1056. *
  1057. * Returns a COM error code. The following error codes are
  1058. * intended to be illustrative and not necessarily comprehensive.
  1059. *
  1060. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1061. *
  1062. * <c E_FAIL>: Error reading/writing value to/from registry.
  1063. *
  1064. *****************************************************************************/
  1065. STDMETHODIMP
  1066. JoyReg_GetSetConfigValue(HKEY hk, LPCTSTR ptszNValue, UINT idJoy,
  1067. DWORD reg, PV pvBuf, DWORD cb, BOOL fSet)
  1068. {
  1069. HRESULT hres;
  1070. int ctch;
  1071. /* Extra +12 because a UINT can be as big as 4 billion */
  1072. TCHAR tsz[max(
  1073. max(
  1074. max(cA(REGSTR_VAL_JOYNCONFIG),
  1075. cA(REGSTR_VAL_JOYNOEMNAME)),
  1076. cA(REGSTR_VAL_JOYNOEMCALLOUT)),
  1077. cA(REGSTR_VAL_JOYNFFCONFIG)) + 12 + 1];
  1078. ctch = wsprintf(tsz, ptszNValue, idJoy + 1);
  1079. AssertF(ctch < cA(tsz));
  1080. if(fSet)
  1081. {
  1082. hres = JoyReg_SetValue(hk, tsz, reg, pvBuf, cb);
  1083. } else
  1084. {
  1085. hres = JoyReg_GetValue(hk, tsz, reg, pvBuf, cb);
  1086. }
  1087. return hres;
  1088. }
  1089. /*****************************************************************************
  1090. *
  1091. * @doc INTERNAL
  1092. *
  1093. * @func HRESULT | hresIdJoypInstanceGUID |
  1094. *
  1095. * Given a joystick ID obtain the corresponding GUID.
  1096. * This routine differs in implementation on WINNT and WIN9x
  1097. * On WINNT there are no predefined GUID for Joystick IDs.
  1098. *
  1099. * @parm IN UINT | idJoy |
  1100. *
  1101. * Joystick identification number.
  1102. *
  1103. * @parm OUT LPGUID | lpguid |
  1104. *
  1105. * Receives the joystick GUID. If no mapping exists,
  1106. * GUID_NULL is passed back
  1107. *
  1108. * On Windows NT all joysticks are HID devices. The corresponding function
  1109. * for WINNT is defined in diWinnt.c
  1110. *
  1111. *****************************************************************************/
  1112. HRESULT EXTERNAL hResIdJoypInstanceGUID_95
  1113. (
  1114. UINT idJoy,
  1115. LPGUID lpguid
  1116. )
  1117. {
  1118. HRESULT hRes;
  1119. hRes = S_OK;
  1120. if( idJoy < cA(rgGUID_Joystick) )
  1121. {
  1122. *lpguid = rgGUID_Joystick[idJoy];
  1123. } else
  1124. {
  1125. hRes = DIERR_NOTFOUND;
  1126. ZeroX(*lpguid);
  1127. }
  1128. return hRes;
  1129. }
  1130. /*****************************************************************************
  1131. *
  1132. * @doc INTERNAL
  1133. *
  1134. * @func HRESULT | JoyReg_GetConfigInternal |
  1135. *
  1136. * Obtain information about a joystick's configuration.
  1137. *
  1138. * @parm UINT | uiJoy |
  1139. *
  1140. * Joystick identification number.
  1141. *
  1142. * @parm PJOYCAPS | pcaps |
  1143. *
  1144. * Receives information about the joystick capabilities.
  1145. * If this parameter is <c NULL>, then joystick
  1146. * capabilities information is not returned.
  1147. *
  1148. * @parm OUT LPDIJOYCONFIG | pcfg |
  1149. *
  1150. * Receives information about the joystick configuration.
  1151. * The caller is assumed to have validated the
  1152. * <e DIJOYCONFIG.dwSize> field.
  1153. *
  1154. * @parm DWORD | fl |
  1155. *
  1156. * Zero or more <c DIJC_*> flags
  1157. * which specify which parts of the structure pointed
  1158. * to by <p pjc> are to be filled in.
  1159. *
  1160. * @returns
  1161. *
  1162. * Returns a COM error code. The following error codes are
  1163. * intended to be illustrative and not necessarily comprehensive.
  1164. *
  1165. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1166. *
  1167. * <c DIERR_NOMOREITEMS>: No more joysticks.
  1168. *
  1169. *****************************************************************************/
  1170. STDMETHODIMP
  1171. JoyReg_GetConfigInternal(UINT idJoy, PJOYCAPS pcaps,
  1172. LPDIJOYCONFIG pcfg, DWORD fl)
  1173. {
  1174. HRESULT hres = E_FAIL;
  1175. EnterProc(JoyReg_GetConfigInternal, (_ "upx", idJoy, pcaps, pcfg, fl));
  1176. AssertF((fl & ~DIJC_GETVALID) == 0);
  1177. /* We only support (0/16) joysticks */
  1178. if( idJoy < cJoyMax )
  1179. {
  1180. /* Force a rescan of all HID device list
  1181. * Some device may have been attached
  1182. * since we last looked
  1183. */
  1184. DIHid_BuildHidList(FALSE);
  1185. if(fl & DIJC_GUIDINSTANCE)
  1186. {
  1187. hres = hResIdJoypInstanceGUID_WDM(idJoy, &pcfg->guidInstance);
  1188. if( (hres != S_OK) && !fWinnt) {
  1189. hres = hResIdJoypInstanceGUID_95(idJoy, &pcfg->guidInstance);
  1190. }
  1191. if( FAILED(hres) )
  1192. {
  1193. goto done;
  1194. }
  1195. }
  1196. if( fl & DIJC_INREGISTRY )
  1197. {
  1198. HKEY hk;
  1199. /* Does the registry entry exist ? */
  1200. hres = JoyReg_OpenConfigKey(idJoy, KEY_QUERY_VALUE, pcaps,REG_OPTION_NON_VOLATILE , &hk);
  1201. if(SUCCEEDED(hres))
  1202. {
  1203. if(fl & DIJC_REGHWCONFIGTYPE)
  1204. {
  1205. hres = JoyReg_GetConfigValue(
  1206. hk, REGSTR_VAL_JOYNCONFIG,
  1207. idJoy, REG_BINARY,
  1208. &pcfg->hwc, cbX(pcfg->hwc));
  1209. if(FAILED(hres))
  1210. {
  1211. goto closedone;
  1212. }
  1213. pcfg->wszType[0] = TEXT('\0');
  1214. if( (pcfg->hwc.dwUsageSettings & JOY_US_ISOEM) ||
  1215. ( !fWinnt && (pcfg->hwc.dwType >= JOY_HW_PREDEFMIN)
  1216. && (pcfg->hwc.dwType < JOY_HW_PREDEFMAX) ) )
  1217. {
  1218. hres = JoyReg_GetConfigValue(
  1219. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  1220. pcfg->wszType, cbX(pcfg->wszType));
  1221. if(FAILED(hres))
  1222. {
  1223. goto closedone;
  1224. }
  1225. }
  1226. }
  1227. if(fl & DIJC_CALLOUT)
  1228. {
  1229. pcfg->wszCallout[0] = TEXT('\0');
  1230. hres = JoyReg_GetConfigValue(
  1231. hk, REGSTR_VAL_JOYNOEMCALLOUT, idJoy, REG_SZ,
  1232. pcfg->wszCallout, cbX(pcfg->wszCallout));
  1233. if(FAILED(hres))
  1234. {
  1235. ZeroX(pcfg->wszCallout);
  1236. hres = S_FALSE;
  1237. /* Note that we fall through and let hres = S_OK */
  1238. }
  1239. }
  1240. if(fl & DIJC_GAIN)
  1241. {
  1242. /*
  1243. * If there is no FF configuration, then
  1244. * default to DI_FFNOMINALMAX gain.
  1245. */
  1246. hres = JoyReg_GetConfigValue(hk,
  1247. REGSTR_VAL_JOYNFFCONFIG,
  1248. idJoy, REG_BINARY,
  1249. &pcfg->dwGain, cbX(pcfg->dwGain));
  1250. if(SUCCEEDED(hres) && ISVALIDGAIN(pcfg->dwGain))
  1251. {
  1252. /* Leave it alone; it's good */
  1253. } else
  1254. {
  1255. hres = S_FALSE;
  1256. pcfg->dwGain = DI_FFNOMINALMAX;
  1257. /* Note that we fall through and let hres = S_OK */
  1258. }
  1259. }
  1260. if( fl & DIJC_WDMGAMEPORT )
  1261. {
  1262. PBUSDEVICEINFO pbdi;
  1263. /*
  1264. * If there is no Gameport Associated with this device
  1265. * then it must be a USB device
  1266. */
  1267. DllEnterCrit();
  1268. if( pbdi = pbdiFromJoyId(idJoy) )
  1269. {
  1270. pcfg->guidGameport = pbdi->guid;
  1271. //lstrcpyW(pcfg->wszGameport, pbdi->wszDisplayName);
  1272. } else
  1273. {
  1274. ZeroX(pcfg->guidGameport);
  1275. //pcfg->wszGameport[0] = TEXT('\0');
  1276. }
  1277. DllLeaveCrit();
  1278. }
  1279. }
  1280. closedone:
  1281. RegCloseKey(hk);
  1282. }
  1283. } else
  1284. {
  1285. hres = DIERR_NOMOREITEMS;
  1286. }
  1287. done:
  1288. ExitBenignOleProc();
  1289. return hres;
  1290. }
  1291. /*****************************************************************************
  1292. *
  1293. * @doc INTERNAL
  1294. *
  1295. * @func HRESULT | JoyReg_GetConfig |
  1296. *
  1297. * Obtain information about a joystick's configuration,
  1298. * taking the MSGAME.VXD driver into account.
  1299. *
  1300. * @parm UINT | uiJoy |
  1301. *
  1302. * Joystick identification number.
  1303. *
  1304. * @parm PJOYCAPS | pcaps |
  1305. *
  1306. * Receives information about the joystick capabilities.
  1307. * If this parameter is <c NULL>, then joystick
  1308. * capabilities information is not returned.
  1309. *
  1310. * @parm OUT LPDIJOYCONFIG | pcfg |
  1311. *
  1312. * Receives information about the joystick configuration.
  1313. * The caller is assumed to have validated the
  1314. * <e DIJOYCONFIG.dwSize> field.
  1315. *
  1316. * @parm DWORD | fl |
  1317. *
  1318. * Zero or more <c DIJC_*> flags
  1319. * which specify which parts of the structure pointed
  1320. * to by <p pjc> are to be filled in.
  1321. *
  1322. * @returns
  1323. *
  1324. * Returns a COM error code. The following error codes are
  1325. * intended to be illustrative and not necessarily comprehensive.
  1326. *
  1327. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1328. *
  1329. * <c DIERR_NOMOREITEMS>: No more joysticks.
  1330. *
  1331. *****************************************************************************/
  1332. STDMETHODIMP
  1333. JoyReg_GetConfig(UINT idJoy, PJOYCAPS pcaps, LPDIJOYCONFIG pcfg, DWORD fl)
  1334. {
  1335. HRESULT hres;
  1336. GUID guid;
  1337. EnterProc(JoyReg_GetConfig, (_ "upx", idJoy, pcaps, pcfg, fl));
  1338. AssertF((fl & ~DIJC_GETVALID) == 0);
  1339. /*
  1340. * First determine if the joystick exits
  1341. * On NT, we use WDM driver.
  1342. * On Win9x, if WDM fails, use static guids.
  1343. */
  1344. hres = hResIdJoypInstanceGUID_WDM(idJoy, &guid);
  1345. if( (hres != S_OK) && !fWinnt ) {
  1346. hres = hResIdJoypInstanceGUID_95(idJoy, &guid);
  1347. }
  1348. if( SUCCEEDED( hres) )
  1349. {
  1350. hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl);
  1351. #ifndef WINNT
  1352. /***************************************************
  1353. *
  1354. * Beginning of hack for Sidewinder Gamepad.
  1355. *
  1356. * The gamepad needs to be polled six times before
  1357. * it realizes what is going on.
  1358. *
  1359. ***************************************************/
  1360. if(SUCCEEDED(hres) && (fl & DIJC_CALLOUT))
  1361. {
  1362. static WCHAR s_wszMSGAME[] = L"MSGAME.VXD";
  1363. if(memcmp(pcfg->wszCallout, s_wszMSGAME, cbX(s_wszMSGAME)) == 0)
  1364. {
  1365. JOYINFOEX ji;
  1366. int i;
  1367. DWORD dwWait;
  1368. SquirtSqflPtszV(sqfl,
  1369. TEXT("Making bonus polls for Sidewinder"));
  1370. /*
  1371. * It's a Sidewinder. Make six
  1372. * bonus polls to shake the stick into submission.
  1373. *
  1374. * Actually, we make 16 bonus polls. The Sidewinder
  1375. * guys said that five or six would be enough.
  1376. * They're wrong.
  1377. *
  1378. * I also sleep 10ms between each poll because that
  1379. * seems to help a bit.
  1380. */
  1381. ji.dwSize = cbX(ji);
  1382. ji.dwFlags = JOY_RETURNALL;
  1383. for(i = 0; i < 16; i++)
  1384. {
  1385. MMRESULT mmrc = joyGetPosEx(idJoy, &ji);
  1386. SquirtSqflPtszV(sqfl,
  1387. TEXT("joyGetPosEx(%d) = %d"),
  1388. idJoy, mmrc);
  1389. Sleep(10);
  1390. }
  1391. /*
  1392. * Now sleep for some time. They forgot to tell us
  1393. * this.
  1394. *
  1395. * Bonus hack! The amount of time we need to sleep
  1396. * is CPU-speed dependent, so we'll grab the sleep
  1397. * time from the registry to allow us to tweak it
  1398. * later.
  1399. *
  1400. * What a bunch of lamers.
  1401. */
  1402. dwWait = RegQueryDIDword(NULL, REGSTR_VAL_GAMEPADDELAY, 100);
  1403. if(dwWait > 10 * 1000)
  1404. {
  1405. dwWait = 10 * 1000;
  1406. }
  1407. Sleep(dwWait);
  1408. /*
  1409. * And then check again.
  1410. */
  1411. hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl);
  1412. }
  1413. }
  1414. /***************************************************
  1415. *
  1416. * End of hack for Sidewinder Gamepad.
  1417. *
  1418. ***************************************************/
  1419. #endif //#ifndef WINNT
  1420. }
  1421. return hres;
  1422. }
  1423. /* This never happens on NT */
  1424. /*****************************************************************************
  1425. *
  1426. * @doc INTERNAL
  1427. *
  1428. * @func HRESULT | JoyReg_JoyIdToDeviceInterface_95 |
  1429. *
  1430. * Given a joystick ID number, obtain the device interface
  1431. * corresponding to it.
  1432. *
  1433. * @parm UINT | idJoy |
  1434. *
  1435. * Joystick ID number, zero-based.
  1436. *
  1437. * @parm PVXDINITPARMS | pvip |
  1438. *
  1439. * Receives init parameters from the driver.
  1440. *
  1441. * @parm LPTSTR | ptszBuf |
  1442. *
  1443. * A buffer of size <c MAX_PATH> in which the device interface
  1444. * path is built. Note that we can get away with a buffer of
  1445. * this size, since the code path exists only on Windows 95,
  1446. * and Windows 95 does not support paths longer than <c MAX_PATH>.
  1447. * (I.e., there ain't no \\?\ support in Win95.)
  1448. *
  1449. * @returns
  1450. *
  1451. * A pointer to the part of the <p ptszBuf> buffer that
  1452. * contains the actual device interface path.
  1453. *
  1454. *****************************************************************************/
  1455. LPSTR EXTERNAL
  1456. JoyReg_JoyIdToDeviceInterface_95(UINT idJoy, PVXDINITPARMS pvip, LPSTR ptszBuf)
  1457. {
  1458. UINT cwch;
  1459. HRESULT hres;
  1460. LPSTR ptszRc;
  1461. if( fWinnt )
  1462. return NULL;
  1463. hres = Hel_Joy_GetInitParms(idJoy, pvip);
  1464. if(SUCCEEDED(hres))
  1465. {
  1466. /*
  1467. * The length counter includes the terminating null.
  1468. */
  1469. cwch = LOWORD(pvip->dwFilenameLengths);
  1470. /*
  1471. * The name that comes from HID is "\DosDevices\blah"
  1472. * but we want to use "\\.\blah". So check if it indeed
  1473. * of the form "\DosDevices\blah" and if so, convert it.
  1474. * If not, then give up.
  1475. *
  1476. * For the string to possibly be a "\DosDevices\", it
  1477. * needs to be of length 12 or longer.
  1478. */
  1479. if(cwch >= 12 && cwch < MAX_PATH)
  1480. {
  1481. /*
  1482. * WideCharToMultiByte does parameter validation so we
  1483. * don't have to.
  1484. */
  1485. WideCharToMultiByte(CP_ACP, 0, pvip->pFilenameBuffer, cwch,
  1486. ptszBuf, MAX_PATH, 0, 0);
  1487. /*
  1488. * The 11th (zero-based) character must be a backslash.
  1489. * And the value of cwch had better be right.
  1490. */
  1491. if(ptszBuf[cwch-1] == ('\0') && ptszBuf[11] == ('\\'))
  1492. {
  1493. /*
  1494. * Wipe out the backslash and make sure the lead-in
  1495. * is "\DosDevices".
  1496. */
  1497. ptszBuf[11] = ('\0');
  1498. if(lstrcmpiA(ptszBuf, ("\\DosDevices")) == 0)
  1499. {
  1500. /*
  1501. * Create a "\\.\" at the start of the string.
  1502. * Note! This code never runs on Alphas so we
  1503. * can do evil unaligned data accesses.
  1504. *
  1505. * (Actually, 8 is a multiple of 4, so everything
  1506. * is aligned after all.)
  1507. */
  1508. *(LPDWORD)&ptszBuf[8] = 0x5C2E5C5C;
  1509. ptszRc = &ptszBuf[8];
  1510. } else
  1511. {
  1512. ptszRc = NULL;
  1513. }
  1514. } else
  1515. {
  1516. ptszRc = NULL;
  1517. }
  1518. } else
  1519. {
  1520. ptszRc = NULL;
  1521. }
  1522. } else
  1523. {
  1524. ptszRc = NULL;
  1525. }
  1526. return ptszRc;
  1527. }
  1528. /*****************************************************************************
  1529. *
  1530. * @doc INTERNAL
  1531. *
  1532. * @func void | JoyReg_SetCalibration |
  1533. *
  1534. * Store information about a joystick's configuration,
  1535. * shadowing the information back into the HID side of
  1536. * things as well.
  1537. *
  1538. * @parm UINT | uiJoy |
  1539. *
  1540. * Joystick identification number.
  1541. *
  1542. * @parm LPJOYREGHWCONFIG | phwc |
  1543. *
  1544. * Contains information about the joystick capabilities.
  1545. * This value supercedes the value in the <p pcfg>.
  1546. *
  1547. * @parm LPCDIJOYCONFIG | pcfg |
  1548. *
  1549. * Contains information about the joystick configuration.
  1550. * The caller is assumed to have validated all fields.
  1551. *
  1552. *****************************************************************************/
  1553. STDMETHODIMP
  1554. TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid,
  1555. LPCTSTR ptszName, LPGUID pguidOut);
  1556. void EXTERNAL
  1557. JoyReg_SetCalibration(UINT idJoy, LPJOYREGHWCONFIG phwc)
  1558. {
  1559. HRESULT hres;
  1560. VXDINITPARMS vip;
  1561. GUID guid;
  1562. CHAR tsz[MAX_PATH];
  1563. LPSTR pszPath;
  1564. TCHAR ptszPath[MAX_PATH];
  1565. EnterProc(JoyReg_SetCalibration, (_ "up", idJoy, phwc));
  1566. pszPath = JoyReg_JoyIdToDeviceInterface_95(idJoy, &vip, tsz);
  1567. if( pszPath )
  1568. #ifdef UNICODE
  1569. AToU( ptszPath, MAX_PATH, pszPath );
  1570. #else
  1571. lstrcpy( (LPSTR)ptszPath, pszPath );
  1572. #endif
  1573. if(pszPath &&
  1574. SUCCEEDED(CDIObj_FindDeviceInternal(ptszPath, &guid)))
  1575. {
  1576. IDirectInputDeviceCallback *pdcb;
  1577. #ifdef DEBUG
  1578. CREATEDCB CreateDcb;
  1579. #endif
  1580. #ifdef DEBUG
  1581. /*
  1582. * If the associated HID device got unplugged, then
  1583. * the instance GUID is no more. So don't get upset
  1584. * if we can't find it. But if we do find it, then
  1585. * it had better be a HID device.
  1586. *
  1587. * CHid_New will properly fail if the associated
  1588. * device is not around.
  1589. */
  1590. hres = hresFindInstanceGUID(&guid, &CreateDcb, 1);
  1591. AssertF(fLimpFF(SUCCEEDED(hres), CreateDcb == CHid_New));
  1592. #endif
  1593. if(SUCCEEDED(hres = CHid_New(0, &guid,
  1594. &IID_IDirectInputDeviceCallback,
  1595. (PPV)&pdcb)))
  1596. {
  1597. LPDIDATAFORMAT pdf;
  1598. /*
  1599. * The VXDINITPARAMS structure tells us where JOYHID
  1600. * decided to place each of the axes. Follow that
  1601. * table to put them into their corresponding location
  1602. * in the HID side.
  1603. */
  1604. hres = pdcb->lpVtbl->GetDataFormat(pdcb, &pdf);
  1605. if(SUCCEEDED(hres))
  1606. {
  1607. UINT uiAxis;
  1608. DIPROPINFO propi;
  1609. propi.pguid = DIPROP_SPECIFICCALIBRATION;
  1610. /*
  1611. * For each axis...
  1612. */
  1613. for(uiAxis = 0; uiAxis < 6; uiAxis++)
  1614. {
  1615. DWORD dwUsage = vip.Usages[uiAxis];
  1616. /*
  1617. * If the axis is mapped to a usage...
  1618. */
  1619. if(dwUsage)
  1620. {
  1621. /*
  1622. * Convert the usage into an object index.
  1623. */
  1624. hres = pdcb->lpVtbl->MapUsage(pdcb, dwUsage,
  1625. &propi.iobj);
  1626. if(SUCCEEDED(hres))
  1627. {
  1628. DIPROPCAL cal;
  1629. /*
  1630. * Convert the old-style calibration into
  1631. * a new-style calibration.
  1632. */
  1633. #define CopyCalibration(f, ui) \
  1634. cal.l##f = (&phwc->hwv.jrvHardware.jp##f.dwX)[ui]
  1635. CopyCalibration(Min, uiAxis);
  1636. CopyCalibration(Max, uiAxis);
  1637. CopyCalibration(Center, uiAxis);
  1638. #undef CopyCalibration
  1639. /*
  1640. * Set the calibration property on the object.
  1641. */
  1642. propi.dwDevType =
  1643. pdf->rgodf[propi.iobj].dwType;
  1644. hres = pdcb->lpVtbl->SetProperty(pdcb, &propi,
  1645. &cal.diph);
  1646. }
  1647. }
  1648. }
  1649. }
  1650. Invoke_Release(&pdcb);
  1651. }
  1652. }
  1653. ExitProc();
  1654. }
  1655. /*****************************************************************************
  1656. *
  1657. * @doc INTERNAL
  1658. *
  1659. * @func HRESULT | JoyReg_SetHWConfig |
  1660. *
  1661. * Store information about a joystick's <t JOYREGHWCONFIG>.
  1662. *
  1663. * @parm UINT | uiJoy |
  1664. *
  1665. * Joystick identification number.
  1666. *
  1667. * @parm LPJOYREGHWCONFIG | phwc |
  1668. *
  1669. * Contains information about the joystick capabilities.
  1670. * This value supercedes the value in the <p pcfg>.
  1671. *
  1672. * @parm LPCDIJOYCONFIG | pcfg |
  1673. *
  1674. * Contains information about the joystick configuration.
  1675. * The caller is assumed to have validated all fields.
  1676. *
  1677. * @parm HKEY | hk |
  1678. *
  1679. * The type key we are munging.
  1680. *
  1681. *
  1682. * @returns
  1683. *
  1684. * Returns a COM error code. The following error codes are
  1685. * intended to be illustrative and not necessarily comprehensive.
  1686. *
  1687. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1688. *
  1689. *****************************************************************************/
  1690. HRESULT INTERNAL
  1691. JoyReg_SetHWConfig(UINT idJoy, LPJOYREGHWCONFIG phwc, LPCDIJOYCONFIG pcfg,
  1692. HKEY hk)
  1693. {
  1694. HRESULT hres;
  1695. HKEY hkSave;
  1696. DWORD dwSam;
  1697. /*
  1698. * The caller has set phwc->dwType, so use it to determine
  1699. * where the data comes from or goes to.
  1700. */
  1701. if( phwc->dwType == JOY_HW_NONE )
  1702. {
  1703. /*
  1704. * Nothing to do
  1705. */
  1706. } else if( phwc->dwType == JOY_HW_CUSTOM )
  1707. {
  1708. /* ISSUE-2001/03/29-timgill Custom HWConfig not handled correctly
  1709. * We don't know the type name and the only time we can look
  1710. * it up is when were modifying an existing config so although we
  1711. * could store the config, we'd never be able to get it back.
  1712. * Should return no better than S_FALSE. This will have to wait.
  1713. */
  1714. } else
  1715. {
  1716. /*
  1717. * Try to access saved values
  1718. */
  1719. // ISSUE-2001/03/29-timgill Dangerous type cast
  1720. PDWORD pdw = (PDWORD)&phwc->hwv;
  1721. dwSam = KEY_QUERY_VALUE;
  1722. while( pdw < &phwc->dwType )
  1723. {
  1724. if( *pdw )
  1725. {
  1726. /*
  1727. * Real config data so write it
  1728. */
  1729. dwSam = KEY_SET_VALUE;
  1730. break;
  1731. }
  1732. pdw++;
  1733. }
  1734. /*
  1735. * If the device is autoloaded and yet the user is manually assigning it
  1736. * to an ID, set the volatile flag. The flag will be set to the driver
  1737. * defined value if a driver ever gets hotplug assigned to this ID but if
  1738. * not, this makes sure that the settings are removed on next reboot.
  1739. */
  1740. if(phwc->hws.dwFlags & JOY_HWS_AUTOLOAD)
  1741. {
  1742. phwc->dwUsageSettings |= JOY_US_VOLATILE;
  1743. }
  1744. hres = JoyReg_OpenSaveKey( phwc->dwType, pcfg, dwSam, &hkSave );
  1745. if( SUCCEEDED(hres) )
  1746. {
  1747. if( dwSam == KEY_SET_VALUE )
  1748. {
  1749. hres = JoyReg_SetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG,
  1750. idJoy, REG_BINARY,
  1751. phwc, cbX(*phwc));
  1752. if( FAILED(hres) )
  1753. {
  1754. // Report the error but live with it
  1755. RPF("JoyReg_SetConfig: failed to set saved config %08x", hres );
  1756. }
  1757. } else
  1758. {
  1759. JOYREGHWCONFIG hwc;
  1760. /*
  1761. * Read it into an extra buffer because we only want it
  1762. * if it's complete.
  1763. */
  1764. hres = JoyReg_GetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG,
  1765. idJoy, REG_BINARY,
  1766. &hwc, cbX(hwc));
  1767. if( hres == S_OK )
  1768. {
  1769. // Assert hws is first and no gap before dwUsageSettings
  1770. CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, hws ) == 0 );
  1771. CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, dwUsageSettings ) == sizeof( hwc.hws ) );
  1772. // Copy the whole structure except the hws
  1773. memcpy( &phwc->dwUsageSettings, &hwc.dwUsageSettings,
  1774. sizeof( hwc ) - sizeof( hwc.hws ) );
  1775. }
  1776. }
  1777. RegCloseKey( hkSave );
  1778. }
  1779. /*
  1780. * If we failed to read, there's probably nothing there and the
  1781. * structure is set up already for a blank config.
  1782. * If we failed to write there probably not much we can do
  1783. */
  1784. }
  1785. hres = JoyReg_SetConfigValue(hk, REGSTR_VAL_JOYNCONFIG,
  1786. idJoy, REG_BINARY,
  1787. phwc, cbX(*phwc));
  1788. if(FAILED(hres))
  1789. {
  1790. goto done;
  1791. }
  1792. if(phwc->dwUsageSettings & JOY_US_ISOEM)
  1793. {
  1794. hres = JoyReg_SetConfigValue(
  1795. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  1796. pcfg->wszType, cbX(pcfg->wszType));
  1797. } else
  1798. {
  1799. hres = JoyReg_SetConfigValue(
  1800. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  1801. 0, 0);
  1802. }
  1803. done:;
  1804. return hres;
  1805. }
  1806. /*****************************************************************************
  1807. *
  1808. * @doc INTERNAL
  1809. *
  1810. * @func HRESULT | JoyReg_SetConfig |
  1811. *
  1812. * Store information about a joystick's configuration.
  1813. *
  1814. * @parm UINT | uiJoy |
  1815. *
  1816. * Joystick identification number.
  1817. *
  1818. * @parm JOYREGHWCONFIG | phwc |
  1819. *
  1820. * Contains information about the joystick capabilities.
  1821. * This value supercedes the value in the <p pcfg>.
  1822. * It may be modified if we needed to load the config
  1823. * info from the saved settings.
  1824. *
  1825. * @parm LPCDIJOYCONFIG | pcfg |
  1826. *
  1827. * Contains information about the joystick configuration.
  1828. * The caller is assumed to have validated all fields.
  1829. *
  1830. * @parm DWORD | fl |
  1831. *
  1832. * Zero or more <c DIJC_*> flags
  1833. * which specify which parts of the structures pointed
  1834. * to by <p phwc> and <p pjc> are to be written out.
  1835. *
  1836. * @returns
  1837. *
  1838. * Returns a COM error code. The following error codes are
  1839. * intended to be illustrative and not necessarily comprehensive.
  1840. *
  1841. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1842. *
  1843. *****************************************************************************/
  1844. JOYREGHWVALUES null_hwv = { 0};
  1845. STDMETHODIMP
  1846. JoyReg_SetConfig(UINT idJoy, LPJOYREGHWCONFIG phwc,
  1847. LPCDIJOYCONFIG pcfg, DWORD fl)
  1848. {
  1849. HRESULT hres;
  1850. EnterProc(JoyReg_SetConfig, (_ "uppx", idJoy, phwc, pcfg, fl));
  1851. AssertF((fl & ~DIJC_INTERNALSETVALID) == 0);
  1852. if(idJoy < cJoyMax )
  1853. {
  1854. if(fl & DIJC_INREGISTRY)
  1855. {
  1856. HKEY hk;
  1857. DWORD dwOptions = 0;
  1858. hres = JoyReg_OpenConfigKey(idJoy, KEY_SET_VALUE, NULL, dwOptions, &hk);
  1859. if(SUCCEEDED(hres))
  1860. {
  1861. if(fl & DIJC_REGHWCONFIGTYPE)
  1862. {
  1863. hres = JoyReg_SetHWConfig(idJoy, phwc, pcfg, hk);
  1864. if(FAILED(hres))
  1865. {
  1866. goto closedone;
  1867. }
  1868. if(fl & DIJC_UPDATEALIAS)
  1869. {
  1870. JoyReg_SetCalibration(idJoy, phwc);
  1871. }
  1872. }
  1873. if(fl & DIJC_CALLOUT)
  1874. {
  1875. hres = JoyReg_SetConfigValue(
  1876. hk, REGSTR_VAL_JOYNOEMCALLOUT, idJoy, REG_SZ,
  1877. pcfg->wszCallout, cbX(pcfg->wszCallout));
  1878. if(FAILED(hres))
  1879. {
  1880. hres = S_FALSE;
  1881. //continue to go
  1882. }
  1883. }
  1884. if(fl & DIJC_GAIN)
  1885. {
  1886. if(ISVALIDGAIN(pcfg->dwGain))
  1887. {
  1888. /*
  1889. * If restoring to nominal, then the key
  1890. * can be deleted; the default value will
  1891. * be assumed subsequently.
  1892. */
  1893. if(pcfg->dwGain == DI_FFNOMINALMAX)
  1894. {
  1895. hres = JoyReg_SetConfigValue(hk,
  1896. TEXT("Joystick%dFFConfiguration"),
  1897. idJoy, REG_SZ, 0, 0);
  1898. } else
  1899. {
  1900. hres = JoyReg_SetConfigValue(hk,
  1901. TEXT("Joystick%dFFConfiguration"),
  1902. idJoy, REG_BINARY,
  1903. &pcfg->dwGain, cbX(pcfg->dwGain));
  1904. }
  1905. if(FAILED(hres))
  1906. {
  1907. hres = S_FALSE;
  1908. goto closedone;
  1909. }
  1910. } else
  1911. {
  1912. RPF("ERROR: SetConfig: Invalid dwGain");
  1913. hres = E_INVALIDARG;
  1914. goto closedone;
  1915. }
  1916. }
  1917. hres = S_OK;
  1918. closedone:;
  1919. RegCloseKey(hk);
  1920. }
  1921. } else
  1922. {
  1923. hres = S_OK;
  1924. }
  1925. } else
  1926. {
  1927. hres = E_FAIL;
  1928. }
  1929. ExitOleProc();
  1930. return hres;
  1931. }
  1932. /*****************************************************************************
  1933. *
  1934. * @doc INTERNAL
  1935. *
  1936. * @func int | ibJoyPosAxis |
  1937. *
  1938. * Returns the offset of the <p iAxis>'th joystick axis
  1939. * in the <t JOYPOS> structure.
  1940. *
  1941. * @parm int | iAxis |
  1942. *
  1943. * The index of the requested axis. X, Y, Z, R, U and V are
  1944. * respctively zero through five.
  1945. *
  1946. * @returns
  1947. *
  1948. * The offset relative to the structure.
  1949. *
  1950. *****************************************************************************/
  1951. #define ibJoyPosAxis(iAxis) \
  1952. (FIELD_OFFSET(JOYPOS, dwX) + cbX(DWORD) * (iAxis)) \
  1953. #define pJoyValue(jp, i) \
  1954. (LPDWORD)pvAddPvCb(&(jp), ibJoyPosAxis(i)) \
  1955. /*
  1956. * The following doesn't do anything at runtime. It is a compile-time
  1957. * check that everything is okay.
  1958. */
  1959. void INLINE
  1960. JoyReg_CheckJoyPosAxis(void)
  1961. {
  1962. #define CheckAxis(x) \
  1963. CAssertF(ibJoyPosAxis(iJoyPosAxis##x) == FIELD_OFFSET(JOYPOS, dw##x))
  1964. CheckAxis(X);
  1965. CheckAxis(Y);
  1966. CheckAxis(Z);
  1967. CheckAxis(R);
  1968. CheckAxis(U);
  1969. CheckAxis(V);
  1970. #undef CheckAxis
  1971. }
  1972. /*****************************************************************************
  1973. *
  1974. * @doc INTERNAL
  1975. *
  1976. * @func HRESULT | JoyReg_IsValidUserValues |
  1977. *
  1978. * Retermine whether the values are ostensibly valid.
  1979. *
  1980. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  1981. *
  1982. * Contains information about the user joystick configuration.
  1983. *
  1984. * @returns
  1985. *
  1986. * Returns a COM error code. The following error codes are
  1987. * intended to be illustrative and not necessarily comprehensive.
  1988. *
  1989. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1990. *
  1991. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>:
  1992. * Something looks bad.
  1993. *
  1994. *****************************************************************************/
  1995. STDMETHODIMP
  1996. JoyReg_IsValidUserValues(LPCDIJOYUSERVALUES pjuv)
  1997. {
  1998. HRESULT hres;
  1999. int iAxis;
  2000. /*
  2001. * First set up the values to values that are out of range so
  2002. * that we will fall back to defaults.
  2003. */
  2004. for(iAxis = 0; iAxis < cJoyPosAxisMax; iAxis++)
  2005. {
  2006. if((int)*pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis) < 0)
  2007. {
  2008. RPF("JOYUSERVALUES: Negative jpMax not a good idea");
  2009. goto bad;
  2010. }
  2011. if(*pJoyValue(pjuv->ruv.jrvRanges.jpMin, iAxis) >
  2012. *pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis))
  2013. {
  2014. RPF("JOYUSERVALUES: Min > Max not a good idea");
  2015. goto bad;
  2016. }
  2017. if(!fInOrder(0, *pJoyValue(pjuv->ruv.jpDeadZone, iAxis), 100))
  2018. {
  2019. RPF("JOYUSERVALUES: DeadZone > 100 not a good idea");
  2020. goto bad;
  2021. }
  2022. }
  2023. hres = S_OK;
  2024. return hres;
  2025. bad:;
  2026. hres = E_INVALIDARG;
  2027. return hres;
  2028. }
  2029. /*****************************************************************************
  2030. *
  2031. * @doc INTERNAL
  2032. *
  2033. * @func HRESULT | JoyReg_GetUserValues |
  2034. *
  2035. * Obtain information about user settings for the joystick.
  2036. *
  2037. *
  2038. * @parm IN OUT LPDIJOYUSERVALUES | pjuv |
  2039. *
  2040. * Receives information about the user joystick configuration.
  2041. * The caller is assumed to have validated the
  2042. * <e DIJOYUSERVALUES.dwSize> field.
  2043. *
  2044. * @parm DWORD | fl |
  2045. *
  2046. * Zero or more <c DIJU_*> flags specifying which parts
  2047. * of the <t DIJOYUSERVALUES> structure contain values
  2048. * which are to be retrieved.
  2049. *
  2050. * @returns
  2051. *
  2052. * Returns a COM error code. The following error codes are
  2053. * intended to be illustrative and not necessarily comprehensive.
  2054. *
  2055. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2056. *
  2057. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2058. * parameters was invalid.
  2059. *
  2060. *****************************************************************************/
  2061. STDMETHODIMP
  2062. JoyReg_GetUserValues(LPDIJOYUSERVALUES pjuv, DWORD fl)
  2063. {
  2064. HRESULT hres;
  2065. HKEY hk;
  2066. LONG lRc;
  2067. EnterProc(JoyReg_GetUserValues, (_ "px", pjuv, fl));
  2068. hres = S_OK; /* If nothing happens, then success */
  2069. if(fl & DIJU_USERVALUES)
  2070. {
  2071. /*
  2072. * Okay, now get the user settings.
  2073. *
  2074. * If anything goes wrong, then just limp with the default values.
  2075. */
  2076. lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG,
  2077. 0, KEY_QUERY_VALUE, &hk);
  2078. if(lRc == ERROR_SUCCESS)
  2079. {
  2080. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYUSERVALUES,
  2081. REG_BINARY, &pjuv->ruv, cbX(pjuv->ruv));
  2082. if(SUCCEEDED(hres))
  2083. {
  2084. /*
  2085. * Sanity-check the values. If anything is screwy,
  2086. * then fall back to the defaults.
  2087. */
  2088. hres = JoyReg_IsValidUserValues(pjuv);
  2089. }
  2090. if(FAILED(hres))
  2091. {
  2092. /*
  2093. * Oh well. Just use the default values, then.
  2094. *
  2095. * Stolen from ibmjoy\msjstick.c.
  2096. */
  2097. ZeroMemory(&pjuv->ruv, cbX(pjuv->ruv));
  2098. #define DEFAULT_RANGE_MAX 65535
  2099. #define DEFAULT_TIMEOUT 5000
  2100. #define DEFAULT_DEADZONE 5
  2101. pjuv->ruv.jrvRanges.jpMax.dwX = DEFAULT_RANGE_MAX;
  2102. pjuv->ruv.jrvRanges.jpMax.dwY = DEFAULT_RANGE_MAX;
  2103. pjuv->ruv.jrvRanges.jpMax.dwZ = DEFAULT_RANGE_MAX;
  2104. pjuv->ruv.jrvRanges.jpMax.dwR = DEFAULT_RANGE_MAX;
  2105. pjuv->ruv.jrvRanges.jpMax.dwU = DEFAULT_RANGE_MAX;
  2106. pjuv->ruv.jrvRanges.jpMax.dwV = DEFAULT_RANGE_MAX;
  2107. pjuv->ruv.jpDeadZone.dwX = DEFAULT_DEADZONE;
  2108. pjuv->ruv.jpDeadZone.dwY = DEFAULT_DEADZONE;
  2109. pjuv->ruv.dwTimeOut = DEFAULT_TIMEOUT;
  2110. }
  2111. RegCloseKey(hk);
  2112. }
  2113. }
  2114. if(fl & DIJU_INDRIVERREGISTRY)
  2115. {
  2116. hres = JoyReg_OpenConfigKey((UINT)-1, KEY_QUERY_VALUE, NULL, FALSE, &hk);
  2117. if(SUCCEEDED(hres))
  2118. {
  2119. if(fl & DIJU_GLOBALDRIVER)
  2120. {
  2121. LONG lRc;
  2122. /*
  2123. * If it doesn't work, then return the default value
  2124. * of "MSANALOG.VXD". We can't blindly use
  2125. * JoyReg_GetValue, because that treats a nonexistent
  2126. * value as having a default of the null string.
  2127. */
  2128. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2129. 0, 0, 0, 0);
  2130. if((lRc == ERROR_SUCCESS || lRc == ERROR_MORE_DATA) &&
  2131. SUCCEEDED(
  2132. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2133. REG_SZ, pjuv->wszGlobalDriver,
  2134. cbX(pjuv->wszGlobalDriver))))
  2135. {
  2136. /* Yay, it worked */
  2137. } else
  2138. {
  2139. CopyMemory(pjuv->wszGlobalDriver,
  2140. c_wszDefPortDriver,
  2141. cbX(c_wszDefPortDriver));
  2142. }
  2143. }
  2144. if(fl & DIJU_GAMEPORTEMULATOR)
  2145. {
  2146. /*
  2147. * If it doesn't work, then just return a null string.
  2148. */
  2149. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR,
  2150. REG_SZ, pjuv->wszGameportEmulator,
  2151. cbX(pjuv->wszGameportEmulator));
  2152. if(FAILED(hres))
  2153. {
  2154. pjuv->wszGameportEmulator[0] = TEXT('\0');
  2155. }
  2156. }
  2157. RegCloseKey(hk);
  2158. }
  2159. }
  2160. /*
  2161. * Warning! CJoy_InitRanges() assumes this never fails.
  2162. */
  2163. hres = S_OK;
  2164. ExitOleProcR();
  2165. return hres;
  2166. }
  2167. /*****************************************************************************
  2168. *
  2169. * @doc INTERNAL
  2170. *
  2171. * @func HRESULT | JoyReg_SetUserValues |
  2172. *
  2173. * Store information about user settings for the joystick.
  2174. *
  2175. *
  2176. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  2177. *
  2178. * Contains information about the user joystick configuration.
  2179. * The caller is assumed to have validated the
  2180. * <e DIJOYUSERVALUES.dwSize> field.
  2181. *
  2182. * @parm DWORD | fl |
  2183. *
  2184. * Zero or more <c DIJU_*> flags specifying which parts
  2185. * of the <t DIJOYUSERVALUES> structure contain values
  2186. * which are to be set.
  2187. *
  2188. * @returns
  2189. *
  2190. * Returns a COM error code. The following error codes are
  2191. * intended to be illustrative and not necessarily comprehensive.
  2192. *
  2193. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2194. *
  2195. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2196. * parameters was invalid.
  2197. *
  2198. *****************************************************************************/
  2199. STDMETHODIMP
  2200. JoyReg_SetUserValues(LPCDIJOYUSERVALUES pjuv, DWORD fl)
  2201. {
  2202. HRESULT hres = E_FAIL;
  2203. HKEY hk;
  2204. EnterProc(JoyReg_SetUserValues, (_ "px", pjuv, fl));
  2205. if(fl & DIJU_USERVALUES)
  2206. {
  2207. /*
  2208. * See if the values are sane.
  2209. */
  2210. if(fl & DIJU_USERVALUES)
  2211. {
  2212. hres = JoyReg_IsValidUserValues(pjuv);
  2213. if(FAILED(hres))
  2214. {
  2215. goto done;
  2216. }
  2217. }
  2218. /*
  2219. * Off to the registry we go.
  2220. */
  2221. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  2222. REGSTR_PATH_JOYCONFIG,
  2223. DI_KEY_ALL_ACCESS,
  2224. REG_OPTION_NON_VOLATILE,
  2225. &hk);
  2226. if(SUCCEEDED(hres))
  2227. {
  2228. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYUSERVALUES,
  2229. REG_BINARY, &pjuv->ruv,
  2230. cbX(pjuv->ruv));
  2231. RegCloseKey(hk);
  2232. if(FAILED(hres))
  2233. {
  2234. goto done;
  2235. }
  2236. } else
  2237. {
  2238. goto done;
  2239. }
  2240. }
  2241. if(fl & DIJU_INDRIVERREGISTRY)
  2242. {
  2243. hres = JoyReg_OpenConfigKey((UINT)-1, KEY_SET_VALUE, NULL, FALSE, &hk);
  2244. if(SUCCEEDED(hres))
  2245. {
  2246. if(fl & DIJU_GLOBALDRIVER)
  2247. {
  2248. /*
  2249. * This is a weird key. The default value is
  2250. * "MSANALOG.VXD", so if we get a null string, we
  2251. * can't use JoyReg_SetValue, because that will
  2252. * delete the key.
  2253. */
  2254. if(pjuv->wszGlobalDriver[0])
  2255. {
  2256. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2257. REG_SZ, pjuv->wszGlobalDriver,
  2258. cbX(pjuv->wszGlobalDriver));
  2259. } else
  2260. {
  2261. LONG lRc;
  2262. lRc = RegSetValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT, 0,
  2263. REG_SZ, (PV)TEXT(""), cbCtch(1));
  2264. if(lRc == ERROR_SUCCESS)
  2265. {
  2266. hres = S_OK;
  2267. } else
  2268. {
  2269. RPF("Unable to write %s to registry",
  2270. REGSTR_VAL_JOYOEMCALLOUT);
  2271. hres = E_FAIL; /* Else, something bad happened */
  2272. }
  2273. }
  2274. if(FAILED(hres))
  2275. {
  2276. goto regdone;
  2277. }
  2278. }
  2279. if(fl & DIJU_GAMEPORTEMULATOR)
  2280. {
  2281. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR,
  2282. REG_SZ, pjuv->wszGameportEmulator,
  2283. cbX(pjuv->wszGameportEmulator));
  2284. if(FAILED(hres))
  2285. {
  2286. goto regdone;
  2287. }
  2288. }
  2289. regdone:;
  2290. RegCloseKey(hk);
  2291. } else
  2292. {
  2293. goto done;
  2294. }
  2295. }
  2296. done:;
  2297. ExitOleProcR();
  2298. return hres;
  2299. }
  2300. /*****************************************************************************
  2301. *
  2302. * @doc INTERNAL
  2303. *
  2304. * @func HRESULT | JoyReg_OpenFFKey |
  2305. *
  2306. * Given a type key, move to its force feedback subkey.
  2307. *
  2308. * @parm HKEY | hkType |
  2309. *
  2310. * The parent type key.
  2311. *
  2312. * @parm REGSAM | sam |
  2313. *
  2314. * Access level desired.
  2315. *
  2316. * @parm PHKEY | phk |
  2317. *
  2318. * Receives created registry key.
  2319. *
  2320. * @returns
  2321. *
  2322. * Returns a COM error code. The following error codes are
  2323. * intended to be illustrative and not necessarily comprehensive.
  2324. *
  2325. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2326. *
  2327. * <c DIERR_NOTFOUND>: Couldn't open the key.
  2328. *
  2329. *****************************************************************************/
  2330. STDMETHODIMP
  2331. JoyReg_OpenFFKey(HKEY hkType, REGSAM sam, PHKEY phk)
  2332. {
  2333. HRESULT hres;
  2334. EnterProc(JoyReg_OpenFFKey, (_ "xx", hkType, sam));
  2335. *phk = 0;
  2336. if(hkType)
  2337. {
  2338. if(RegOpenKeyEx(hkType, TEXT("OEMForceFeedback"), 0, sam, phk) == 0)
  2339. {
  2340. hres = S_OK;
  2341. } else
  2342. {
  2343. hres = E_FAIL;
  2344. }
  2345. } else
  2346. {
  2347. hres = DIERR_NOTFOUND;
  2348. }
  2349. ExitBenignOleProc();
  2350. return hres;
  2351. }
  2352. /*****************************************************************************
  2353. *
  2354. * @doc INTERNAL
  2355. *
  2356. * @func TCHAR | CJoyCfg_CharFromType |
  2357. *
  2358. * Convert a predefined type number to a character.
  2359. *
  2360. * @func UINT | CJoyCfg_TypeFromChar |
  2361. *
  2362. * Convert a character back to a predefined type number.
  2363. *
  2364. *****************************************************************************/
  2365. #define JoyCfg_CharFromType(t) ((TCHAR)(L'0' + t))
  2366. #define JoyCfg_TypeFromChar(tch) ((tch) - L'0')
  2367. /*****************************************************************************
  2368. *
  2369. * @doc EXTERNAL
  2370. *
  2371. * @func HRESULT | JoyReg_GetPredefTypeInfo |
  2372. *
  2373. * Obtain information about a predefined joystick type.
  2374. *
  2375. * @parm LPCWSTR | pwszType |
  2376. *
  2377. * Points to the name of the type. It is known to begin
  2378. * with a "#". The remainder has not yet been parsed.
  2379. *
  2380. * @parm IN OUT LPDIJOYTYPEINFO | pjti |
  2381. *
  2382. * Receives information about the joystick type,
  2383. * already validated.
  2384. *
  2385. * @parm DWORD | dwFlags |
  2386. *
  2387. * Zero or more <c DITC_*> flags
  2388. * which specify which parts of the structure pointed
  2389. * to by <p pjti> are to be filled in.
  2390. *
  2391. * @returns
  2392. *
  2393. * Returns a COM error code. The following error codes are
  2394. * intended to be illustrative and not necessarily comprehensive.
  2395. *
  2396. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2397. *
  2398. * <c DIERR_NOTFOUND>: The joystick type was not found.
  2399. *
  2400. *****************************************************************************/
  2401. HRESULT EXTERNAL
  2402. JoyReg_GetPredefTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl)
  2403. {
  2404. HRESULT hres;
  2405. UINT itype;
  2406. EnterProcI(JoyReg_GetPredefTypeInfo, (_ "Wpx", pwszType, pjti, fl));
  2407. //(MarcAnd) These TEXT('blah') things should be L'blah' as the string is always wide
  2408. AssertF(pwszType[0] == TEXT('#'));
  2409. itype = JoyCfg_TypeFromChar(pwszType[1]);
  2410. if(fInOrder(JOY_HW_PREDEFMIN, itype, JOY_HW_PREDEFMAX) &&
  2411. pwszType[2] == TEXT('\0'))
  2412. {
  2413. /*
  2414. * No real point in checking the bits in fl, since
  2415. * setting it up is so easy.
  2416. */
  2417. pjti->hws = c_rghwsPredef[itype - JOY_HW_PREDEFMIN];
  2418. LoadStringW(g_hinst, IDS_PREDEFJOYTYPE + itype,
  2419. pjti->wszDisplayName, cA(pjti->wszDisplayName));
  2420. pjti->wszCallout[0] = TEXT('\0');
  2421. ZeroX(pjti->clsidConfig);
  2422. if(fl & DITC_FLAGS1 )
  2423. {
  2424. pjti->dwFlags1 = 0x0;
  2425. }
  2426. if( fl & DITC_HARDWAREID )
  2427. {
  2428. lstrcpyW(pjti->wszHardwareId, c_rghwIdPredef[itype-JOY_HW_PREDEFMIN] );
  2429. }
  2430. hres = S_OK;
  2431. } else
  2432. {
  2433. hres = DIERR_NOTFOUND;
  2434. }
  2435. ExitOleProc();
  2436. return hres;
  2437. }
  2438. #if 0 //don't delete it now.
  2439. /*****************************************************************************
  2440. *
  2441. * @doc INTERNAL
  2442. *
  2443. * @func HRESULT | JoyCfg_GetIDByOemName |
  2444. *
  2445. * Get the Id by OEMNAME
  2446. *
  2447. * @parm IN LPTSTR | szOEMNAME |
  2448. *
  2449. * String used to find the ID.
  2450. *
  2451. * @parm IN LPUNIT | lpID |
  2452. *
  2453. * The ID to get.
  2454. *
  2455. * @returns
  2456. *
  2457. * A COM success code unless the current configuration key could not
  2458. * be opened, or could not find the OEMNAME.
  2459. *
  2460. *****************************************************************************/
  2461. HRESULT EXTERNAL JoyReg_GetIDByOemName( LPTSTR szOemName, PUINT pId )
  2462. {
  2463. HRESULT hres = E_FAIL;
  2464. LONG lRc;
  2465. HKEY hkCurrCfg;
  2466. UINT JoyId;
  2467. TCHAR szTestName[MAX_JOYSTRING];
  2468. TCHAR szOemNameKey[MAX_JOYSTRING];
  2469. DWORD cb;
  2470. EnterProcI(JoyReg_GetIDByOemName, (_ "sp", szOemName, pId ));
  2471. hres = JoyReg_OpenConfigKey( (UINT)(-1), KEY_WRITE, NULL, REG_OPTION_NON_VOLATILE, &hkCurrCfg );
  2472. if( SUCCEEDED( hres ) )
  2473. {
  2474. for( JoyId = 0; (JoyId < 16) || ( lRc == ERROR_SUCCESS ); JoyId++ )
  2475. {
  2476. wsprintf( szOemNameKey, REGSTR_VAL_JOYNOEMNAME, JoyId+1 );
  2477. cb = sizeof( szTestName );
  2478. lRc = RegQueryValueEx( hkCurrCfg, szOemNameKey, 0, NULL, (PBYTE)szTestName, &cb );
  2479. if( lRc == ERROR_SUCCESS )
  2480. {
  2481. if( !lstrcmpi( szOemName, szTestName ) )
  2482. {
  2483. *pId = JoyId;
  2484. pId ++;
  2485. hres = S_OK;
  2486. break;
  2487. }
  2488. }
  2489. }
  2490. }
  2491. else
  2492. {
  2493. SquirtSqflPtszV(sqfl | sqflError,
  2494. TEXT("JoyReg_OpenConfigKey failed code 0x%08x"), hres );
  2495. }
  2496. ExitOleProc();
  2497. return hres;
  2498. } /* JoyReg_GetIDByOemName */
  2499. #endif