Leaked source code of windows server 2003
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.

2851 lines
84 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. pcfg->dwGain = DI_FFNOMINALMAX;
  1256. hres = S_FALSE;
  1257. }
  1258. }
  1259. if( fl & DIJC_WDMGAMEPORT )
  1260. {
  1261. PBUSDEVICEINFO pbdi;
  1262. /*
  1263. * If there is no Gameport Associated with this device
  1264. * then it must be a USB device
  1265. */
  1266. DllEnterCrit();
  1267. if( pbdi = pbdiFromJoyId(idJoy) )
  1268. {
  1269. pcfg->guidGameport = pbdi->guid;
  1270. //lstrcpyW(pcfg->wszGameport, pbdi->wszDisplayName);
  1271. } else
  1272. {
  1273. ZeroX(pcfg->guidGameport);
  1274. hres = S_FALSE;
  1275. }
  1276. DllLeaveCrit();
  1277. }
  1278. }
  1279. closedone:
  1280. if( FAILED(hres) ) {
  1281. DIJOYTYPEINFO dijti;
  1282. AssertF( pcfg->dwSize == sizeof(DIJOYCONFIG_DX5)
  1283. || pcfg->dwSize == sizeof(DIJOYCONFIG_DX6) );
  1284. hres = DIWdm_JoyHidMapping(idJoy, NULL, pcfg, &dijti );
  1285. if( FAILED(hres) ) {
  1286. hres = E_FAIL;
  1287. }
  1288. }
  1289. RegCloseKey(hk);
  1290. }
  1291. } else
  1292. {
  1293. hres = DIERR_NOMOREITEMS;
  1294. }
  1295. done:
  1296. ExitBenignOleProc();
  1297. return hres;
  1298. }
  1299. /*****************************************************************************
  1300. *
  1301. * @doc INTERNAL
  1302. *
  1303. * @func HRESULT | JoyReg_GetConfig |
  1304. *
  1305. * Obtain information about a joystick's configuration,
  1306. * taking the MSGAME.VXD driver into account.
  1307. *
  1308. * @parm UINT | uiJoy |
  1309. *
  1310. * Joystick identification number.
  1311. *
  1312. * @parm PJOYCAPS | pcaps |
  1313. *
  1314. * Receives information about the joystick capabilities.
  1315. * If this parameter is <c NULL>, then joystick
  1316. * capabilities information is not returned.
  1317. *
  1318. * @parm OUT LPDIJOYCONFIG | pcfg |
  1319. *
  1320. * Receives information about the joystick configuration.
  1321. * The caller is assumed to have validated the
  1322. * <e DIJOYCONFIG.dwSize> field.
  1323. *
  1324. * @parm DWORD | fl |
  1325. *
  1326. * Zero or more <c DIJC_*> flags
  1327. * which specify which parts of the structure pointed
  1328. * to by <p pjc> are to be filled in.
  1329. *
  1330. * @returns
  1331. *
  1332. * Returns a COM error code. The following error codes are
  1333. * intended to be illustrative and not necessarily comprehensive.
  1334. *
  1335. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1336. *
  1337. * <c DIERR_NOMOREITEMS>: No more joysticks.
  1338. *
  1339. *****************************************************************************/
  1340. STDMETHODIMP
  1341. JoyReg_GetConfig(UINT idJoy, PJOYCAPS pcaps, LPDIJOYCONFIG pcfg, DWORD fl)
  1342. {
  1343. HRESULT hres;
  1344. GUID guid;
  1345. EnterProc(JoyReg_GetConfig, (_ "upx", idJoy, pcaps, pcfg, fl));
  1346. AssertF((fl & ~DIJC_GETVALID) == 0);
  1347. /*
  1348. * First determine if the joystick exits
  1349. * On NT, we use WDM driver.
  1350. * On Win9x, if WDM fails, use static guids.
  1351. */
  1352. hres = hResIdJoypInstanceGUID_WDM(idJoy, &guid);
  1353. if( (hres != S_OK) && !fWinnt ) {
  1354. hres = hResIdJoypInstanceGUID_95(idJoy, &guid);
  1355. }
  1356. if( SUCCEEDED( hres) )
  1357. {
  1358. hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl);
  1359. #ifndef WINNT
  1360. /***************************************************
  1361. *
  1362. * Beginning of hack for Sidewinder Gamepad.
  1363. *
  1364. * The gamepad needs to be polled six times before
  1365. * it realizes what is going on.
  1366. *
  1367. ***************************************************/
  1368. if(SUCCEEDED(hres) && (fl & DIJC_CALLOUT))
  1369. {
  1370. static WCHAR s_wszMSGAME[] = L"MSGAME.VXD";
  1371. if(memcmp(pcfg->wszCallout, s_wszMSGAME, cbX(s_wszMSGAME)) == 0)
  1372. {
  1373. JOYINFOEX ji;
  1374. int i;
  1375. DWORD dwWait;
  1376. SquirtSqflPtszV(sqfl,
  1377. TEXT("Making bonus polls for Sidewinder"));
  1378. /*
  1379. * It's a Sidewinder. Make six
  1380. * bonus polls to shake the stick into submission.
  1381. *
  1382. * Actually, we make 16 bonus polls. The Sidewinder
  1383. * guys said that five or six would be enough.
  1384. * They're wrong.
  1385. *
  1386. * I also sleep 10ms between each poll because that
  1387. * seems to help a bit.
  1388. */
  1389. ji.dwSize = cbX(ji);
  1390. ji.dwFlags = JOY_RETURNALL;
  1391. for(i = 0; i < 16; i++)
  1392. {
  1393. MMRESULT mmrc = joyGetPosEx(idJoy, &ji);
  1394. SquirtSqflPtszV(sqfl,
  1395. TEXT("joyGetPosEx(%d) = %d"),
  1396. idJoy, mmrc);
  1397. Sleep(10);
  1398. }
  1399. /*
  1400. * Now sleep for some time. They forgot to tell us
  1401. * this.
  1402. *
  1403. * Bonus hack! The amount of time we need to sleep
  1404. * is CPU-speed dependent, so we'll grab the sleep
  1405. * time from the registry to allow us to tweak it
  1406. * later.
  1407. *
  1408. * What a bunch of lamers.
  1409. */
  1410. dwWait = RegQueryDIDword(NULL, REGSTR_VAL_GAMEPADDELAY, 100);
  1411. if(dwWait > 10 * 1000)
  1412. {
  1413. dwWait = 10 * 1000;
  1414. }
  1415. Sleep(dwWait);
  1416. /*
  1417. * And then check again.
  1418. */
  1419. hres = JoyReg_GetConfigInternal(idJoy, pcaps, pcfg, fl);
  1420. }
  1421. }
  1422. /***************************************************
  1423. *
  1424. * End of hack for Sidewinder Gamepad.
  1425. *
  1426. ***************************************************/
  1427. #endif //#ifndef WINNT
  1428. }
  1429. return hres;
  1430. }
  1431. /* This never happens on NT */
  1432. /*****************************************************************************
  1433. *
  1434. * @doc INTERNAL
  1435. *
  1436. * @func HRESULT | JoyReg_JoyIdToDeviceInterface_95 |
  1437. *
  1438. * Given a joystick ID number, obtain the device interface
  1439. * corresponding to it.
  1440. *
  1441. * @parm UINT | idJoy |
  1442. *
  1443. * Joystick ID number, zero-based.
  1444. *
  1445. * @parm PVXDINITPARMS | pvip |
  1446. *
  1447. * Receives init parameters from the driver.
  1448. *
  1449. * @parm LPTSTR | ptszBuf |
  1450. *
  1451. * A buffer of size <c MAX_PATH> in which the device interface
  1452. * path is built. Note that we can get away with a buffer of
  1453. * this size, since the code path exists only on Windows 95,
  1454. * and Windows 95 does not support paths longer than <c MAX_PATH>.
  1455. * (I.e., there ain't no \\?\ support in Win95.)
  1456. *
  1457. * @returns
  1458. *
  1459. * A pointer to the part of the <p ptszBuf> buffer that
  1460. * contains the actual device interface path.
  1461. *
  1462. *****************************************************************************/
  1463. LPSTR EXTERNAL
  1464. JoyReg_JoyIdToDeviceInterface_95(UINT idJoy, PVXDINITPARMS pvip, LPSTR ptszBuf)
  1465. {
  1466. UINT cwch;
  1467. HRESULT hres;
  1468. LPSTR ptszRc;
  1469. if( fWinnt )
  1470. return NULL;
  1471. hres = Hel_Joy_GetInitParms(idJoy, pvip);
  1472. if(SUCCEEDED(hres))
  1473. {
  1474. /*
  1475. * The length counter includes the terminating null.
  1476. */
  1477. cwch = LOWORD(pvip->dwFilenameLengths);
  1478. /*
  1479. * The name that comes from HID is "\DosDevices\blah"
  1480. * but we want to use "\\.\blah". So check if it indeed
  1481. * of the form "\DosDevices\blah" and if so, convert it.
  1482. * If not, then give up.
  1483. *
  1484. * For the string to possibly be a "\DosDevices\", it
  1485. * needs to be of length 12 or longer.
  1486. */
  1487. if(cwch >= 12 && cwch < MAX_PATH)
  1488. {
  1489. /*
  1490. * WideCharToMultiByte does parameter validation so we
  1491. * don't have to.
  1492. */
  1493. WideCharToMultiByte(CP_ACP, 0, pvip->pFilenameBuffer, cwch,
  1494. ptszBuf, MAX_PATH, 0, 0);
  1495. /*
  1496. * The 11th (zero-based) character must be a backslash.
  1497. * And the value of cwch had better be right.
  1498. */
  1499. if(ptszBuf[cwch-1] == ('\0') && ptszBuf[11] == ('\\'))
  1500. {
  1501. /*
  1502. * Wipe out the backslash and make sure the lead-in
  1503. * is "\DosDevices".
  1504. */
  1505. ptszBuf[11] = ('\0');
  1506. if(lstrcmpiA(ptszBuf, ("\\DosDevices")) == 0)
  1507. {
  1508. /*
  1509. * Create a "\\.\" at the start of the string.
  1510. * Note! This code never runs on Alphas so we
  1511. * can do evil unaligned data accesses.
  1512. *
  1513. * (Actually, 8 is a multiple of 4, so everything
  1514. * is aligned after all.)
  1515. */
  1516. *(LPDWORD)&ptszBuf[8] = 0x5C2E5C5C;
  1517. ptszRc = &ptszBuf[8];
  1518. } else
  1519. {
  1520. ptszRc = NULL;
  1521. }
  1522. } else
  1523. {
  1524. ptszRc = NULL;
  1525. }
  1526. } else
  1527. {
  1528. ptszRc = NULL;
  1529. }
  1530. } else
  1531. {
  1532. ptszRc = NULL;
  1533. }
  1534. return ptszRc;
  1535. }
  1536. /*****************************************************************************
  1537. *
  1538. * @doc INTERNAL
  1539. *
  1540. * @func void | JoyReg_SetCalibration |
  1541. *
  1542. * Store information about a joystick's configuration,
  1543. * shadowing the information back into the HID side of
  1544. * things as well.
  1545. *
  1546. * @parm UINT | uiJoy |
  1547. *
  1548. * Joystick identification number.
  1549. *
  1550. * @parm LPJOYREGHWCONFIG | phwc |
  1551. *
  1552. * Contains information about the joystick capabilities.
  1553. * This value supercedes the value in the <p pcfg>.
  1554. *
  1555. * @parm LPCDIJOYCONFIG | pcfg |
  1556. *
  1557. * Contains information about the joystick configuration.
  1558. * The caller is assumed to have validated all fields.
  1559. *
  1560. *****************************************************************************/
  1561. STDMETHODIMP
  1562. TFORM(CDIObj_FindDevice)(PV pdiT, REFGUID rguid,
  1563. LPCTSTR ptszName, LPGUID pguidOut);
  1564. void EXTERNAL
  1565. JoyReg_SetCalibration(UINT idJoy, LPJOYREGHWCONFIG phwc)
  1566. {
  1567. HRESULT hres;
  1568. VXDINITPARMS vip;
  1569. GUID guid;
  1570. CHAR tsz[MAX_PATH];
  1571. LPSTR pszPath;
  1572. TCHAR ptszPath[MAX_PATH];
  1573. EnterProc(JoyReg_SetCalibration, (_ "up", idJoy, phwc));
  1574. pszPath = JoyReg_JoyIdToDeviceInterface_95(idJoy, &vip, tsz);
  1575. if( pszPath )
  1576. #ifdef UNICODE
  1577. AToU( ptszPath, MAX_PATH, pszPath );
  1578. #else
  1579. lstrcpy( (LPSTR)ptszPath, pszPath );
  1580. #endif
  1581. if(pszPath &&
  1582. SUCCEEDED(CDIObj_FindDeviceInternal(ptszPath, &guid)))
  1583. {
  1584. IDirectInputDeviceCallback *pdcb;
  1585. #ifdef DEBUG
  1586. CREATEDCB CreateDcb;
  1587. #endif
  1588. #ifdef DEBUG
  1589. /*
  1590. * If the associated HID device got unplugged, then
  1591. * the instance GUID is no more. So don't get upset
  1592. * if we can't find it. But if we do find it, then
  1593. * it had better be a HID device.
  1594. *
  1595. * CHid_New will properly fail if the associated
  1596. * device is not around.
  1597. */
  1598. hres = hresFindInstanceGUID(&guid, &CreateDcb, 1);
  1599. AssertF(fLimpFF(SUCCEEDED(hres), CreateDcb == CHid_New));
  1600. #endif
  1601. if(SUCCEEDED(hres = CHid_New(0, &guid,
  1602. &IID_IDirectInputDeviceCallback,
  1603. (PPV)&pdcb)))
  1604. {
  1605. LPDIDATAFORMAT pdf;
  1606. /*
  1607. * The VXDINITPARAMS structure tells us where JOYHID
  1608. * decided to place each of the axes. Follow that
  1609. * table to put them into their corresponding location
  1610. * in the HID side.
  1611. */
  1612. hres = pdcb->lpVtbl->GetDataFormat(pdcb, &pdf);
  1613. if(SUCCEEDED(hres))
  1614. {
  1615. UINT uiAxis;
  1616. DIPROPINFO propi;
  1617. propi.pguid = DIPROP_SPECIFICCALIBRATION;
  1618. /*
  1619. * For each axis...
  1620. */
  1621. for(uiAxis = 0; uiAxis < 6; uiAxis++)
  1622. {
  1623. DWORD dwUsage = vip.Usages[uiAxis];
  1624. /*
  1625. * If the axis is mapped to a usage...
  1626. */
  1627. if(dwUsage)
  1628. {
  1629. /*
  1630. * Convert the usage into an object index.
  1631. */
  1632. hres = pdcb->lpVtbl->MapUsage(pdcb, dwUsage,
  1633. &propi.iobj);
  1634. if(SUCCEEDED(hres))
  1635. {
  1636. DIPROPCAL cal;
  1637. /*
  1638. * Convert the old-style calibration into
  1639. * a new-style calibration.
  1640. */
  1641. #define CopyCalibration(f, ui) \
  1642. cal.l##f = (&phwc->hwv.jrvHardware.jp##f.dwX)[ui]
  1643. CopyCalibration(Min, uiAxis);
  1644. CopyCalibration(Max, uiAxis);
  1645. CopyCalibration(Center, uiAxis);
  1646. #undef CopyCalibration
  1647. /*
  1648. * Set the calibration property on the object.
  1649. */
  1650. propi.dwDevType =
  1651. pdf->rgodf[propi.iobj].dwType;
  1652. hres = pdcb->lpVtbl->SetProperty(pdcb, &propi,
  1653. &cal.diph);
  1654. }
  1655. }
  1656. }
  1657. }
  1658. Invoke_Release(&pdcb);
  1659. }
  1660. }
  1661. ExitProc();
  1662. }
  1663. /*****************************************************************************
  1664. *
  1665. * @doc INTERNAL
  1666. *
  1667. * @func HRESULT | JoyReg_SetHWConfig |
  1668. *
  1669. * Store information about a joystick's <t JOYREGHWCONFIG>.
  1670. *
  1671. * @parm UINT | uiJoy |
  1672. *
  1673. * Joystick identification number.
  1674. *
  1675. * @parm LPJOYREGHWCONFIG | phwc |
  1676. *
  1677. * Contains information about the joystick capabilities.
  1678. * This value supercedes the value in the <p pcfg>.
  1679. *
  1680. * @parm LPCDIJOYCONFIG | pcfg |
  1681. *
  1682. * Contains information about the joystick configuration.
  1683. * The caller is assumed to have validated all fields.
  1684. *
  1685. * @parm HKEY | hk |
  1686. *
  1687. * The type key we are munging.
  1688. *
  1689. *
  1690. * @returns
  1691. *
  1692. * Returns a COM error code. The following error codes are
  1693. * intended to be illustrative and not necessarily comprehensive.
  1694. *
  1695. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1696. *
  1697. *****************************************************************************/
  1698. HRESULT INTERNAL
  1699. JoyReg_SetHWConfig(UINT idJoy, LPJOYREGHWCONFIG phwc, LPCDIJOYCONFIG pcfg,
  1700. HKEY hk)
  1701. {
  1702. HRESULT hres;
  1703. HKEY hkSave;
  1704. DWORD dwSam;
  1705. /*
  1706. * The caller has set phwc->dwType, so use it to determine
  1707. * where the data comes from or goes to.
  1708. */
  1709. if( phwc->dwType == JOY_HW_NONE )
  1710. {
  1711. /*
  1712. * Nothing to do
  1713. */
  1714. } else if( phwc->dwType == JOY_HW_CUSTOM )
  1715. {
  1716. /* ISSUE-2001/03/29-timgill Custom HWConfig not handled correctly
  1717. * We don't know the type name and the only time we can look
  1718. * it up is when were modifying an existing config so although we
  1719. * could store the config, we'd never be able to get it back.
  1720. * Should return no better than S_FALSE. This will have to wait.
  1721. */
  1722. } else
  1723. {
  1724. /*
  1725. * Try to access saved values
  1726. */
  1727. // ISSUE-2001/03/29-timgill Dangerous type cast
  1728. PDWORD pdw = (PDWORD)&phwc->hwv;
  1729. dwSam = KEY_QUERY_VALUE;
  1730. while( pdw < &phwc->dwType )
  1731. {
  1732. if( *pdw )
  1733. {
  1734. /*
  1735. * Real config data so write it
  1736. */
  1737. dwSam = KEY_SET_VALUE;
  1738. break;
  1739. }
  1740. pdw++;
  1741. }
  1742. /*
  1743. * If the device is autoloaded and yet the user is manually assigning it
  1744. * to an ID, set the volatile flag. The flag will be set to the driver
  1745. * defined value if a driver ever gets hotplug assigned to this ID but if
  1746. * not, this makes sure that the settings are removed on next reboot.
  1747. */
  1748. if(phwc->hws.dwFlags & JOY_HWS_AUTOLOAD)
  1749. {
  1750. phwc->dwUsageSettings |= JOY_US_VOLATILE;
  1751. }
  1752. hres = JoyReg_OpenSaveKey( phwc->dwType, pcfg, dwSam, &hkSave );
  1753. if( SUCCEEDED(hres) )
  1754. {
  1755. if( dwSam == KEY_SET_VALUE )
  1756. {
  1757. hres = JoyReg_SetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG,
  1758. idJoy, REG_BINARY,
  1759. phwc, cbX(*phwc));
  1760. if( FAILED(hres) )
  1761. {
  1762. // Report the error but live with it
  1763. RPF("JoyReg_SetConfig: failed to set saved config %08x", hres );
  1764. }
  1765. } else
  1766. {
  1767. JOYREGHWCONFIG hwc;
  1768. /*
  1769. * Read it into an extra buffer because we only want it
  1770. * if it's complete.
  1771. */
  1772. hres = JoyReg_GetConfigValue(hkSave, REGSTR_VAL_JOYNCONFIG,
  1773. idJoy, REG_BINARY,
  1774. &hwc, cbX(hwc));
  1775. if( hres == S_OK )
  1776. {
  1777. // Assert hws is first and no gap before dwUsageSettings
  1778. CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, hws ) == 0 );
  1779. CAssertF( FIELD_OFFSET( JOYREGHWCONFIG, dwUsageSettings ) == sizeof( hwc.hws ) );
  1780. // Copy the whole structure except the hws
  1781. memcpy( &phwc->dwUsageSettings, &hwc.dwUsageSettings,
  1782. sizeof( hwc ) - sizeof( hwc.hws ) );
  1783. }
  1784. }
  1785. RegCloseKey( hkSave );
  1786. }
  1787. /*
  1788. * If we failed to read, there's probably nothing there and the
  1789. * structure is set up already for a blank config.
  1790. * If we failed to write there probably not much we can do
  1791. */
  1792. }
  1793. hres = JoyReg_SetConfigValue(hk, REGSTR_VAL_JOYNCONFIG,
  1794. idJoy, REG_BINARY,
  1795. phwc, cbX(*phwc));
  1796. if(FAILED(hres))
  1797. {
  1798. goto done;
  1799. }
  1800. if(phwc->dwUsageSettings & JOY_US_ISOEM)
  1801. {
  1802. hres = JoyReg_SetConfigValue(
  1803. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  1804. pcfg->wszType, cbX(pcfg->wszType));
  1805. } else
  1806. {
  1807. hres = JoyReg_SetConfigValue(
  1808. hk, REGSTR_VAL_JOYNOEMNAME, idJoy, REG_SZ,
  1809. 0, 0);
  1810. }
  1811. done:;
  1812. return hres;
  1813. }
  1814. /*****************************************************************************
  1815. *
  1816. * @doc INTERNAL
  1817. *
  1818. * @func HRESULT | JoyReg_SetConfig |
  1819. *
  1820. * Store information about a joystick's configuration.
  1821. *
  1822. * @parm UINT | uiJoy |
  1823. *
  1824. * Joystick identification number.
  1825. *
  1826. * @parm JOYREGHWCONFIG | phwc |
  1827. *
  1828. * Contains information about the joystick capabilities.
  1829. * This value supercedes the value in the <p pcfg>.
  1830. * It may be modified if we needed to load the config
  1831. * info from the saved settings.
  1832. *
  1833. * @parm LPCDIJOYCONFIG | pcfg |
  1834. *
  1835. * Contains information about the joystick configuration.
  1836. * The caller is assumed to have validated all fields.
  1837. *
  1838. * @parm DWORD | fl |
  1839. *
  1840. * Zero or more <c DIJC_*> flags
  1841. * which specify which parts of the structures pointed
  1842. * to by <p phwc> and <p pjc> are to be written out.
  1843. *
  1844. * @returns
  1845. *
  1846. * Returns a COM error code. The following error codes are
  1847. * intended to be illustrative and not necessarily comprehensive.
  1848. *
  1849. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1850. *
  1851. *****************************************************************************/
  1852. JOYREGHWVALUES null_hwv = { 0};
  1853. STDMETHODIMP
  1854. JoyReg_SetConfig(UINT idJoy, LPJOYREGHWCONFIG phwc,
  1855. LPCDIJOYCONFIG pcfg, DWORD fl)
  1856. {
  1857. HRESULT hres;
  1858. EnterProc(JoyReg_SetConfig, (_ "uppx", idJoy, phwc, pcfg, fl));
  1859. AssertF((fl & ~DIJC_INTERNALSETVALID) == 0);
  1860. if(idJoy < cJoyMax )
  1861. {
  1862. if(fl & DIJC_INREGISTRY)
  1863. {
  1864. HKEY hk;
  1865. DWORD dwOptions = 0;
  1866. hres = JoyReg_OpenConfigKey(idJoy, KEY_SET_VALUE, NULL, dwOptions, &hk);
  1867. if(SUCCEEDED(hres))
  1868. {
  1869. if(fl & DIJC_REGHWCONFIGTYPE)
  1870. {
  1871. hres = JoyReg_SetHWConfig(idJoy, phwc, pcfg, hk);
  1872. if(FAILED(hres))
  1873. {
  1874. goto closedone;
  1875. }
  1876. if(fl & DIJC_UPDATEALIAS)
  1877. {
  1878. JoyReg_SetCalibration(idJoy, phwc);
  1879. }
  1880. }
  1881. if(fl & DIJC_CALLOUT)
  1882. {
  1883. hres = JoyReg_SetConfigValue(
  1884. hk, REGSTR_VAL_JOYNOEMCALLOUT, idJoy, REG_SZ,
  1885. pcfg->wszCallout, cbX(pcfg->wszCallout));
  1886. if(FAILED(hres))
  1887. {
  1888. hres = S_FALSE;
  1889. //continue to go
  1890. }
  1891. }
  1892. if(fl & DIJC_GAIN)
  1893. {
  1894. if(ISVALIDGAIN(pcfg->dwGain))
  1895. {
  1896. /*
  1897. * If restoring to nominal, then the key
  1898. * can be deleted; the default value will
  1899. * be assumed subsequently.
  1900. */
  1901. if(pcfg->dwGain == DI_FFNOMINALMAX)
  1902. {
  1903. hres = JoyReg_SetConfigValue(hk,
  1904. TEXT("Joystick%dFFConfiguration"),
  1905. idJoy, REG_SZ, 0, 0);
  1906. } else
  1907. {
  1908. hres = JoyReg_SetConfigValue(hk,
  1909. TEXT("Joystick%dFFConfiguration"),
  1910. idJoy, REG_BINARY,
  1911. &pcfg->dwGain, cbX(pcfg->dwGain));
  1912. }
  1913. if(FAILED(hres))
  1914. {
  1915. hres = S_FALSE;
  1916. goto closedone;
  1917. }
  1918. } else
  1919. {
  1920. RPF("ERROR: SetConfig: Invalid dwGain");
  1921. hres = E_INVALIDARG;
  1922. goto closedone;
  1923. }
  1924. }
  1925. hres = S_OK;
  1926. closedone:;
  1927. RegCloseKey(hk);
  1928. }
  1929. } else
  1930. {
  1931. hres = S_OK;
  1932. }
  1933. } else
  1934. {
  1935. hres = E_FAIL;
  1936. }
  1937. ExitOleProc();
  1938. return hres;
  1939. }
  1940. /*****************************************************************************
  1941. *
  1942. * @doc INTERNAL
  1943. *
  1944. * @func int | ibJoyPosAxis |
  1945. *
  1946. * Returns the offset of the <p iAxis>'th joystick axis
  1947. * in the <t JOYPOS> structure.
  1948. *
  1949. * @parm int | iAxis |
  1950. *
  1951. * The index of the requested axis. X, Y, Z, R, U and V are
  1952. * respctively zero through five.
  1953. *
  1954. * @returns
  1955. *
  1956. * The offset relative to the structure.
  1957. *
  1958. *****************************************************************************/
  1959. #define ibJoyPosAxis(iAxis) \
  1960. (FIELD_OFFSET(JOYPOS, dwX) + cbX(DWORD) * (iAxis)) \
  1961. #define pJoyValue(jp, i) \
  1962. (LPDWORD)pvAddPvCb(&(jp), ibJoyPosAxis(i)) \
  1963. /*
  1964. * The following doesn't do anything at runtime. It is a compile-time
  1965. * check that everything is okay.
  1966. */
  1967. void INLINE
  1968. JoyReg_CheckJoyPosAxis(void)
  1969. {
  1970. #define CheckAxis(x) \
  1971. CAssertF(ibJoyPosAxis(iJoyPosAxis##x) == FIELD_OFFSET(JOYPOS, dw##x))
  1972. CheckAxis(X);
  1973. CheckAxis(Y);
  1974. CheckAxis(Z);
  1975. CheckAxis(R);
  1976. CheckAxis(U);
  1977. CheckAxis(V);
  1978. #undef CheckAxis
  1979. }
  1980. /*****************************************************************************
  1981. *
  1982. * @doc INTERNAL
  1983. *
  1984. * @func HRESULT | JoyReg_IsValidUserValues |
  1985. *
  1986. * Retermine whether the values are ostensibly valid.
  1987. *
  1988. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  1989. *
  1990. * Contains information about the user joystick configuration.
  1991. *
  1992. * @returns
  1993. *
  1994. * Returns a COM error code. The following error codes are
  1995. * intended to be illustrative and not necessarily comprehensive.
  1996. *
  1997. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1998. *
  1999. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>:
  2000. * Something looks bad.
  2001. *
  2002. *****************************************************************************/
  2003. STDMETHODIMP
  2004. JoyReg_IsValidUserValues(LPCDIJOYUSERVALUES pjuv)
  2005. {
  2006. HRESULT hres;
  2007. int iAxis;
  2008. /*
  2009. * First set up the values to values that are out of range so
  2010. * that we will fall back to defaults.
  2011. */
  2012. for(iAxis = 0; iAxis < cJoyPosAxisMax; iAxis++)
  2013. {
  2014. if((int)*pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis) < 0)
  2015. {
  2016. RPF("JOYUSERVALUES: Negative jpMax not a good idea");
  2017. goto bad;
  2018. }
  2019. if(*pJoyValue(pjuv->ruv.jrvRanges.jpMin, iAxis) >
  2020. *pJoyValue(pjuv->ruv.jrvRanges.jpMax, iAxis))
  2021. {
  2022. RPF("JOYUSERVALUES: Min > Max not a good idea");
  2023. goto bad;
  2024. }
  2025. if(!fInOrder(0, *pJoyValue(pjuv->ruv.jpDeadZone, iAxis), 100))
  2026. {
  2027. RPF("JOYUSERVALUES: DeadZone > 100 not a good idea");
  2028. goto bad;
  2029. }
  2030. }
  2031. hres = S_OK;
  2032. return hres;
  2033. bad:;
  2034. hres = E_INVALIDARG;
  2035. return hres;
  2036. }
  2037. /*****************************************************************************
  2038. *
  2039. * @doc INTERNAL
  2040. *
  2041. * @func HRESULT | JoyReg_GetUserValues |
  2042. *
  2043. * Obtain information about user settings for the joystick.
  2044. *
  2045. *
  2046. * @parm IN OUT LPDIJOYUSERVALUES | pjuv |
  2047. *
  2048. * Receives information about the user joystick configuration.
  2049. * The caller is assumed to have validated the
  2050. * <e DIJOYUSERVALUES.dwSize> field.
  2051. *
  2052. * @parm DWORD | fl |
  2053. *
  2054. * Zero or more <c DIJU_*> flags specifying which parts
  2055. * of the <t DIJOYUSERVALUES> structure contain values
  2056. * which are to be retrieved.
  2057. *
  2058. * @returns
  2059. *
  2060. * Returns a COM error code. The following error codes are
  2061. * intended to be illustrative and not necessarily comprehensive.
  2062. *
  2063. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2064. *
  2065. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2066. * parameters was invalid.
  2067. *
  2068. *****************************************************************************/
  2069. STDMETHODIMP
  2070. JoyReg_GetUserValues(LPDIJOYUSERVALUES pjuv, DWORD fl)
  2071. {
  2072. HRESULT hres;
  2073. HKEY hk;
  2074. LONG lRc;
  2075. EnterProc(JoyReg_GetUserValues, (_ "px", pjuv, fl));
  2076. hres = S_OK; /* If nothing happens, then success */
  2077. if(fl & DIJU_USERVALUES)
  2078. {
  2079. /*
  2080. * Okay, now get the user settings.
  2081. *
  2082. * If anything goes wrong, then just limp with the default values.
  2083. */
  2084. lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG,
  2085. 0, KEY_QUERY_VALUE, &hk);
  2086. if(lRc == ERROR_SUCCESS)
  2087. {
  2088. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYUSERVALUES,
  2089. REG_BINARY, &pjuv->ruv, cbX(pjuv->ruv));
  2090. if(SUCCEEDED(hres))
  2091. {
  2092. /*
  2093. * Sanity-check the values. If anything is screwy,
  2094. * then fall back to the defaults.
  2095. */
  2096. hres = JoyReg_IsValidUserValues(pjuv);
  2097. }
  2098. if(FAILED(hres))
  2099. {
  2100. /*
  2101. * Oh well. Just use the default values, then.
  2102. *
  2103. * Stolen from ibmjoy\msjstick.c.
  2104. */
  2105. ZeroMemory(&pjuv->ruv, cbX(pjuv->ruv));
  2106. #define DEFAULT_RANGE_MAX 65535
  2107. #define DEFAULT_TIMEOUT 5000
  2108. #define DEFAULT_DEADZONE 5
  2109. pjuv->ruv.jrvRanges.jpMax.dwX = DEFAULT_RANGE_MAX;
  2110. pjuv->ruv.jrvRanges.jpMax.dwY = DEFAULT_RANGE_MAX;
  2111. pjuv->ruv.jrvRanges.jpMax.dwZ = DEFAULT_RANGE_MAX;
  2112. pjuv->ruv.jrvRanges.jpMax.dwR = DEFAULT_RANGE_MAX;
  2113. pjuv->ruv.jrvRanges.jpMax.dwU = DEFAULT_RANGE_MAX;
  2114. pjuv->ruv.jrvRanges.jpMax.dwV = DEFAULT_RANGE_MAX;
  2115. pjuv->ruv.jpDeadZone.dwX = DEFAULT_DEADZONE;
  2116. pjuv->ruv.jpDeadZone.dwY = DEFAULT_DEADZONE;
  2117. pjuv->ruv.dwTimeOut = DEFAULT_TIMEOUT;
  2118. }
  2119. RegCloseKey(hk);
  2120. }
  2121. }
  2122. if(fl & DIJU_INDRIVERREGISTRY)
  2123. {
  2124. hres = JoyReg_OpenConfigKey((UINT)-1, KEY_QUERY_VALUE, NULL, FALSE, &hk);
  2125. if(SUCCEEDED(hres))
  2126. {
  2127. if(fl & DIJU_GLOBALDRIVER)
  2128. {
  2129. /*
  2130. * If it doesn't work, then return the default value
  2131. * of "MSANALOG.VXD". We can't blindly use
  2132. * JoyReg_GetValue, because that treats a nonexistent
  2133. * value as having a default of the null string.
  2134. */
  2135. lRc = RegQueryValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2136. 0, 0, 0, 0);
  2137. if((lRc == ERROR_SUCCESS || lRc == ERROR_MORE_DATA) &&
  2138. SUCCEEDED(
  2139. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2140. REG_SZ, pjuv->wszGlobalDriver,
  2141. cbX(pjuv->wszGlobalDriver))))
  2142. {
  2143. /* Yay, it worked */
  2144. } else
  2145. {
  2146. CopyMemory(pjuv->wszGlobalDriver,
  2147. c_wszDefPortDriver,
  2148. cbX(c_wszDefPortDriver));
  2149. }
  2150. }
  2151. if(fl & DIJU_GAMEPORTEMULATOR)
  2152. {
  2153. /*
  2154. * If it doesn't work, then just return a null string.
  2155. */
  2156. hres = JoyReg_GetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR,
  2157. REG_SZ, pjuv->wszGameportEmulator,
  2158. cbX(pjuv->wszGameportEmulator));
  2159. if(FAILED(hres))
  2160. {
  2161. pjuv->wszGameportEmulator[0] = TEXT('\0');
  2162. }
  2163. }
  2164. RegCloseKey(hk);
  2165. }
  2166. }
  2167. /*
  2168. * Warning! CJoy_InitRanges() assumes this never fails.
  2169. */
  2170. hres = S_OK;
  2171. ExitOleProcR();
  2172. return hres;
  2173. }
  2174. /*****************************************************************************
  2175. *
  2176. * @doc INTERNAL
  2177. *
  2178. * @func HRESULT | JoyReg_SetUserValues |
  2179. *
  2180. * Store information about user settings for the joystick.
  2181. *
  2182. *
  2183. * @parm IN LPCDIJOYUSERVALUES | pjuv |
  2184. *
  2185. * Contains information about the user joystick configuration.
  2186. * The caller is assumed to have validated the
  2187. * <e DIJOYUSERVALUES.dwSize> field.
  2188. *
  2189. * @parm DWORD | fl |
  2190. *
  2191. * Zero or more <c DIJU_*> flags specifying which parts
  2192. * of the <t DIJOYUSERVALUES> structure contain values
  2193. * which are to be set.
  2194. *
  2195. * @returns
  2196. *
  2197. * Returns a COM error code. The following error codes are
  2198. * intended to be illustrative and not necessarily comprehensive.
  2199. *
  2200. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2201. *
  2202. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  2203. * parameters was invalid.
  2204. *
  2205. *****************************************************************************/
  2206. STDMETHODIMP
  2207. JoyReg_SetUserValues(LPCDIJOYUSERVALUES pjuv, DWORD fl)
  2208. {
  2209. HRESULT hres = E_FAIL;
  2210. HKEY hk;
  2211. EnterProc(JoyReg_SetUserValues, (_ "px", pjuv, fl));
  2212. if(fl & DIJU_USERVALUES)
  2213. {
  2214. /*
  2215. * See if the values are sane.
  2216. */
  2217. if(fl & DIJU_USERVALUES)
  2218. {
  2219. hres = JoyReg_IsValidUserValues(pjuv);
  2220. if(FAILED(hres))
  2221. {
  2222. goto done;
  2223. }
  2224. }
  2225. /*
  2226. * Off to the registry we go.
  2227. */
  2228. hres = hresMumbleKeyEx(HKEY_LOCAL_MACHINE,
  2229. REGSTR_PATH_JOYCONFIG,
  2230. DI_KEY_ALL_ACCESS,
  2231. REG_OPTION_NON_VOLATILE,
  2232. &hk);
  2233. if(SUCCEEDED(hres))
  2234. {
  2235. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYUSERVALUES,
  2236. REG_BINARY, &pjuv->ruv,
  2237. cbX(pjuv->ruv));
  2238. RegCloseKey(hk);
  2239. if(FAILED(hres))
  2240. {
  2241. goto done;
  2242. }
  2243. } else
  2244. {
  2245. goto done;
  2246. }
  2247. }
  2248. if(fl & DIJU_INDRIVERREGISTRY)
  2249. {
  2250. hres = JoyReg_OpenConfigKey((UINT)-1, KEY_SET_VALUE, NULL, FALSE, &hk);
  2251. if(SUCCEEDED(hres))
  2252. {
  2253. if(fl & DIJU_GLOBALDRIVER)
  2254. {
  2255. /*
  2256. * This is a weird key. The default value is
  2257. * "MSANALOG.VXD", so if we get a null string, we
  2258. * can't use JoyReg_SetValue, because that will
  2259. * delete the key.
  2260. */
  2261. if(pjuv->wszGlobalDriver[0])
  2262. {
  2263. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYOEMCALLOUT,
  2264. REG_SZ, pjuv->wszGlobalDriver,
  2265. cbX(pjuv->wszGlobalDriver));
  2266. } else
  2267. {
  2268. LONG lRc;
  2269. lRc = RegSetValueEx(hk, REGSTR_VAL_JOYOEMCALLOUT, 0,
  2270. REG_SZ, (PV)TEXT(""), cbCtch(1));
  2271. if(lRc == ERROR_SUCCESS)
  2272. {
  2273. hres = S_OK;
  2274. } else
  2275. {
  2276. RPF("Unable to write %s to registry",
  2277. REGSTR_VAL_JOYOEMCALLOUT);
  2278. hres = E_FAIL; /* Else, something bad happened */
  2279. }
  2280. }
  2281. if(FAILED(hres))
  2282. {
  2283. goto regdone;
  2284. }
  2285. }
  2286. if(fl & DIJU_GAMEPORTEMULATOR)
  2287. {
  2288. hres = JoyReg_SetValue(hk, REGSTR_VAL_JOYGAMEPORTEMULATOR,
  2289. REG_SZ, pjuv->wszGameportEmulator,
  2290. cbX(pjuv->wszGameportEmulator));
  2291. if(FAILED(hres))
  2292. {
  2293. goto regdone;
  2294. }
  2295. }
  2296. regdone:;
  2297. RegCloseKey(hk);
  2298. } else
  2299. {
  2300. goto done;
  2301. }
  2302. }
  2303. done:;
  2304. ExitOleProcR();
  2305. return hres;
  2306. }
  2307. /*****************************************************************************
  2308. *
  2309. * @doc INTERNAL
  2310. *
  2311. * @func HRESULT | JoyReg_OpenFFKey |
  2312. *
  2313. * Given a type key, move to its force feedback subkey.
  2314. *
  2315. * @parm HKEY | hkType |
  2316. *
  2317. * The parent type key.
  2318. *
  2319. * @parm REGSAM | sam |
  2320. *
  2321. * Access level desired.
  2322. *
  2323. * @parm PHKEY | phk |
  2324. *
  2325. * Receives created registry key.
  2326. *
  2327. * @returns
  2328. *
  2329. * Returns a COM error code. The following error codes are
  2330. * intended to be illustrative and not necessarily comprehensive.
  2331. *
  2332. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2333. *
  2334. * <c DIERR_NOTFOUND>: Couldn't open the key.
  2335. *
  2336. *****************************************************************************/
  2337. STDMETHODIMP
  2338. JoyReg_OpenFFKey(HKEY hkType, REGSAM sam, PHKEY phk)
  2339. {
  2340. HRESULT hres;
  2341. EnterProc(JoyReg_OpenFFKey, (_ "xx", hkType, sam));
  2342. *phk = 0;
  2343. if(hkType)
  2344. {
  2345. if(RegOpenKeyEx(hkType, TEXT("OEMForceFeedback"), 0, sam, phk) == 0)
  2346. {
  2347. hres = S_OK;
  2348. } else
  2349. {
  2350. hres = E_FAIL;
  2351. }
  2352. } else
  2353. {
  2354. hres = DIERR_NOTFOUND;
  2355. }
  2356. ExitBenignOleProc();
  2357. return hres;
  2358. }
  2359. /*****************************************************************************
  2360. *
  2361. * @doc INTERNAL
  2362. *
  2363. * @func TCHAR | CJoyCfg_CharFromType |
  2364. *
  2365. * Convert a predefined type number to a character.
  2366. *
  2367. * @func UINT | CJoyCfg_TypeFromChar |
  2368. *
  2369. * Convert a character back to a predefined type number.
  2370. *
  2371. *****************************************************************************/
  2372. #define JoyCfg_CharFromType(t) ((TCHAR)(L'0' + t))
  2373. #define JoyCfg_TypeFromChar(tch) ((tch) - L'0')
  2374. /*****************************************************************************
  2375. *
  2376. * @doc EXTERNAL
  2377. *
  2378. * @func HRESULT | JoyReg_GetPredefTypeInfo |
  2379. *
  2380. * Obtain information about a predefined joystick type.
  2381. *
  2382. * @parm LPCWSTR | pwszType |
  2383. *
  2384. * Points to the name of the type. It is known to begin
  2385. * with a "#". The remainder has not yet been parsed.
  2386. *
  2387. * @parm IN OUT LPDIJOYTYPEINFO | pjti |
  2388. *
  2389. * Receives information about the joystick type,
  2390. * already validated.
  2391. *
  2392. * @parm DWORD | dwFlags |
  2393. *
  2394. * Zero or more <c DITC_*> flags
  2395. * which specify which parts of the structure pointed
  2396. * to by <p pjti> are to be filled in.
  2397. *
  2398. * @returns
  2399. *
  2400. * Returns a COM error code. The following error codes are
  2401. * intended to be illustrative and not necessarily comprehensive.
  2402. *
  2403. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2404. *
  2405. * <c DIERR_NOTFOUND>: The joystick type was not found.
  2406. *
  2407. *****************************************************************************/
  2408. HRESULT EXTERNAL
  2409. JoyReg_GetPredefTypeInfo(LPCWSTR pwszType, LPDIJOYTYPEINFO pjti, DWORD fl)
  2410. {
  2411. HRESULT hres;
  2412. UINT itype;
  2413. EnterProcI(JoyReg_GetPredefTypeInfo, (_ "Wpx", pwszType, pjti, fl));
  2414. //(MarcAnd) These TEXT('blah') things should be L'blah' as the string is always wide
  2415. AssertF(pwszType[0] == TEXT('#'));
  2416. itype = JoyCfg_TypeFromChar(pwszType[1]);
  2417. if(fInOrder(JOY_HW_PREDEFMIN, itype, JOY_HW_PREDEFMAX) &&
  2418. pwszType[2] == TEXT('\0'))
  2419. {
  2420. /*
  2421. * No real point in checking the bits in fl, since
  2422. * setting it up is so easy.
  2423. */
  2424. pjti->hws = c_rghwsPredef[itype - JOY_HW_PREDEFMIN];
  2425. LoadStringW(g_hinst, IDS_PREDEFJOYTYPE + itype,
  2426. pjti->wszDisplayName, cA(pjti->wszDisplayName));
  2427. pjti->wszCallout[0] = TEXT('\0');
  2428. ZeroX(pjti->clsidConfig);
  2429. if(fl & DITC_FLAGS1 )
  2430. {
  2431. pjti->dwFlags1 = 0x0;
  2432. }
  2433. if( fl & DITC_HARDWAREID )
  2434. {
  2435. lstrcpyW(pjti->wszHardwareId, c_rghwIdPredef[itype-JOY_HW_PREDEFMIN] );
  2436. }
  2437. hres = S_OK;
  2438. } else
  2439. {
  2440. hres = DIERR_NOTFOUND;
  2441. }
  2442. ExitOleProc();
  2443. return hres;
  2444. }
  2445. #if 0 //don't delete it now.
  2446. /*****************************************************************************
  2447. *
  2448. * @doc INTERNAL
  2449. *
  2450. * @func HRESULT | JoyCfg_GetIDByOemName |
  2451. *
  2452. * Get the Id by OEMNAME
  2453. *
  2454. * @parm IN LPTSTR | szOEMNAME |
  2455. *
  2456. * String used to find the ID.
  2457. *
  2458. * @parm IN LPUNIT | lpID |
  2459. *
  2460. * The ID to get.
  2461. *
  2462. * @returns
  2463. *
  2464. * A COM success code unless the current configuration key could not
  2465. * be opened, or could not find the OEMNAME.
  2466. *
  2467. *****************************************************************************/
  2468. HRESULT EXTERNAL JoyReg_GetIDByOemName( LPTSTR szOemName, PUINT pId )
  2469. {
  2470. HRESULT hres = E_FAIL;
  2471. LONG lRc;
  2472. HKEY hkCurrCfg;
  2473. UINT JoyId;
  2474. TCHAR szTestName[MAX_JOYSTRING];
  2475. TCHAR szOemNameKey[MAX_JOYSTRING];
  2476. DWORD cb;
  2477. EnterProcI(JoyReg_GetIDByOemName, (_ "sp", szOemName, pId ));
  2478. hres = JoyReg_OpenConfigKey( (UINT)(-1), KEY_WRITE, NULL, REG_OPTION_NON_VOLATILE, &hkCurrCfg );
  2479. if( SUCCEEDED( hres ) )
  2480. {
  2481. for( JoyId = 0; (JoyId < 16) || ( lRc == ERROR_SUCCESS ); JoyId++ )
  2482. {
  2483. wsprintf( szOemNameKey, REGSTR_VAL_JOYNOEMNAME, JoyId+1 );
  2484. cb = sizeof( szTestName );
  2485. lRc = RegQueryValueEx( hkCurrCfg, szOemNameKey, 0, NULL, (PBYTE)szTestName, &cb );
  2486. if( lRc == ERROR_SUCCESS )
  2487. {
  2488. if( !lstrcmpi( szOemName, szTestName ) )
  2489. {
  2490. *pId = JoyId;
  2491. pId ++;
  2492. hres = S_OK;
  2493. break;
  2494. }
  2495. }
  2496. }
  2497. }
  2498. else
  2499. {
  2500. SquirtSqflPtszV(sqfl | sqflError,
  2501. TEXT("JoyReg_OpenConfigKey failed code 0x%08x"), hres );
  2502. }
  2503. ExitOleProc();
  2504. return hres;
  2505. } /* JoyReg_GetIDByOemName */
  2506. #endif