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.

2036 lines
52 KiB

  1. //****************************************************************************
  2. //
  3. // File: joycpl.c
  4. // Content: Joystick configuration and testing
  5. // History:
  6. // Date By Reason
  7. // ==== == ======
  8. // 03-oct-94 craige initial implementation
  9. // 05-nov-94 craige generalized 4 axis joysticks and other improvements
  10. // 11-nov-94 craige allow multiple copies of tab to run
  11. // 22-nov-94 craige tweaks to calibration code
  12. // 29-nov-94 craige small bugs
  13. // 08-dec-94 craige generalized second joystick
  14. // 11-dec-94 craige split into component parts
  15. // 15-dec-94 craige allow N joysticks
  16. // 18-dec-94 craige process UV
  17. // 05-jan-95 craige external rudder bug
  18. // 05-mar-95 craige Bug 9998: pass id -1 to get base dev caps
  19. // Bug 15334: allow reset of user values for compatiblity
  20. // 06-mar-95 craige Bug 7608: deleting VxD name if joystick not present
  21. // caused unplugged joystick to never come back
  22. // 06-may-96 richj ported to NT
  23. //
  24. // Copyright (c) Microsoft Corporation 1994
  25. //
  26. //****************************************************************************
  27. #include "joycpl.h"
  28. extern HINSTANCE hInstance; // main.c
  29. #define cchLENGTH(_sz) (sizeof(_sz)/sizeof(_sz[0]))
  30. #define GetString(_sz,_ids) LoadString (hInstance, _ids, _sz, cchLENGTH(_sz))
  31. #ifdef DEBUG
  32. void cdecl MBOX(LPSTR szFormat, ...)
  33. {
  34. char ach[256];
  35. wvsprintf( ach,szFormat,(LPSTR)(&szFormat+1));
  36. MessageBox( NULL, ach, "JOYCPL", MB_OK | MB_SYSTEMMODAL );
  37. }
  38. #endif
  39. /***************************************************************************
  40. MEMORY MANAGEMENT ROUTINES FOLLOW
  41. ***************************************************************************/
  42. #ifdef DEBUG
  43. DWORD allocCount;
  44. #endif
  45. /*
  46. * DoAlloc - allocate memory
  47. */
  48. LPVOID DoAlloc( DWORD size )
  49. {
  50. LPVOID res;
  51. res = LocalAlloc( LPTR, size );
  52. #ifdef DEBUG
  53. allocCount++;
  54. #endif
  55. return res;
  56. } /* DoAlloc */
  57. /*
  58. * DoFree - free allocated memory
  59. */
  60. void DoFree( LPVOID ptr )
  61. {
  62. if( ptr != NULL ) {
  63. LocalFree( ptr );
  64. #ifdef DEBUG
  65. allocCount--;
  66. if( allocCount < 0 ) {
  67. DPF( "JOYCPL: Too many frees, allocCount=%d\r\n", allocCount );
  68. }
  69. #endif
  70. }
  71. } /* DoFree */
  72. /***************************************************************************
  73. REGISTRY RELATED ROUTINES FOLLOW
  74. ***************************************************************************/
  75. /*
  76. * getDevCaps - get the joystick device caps
  77. */
  78. static void getDevCaps( LPGLOBALVARS pgv )
  79. {
  80. JOYCAPS jc;
  81. if( joyGetDevCaps( pgv->iJoyId, &jc, sizeof( jc ) ) == JOYERR_NOERROR ) {
  82. pgv->joyRange.jpMin.dwX = jc.wXmin;
  83. pgv->joyRange.jpMax.dwX = jc.wXmax;
  84. pgv->joyRange.jpMin.dwY = jc.wYmin;
  85. pgv->joyRange.jpMax.dwY = jc.wYmax;
  86. pgv->joyRange.jpMin.dwZ = jc.wZmin;
  87. pgv->joyRange.jpMax.dwZ = jc.wZmax;
  88. pgv->joyRange.jpMin.dwR = jc.wRmin;
  89. pgv->joyRange.jpMax.dwR = jc.wRmax;
  90. pgv->joyRange.jpMin.dwU = jc.wUmin;
  91. pgv->joyRange.jpMax.dwU = jc.wUmax;
  92. pgv->joyRange.jpMin.dwV = jc.wVmin;
  93. pgv->joyRange.jpMax.dwV = jc.wVmax;
  94. pgv->dwMaxAxes = (DWORD) jc.wMaxAxes;
  95. }
  96. } /* getDevCaps */
  97. extern MMRESULT WINAPI joyConfigChanged( DWORD dwFlags );
  98. /*
  99. * RegistryUpdated - notify the driver that the registry is updated
  100. */
  101. void RegistryUpdated( LPGLOBALVARS pgv )
  102. {
  103. joyConfigChanged( 0 );
  104. if( pgv != NULL ) {
  105. getDevCaps( pgv ); // devcaps could change
  106. }
  107. } /* RegistryUpdated */
  108. /*
  109. * createSettingsKeyFromCurr - create a settings key for a specific joystick
  110. */
  111. static void createSettingsKeyFromCurr( LPGLOBALVARS pgv, LPSTR str )
  112. {
  113. char tmp[MAX_STR];
  114. int type;
  115. LPJOYDATA pjd;
  116. pjd = pgv->pjd;
  117. if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) {
  118. type = pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY;
  119. if( type < 0 || type >= pjd->oemCount ) {
  120. tmp[0] = 0;
  121. } else {
  122. strcpy( tmp, pjd->oemList[type].keyname );
  123. }
  124. } else {
  125. wsprintf( tmp, "predef%d", pgv->joyHWCurr.dwType );
  126. }
  127. wsprintf( str, "%s\\%s", pjd->regSettingsCfgKey, tmp );
  128. } /* createSettingsKeyFromCurr */
  129. /*
  130. * regSaveSpecificJoyHW - save specific joystick hardware config. to the registry
  131. */
  132. static void regSaveSpecificJoyHW( LPGLOBALVARS pgv )
  133. {
  134. char str[MAX_STR];
  135. HKEY hkey;
  136. char jcfg[MAX_STR];
  137. if( pgv->joyHWCurr.dwType == JOY_HW_NONE ) {
  138. return;
  139. }
  140. if( !(pgv->joyActiveFlags & HASJOY) ) {
  141. return;
  142. }
  143. createSettingsKeyFromCurr( pgv, str );
  144. if( !RegCreateKey( HKEY_LOCAL_MACHINE, str, &hkey ) ) {
  145. GETKEYNAME( pgv, jcfg, REGSTR_VAL_JOYNCONFIG );
  146. RegSetValueEx( hkey, jcfg, 0, REG_BINARY,
  147. (CONST LPBYTE)&pgv->joyHWCurr, sizeof( pgv->joyHWCurr ));
  148. RegCloseKey( hkey );
  149. }
  150. } /* regSaveSpecificJoyHW */
  151. /*
  152. * regCreateCurrKey - create the current joystick settings key
  153. */
  154. static HKEY regCreateCurrKey( LPGLOBALVARS pgv )
  155. {
  156. HKEY hkey;
  157. if( !RegCreateKey( HKEY_LOCAL_MACHINE, pgv->pjd->regCurrCfgKey, &hkey ) ) {
  158. return hkey;
  159. } else {
  160. return NULL;
  161. }
  162. } /* regCreateCurrKey */
  163. /*
  164. * RegSaveCurrentJoyHW - save the joystick info to the current entry in
  165. * the registry
  166. */
  167. void RegSaveCurrentJoyHW( LPGLOBALVARS pgv )
  168. {
  169. HKEY hkey;
  170. LPSTR sptr;
  171. char vname[MAX_STR];
  172. char oname[MAX_STR];
  173. char coname[MAX_STR];
  174. int type;
  175. LPJOYDATA pjd;
  176. if( pgv->joyHWCurr.dwType == JOY_HW_NONE ) {
  177. return;
  178. }
  179. if( !(pgv->joyActiveFlags & HASJOY) ) {
  180. return;
  181. }
  182. hkey = regCreateCurrKey( pgv );
  183. if( hkey == NULL ) {
  184. DPF( "Could not save current joystick settings!\r\n" );
  185. return;
  186. }
  187. pjd = pgv->pjd;
  188. if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) {
  189. sptr = pjd->oemList[ pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY ].keyname;
  190. }
  191. GETKEYNAME( pgv, vname, REGSTR_VAL_JOYNCONFIG );
  192. GETKEYNAME( pgv, oname, REGSTR_VAL_JOYNOEMNAME );
  193. GETKEYNAME( pgv, coname, REGSTR_VAL_JOYNOEMCALLOUT );
  194. RegSetValueEx( hkey, vname, 0, REG_BINARY,
  195. (CONST LPBYTE)&pgv->joyHWCurr, sizeof( pgv->joyHWCurr ) );
  196. if( pgv->joyHWCurr.dwUsageSettings & JOY_US_ISOEM ) {
  197. RegSetValueEx( hkey, oname, 0, REG_SZ, sptr, strlen( sptr ) + 1 );
  198. /*
  199. * set up VxD name for this joystick
  200. */
  201. type = pgv->joyHWCurr.dwType - JOY_HW_LASTENTRY;
  202. if( (pjd->oemList[type].vxd_name[0] != 0) ) {
  203. RegSetValueEx( hkey, coname, 0, REG_SZ, pjd->oemList[type].vxd_name,
  204. strlen( pjd->oemList[type].vxd_name )+1 );
  205. } else {
  206. RegDeleteValue( hkey, coname );
  207. }
  208. } else {
  209. RegDeleteValue( hkey, oname );
  210. RegDeleteValue( hkey, coname );
  211. }
  212. RegCloseKey( hkey );
  213. } /* RegSaveCurrentJoyHW */
  214. /*
  215. * regPermSaveAllInfo - save joystick data to the registry for good
  216. */
  217. static void regPermSaveAllInfo( LPGLOBALVARS pgv )
  218. {
  219. // save specific hardware settings to the registry
  220. regSaveSpecificJoyHW( pgv );
  221. // save current current hardware to the registry
  222. RegSaveCurrentJoyHW( pgv );
  223. RegistryUpdated( pgv );
  224. } /* regPermSaveAllInfo */
  225. /*
  226. * setHWCurrType - set the current hardware type (check for OEM type)
  227. */
  228. static BOOL setHWCurrType( LPGLOBALVARS pgv, HKEY hkey, LPJOYREGHWCONFIG pcfg )
  229. {
  230. char str[MAX_STR];
  231. char pname[MAX_STR];
  232. int i;
  233. DWORD regtype;
  234. DWORD cb;
  235. LPJOYDATA pjd;
  236. if( !(pcfg->dwUsageSettings & JOY_US_ISOEM) ) {
  237. return TRUE;
  238. }
  239. GETKEYNAME( pgv, pname, REGSTR_VAL_JOYNOEMNAME );
  240. cb = sizeof( str );
  241. if( RegQueryValueEx( hkey, pname, NULL, &regtype, (CONST LPBYTE)str, &cb)) {
  242. return FALSE;
  243. }
  244. if( regtype != REG_SZ ) {
  245. return FALSE;
  246. }
  247. pjd = pgv->pjd;
  248. for( i=0;i<pjd->oemCount;i++ ) {
  249. if( !_stricmp( str, pjd->oemList[i].keyname ) ) {
  250. pcfg->dwType = i + JOY_HW_LASTENTRY;
  251. return TRUE;
  252. }
  253. }
  254. return FALSE;
  255. } /* setHWCurrType */
  256. /*
  257. * regGetCurrHW - get the information about the current configuration
  258. * from the registry
  259. */
  260. static void regGetCurrHW( LPGLOBALVARS pgv )
  261. {
  262. DWORD regtype;
  263. DWORD cb;
  264. JOYREGHWCONFIG config;
  265. HKEY hkey;
  266. char str[MAX_STR];
  267. JOYCAPS jc;
  268. pgv->joyHWCurr = pgv->pjd->joyHWDefaults[ JOY_HW_NONE ];
  269. // Give the joystick driver a chance to write its current settings,
  270. // if there are none.
  271. //
  272. joyGetDevCaps( pgv->iJoyId, &jc, sizeof( jc ) );
  273. // Read those current settings (if they exist), and use them to determine
  274. // what type of joystick we've got
  275. //
  276. if ((hkey = regCreateCurrKey (pgv)) != NULL)
  277. {
  278. cb = sizeof( config );
  279. GETKEYNAME( pgv, str, REGSTR_VAL_JOYNCONFIG );
  280. if( !RegQueryValueEx( hkey, str, NULL,
  281. &regtype, (CONST LPBYTE)&config, &cb)) {
  282. if( regtype == REG_BINARY && cb == sizeof( config ) ) {
  283. if( setHWCurrType( pgv, hkey, &config ) ) {
  284. pgv->joyHWCurr = config;
  285. }
  286. }
  287. }
  288. RegCloseKey( hkey );
  289. }
  290. // Does this joystick match a known type?
  291. //
  292. if (pgv->joyHWCurr.hws.dwNumButtons != 0)
  293. {
  294. int ii;
  295. for ( ii=0;ii<pgv->pjd->oemCount;ii++ )
  296. {
  297. if ( (pgv->pjd->oemList[ii].hws.dwFlags ==
  298. pgv->joyHWCurr.hws.dwFlags) &&
  299. (pgv->pjd->oemList[ii].hws.dwNumButtons ==
  300. pgv->joyHWCurr.hws.dwNumButtons) )
  301. {
  302. pgv->joyHWCurr.dwType = ii + JOY_HW_LASTENTRY;
  303. break;
  304. }
  305. }
  306. if (pgv->joyHWCurr.dwType == JOY_HW_NONE)
  307. {
  308. pgv->joyHWCurr.dwType = JOY_HW_CUSTOM;
  309. }
  310. }
  311. } /* regGetCurrHW */
  312. /*
  313. * regGetOEMStr - get an OEM string
  314. */
  315. static BOOL regGetOEMStr( HKEY hkey, LPSTR keyname, LPSTR buff, int size,
  316. LPSTR *res )
  317. {
  318. DWORD cb;
  319. DWORD type;
  320. LPSTR str;
  321. int slen;
  322. cb = size;
  323. slen = 1;
  324. if( !RegQueryValueEx( hkey, keyname, NULL, &type, (CONST LPBYTE)buff, &cb ) ) {
  325. if( type == REG_SZ ) {
  326. slen = strlen( buff ) + 1;
  327. }
  328. }
  329. str = DoAlloc( slen );
  330. if( str != NULL ) {
  331. if( slen == 1 ) {
  332. str[0] = 0;
  333. } else {
  334. strcpy( str, buff );
  335. }
  336. }
  337. *res = str;
  338. if( str == NULL ) {
  339. return TRUE;
  340. }
  341. return FALSE;
  342. } /* regGetOEMStr */
  343. /*
  344. * checkNonStandardUserVals
  345. */
  346. static BOOL checkNonStandardUserVals( LPJOYREGUSERVALUES puv )
  347. {
  348. if( (puv->jrvRanges.jpMin.dwX != RANGE_MIN) ||
  349. (puv->jrvRanges.jpMin.dwY != RANGE_MIN) ||
  350. (puv->jrvRanges.jpMin.dwZ != RANGE_MIN) ||
  351. (puv->jrvRanges.jpMin.dwR != RANGE_MIN) ||
  352. (puv->jrvRanges.jpMin.dwU != RANGE_MIN) ||
  353. (puv->jrvRanges.jpMin.dwV != RANGE_MIN) ||
  354. (puv->jrvRanges.jpMax.dwX != RANGE_MAX) ||
  355. (puv->jrvRanges.jpMax.dwY != RANGE_MAX) ||
  356. (puv->jrvRanges.jpMax.dwZ != RANGE_MAX) ||
  357. (puv->jrvRanges.jpMax.dwR != RANGE_MAX) ||
  358. (puv->jrvRanges.jpMax.dwU != RANGE_MAX) ||
  359. (puv->jrvRanges.jpMax.dwV != RANGE_MAX) ||
  360. (puv->dwTimeOut != 0x1000) ||
  361. (puv->jpDeadZone.dwX != 0) ||
  362. (puv->jpDeadZone.dwY != 0) ) {
  363. return TRUE;
  364. }
  365. return FALSE;
  366. } /* checkNonStandardUserVals */
  367. /*
  368. * regSetUserVals - set user values to our defaults
  369. */
  370. static void regSetUserVals( LPJOYDATA pjd, BOOL retest )
  371. {
  372. JOYREGUSERVALUES uv;
  373. JOYREGUSERVALUES ouv;
  374. HKEY hkey;
  375. DWORD regtype;
  376. DWORD cb;
  377. if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) {
  378. /*
  379. * build the default settings
  380. */
  381. memset( &uv, 0, sizeof( uv ) );
  382. uv.dwTimeOut = 0x1000;
  383. uv.jpDeadZone.dwX = 0;
  384. uv.jpDeadZone.dwY = 0;
  385. uv.jrvRanges.jpMin.dwX = RANGE_MIN;
  386. uv.jrvRanges.jpMin.dwY = RANGE_MIN;
  387. uv.jrvRanges.jpMin.dwZ = RANGE_MIN;
  388. uv.jrvRanges.jpMin.dwR = RANGE_MIN;
  389. uv.jrvRanges.jpMin.dwU = RANGE_MIN;
  390. uv.jrvRanges.jpMin.dwV = RANGE_MIN;
  391. uv.jrvRanges.jpMax.dwX = RANGE_MAX;
  392. uv.jrvRanges.jpMax.dwY = RANGE_MAX;
  393. uv.jrvRanges.jpMax.dwZ = RANGE_MAX;
  394. uv.jrvRanges.jpMax.dwR = RANGE_MAX;
  395. uv.jrvRanges.jpMax.dwU = RANGE_MAX;
  396. uv.jrvRanges.jpMax.dwV = RANGE_MAX;
  397. if( retest ) {
  398. /*
  399. * see if the values have changed since we last set them:
  400. * if yes, then we need to reset our remembered values
  401. */
  402. DPF( "Looking for USER entries\r\n" );
  403. cb = sizeof( ouv );
  404. if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, NULL,
  405. &regtype, (CONST LPBYTE)&ouv, &cb)) {
  406. DPF( "found REGSTR_VAL_JOYUSERVALUES\r\n" );
  407. if( regtype == REG_BINARY && cb == sizeof( ouv ) ) {
  408. if( memcmp( &uv, &ouv, sizeof( uv ) ) ) {
  409. DPF( "USER entries changed!\r\n" );
  410. pjd->bHasUserVals = TRUE;
  411. pjd->bDeleteUserVals = FALSE;
  412. pjd->userVals = ouv;
  413. }
  414. }
  415. } else {
  416. if( pjd->bHasUserVals ) {
  417. DPF( "USER entries changed, no longer exist!\r\n" );
  418. pjd->bHasUserVals = FALSE;
  419. pjd->bDeleteUserVals = TRUE;
  420. }
  421. }
  422. }
  423. /*
  424. * set our new values
  425. */
  426. RegSetValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, 0, REG_BINARY,
  427. (CONST LPBYTE)&uv, sizeof( uv ) );
  428. RegCloseKey( hkey );
  429. }
  430. } /* regSetUserVals */
  431. /*
  432. * regUserValsInit - save old user values, and init to ones we like
  433. */
  434. static void regUserValsInit( LPJOYDATA pjd )
  435. {
  436. HKEY hkey;
  437. DWORD regtype;
  438. DWORD cb;
  439. pjd->bHasUserVals = FALSE;
  440. pjd->bDeleteUserVals = FALSE;
  441. if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) {
  442. cb = sizeof( pjd->userVals );
  443. if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, NULL,
  444. &regtype, (CONST LPBYTE)&pjd->userVals, &cb)) {
  445. if( regtype == REG_BINARY && cb == sizeof( pjd->userVals ) ) {
  446. pjd->bHasUserVals = TRUE;
  447. DPF( "USER entries exist!\r\n" );
  448. }
  449. pjd->bHasNonStandardUserVals = checkNonStandardUserVals( &pjd->userVals );
  450. } else {
  451. pjd->bDeleteUserVals = TRUE;
  452. pjd->bHasNonStandardUserVals = FALSE;
  453. DPF( "USER entries don't exist!\r\n" );
  454. }
  455. RegCloseKey( hkey );
  456. }
  457. regSetUserVals( pjd, FALSE );
  458. } /* regUserValsInit */
  459. /*
  460. * regUserValsFini - restore old user values
  461. */
  462. static void regUserValsFini( LPJOYDATA pjd )
  463. {
  464. HKEY hkey;
  465. if( pjd->bResetUserVals ) {
  466. RegDeleteValue( hkey, REGSTR_VAL_JOYUSERVALUES );
  467. RegistryUpdated( NULL );
  468. } else if( pjd->bHasUserVals || pjd->bDeleteUserVals ) {
  469. if( !RegOpenKey( HKEY_LOCAL_MACHINE, pjd->regCfgKey, &hkey ) ) {
  470. if( pjd->bHasUserVals ) {
  471. DPF( "resetting USER entries!\r\n" );
  472. RegSetValueEx( hkey, REGSTR_VAL_JOYUSERVALUES, 0, REG_BINARY,
  473. (CONST LPBYTE)&pjd->userVals, sizeof( pjd->userVals ) );
  474. } else {
  475. DPF( "deleting USER entries!\r\n" );
  476. RegDeleteValue( hkey, REGSTR_VAL_JOYUSERVALUES );
  477. }
  478. RegistryUpdated( NULL );
  479. }
  480. pjd->bHasUserVals = FALSE;
  481. pjd->bDeleteUserVals = FALSE;
  482. }
  483. } /* regUserValsFini */
  484. /***************************************************************************
  485. CUSTOM JOYSTICK SELECTION FUNCTIONS FOLLOW
  486. ***************************************************************************/
  487. /*
  488. * custom joystick variables
  489. */
  490. typedef struct {
  491. LPGLOBALVARS pgv;
  492. BOOL bHasZ;
  493. BOOL bHasR;
  494. BOOL bHasPOV;
  495. BOOL bIsYoke;
  496. BOOL bIsGamePad;
  497. BOOL bIsCarCtrl;
  498. BOOL bHas2Buttons;
  499. } cust_vars, *LPCUSTVARS;
  500. /*
  501. * enableCustomSpecial - enable the special section of the custom dialog box
  502. */
  503. static void enableCustomSpecial( HWND hwnd, BOOL on )
  504. {
  505. EnableWindow( GetDlgItem( hwnd, IDC_JOYISYOKE ), on );
  506. EnableWindow( GetDlgItem( hwnd, IDC_JOYISGAMEPAD ), on );
  507. EnableWindow( GetDlgItem( hwnd, IDC_JOYISCARCTRL ), on );
  508. CheckDlgButton( hwnd, IDC_JOYUSESPECIAL, on );
  509. if( !on ) {
  510. CheckDlgButton( hwnd, IDC_JOYISYOKE, FALSE );
  511. CheckDlgButton( hwnd, IDC_JOYISGAMEPAD, FALSE );
  512. CheckDlgButton( hwnd, IDC_JOYISCARCTRL, FALSE );
  513. }
  514. } /* enableCustomSpecial */
  515. /*
  516. * context help for the custom settings dialog
  517. */
  518. const static DWORD aCustomHelpIDs[] = { // Context Help IDs
  519. IDC_GROUPBOX, IDH_JOYSTICK_CUSTOM_AXES,
  520. IDC_GROUPBOX_2, IDH_JOYSTICK_CUSTOM_BUTTONS,
  521. IDC_GROUPBOX_3, IDH_JOYSTICK_GROUPBOX,
  522. IDC_JOY2AXIS, IDH_JOYSTICK_CUSTOM_AXES,
  523. IDC_JOY3AXIS, IDH_JOYSTICK_CUSTOM_AXES,
  524. IDC_JOY4AXIS, IDH_JOYSTICK_CUSTOM_AXES,
  525. IDC_JOY2BUTTON, IDH_JOYSTICK_CUSTOM_BUTTONS,
  526. IDC_JOY4BUTTON, IDH_JOYSTICK_CUSTOM_BUTTONS,
  527. IDC_JOYHASPOV, IDH_JOYSTICK_CUSTOM_POV_HAT,
  528. IDC_JOYISYOKE, IDH_JOYSTICK_CUSTOM_FLIGHT_YOKE,
  529. IDC_JOYISGAMEPAD, IDH_JOYSTICK_CUSTOM_GAME_PAD,
  530. IDC_JOYISCARCTRL, IDH_JOYSTICK_CUSTOM_CAR_CONTROL,
  531. IDC_JOYUSESPECIAL, IDH_JOYSTICK_CUSTOM_CUSTOM_FEATURES,
  532. 0, 0
  533. };
  534. /*
  535. * CustomProc - callback procedure for custom joystick setup
  536. */
  537. BOOL CALLBACK CustomProc( HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
  538. {
  539. int id;
  540. LPGLOBALVARS pgv;
  541. LPCUSTVARS pcv;
  542. switch( umsg ) {
  543. case WM_DESTROY:
  544. /*
  545. * don't free the dialog's variables here, they are returned to the
  546. * creator; the creator will free them
  547. */
  548. break;
  549. case WM_INITDIALOG:
  550. /*
  551. * create variables for the custom dialog
  552. */
  553. pcv = DoAlloc( sizeof( cust_vars ) );
  554. SetWindowLong( hwnd, DWL_USER, (LONG) pcv );
  555. if( pcv == NULL ) {
  556. EndDialog( hwnd, 0 );
  557. return FALSE;
  558. }
  559. pgv = (LPGLOBALVARS) lParam;
  560. pcv->pgv = pgv;
  561. /*
  562. * set up initial dialog state
  563. */
  564. pcv->bHasZ = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASZ);
  565. pcv->bHasR = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASR);
  566. pcv->bHas2Buttons = (pgv->joyHWCurr.hws.dwNumButtons == 2);
  567. pcv->bHasPOV = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASPOV);
  568. pcv->bIsYoke = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISYOKE);
  569. pcv->bIsGamePad = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISGAMEPAD);
  570. pcv->bIsCarCtrl = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_ISCARCTRL);
  571. if( pcv->bHasZ && pcv->bHasR ) {
  572. CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY4AXIS );
  573. } else if( pcv->bHasZ ) {
  574. CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY3AXIS );
  575. } else {
  576. CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, IDC_JOY2AXIS );
  577. }
  578. if( pcv->bHas2Buttons ) {
  579. CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, IDC_JOY2BUTTON );
  580. } else {
  581. CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, IDC_JOY4BUTTON );
  582. }
  583. CheckDlgButton( hwnd, IDC_JOYHASPOV, pcv->bHasPOV );
  584. id = -1;
  585. if( pcv->bIsYoke ) {
  586. id = IDC_JOYISYOKE;
  587. } else if( pcv->bIsGamePad ) {
  588. id = IDC_JOYISGAMEPAD;
  589. } else if( pcv->bIsCarCtrl ) {
  590. id = IDC_JOYISCARCTRL;
  591. }
  592. if( id != -1 ) {
  593. enableCustomSpecial( hwnd, TRUE );
  594. CheckRadioButton( hwnd, IDC_JOYISYOKE, IDC_JOYISCARCTRL, id );
  595. } else {
  596. enableCustomSpecial( hwnd, FALSE );
  597. }
  598. return FALSE;
  599. case WM_HELP:
  600. WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, cszHelpFile,
  601. HELP_WM_HELP, (DWORD)(LPSTR) aCustomHelpIDs);
  602. return TRUE;
  603. case WM_CONTEXTMENU:
  604. WinHelp((HWND) wParam, cszHelpFile, HELP_CONTEXTMENU,
  605. (DWORD)(LPVOID) aCustomHelpIDs);
  606. return TRUE;
  607. case WM_COMMAND:
  608. pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER );
  609. id = GET_WM_COMMAND_ID(wParam, lParam);
  610. switch( id ) {
  611. case IDC_JOY2AXIS:
  612. case IDC_JOY3AXIS:
  613. case IDC_JOY4AXIS:
  614. CheckRadioButton( hwnd, IDC_JOY2AXIS, IDC_JOY4AXIS, id );
  615. pcv->bHasZ = FALSE;
  616. pcv->bHasR = FALSE;
  617. if( id == IDC_JOY3AXIS ) {
  618. pcv->bHasZ = TRUE;
  619. } else if( id == IDC_JOY4AXIS ) {
  620. pcv->bHasZ = TRUE;
  621. pcv->bHasR = TRUE;
  622. }
  623. break;
  624. case IDC_JOY2BUTTON:
  625. case IDC_JOY4BUTTON:
  626. CheckRadioButton( hwnd, IDC_JOY2BUTTON, IDC_JOY4BUTTON, id );
  627. pcv->bHas2Buttons = (id == IDC_JOY2BUTTON);
  628. break;
  629. case IDC_JOYUSESPECIAL:
  630. enableCustomSpecial( hwnd, IsDlgButtonChecked( hwnd, IDC_JOYUSESPECIAL ) );
  631. pcv->bIsYoke = FALSE;
  632. pcv->bIsGamePad = FALSE;
  633. pcv->bIsCarCtrl = FALSE;
  634. break;
  635. case IDC_JOYHASPOV:
  636. pcv->bHasPOV = !pcv->bHasPOV;
  637. break;
  638. case IDC_JOYISYOKE:
  639. case IDC_JOYISGAMEPAD:
  640. case IDC_JOYISCARCTRL:
  641. pcv->bIsYoke = (id == IDC_JOYISYOKE);
  642. pcv->bIsGamePad = (id == IDC_JOYISGAMEPAD);
  643. pcv->bIsCarCtrl = (id == IDC_JOYISCARCTRL);
  644. CheckRadioButton( hwnd, IDC_JOYISYOKE, IDC_JOYISCARCTRL, id );
  645. break;
  646. case IDCANCEL:
  647. pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER );
  648. DoFree( pcv );
  649. EndDialog( hwnd, 0 );
  650. break;
  651. case IDOK:
  652. pcv = (LPCUSTVARS) GetWindowLong( hwnd, DWL_USER );
  653. EndDialog(hwnd, (int) pcv );
  654. break;
  655. }
  656. break;
  657. default:
  658. break;
  659. }
  660. return FALSE;
  661. } /* CustomProc */
  662. /***************************************************************************
  663. MAIN DIALOG FUNCTIONS FOLLOW
  664. ***************************************************************************/
  665. /*
  666. * variables used by joystick tab dialog
  667. */
  668. typedef struct {
  669. LPGLOBALVARS pgv;
  670. } JTVARS, *LPJTVARS;
  671. /*
  672. * numJoyAxes - get number of axes on a joystick
  673. */
  674. static int numJoyAxes( LPGLOBALVARS pgv )
  675. {
  676. DWORD flags;
  677. int axis_count;
  678. flags = pgv->joyHWCurr.hws.dwFlags;
  679. axis_count = 2;
  680. if( flags & JOY_HWS_HASZ ) {
  681. axis_count++;
  682. }
  683. if( flags & JOY_HWS_HASR ) {
  684. axis_count++;
  685. }
  686. if( (flags & JOY_HWS_HASPOV) && (flags & JOY_HWS_POVISPOLL) ) {
  687. axis_count++;
  688. }
  689. return axis_count;
  690. } /* numJoyAxes */
  691. /*
  692. * saveHWSettings - save the current hardware settings
  693. */
  694. static void saveHWSettings( LPGLOBALVARS pgv )
  695. {
  696. pgv->joyHWOrig = pgv->joyHWCurr;
  697. } /* saveHWSettings */
  698. /*
  699. * restoreHWSettings - restore current hw settings to saved values
  700. */
  701. static void restoreHWSettings( LPGLOBALVARS pgv )
  702. {
  703. pgv->joyHWCurr = pgv->joyHWOrig;
  704. RegSaveCurrentJoyHW( pgv );
  705. } /* restoreHWSettings */
  706. /*
  707. * getActiveFlags - poll and test which joysticks are currently plugged in
  708. */
  709. static unsigned getActiveFlags( LPGLOBALVARS pgv )
  710. {
  711. JOYINFOEX ji;
  712. MMRESULT rc;
  713. unsigned val;
  714. /*
  715. * check for presense of joystick 1 and joystick 2
  716. */
  717. val = 0;
  718. ji.dwSize = sizeof( ji );
  719. ji.dwFlags = JOY_RETURNX|JOY_RETURNY|JOY_CAL_READXYONLY|JOY_CAL_READALWAYS;
  720. rc = joyGetPosEx( pgv->iJoyId, &ji );
  721. DPF( "joyGetPosEx = %d\r\n", rc );
  722. if( rc == JOYERR_NOERROR ) {
  723. val = HASJOY;
  724. }
  725. /*
  726. * check if either could have a rudder attached.
  727. */
  728. ji.dwFlags = JOY_RETURNR | JOY_CAL_READRONLY;
  729. if( (numJoyAxes( pgv ) < 4) &&
  730. !(pgv->joyHWCurr.hws.dwFlags & JOY_HWS_HASR ) ) {
  731. rc = joyGetPosEx( pgv->iJoyId, &ji );
  732. if( rc ==JOYERR_NOERROR ) {
  733. val |= HASRUDDERMAYBE;
  734. }
  735. }
  736. return val;
  737. } /* getActiveFlags */
  738. /*
  739. * enableTestCal - enable/disable test and calibrate buttons
  740. */
  741. static void enableTestCal( HWND hwnd, int hw_type )
  742. {
  743. BOOL enable;
  744. enable = (hw_type != JOY_HW_NONE);
  745. EnableWindow( GetDlgItem( hwnd, IDC_JOYCALIBRATE ), enable );
  746. EnableWindow( GetDlgItem( hwnd, IDC_JOYTEST ), enable );
  747. } /* enableTestCal */
  748. /*
  749. * cleanUpJoyDlg - clean up allocated stuff
  750. */
  751. static void cleanUpJoyDlg( HWND hwnd )
  752. {
  753. LPGLOBALVARS pgv;
  754. pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER );
  755. if( pgv == NULL ) {
  756. return;
  757. }
  758. /*
  759. * ditch timer
  760. */
  761. if( pgv->pjd->bHasTimer ) {
  762. KillTimer( hwnd, TIMER_ID );
  763. pgv->pjd->bHasTimer = FALSE;
  764. }
  765. /*
  766. * done with our variables
  767. */
  768. #if defined( WANT_SHEETS )
  769. DoFree( pgv );
  770. #endif
  771. } /* cleanUpJoyDlg */
  772. /*
  773. * enableJoyWindows - enable controls for a joystick
  774. */
  775. static void enableJoyWindows( LPGLOBALVARS pgv, HWND hwnd, BOOL enable )
  776. {
  777. // EnableWindow( GetDlgItem(hwnd,IDC_JOYSELECT), enable );
  778. // EnableWindow( GetDlgItem(hwnd,IDC_JOYSELECTMSG), enable );
  779. // EnableWindow( GetDlgItem(hwnd,IDC_JOYSTICK1_FRAME), enable );
  780. EnableWindow( GetDlgItem(hwnd,IDC_JOYCALIBRATE), enable );
  781. EnableWindow( GetDlgItem(hwnd,IDC_JOYTEST), enable );
  782. } /* enableJoyWindows */
  783. /*
  784. * enableActiveJoystick - enable dialog controls based on presence of joysticks
  785. */
  786. static void enableActiveJoystick( LPGLOBALVARS pgv, HWND hwnd )
  787. {
  788. BOOL allowj;
  789. HINSTANCE hinst;
  790. char str[MAX_STR];
  791. unsigned joys;
  792. LPSTR text;
  793. /*
  794. * check what joysticks are active; if it hasn't changed, just return
  795. */
  796. joys = getActiveFlags( pgv );
  797. if( pgv->joyActiveFlags == joys ) {
  798. return;
  799. }
  800. pgv->joyActiveFlags = joys;
  801. /*
  802. * turn off the rudder if it is gone
  803. */
  804. if( !(joys & HASRUDDERMAYBE) ) {
  805. pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_HASRUDDER;
  806. CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, FALSE );
  807. }
  808. /*
  809. * enable the appropriate windows
  810. */
  811. allowj = ((joys & HASJOY) != 0);
  812. enableJoyWindows( pgv, hwnd, allowj );
  813. EnableWindow( GetDlgItem( hwnd, IDC_JOY1HASRUDDER ), allowj && (joys & HASRUDDERMAYBE) );
  814. /*
  815. * set message for the user if there is no joystick plugged in, or if
  816. * there is no joystick driver present
  817. */
  818. if( allowj ) {
  819. text = "";
  820. } else {
  821. str[0] = 0;
  822. text = str;
  823. hinst = GetWindowInstance( hwnd );
  824. if( joyGetNumDevs() ) {
  825. LoadString( hinst , IDS_JOYUNPLUGGED, str, sizeof( str ) );
  826. } else {
  827. LoadString( hinst , IDS_JOYNOTPRESENT, str, sizeof( str ) );
  828. }
  829. }
  830. SetWindowText( GetDlgItem( hwnd, IDC_JOYMSG ), text );
  831. if( allowj ) {
  832. enableTestCal( hwnd, pgv->joyHWCurr.dwType );
  833. }
  834. if( allowj ) {
  835. pgv->joyHWCurr.dwUsageSettings |= JOY_US_PRESENT;
  836. } else {
  837. pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_PRESENT;
  838. }
  839. RegSaveCurrentJoyHW( pgv );
  840. RegistryUpdated( pgv );
  841. } /* enableActiveJoystick */
  842. /*
  843. * getNewJoyInfo - get information from the registry about a new joystick.
  844. * If no info, default to joyHWDefault settings
  845. */
  846. static void getNewJoyInfo( LPGLOBALVARS pgv, HWND hwnd )
  847. {
  848. UINT index;
  849. DWORD hw_type;
  850. HKEY hkey;
  851. char str[MAX_STR];
  852. char jcfg[MAX_STR];
  853. DWORD regtype;
  854. JOYREGHWCONFIG config;
  855. DWORD cb;
  856. BOOL same;
  857. int rc;
  858. GETKEYNAME( pgv, jcfg, REGSTR_VAL_JOYNCONFIG );
  859. /*
  860. * get the hardware type
  861. */
  862. index = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETCURSEL, 0, 0L );
  863. hw_type = SendDlgItemMessage( hwnd,IDC_JOYSELECT,CB_GETITEMDATA,index,0L );
  864. same = (hw_type == pgv->joyHWCurr.dwType);
  865. /*
  866. * read the info from the registry if a new hardware type selected
  867. */
  868. if( !same ) {
  869. pgv->joyHWCurr = pgv->pjd->joyHWDefaults[ hw_type ];
  870. createSettingsKeyFromCurr( pgv, str );
  871. if( !RegOpenKey( HKEY_LOCAL_MACHINE, str, &hkey ) ) {
  872. cb = sizeof( pgv->joyHWCurr );
  873. if( !RegQueryValueEx( hkey, jcfg, NULL, &regtype,
  874. (CONST LPBYTE)&config, &cb) ) {
  875. if( regtype == REG_BINARY && cb == sizeof( config ) ) {
  876. pgv->joyHWCurr.hws = config.hws;
  877. pgv->joyHWCurr.hwv = config.hwv;
  878. pgv->joyHWCurr.dwUsageSettings = config.dwUsageSettings;
  879. }
  880. }
  881. RegCloseKey( hkey );
  882. }
  883. /*
  884. * set up the rudder bit
  885. */
  886. if( pgv->joyHWCurr.dwUsageSettings & JOY_US_HASRUDDER ) {
  887. CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, TRUE );
  888. } else {
  889. if( IsDlgButtonChecked( hwnd, IDC_JOY1HASRUDDER ) ) {
  890. pgv->joyHWCurr.dwUsageSettings |= JOY_US_HASRUDDER;
  891. } else {
  892. pgv->joyHWCurr.dwUsageSettings &= ~JOY_US_HASRUDDER;
  893. }
  894. }
  895. }
  896. /*
  897. * disable test/calibrate buttons based on hardware picked
  898. */
  899. enableTestCal( hwnd, hw_type );
  900. /*
  901. * if custom selected, go get the data from the user
  902. */
  903. if( hw_type == JOY_HW_CUSTOM ) {
  904. rc = DialogBoxParam((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),
  905. MAKEINTRESOURCE(IDD_JOYCUSTOM), hwnd,
  906. CustomProc, (LONG) pgv );
  907. if( rc ) {
  908. LPCUSTVARS pcv;
  909. pcv = (LPCUSTVARS) rc;
  910. pgv->joyHWCurr.dwUsageSettings |= JOY_US_PRESENT;
  911. pgv->joyHWCurr.hws.dwFlags &= ~(JOY_HWS_HASR|JOY_HWS_HASZ|
  912. JOY_HWS_HASU| JOY_HWS_HASV|
  913. JOY_HWS_HASPOV|JOY_HWS_ISYOKE| JOY_HWS_ISGAMEPAD|
  914. JOY_HWS_ISCARCTRL| JOY_HWS_POVISPOLL|
  915. JOY_HWS_POVISBUTTONCOMBOS );
  916. /*
  917. * NOTE: for a custom joystick, we always assume that Z is
  918. * implemented on J2 Y.
  919. */
  920. if( pcv->bHasZ ) {
  921. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASZ;
  922. }
  923. /*
  924. * NOTE: for a custom joystick, we always assume that R is
  925. * implemented on J2 X.
  926. */
  927. if( pcv->bHasR ) {
  928. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASR;
  929. }
  930. if( pcv->bHasPOV ) {
  931. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_HASPOV;
  932. }
  933. if( pcv->bIsYoke ) {
  934. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISYOKE;
  935. }
  936. if( pcv->bIsGamePad ) {
  937. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISGAMEPAD;
  938. }
  939. if( pcv->bIsCarCtrl ) {
  940. pgv->joyHWCurr.hws.dwFlags |= JOY_HWS_ISCARCTRL;
  941. }
  942. if( pcv->bHas2Buttons ) {
  943. pgv->joyHWCurr.hws.dwNumButtons = 2;
  944. } else {
  945. pgv->joyHWCurr.hws.dwNumButtons = 4;
  946. }
  947. DoFree( pcv );
  948. same = FALSE;
  949. }
  950. }
  951. /*
  952. * update the registry with the new current joystick
  953. */
  954. if( !same ) {
  955. RegSaveCurrentJoyHW( pgv );
  956. RegistryUpdated( pgv );
  957. PropSheet_Changed( GetParent(hwnd), hwnd );
  958. pgv->joyActiveFlags = (unsigned) -1;
  959. enableActiveJoystick( pgv, hwnd );
  960. }
  961. } /* getNewJoyInfo */
  962. /*
  963. * initCurrentHW - set up the current hardware for the first time
  964. */
  965. static void initCurrentHW( LPGLOBALVARS pgv )
  966. {
  967. regGetCurrHW( pgv );
  968. pgv->joyActiveFlags = (unsigned) -1;
  969. saveHWSettings( pgv );
  970. } /* initCurrentHW */
  971. /*
  972. * newJoyId - set up for a new joystick id
  973. */
  974. static LPGLOBALVARS newJoyId( LPGLOBALVARS pgv, HWND hwnd, int joyid )
  975. {
  976. UINT index;
  977. UINT indexMax;
  978. if( joyid == pgv->iJoyId ) {
  979. return pgv;
  980. }
  981. #if !defined( WANT_SHEETS )
  982. pgv = &pgv->pjd->pgvlist[ joyid ];
  983. #endif
  984. pgv->iJoyId = joyid;
  985. /*
  986. * save the pointer to the variables
  987. */
  988. SetWindowLong( hwnd, DWL_USER, (LONG) pgv );
  989. #if defined( WANT_SHEETS )
  990. /*
  991. * set up current joystick hardware
  992. */
  993. initCurrentHW( pgv );
  994. #endif
  995. /*
  996. * set up windows
  997. */
  998. pgv->joyActiveFlags = (unsigned) -1;
  999. enableActiveJoystick( pgv, hwnd );
  1000. if( pgv->joyHWCurr.dwUsageSettings & JOY_US_HASRUDDER ) {
  1001. CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, TRUE );
  1002. } else {
  1003. CheckDlgButton( hwnd, IDC_JOY1HASRUDDER, FALSE );
  1004. }
  1005. /*
  1006. * select the current info
  1007. */
  1008. indexMax = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETCOUNT, 0, 0 );
  1009. for (index = 0; index < indexMax; index++)
  1010. {
  1011. DWORD type;
  1012. type = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_GETITEMDATA,
  1013. index, 0 );
  1014. if (type == pgv->joyHWCurr.dwType)
  1015. break;
  1016. }
  1017. if (index == indexMax)
  1018. index = 1; // custom
  1019. SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETCURSEL, index, 0L );
  1020. #if !defined( WANT_SHEETS )
  1021. SendDlgItemMessage( hwnd, IDC_JOYCURRENTID, CB_SETCURSEL, pgv->iJoyId, 0L );
  1022. #endif
  1023. return pgv;
  1024. } /* newJoyId */
  1025. /*
  1026. * showResetInfo
  1027. */
  1028. static void showResetInfo( HWND hwnd, BOOL show )
  1029. {
  1030. EnableWindow( GetDlgItem( hwnd, IDC_JOYTROUBLESHOOT_FRAME ), show );
  1031. EnableWindow( GetDlgItem( hwnd, IDC_JOYTROUBLESHOOT_TEXT ), show );
  1032. EnableWindow( GetDlgItem( hwnd, IDC_JOYRESET ), show );
  1033. } /* showResetInfo */
  1034. /*
  1035. * doJoyDlgInitDialog - process initialization for joystick tabbed dialog
  1036. */
  1037. static BOOL doJoyDlgInitDialog( HWND hwnd, LPARAM lParam )
  1038. {
  1039. HINSTANCE hinst;
  1040. LPPROPSHEETPAGE ppsp;
  1041. int i;
  1042. char str[MAX_STR];
  1043. LPGLOBALVARS pgv;
  1044. LPJOYDATA pjd;
  1045. LPJOYDATAPTR pjdp;
  1046. HKEY hkey;
  1047. /*
  1048. * pointer to data
  1049. */
  1050. ppsp = (LPPROPSHEETPAGE) lParam;
  1051. pjdp = (LPJOYDATAPTR) ppsp->lParam;
  1052. pjd = pjdp->pjd;
  1053. /*
  1054. * create global variables. These will be used by all dialogs
  1055. */
  1056. #if defined( WANT_SHEETS )
  1057. pgv = DoAlloc( sizeof( GLOBALVARS ) );
  1058. if( pgv == NULL ) {
  1059. return FALSE;
  1060. }
  1061. /*
  1062. * get joystick id that this sheet is for
  1063. */
  1064. pgv->iJoyId = pjdp->iJoyId;
  1065. pgv->pjd = pjd;
  1066. DPF( "Tab for joystick %d started\r\n", pgv->iJoyId );
  1067. #else
  1068. pgv = &pjd->pgvlist[ pjdp->iJoyId ];
  1069. #endif
  1070. /*
  1071. * get device caps
  1072. */
  1073. getDevCaps( pgv );
  1074. /*
  1075. * how many predefined joystick types should we display?
  1076. */
  1077. pgv->cJoystickTypes = 2; // display None and Custom only
  1078. if( !RegOpenKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYSTICK, &hkey ) ) {
  1079. DWORD type;
  1080. DWORD val = 0;
  1081. DWORD cb = sizeof(val);
  1082. if( !RegQueryValueEx( hkey, REGSTR_VAL_JOYTYPES, NULL,
  1083. &type, (CONST LPBYTE)&val, &cb) ) {
  1084. pgv->cJoystickTypes += val;
  1085. }
  1086. RegCloseKey( hkey );
  1087. }
  1088. pgv->cJoystickTypes = max( pgv->cJoystickTypes, 2 ); // Must have none/cust
  1089. pgv->cJoystickTypes = min( pgv->cJoystickTypes, 12 );
  1090. /*
  1091. * callback timer for checking if joysticks are plugged/unplugged
  1092. */
  1093. if( !pjd->bHasTimer ) {
  1094. pjd->bHasTimer = SetTimer( hwnd, TIMER_ID, JOYCHECKTIME, NULL );
  1095. pjd->bUseTimer = TRUE;
  1096. }
  1097. /*
  1098. * set up pre-defined joystick list
  1099. */
  1100. hinst = GetWindowInstance( hwnd );
  1101. for( i=IDS_JOYHW0; i<(IDS_JOYHW0 + pgv->cJoystickTypes); i++ ) {
  1102. if( LoadString( hinst , i, str, sizeof( str ) ) ) {
  1103. UINT dwItem;
  1104. dwItem = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_ADDSTRING, 0,
  1105. (LONG) (LPSTR) str );
  1106. SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETITEMDATA, dwItem,
  1107. i -IDS_JOYHW0 + JOY_HW_NONE );
  1108. }
  1109. }
  1110. /*
  1111. * set up OEM joystick list
  1112. */
  1113. for( i=0;i<pjd->oemCount;i++ ) {
  1114. UINT dwItem;
  1115. dwItem = SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_ADDSTRING, 0,
  1116. (LONG) (LPSTR) pjd->oemList[i].ident_string );
  1117. SendDlgItemMessage( hwnd, IDC_JOYSELECT, CB_SETITEMDATA,
  1118. dwItem, i +JOY_HW_LASTENTRY);
  1119. }
  1120. /*
  1121. * set up joystick choices list
  1122. */
  1123. #if !defined(WANT_SHEETS)
  1124. {
  1125. int numdevs;
  1126. char strid[MAX_STR];
  1127. if( LoadString( hinst, IDS_JOY, str, sizeof( str ) ) ) {
  1128. numdevs = joyGetNumDevs();
  1129. for( i=0;i<numdevs;i++ ) {
  1130. wsprintf( strid, "%s %d", str, i+1 );
  1131. SendDlgItemMessage( hwnd, IDC_JOYCURRENTID, CB_ADDSTRING, 0,
  1132. (LONG) (LPSTR) strid );
  1133. }
  1134. }
  1135. }
  1136. #endif
  1137. pgv->iJoyId = -1;
  1138. newJoyId( pgv, hwnd, pjdp->iJoyId );
  1139. /*
  1140. * enable/disable our Reset button
  1141. */
  1142. showResetInfo( hwnd, pjd->bHasNonStandardUserVals );
  1143. return TRUE;
  1144. } /* doJoyDlgInitDialog */
  1145. /*
  1146. * doJoyDlgCommand - process WM_COMMAND message for main joystick tabbed dialog
  1147. */
  1148. static void doJoyDlgCommand( HWND hwnd, int id, HWND hctl, UINT code )
  1149. {
  1150. LPGLOBALVARS pgv;
  1151. pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER );
  1152. switch( id ) {
  1153. /*
  1154. * new joystick has been picked
  1155. */
  1156. case IDC_JOYSELECT:
  1157. if( code == CBN_SELCHANGE ) {
  1158. getNewJoyInfo( pgv, hwnd );
  1159. }
  1160. break;
  1161. #if !defined( WANT_SHEET )
  1162. /*
  1163. * new joystick id has been picked
  1164. */
  1165. case IDC_JOYCURRENTID:
  1166. if( code == CBN_SELCHANGE ) {
  1167. int joyid;
  1168. joyid = SendDlgItemMessage( hwnd, IDC_JOYCURRENTID, CB_GETCURSEL, 0, 0L );
  1169. pgv = newJoyId( pgv, hwnd, joyid );
  1170. regSetUserVals( pgv->pjd, TRUE );
  1171. RegSaveCurrentJoyHW( pgv );
  1172. RegistryUpdated( pgv );
  1173. }
  1174. break;
  1175. #endif
  1176. /*
  1177. * calibrate current joystick
  1178. */
  1179. case IDC_JOYCALIBRATE:
  1180. pgv->pjd->bUseTimer = FALSE;
  1181. DoCalibrate( pgv, hwnd );
  1182. pgv->pjd->bUseTimer = TRUE;
  1183. break;
  1184. /*
  1185. * test either joystick 1 or joystick 2
  1186. */
  1187. case IDC_JOYTEST:
  1188. pgv->pjd->bUseTimer = FALSE;
  1189. DoTest( pgv, hwnd, NULL, pgv );
  1190. pgv->pjd->bUseTimer = TRUE;
  1191. break;
  1192. /*
  1193. * reset to user values
  1194. */
  1195. case IDC_JOYRESET:
  1196. pgv->pjd->bResetUserVals = TRUE;
  1197. PropSheet_Changed( GetParent(hwnd), hwnd );
  1198. break;
  1199. /*
  1200. * rudder selected/unselected
  1201. */
  1202. case IDC_JOY1HASRUDDER:
  1203. {
  1204. LPJOYREGHWCONFIG pcfg;
  1205. /*
  1206. * rudder status changed, force recalibration (leave POV alone if
  1207. * it was button based)
  1208. */
  1209. pcfg = &pgv->joyHWCurr;
  1210. if( (pcfg->hws.dwFlags & JOY_HWS_HASPOV) &&
  1211. (pcfg->hws.dwFlags & JOY_HWS_POVISBUTTONCOMBOS) ) {
  1212. pcfg->hwv.dwCalFlags &= JOY_ISCAL_POV;
  1213. } else {
  1214. pcfg->hwv.dwCalFlags = 0;
  1215. }
  1216. if( IsDlgButtonChecked( hwnd, id ) ) {
  1217. pcfg->dwUsageSettings |= JOY_US_HASRUDDER;
  1218. } else {
  1219. pcfg->dwUsageSettings &= ~JOY_US_HASRUDDER;
  1220. }
  1221. pgv->joyActiveFlags = (unsigned) -1;
  1222. enableActiveJoystick( pgv, hwnd );
  1223. PropSheet_Changed( GetParent(hwnd), hwnd );
  1224. break;
  1225. }
  1226. case ID_APPLY:
  1227. {
  1228. DPF( "ID_APPLY\r\n" );
  1229. #if !defined( WANT_SHEETS )
  1230. {
  1231. int i;
  1232. int numjoys;
  1233. numjoys = joyGetNumDevs();
  1234. for( i=0;i<numjoys;i++ ) {
  1235. regPermSaveAllInfo( &pgv->pjd->pgvlist[i] );
  1236. saveHWSettings( &pgv->pjd->pgvlist[i] );
  1237. }
  1238. }
  1239. #else
  1240. regPermSaveAllInfo( pgv );
  1241. saveHWSettings( pgv );
  1242. #endif
  1243. if( pgv->pjd->bResetUserVals ) {
  1244. regUserValsFini( pgv->pjd );
  1245. regUserValsInit( pgv->pjd );
  1246. pgv->pjd->bResetUserVals = FALSE;
  1247. }
  1248. showResetInfo( hwnd, pgv->pjd->bHasNonStandardUserVals );
  1249. break;
  1250. }
  1251. case ID_INIT:
  1252. DPF( "ID_INIT\r\n" );
  1253. /*
  1254. * we've been re-activated, reset the current joystick settings
  1255. */
  1256. regSetUserVals( pgv->pjd, TRUE );
  1257. RegSaveCurrentJoyHW( pgv );
  1258. RegistryUpdated( pgv );
  1259. break;
  1260. case IDOK:
  1261. DPF( "IDOK\r\n" );
  1262. EndDialog(hwnd, TRUE );
  1263. break;
  1264. case IDCANCEL:
  1265. DPF( "IDCANCEL\r\n" );
  1266. pgv->pjd->bResetUserVals = FALSE;
  1267. #if !defined( WANT_SHEETS )
  1268. {
  1269. int i;
  1270. int numjoys;
  1271. numjoys = joyGetNumDevs();
  1272. for( i=0;i<numjoys;i++ ) {
  1273. restoreHWSettings( &pgv->pjd->pgvlist[i] );
  1274. }
  1275. }
  1276. #else
  1277. restoreHWSettings( pgv );
  1278. #endif
  1279. RegistryUpdated( pgv );
  1280. EndDialog(hwnd, FALSE );
  1281. break;
  1282. default:
  1283. break;
  1284. }
  1285. } /* doJoyDlgCommand */
  1286. /*
  1287. * context help for the main dialog
  1288. */
  1289. const static DWORD aJoystickHelpIDs[] = { // Context Help IDs
  1290. IDC_JOYCURRENTIDMSG, IDH_JOYSTICK_CURRENT,
  1291. IDC_JOYCURRENTID, IDH_JOYSTICK_CURRENT,
  1292. IDC_JOYSELECTMSG, IDH_JOYSTICK_SELECT,
  1293. IDC_JOYSELECT, IDH_JOYSTICK_SELECT,
  1294. IDC_JOY1HASRUDDER, IDH_JOYSTICK_RUDDER,
  1295. IDC_JOYCALIBRATE, IDH_JOYSTICK_CALIBRATE,
  1296. IDC_JOYTEST, IDH_JOYSTICK_TEST,
  1297. IDC_JOYSTICK1_FRAME, IDH_JOYSTICK_GROUPBOX,
  1298. IDC_JOYMSG, NO_HELP,
  1299. IDC_ICON_1, NO_HELP,
  1300. IDC_ICON_2, NO_HELP,
  1301. IDC_JOYTROUBLESHOOT_FRAME, IDH_JOYSTICK_RESET,
  1302. IDC_JOYRESET, IDH_JOYSTICK_RESET,
  1303. IDC_JOYTROUBLESHOOT_TEXT, NO_HELP,
  1304. 0, 0
  1305. };
  1306. /*
  1307. * JoystickDlg - dialog procedure for joystick tabbed dialog
  1308. */
  1309. BOOL CALLBACK JoystickDlg( HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
  1310. {
  1311. BOOL rc;
  1312. switch( umsg ) {
  1313. case WM_INITDIALOG:
  1314. rc = doJoyDlgInitDialog( hwnd, lParam );
  1315. if( !rc ) {
  1316. EndDialog( hwnd, 0 );
  1317. }
  1318. return FALSE;
  1319. case WM_COMMAND:
  1320. HANDLE_WM_COMMAND( hwnd, wParam, lParam, doJoyDlgCommand );
  1321. break;
  1322. case WM_ACTIVATE:
  1323. /*
  1324. * we've been activated, pretend we were re-selected
  1325. */
  1326. if( LOWORD( wParam ) != WA_INACTIVE ) {
  1327. FORWARD_WM_COMMAND( hwnd, ID_INIT, 0, 0, SendMessage );
  1328. }
  1329. break;
  1330. case WM_DESTROY:
  1331. cleanUpJoyDlg( hwnd );
  1332. break;
  1333. case WM_TIMER:
  1334. {
  1335. LPGLOBALVARS pgv;
  1336. pgv = (LPGLOBALVARS) GetWindowLong( hwnd, DWL_USER );
  1337. if( pgv->pjd->bUseTimer ) {
  1338. pgv->pjd->bUseTimer = FALSE;
  1339. enableActiveJoystick( pgv, hwnd );
  1340. pgv->pjd->bUseTimer = TRUE;
  1341. }
  1342. break;
  1343. }
  1344. case WM_HELP:
  1345. WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, cszHelpFile,
  1346. HELP_WM_HELP, (DWORD)(LPSTR) aJoystickHelpIDs);
  1347. return TRUE;
  1348. case WM_CONTEXTMENU:
  1349. WinHelp((HWND) wParam, cszHelpFile, HELP_CONTEXTMENU,
  1350. (DWORD)(LPVOID) aJoystickHelpIDs);
  1351. return TRUE;
  1352. case WM_NOTIFY:
  1353. {
  1354. NMHDR FAR * lpnm = (NMHDR FAR *)lParam;
  1355. switch(lpnm->code) {
  1356. case PSN_KILLACTIVE:
  1357. FORWARD_WM_COMMAND( hwnd, IDOK, 0, 0, SendMessage );
  1358. return TRUE;
  1359. case PSN_APPLY:
  1360. FORWARD_WM_COMMAND( hwnd, ID_APPLY, 0, 0, SendMessage );
  1361. return TRUE;
  1362. case PSN_SETACTIVE:
  1363. FORWARD_WM_COMMAND( hwnd, ID_INIT, 0, 0, SendMessage );
  1364. return TRUE;
  1365. case PSN_RESET:
  1366. FORWARD_WM_COMMAND( hwnd, IDCANCEL, 0, 0, SendMessage );
  1367. return TRUE;
  1368. }
  1369. break;
  1370. }
  1371. default:
  1372. break;
  1373. }
  1374. return FALSE;
  1375. } /* JoystickDlg */
  1376. /***************************************************************************
  1377. GLOBAL JOYSTICK DATA FUNCTIONS FOLLOW
  1378. ***************************************************************************/
  1379. /*
  1380. * default joysticks
  1381. */
  1382. #define TYPE00 0
  1383. #define TYPE01 0
  1384. #define TYPE02 0
  1385. #define TYPE03 0
  1386. #define TYPE04 JOY_HWS_ISGAMEPAD
  1387. #define TYPE05 JOY_HWS_ISYOKE
  1388. #define TYPE06 JOY_HWS_HASZ | JOY_HWS_ISYOKE
  1389. #define TYPE07 JOY_HWS_HASZ
  1390. #define TYPE08 JOY_HWS_HASZ
  1391. #define TYPE09 JOY_HWS_ISGAMEPAD
  1392. #define TYPE10 JOY_HWS_ISYOKE
  1393. #define TYPE11 JOY_HWS_HASZ | JOY_HWS_ISYOKE
  1394. static JOYREGHWCONFIG _joyHWDefaults[] =
  1395. {
  1396. { {TYPE00,0},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_NONE},
  1397. { {TYPE01,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_CUSTOM},
  1398. { {TYPE02,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2A_2B_GENERIC},
  1399. { {TYPE03,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2A_4B_GENERIC},
  1400. { {TYPE04,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_GAMEPAD},
  1401. { {TYPE05,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_FLIGHTYOKE},
  1402. { {TYPE06,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_2B_FLIGHTYOKETHROTTLE},
  1403. { {TYPE07,2},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_3A_2B_GENERIC},
  1404. { {TYPE08,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_3A_4B_GENERIC},
  1405. { {TYPE09,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_GAMEPAD},
  1406. { {TYPE10,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_FLIGHTYOKE},
  1407. { {TYPE11,4},JOY_US_PRESENT,{{0,0,0,0,0,0,0,0,0},{0,0,0,0}},JOY_HW_4B_FLIGHTYOKETHROTTLE},
  1408. };
  1409. /*
  1410. * registry strings for calibration messages
  1411. */
  1412. static LPSTR _oemCalRegStrs[] =
  1413. {
  1414. REGSTR_VAL_JOYOEMCAL1,
  1415. REGSTR_VAL_JOYOEMCAL2,
  1416. REGSTR_VAL_JOYOEMCAL3,
  1417. REGSTR_VAL_JOYOEMCAL4,
  1418. REGSTR_VAL_JOYOEMCAL5,
  1419. REGSTR_VAL_JOYOEMCAL6,
  1420. REGSTR_VAL_JOYOEMCAL7,
  1421. REGSTR_VAL_JOYOEMCAL8,
  1422. REGSTR_VAL_JOYOEMCAL9,
  1423. REGSTR_VAL_JOYOEMCAL10,
  1424. REGSTR_VAL_JOYOEMCAL11,
  1425. REGSTR_VAL_JOYOEMCAL12,
  1426. };
  1427. /*
  1428. * base registry keys
  1429. */
  1430. static char szCfgKey[] = REGSTR_PATH_JOYCONFIG;
  1431. static char szCurrCfgKey[] = REGSTR_KEY_JOYCURR;
  1432. static char szSettingsCfgKey[] = REGSTR_KEY_JOYSETTINGS;
  1433. /*
  1434. * freeOEMListItem - free a list of oem data
  1435. */
  1436. static void freeOEMListItem( LPJOYDATA pjd, int i )
  1437. {
  1438. int j;
  1439. DoFree( pjd->oemList[i].keyname );
  1440. DoFree( pjd->oemList[i].ident_string );
  1441. DoFree( pjd->oemList[i].vxd_name );
  1442. DoFree( pjd->oemList[i].xy_label );
  1443. DoFree( pjd->oemList[i].z_label );
  1444. DoFree( pjd->oemList[i].r_label );
  1445. DoFree( pjd->oemList[i].u_label );
  1446. DoFree( pjd->oemList[i].v_label );
  1447. DoFree( pjd->oemList[i].pov_label );
  1448. DoFree( pjd->oemList[i].testmove_desc );
  1449. DoFree( pjd->oemList[i].testbutton_desc );
  1450. DoFree( pjd->oemList[i].testmove_cap );
  1451. DoFree( pjd->oemList[i].testbutton_cap );
  1452. DoFree( pjd->oemList[i].testwin_cap );
  1453. DoFree( pjd->oemList[i].cal_cap );
  1454. DoFree( pjd->oemList[i].calwin_cap );
  1455. for( j=0;j<NUM_CAL_STRS;j++ ) {
  1456. DoFree( pjd->oemList[i].cal_strs[j] );
  1457. }
  1458. } /* freeOEMListItem */
  1459. /*
  1460. * initHWDefaults - initialize the hardware list: use defaults + OEM types
  1461. * defined in the registry
  1462. */
  1463. static void initHWDefaults( LPJOYDATA pjd )
  1464. {
  1465. int list_size;
  1466. int def_size;
  1467. DWORD isubkey;
  1468. DWORD keyidx;
  1469. HKEY hkey;
  1470. HKEY hsubkey;
  1471. char str[MAX_STR];
  1472. DWORD clsize;
  1473. DWORD num_subkeys;
  1474. DWORD dont_care;
  1475. DWORD longest_key;
  1476. FILETIME ftime;
  1477. LPSTR keyname;
  1478. JOYREGHWSETTINGS hws;
  1479. DWORD longest_val;
  1480. DWORD type;
  1481. DWORD cb;
  1482. int i;
  1483. int j;
  1484. int ctype;
  1485. LPSTR tmpstr;
  1486. int fail;
  1487. def_size = sizeof( _joyHWDefaults )/sizeof( _joyHWDefaults[0] );
  1488. list_size = def_size;
  1489. pjd->oemCount = 0;
  1490. if( !RegOpenKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, &hkey ) ) {
  1491. clsize = sizeof( str );
  1492. if( !RegQueryInfoKey ( hkey, str, &clsize, NULL, &num_subkeys,
  1493. &longest_key, &dont_care, &dont_care, &dont_care,
  1494. &dont_care, // address of buffer for longest value data length
  1495. &dont_care, &ftime ) ) {
  1496. pjd->oemList = DoAlloc( num_subkeys * sizeof( OEMLIST ));
  1497. if( pjd->oemList != NULL ) {
  1498. pjd->oemCount = num_subkeys;
  1499. list_size += num_subkeys;
  1500. }
  1501. longest_key++;
  1502. }
  1503. }
  1504. pjd->joyHWDefaults = DoAlloc( list_size * sizeof( JOYREGHWCONFIG ) );
  1505. if( pjd->joyHWDefaults == NULL ) {
  1506. pjd->joyHWDefaults = _joyHWDefaults;
  1507. } else {
  1508. memcpy( pjd->joyHWDefaults, _joyHWDefaults, def_size * sizeof( JOYREGHWCONFIG ) );
  1509. /*
  1510. * if we have keys in the registry, go fetch them
  1511. */
  1512. if( list_size > def_size ) {
  1513. isubkey = 0;
  1514. keyidx = 0;
  1515. keyname = DoAlloc( longest_key );
  1516. if( keyname == NULL ) {
  1517. keyname = str;
  1518. longest_key = sizeof( str );
  1519. }
  1520. /*
  1521. * run through all keys, getting the info on them
  1522. */
  1523. while( !RegEnumKey( hkey, keyidx, keyname, longest_key ) ) {
  1524. if( !RegOpenKey( hkey, keyname, &hsubkey ) ) {
  1525. if( !RegQueryInfoKey ( hsubkey, str, &clsize, NULL,
  1526. &dont_care, &dont_care, &dont_care, &dont_care,
  1527. &dont_care, &longest_val, &dont_care, &ftime ) ) {
  1528. pjd->oemList[isubkey].keyname = DoAlloc( strlen( keyname ) +1 );
  1529. tmpstr = DoAlloc( longest_val+1 );
  1530. if( pjd->oemList[isubkey].keyname != NULL && tmpstr != NULL ) {
  1531. strcpy( pjd->oemList[isubkey].keyname, keyname );
  1532. cb = sizeof( hws );
  1533. if( !RegQueryValueEx( hsubkey, REGSTR_VAL_JOYOEMDATA, NULL,
  1534. &type, (CONST LPBYTE)&hws, &cb) ) {
  1535. if( type == REG_BINARY && cb == sizeof( hws ) ) {
  1536. pjd->oemList[isubkey].hws = hws;
  1537. }
  1538. }
  1539. fail = 0;
  1540. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALLOUT,
  1541. tmpstr, longest_val,
  1542. &pjd->oemList[isubkey].vxd_name );
  1543. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMNAME,
  1544. tmpstr, longest_val,
  1545. &pjd->oemList[isubkey].ident_string );
  1546. for( j=0;j<NUM_CAL_STRS;j++ ) {
  1547. fail |= regGetOEMStr( hsubkey, _oemCalRegStrs[j],
  1548. tmpstr, longest_val,
  1549. &pjd->oemList[isubkey].cal_strs[j] );
  1550. }
  1551. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMXYLABEL,
  1552. tmpstr, longest_val,
  1553. &pjd->oemList[isubkey].xy_label );
  1554. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMZLABEL,
  1555. tmpstr, longest_val,
  1556. &pjd->oemList[isubkey].z_label );
  1557. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMRLABEL,
  1558. tmpstr, longest_val,
  1559. &pjd->oemList[isubkey].r_label );
  1560. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMULABEL,
  1561. tmpstr, longest_val,
  1562. &pjd->oemList[isubkey].u_label );
  1563. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMVLABEL,
  1564. tmpstr, longest_val,
  1565. &pjd->oemList[isubkey].v_label );
  1566. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMPOVLABEL,
  1567. tmpstr, longest_val,
  1568. &pjd->oemList[isubkey].pov_label );
  1569. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTMOVEDESC,
  1570. tmpstr, longest_val,
  1571. &pjd->oemList[isubkey].testmove_desc );
  1572. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTBUTTONDESC,
  1573. tmpstr, longest_val,
  1574. &pjd->oemList[isubkey].testbutton_desc );
  1575. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTMOVECAP,
  1576. tmpstr, longest_val,
  1577. &pjd->oemList[isubkey].testmove_cap );
  1578. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTBUTTONCAP,
  1579. tmpstr, longest_val,
  1580. &pjd->oemList[isubkey].testbutton_cap );
  1581. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMTESTWINCAP,
  1582. tmpstr, longest_val,
  1583. &pjd->oemList[isubkey].testwin_cap );
  1584. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALCAP,
  1585. tmpstr, longest_val,
  1586. &pjd->oemList[isubkey].cal_cap );
  1587. fail |= regGetOEMStr( hsubkey, REGSTR_VAL_JOYOEMCALWINCAP,
  1588. tmpstr, longest_val,
  1589. &pjd->oemList[isubkey].calwin_cap );
  1590. if( fail ) {
  1591. freeOEMListItem( pjd, isubkey );
  1592. } else {
  1593. isubkey++;
  1594. }
  1595. } else {
  1596. DoFree( pjd->oemList[isubkey].keyname );
  1597. }
  1598. DoFree( tmpstr );
  1599. RegCloseKey( hsubkey );
  1600. }
  1601. }
  1602. keyidx++;
  1603. }
  1604. pjd->oemCount = isubkey;
  1605. /*
  1606. * sort the list, and then fill in the joyHWDefault array
  1607. */
  1608. if( pjd->oemCount > 0 ) {
  1609. for( i=0;i<pjd->oemCount;i++ ) {
  1610. for( j=i;j<pjd->oemCount;j++ ) {
  1611. OEMLIST ol;
  1612. if( strcmp( pjd->oemList[i].ident_string,
  1613. pjd->oemList[j].ident_string ) > 0 ) {
  1614. ol = pjd->oemList[i];
  1615. pjd->oemList[i] = pjd->oemList[j];
  1616. pjd->oemList[j] = ol;
  1617. }
  1618. }
  1619. }
  1620. for( i=0;i<pjd->oemCount;i++ ) {
  1621. ctype = i+JOY_HW_LASTENTRY;
  1622. memset( &pjd->joyHWDefaults[ctype], 0,
  1623. sizeof( pjd->joyHWDefaults[ctype] ) );
  1624. pjd->joyHWDefaults[ctype].hws = pjd->oemList[i].hws;
  1625. pjd->joyHWDefaults[ctype].dwUsageSettings = JOY_US_ISOEM|JOY_US_PRESENT;
  1626. pjd->joyHWDefaults[ctype].dwType = ctype;
  1627. }
  1628. }
  1629. if( keyname != str ) {
  1630. DoFree( keyname );
  1631. }
  1632. }
  1633. }
  1634. } /* initHWDefaults */
  1635. /*
  1636. * finiHWList - finished with the hardware list, free it
  1637. */
  1638. static void finiHWList( LPJOYDATA pjd )
  1639. {
  1640. int i;
  1641. if( pjd->joyHWDefaults != NULL ) {
  1642. if( pjd->joyHWDefaults != _joyHWDefaults ) {
  1643. DoFree( pjd->joyHWDefaults );
  1644. }
  1645. pjd->joyHWDefaults = NULL;
  1646. }
  1647. if( pjd->oemList != NULL ) {
  1648. for( i=0;i<pjd->oemCount;i++ ) {
  1649. freeOEMListItem( pjd, i );
  1650. }
  1651. DoFree( pjd->oemList );
  1652. pjd->oemList = NULL;
  1653. pjd->oemCount = 0;
  1654. }
  1655. } /* finiHWList */
  1656. /*
  1657. * getRegKeys - get the registry keys we need
  1658. */
  1659. static void getRegKeys( LPJOYDATA pjd )
  1660. {
  1661. int len;
  1662. JOYCAPS jc;
  1663. if (joyGetDevCaps (0, &jc, sizeof(jc)) != JOYERR_NOERROR)
  1664. lstrcpy (jc.szRegKey, TEXT("joystick.dll<0000>"));
  1665. /*
  1666. * set up registry keys
  1667. */
  1668. pjd->regCfgKey = NULL;
  1669. pjd->regCurrCfgKey = NULL;
  1670. pjd->regSettingsCfgKey = NULL;
  1671. len = sizeof( szCfgKey );
  1672. pjd->regCfgKey = DoAlloc( len );
  1673. if( pjd->regCfgKey != NULL ) {
  1674. strcpy( pjd->regCfgKey, szCfgKey );
  1675. pjd->regCurrCfgKey = DoAlloc( len +1 +1 +lstrlen(jc.szRegKey) +sizeof( szCurrCfgKey ) );
  1676. if( pjd->regCurrCfgKey != NULL ) {
  1677. strcpy( pjd->regCurrCfgKey, pjd->regCfgKey );
  1678. strcat( pjd->regCurrCfgKey, "\\" );
  1679. strcat( pjd->regCurrCfgKey, jc.szRegKey );
  1680. strcat( pjd->regCurrCfgKey, "\\" );
  1681. strcat( pjd->regCurrCfgKey, szCurrCfgKey );
  1682. }
  1683. pjd->regSettingsCfgKey = DoAlloc( len +1 +1 +lstrlen(jc.szRegKey) +sizeof( szSettingsCfgKey ) );
  1684. if( pjd->regSettingsCfgKey != NULL ) {
  1685. strcpy( pjd->regSettingsCfgKey, pjd->regCfgKey );
  1686. strcat( pjd->regSettingsCfgKey, "\\" );
  1687. strcat( pjd->regSettingsCfgKey, jc.szRegKey );
  1688. strcat( pjd->regSettingsCfgKey, "\\" );
  1689. strcat( pjd->regSettingsCfgKey, szSettingsCfgKey );
  1690. }
  1691. }
  1692. } /* getRegKeys */
  1693. /*
  1694. * JoystickDataInit
  1695. */
  1696. LPJOYDATA JoystickDataInit( void )
  1697. {
  1698. LPJOYDATA pjd;
  1699. pjd = DoAlloc( sizeof( JOYDATA ) );
  1700. if( pjd == NULL ) {
  1701. return NULL;
  1702. }
  1703. /*
  1704. * go set up all our defaults + oem lists
  1705. */
  1706. initHWDefaults( pjd );
  1707. /*
  1708. * get registry keys used by everyone
  1709. */
  1710. getRegKeys( pjd );
  1711. /*
  1712. * brushes for use by button display and bar display (z & r info)
  1713. */
  1714. pjd->hbUp = CreateSolidBrush( ACTIVE_COLOR );
  1715. pjd->hbDown = CreateSolidBrush( INACTIVE_COLOR );
  1716. /*
  1717. * set up user values we like
  1718. */
  1719. regUserValsInit( pjd );
  1720. #if !defined( WANT_SHEETS )
  1721. {
  1722. /*
  1723. * set up array of "global" vars (global to a joystick id)
  1724. */
  1725. int numjoys;
  1726. int i;
  1727. numjoys = joyGetNumDevs();
  1728. if( numjoys == 0 ) {
  1729. return NULL;
  1730. }
  1731. pjd->pgvlist = DoAlloc( sizeof( GLOBALVARS ) * numjoys );
  1732. if( pjd->pgvlist == NULL ) {
  1733. return NULL;
  1734. }
  1735. for( i=0;i<numjoys;i++ ) {
  1736. pjd->pgvlist[i].iJoyId = i;
  1737. pjd->pgvlist[i].pjd = pjd;
  1738. initCurrentHW( &pjd->pgvlist[i] );
  1739. }
  1740. }
  1741. #endif
  1742. return pjd;
  1743. } /* JoystickDataInit */
  1744. /*
  1745. * JoystickDataFini - finished with DLL wide joystick data data
  1746. */
  1747. void JoystickDataFini( LPJOYDATA pjd )
  1748. {
  1749. /*
  1750. * ditch brushes
  1751. */
  1752. if( pjd->hbUp != NULL ) {
  1753. DeleteObject( pjd->hbUp );
  1754. }
  1755. if( pjd->hbDown != NULL ) {
  1756. DeleteObject( pjd->hbDown );
  1757. }
  1758. /*
  1759. * done with hardware list
  1760. */
  1761. finiHWList( pjd );
  1762. /*
  1763. * restore user values in registry
  1764. */
  1765. regUserValsFini( pjd );
  1766. /*
  1767. * done with registry keys
  1768. */
  1769. DoFree( pjd->regCfgKey );
  1770. DoFree( pjd->regCurrCfgKey );
  1771. DoFree( pjd->regSettingsCfgKey );
  1772. #if !defined( WANT_SHEETS )
  1773. DoFree( pjd->pgvlist );
  1774. #endif
  1775. /*
  1776. * free up the joystick data
  1777. */
  1778. DoFree( pjd );
  1779. #ifdef DEBUG
  1780. if( allocCount != 0 ) {
  1781. MBOX( "Memory left unfreed: %d allocations", allocCount );
  1782. }
  1783. #endif
  1784. } /* JoystickDataFini */