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.

1644 lines
40 KiB

  1. //****************************************************************************
  2. //
  3. // File: joycal.c
  4. // Content: Joystick calibration dialog
  5. // History:
  6. // Date By Reason
  7. // ==== == ======
  8. // 11-dec-94 craige split out of joycpl.c; some tweaks
  9. // 15-dec-94 craige allow N joysticks
  10. // 17-dec-94 craige new UI as requested by ChrisB
  11. // 18-dec-94 craige process UV
  12. // 05-jan-95 craige new centering confirmation messages
  13. // 04-mar-95 craige bug 10761 - separate strings for pluralization
  14. // bug 12036 - now works when "Back" clicked off of
  15. // custom 4-axis with POV hat
  16. //
  17. // Copyright (c) Microsoft Corporation 1994-1995
  18. //
  19. //****************************************************************************
  20. #include "joycpl.h"
  21. /*
  22. * This has the look and feel of a wizard, but isn't This leads to the
  23. * obvious...
  24. *
  25. * Q: Why isn't this a "real" wizard?
  26. *
  27. * A: - it doesn't have multiple pages, it has a single page. the user
  28. * sees different joystick items activate and de-activate on the dialog
  29. * as he/she calibrates each axis. fussing with multiple sheets for each
  30. * axis would be confusing and unnecessary.
  31. */
  32. /*
  33. * calibration states
  34. */
  35. typedef enum {
  36. JCS_INIT=-1,
  37. JCS_XY_CENTER1,
  38. JCS_XY_MOVE,
  39. JCS_XY_CENTER2,
  40. JCS_Z_MOVE,
  41. JCS_Z_PLACEHOLDER,
  42. JCS_R_MOVE,
  43. JCS_R_PLACEHOLDER,
  44. JCS_U_MOVE,
  45. JCS_U_PLACEHOLDER,
  46. JCS_V_MOVE,
  47. JCS_V_PLACEHOLDER,
  48. JCS_POV_MOVEUP,
  49. JCS_POV_MOVERIGHT,
  50. JCS_POV_MOVEDOWN,
  51. JCS_POV_MOVELEFT,
  52. JCS_FINI
  53. } cal_states;
  54. typedef enum {
  55. JC_XY=0,
  56. JC_Z,
  57. JC_POV_UP,
  58. JC_POV_RIGHT,
  59. JC_POV_DOWN,
  60. JC_POV_LEFT,
  61. JC_R,
  62. JC_U,
  63. JC_V,
  64. JC_FINI
  65. } cal_wins;
  66. /*
  67. * variables used in calibration
  68. */
  69. typedef struct {
  70. LPGLOBALVARS pgv;
  71. cal_states cState;
  72. BOOL bHasTimer;
  73. BOOL bUseTimer;
  74. HINSTANCE hinst;
  75. JOYINFOEX ji;
  76. JOYRANGE jr;
  77. DWORD pov[JOY_POV_NUMDIRS];
  78. int iAxisCount;
  79. BOOL bPOVdone;
  80. } CALVARS, *LPCALVARS;
  81. #define JOY_CALIB_FLAGS JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | \
  82. JOY_RETURNR | JOY_RETURNU | JOY_RETURNV | \
  83. JOY_RETURNBUTTONS | JOY_RETURNRAWDATA
  84. /*
  85. * setDefaultButton - make a button the default window
  86. */
  87. static void setDefaultButton( HWND hwnd, HWND hwdb )
  88. {
  89. DWORD style;
  90. int i;
  91. HWND hwb;
  92. int idList[] = { IDC_JOYCALBACK,
  93. IDC_JOYCALNEXT,
  94. IDC_JOYPICKPOV,
  95. IDC_JOYCALDONE,
  96. IDC_JOYTEST };
  97. /*
  98. * turn off the current default push button
  99. */
  100. for( i=0;i<sizeof( idList )/sizeof( idList[0] );i++ ) {
  101. hwb = GetDlgItem( hwnd, idList[i] );
  102. style = GetWindowLong( hwb, GWL_STYLE );
  103. if( style & BS_DEFPUSHBUTTON ) {
  104. style &= ~BS_DEFPUSHBUTTON;
  105. style |= BS_PUSHBUTTON;
  106. SetWindowLong( hwb, GWL_STYLE, style );
  107. }
  108. }
  109. /*
  110. * make the specified button the default
  111. */
  112. style = GetWindowLong( hwdb, GWL_STYLE );
  113. style &= ~(BS_PUSHBUTTON|BS_DEFPUSHBUTTON);
  114. style |= BS_DEFPUSHBUTTON;
  115. SetWindowLong( hwdb, GWL_STYLE, style );
  116. } /* setDefaultButton */
  117. /*
  118. * setLabel
  119. *
  120. * set the label for an axis based on current calibration state
  121. */
  122. static void setLabel(
  123. LPGLOBALVARS pgv,
  124. HWND hwnd,
  125. UINT id,
  126. LPJOYREGHWCONFIG pcfg,
  127. DWORD bit )
  128. {
  129. char str[MAX_STR];
  130. char calstr[MAX_STR];
  131. int type;
  132. HINSTANCE hinst;
  133. HWND hwtext;
  134. hinst = GetWindowInstance( hwnd );
  135. /*
  136. * get text for this axis label...
  137. */
  138. if( pcfg->dwUsageSettings & JOY_US_ISOEM ) {
  139. type = pcfg->dwType - JOY_HW_LASTENTRY;
  140. if( type < 0 || type >= pgv->pjd->oemCount ) {
  141. type = -1;
  142. }
  143. } else {
  144. type = -1;
  145. }
  146. switch( id ) {
  147. case IDC_JOYLIST1_LABEL:
  148. if( (type == -1) || (pgv->pjd->oemList[type].xy_label[0] == 0) ) {
  149. if( !LoadString( hinst, IDS_XYAXIS_LABEL, str, sizeof( str ) ) ) {
  150. return;
  151. }
  152. } else {
  153. strcpy( str, pgv->pjd->oemList[type].xy_label );
  154. }
  155. break;
  156. case IDC_JOYLIST2_LABEL:
  157. if( (type == -1) || (pgv->pjd->oemList[type].z_label[0] == 0 ) ) {
  158. if( !LoadString( hinst, IDS_ZAXIS_LABEL, str, sizeof( str ) ) ) {
  159. return;
  160. }
  161. } else {
  162. strcpy( str, pgv->pjd->oemList[type].z_label );
  163. }
  164. break;
  165. case IDC_JOYLIST3_LABEL:
  166. if( (type == -1) || (pgv->pjd->oemList[type].r_label[0] == 0) ) {
  167. if( !LoadString( hinst, IDS_RAXIS_LABEL, str, sizeof( str ) ) ) {
  168. return;
  169. }
  170. } else {
  171. strcpy( str, pgv->pjd->oemList[type].r_label );
  172. }
  173. break;
  174. case IDC_JOYLIST4_LABEL:
  175. if( (type == -1) || (pgv->pjd->oemList[type].u_label[0] == 0) ) {
  176. if( !LoadString( hinst, IDS_UAXIS_LABEL, str, sizeof( str ) ) ) {
  177. return;
  178. }
  179. } else {
  180. strcpy( str, pgv->pjd->oemList[type].u_label );
  181. }
  182. break;
  183. case IDC_JOYLIST5_LABEL:
  184. if( (type == -1) || (pgv->pjd->oemList[type].v_label[0] == 0) ) {
  185. if( !LoadString( hinst, IDS_VAXIS_LABEL, str, sizeof( str ) ) ) {
  186. return;
  187. }
  188. } else {
  189. strcpy( str, pgv->pjd->oemList[type].v_label );
  190. }
  191. break;
  192. case IDC_JOYPOV_LABEL:
  193. if( (type == -1) || (pgv->pjd->oemList[type].pov_label[0] == 0) ) {
  194. if( !LoadString( hinst, IDS_POVAXIS_LABEL, str, sizeof( str ) ) ) {
  195. return;
  196. }
  197. } else {
  198. strcpy( str, pgv->pjd->oemList[type].pov_label );
  199. }
  200. break;
  201. }
  202. /*
  203. * tack on the calibration indicator if needed
  204. */
  205. if( pcfg->hwv.dwCalFlags & bit ) {
  206. if( !LoadString( hinst, IDS_JOYCALINDICATOR,
  207. calstr, sizeof( calstr ) ) ) {
  208. return;
  209. }
  210. if( strlen( str ) + strlen( calstr ) + 1 >= sizeof( str ) ) {
  211. return;
  212. }
  213. strcat( str, " " );
  214. strcat( str, calstr );
  215. }
  216. hwtext = GetDlgItem( hwnd, id );
  217. if( hwtext != NULL ) {
  218. SetWindowText( hwtext, str );
  219. }
  220. } /* setLabel */
  221. /*
  222. * enableCalWindows - enable or disable specific calibration windows
  223. */
  224. static void enableCalWindows(
  225. LPGLOBALVARS pgv,
  226. LPJOYREGHWCONFIG pcfg,
  227. HWND hwnd,
  228. cal_wins id )
  229. {
  230. BOOL on;
  231. HWND hwlb;
  232. HWND hwb;
  233. // HWND hwcb;
  234. int iid;
  235. /*
  236. * set up the buttons
  237. */
  238. hwb = GetDlgItem( hwnd,IDC_JOYCALDONE );
  239. if( id == JC_FINI ) {
  240. ShowWindow( GetDlgItem( hwnd, IDC_JOYCALNEXT ), SW_HIDE );
  241. ShowWindow( GetDlgItem( hwnd, IDC_JOYTEST ), SW_NORMAL );
  242. EnableWindow( hwb, TRUE );
  243. ShowWindow( hwb, SW_NORMAL );
  244. SetFocus( hwb );
  245. setDefaultButton( hwnd, hwb );
  246. } else {
  247. ShowWindow( GetDlgItem( hwnd, IDC_JOYCALNEXT ), SW_NORMAL );
  248. ShowWindow( GetDlgItem( hwnd, IDC_JOYTEST ), SW_HIDE );
  249. EnableWindow( hwb, FALSE );
  250. ShowWindow( hwb, SW_HIDE );
  251. }
  252. /*
  253. * set up the labels with the (done) after it...
  254. */
  255. setLabel( pgv, hwnd, IDC_JOYLIST1_LABEL, pcfg, JOY_ISCAL_XY );
  256. if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  257. setLabel( pgv, hwnd, IDC_JOYLIST2_LABEL, pcfg, JOY_ISCAL_Z );
  258. }
  259. if( (pcfg->hws.dwFlags & JOY_HWS_HASR) || (pcfg->dwUsageSettings & JOY_US_HASRUDDER)) {
  260. setLabel( pgv, hwnd, IDC_JOYLIST3_LABEL, pcfg, JOY_ISCAL_R );
  261. }
  262. if( pcfg->hws.dwFlags & JOY_HWS_HASPOV ) {
  263. setLabel( pgv, hwnd, IDC_JOYPOV_LABEL, pcfg, JOY_ISCAL_POV );
  264. }
  265. if( pcfg->hws.dwFlags & JOY_HWS_HASU ) {
  266. setLabel( pgv, hwnd, IDC_JOYLIST4_LABEL, pcfg, JOY_ISCAL_U );
  267. }
  268. if( pcfg->hws.dwFlags & JOY_HWS_HASV ) {
  269. setLabel( pgv, hwnd, IDC_JOYLIST5_LABEL, pcfg, JOY_ISCAL_V );
  270. }
  271. /*
  272. * set up the XY window
  273. */
  274. on = FALSE;
  275. if( id == JC_XY ) {
  276. on = TRUE;
  277. }
  278. hwlb = GetDlgItem( hwnd, IDC_JOYLIST1 );
  279. if( !on ) {
  280. InvalidateRect( hwlb, NULL, TRUE );
  281. }
  282. EnableWindow( hwlb, on );
  283. EnableWindow( GetDlgItem( hwnd, IDC_JOYLIST1_LABEL ), on );
  284. /*
  285. * set up the Z window
  286. */
  287. on = FALSE;
  288. if( id == JC_Z ) {
  289. on = TRUE;
  290. }
  291. hwlb = GetDlgItem( hwnd, IDC_JOYLIST2 );
  292. if( !on ) {
  293. InvalidateRect( hwlb, NULL, TRUE );
  294. }
  295. EnableWindow( hwlb, on );
  296. EnableWindow( GetDlgItem( hwnd, IDC_JOYLIST2_LABEL ), on );
  297. /*
  298. * set up the R window
  299. */
  300. on = FALSE;
  301. if( id == JC_R ) {
  302. on = TRUE;
  303. }
  304. hwlb = GetDlgItem( hwnd, IDC_JOYLIST3 );
  305. if( !on ) {
  306. InvalidateRect( hwlb, NULL, TRUE );
  307. }
  308. EnableWindow( hwlb, on );
  309. EnableWindow( GetDlgItem( hwnd, IDC_JOYLIST3_LABEL ), on );
  310. /*
  311. * set up the U window
  312. */
  313. on = FALSE;
  314. if( id == JC_U ) {
  315. on = TRUE;
  316. }
  317. hwlb = GetDlgItem( hwnd, IDC_JOYLIST4 );
  318. if( hwlb != NULL ) {
  319. if( !on ) {
  320. InvalidateRect( hwlb, NULL, TRUE );
  321. }
  322. EnableWindow( hwlb, on );
  323. EnableWindow( GetDlgItem( hwnd, IDC_JOYLIST4_LABEL ), on );
  324. }
  325. /*
  326. * set up the V window
  327. */
  328. on = FALSE;
  329. if( id == JC_V ) {
  330. on = TRUE;
  331. }
  332. hwlb = GetDlgItem( hwnd, IDC_JOYLIST5 );
  333. if( hwlb != NULL ) {
  334. if( !on ) {
  335. InvalidateRect( hwlb, NULL, TRUE );
  336. }
  337. EnableWindow( hwlb, on );
  338. EnableWindow( GetDlgItem( hwnd, IDC_JOYLIST5_LABEL ), on );
  339. }
  340. /*
  341. * set up the POV icon
  342. */
  343. on = FALSE;
  344. if( id >= JC_POV_UP && id <= JC_POV_LEFT ) {
  345. on = TRUE;
  346. }
  347. EnableWindow( GetDlgItem( hwnd, IDC_JOYPOV_LABEL ), on );
  348. hwb = GetDlgItem( hwnd, IDC_JOYPICKPOV );
  349. EnableWindow( hwb, on );
  350. if( on ) {
  351. ShowWindow( hwb, SW_NORMAL );
  352. SetFocus( hwb );
  353. setDefaultButton( hwnd, hwb );
  354. switch( id ) {
  355. case JC_POV_UP:
  356. iid = IDI_JOYPOV_UP;
  357. break;
  358. case JC_POV_RIGHT:
  359. iid = IDI_JOYPOV_RIGHT;
  360. break;
  361. case JC_POV_LEFT:
  362. iid = IDI_JOYPOV_LEFT;
  363. break;
  364. case JC_POV_DOWN:
  365. iid = IDI_JOYPOV_DOWN;
  366. break;
  367. }
  368. } else {
  369. ShowWindow( hwb, SW_HIDE );
  370. UpdateWindow( hwb );
  371. iid = IDI_JOYPOV_GRAYED;
  372. }
  373. ChangeIcon( hwnd, iid, IDC_JOYPOV );
  374. } /* enableCalWindows */
  375. /*
  376. * getJoyName - get the name of a joystick
  377. */
  378. static int getJoyName( LPJOYREGHWCONFIG pcfg, BOOL plural )
  379. {
  380. int str2id;
  381. if( pcfg->hws.dwFlags & JOY_HWS_ISYOKE ) {
  382. if( plural ) {
  383. str2id = IDS_JOYCAL_YOKES;
  384. } else {
  385. str2id = IDS_JOYCAL_YOKE;
  386. }
  387. } else if( pcfg->hws.dwFlags & JOY_HWS_ISCARCTRL ) {
  388. if( plural ) {
  389. str2id = IDS_JOYCAL_CARS;
  390. } else {
  391. str2id = IDS_JOYCAL_CAR;
  392. }
  393. } else if( pcfg->hws.dwFlags & JOY_HWS_ISGAMEPAD ) {
  394. if( plural ) {
  395. str2id = IDS_JOYCAL_GAMEPADS;
  396. } else {
  397. str2id = IDS_JOYCAL_GAMEPAD;
  398. }
  399. } else {
  400. if( plural ) {
  401. str2id = IDS_JOY2S;
  402. } else {
  403. str2id = IDS_JOY2;
  404. }
  405. }
  406. return str2id;
  407. } /* getJoyName */
  408. /*
  409. * joyCalStateChange - calibration state change
  410. */
  411. static BOOL joyCalStateChange( LPCALVARS pcv, HWND hwnd, BOOL back )
  412. {
  413. HINSTANCE hinst;
  414. HWND hwtext;
  415. int strid;
  416. int stridx;
  417. int str2id;
  418. int str3id;
  419. int str4id;
  420. char str[2*MAX_STR];
  421. char buff[2*MAX_STR];
  422. char str2[64];
  423. char str3[64];
  424. char str4[64];
  425. BOOL done;
  426. LPJOYREGHWCONFIG pcfg;
  427. BOOL rc;
  428. int type;
  429. LPGLOBALVARS pgv;
  430. BOOL isdone;
  431. /*
  432. * move to the next state: get the appropriate string
  433. * to display, and enable the correct controls
  434. */
  435. pgv = pcv->pgv;
  436. rc = TRUE;
  437. done = FALSE;
  438. pcfg = &pgv->joyHWCurr;
  439. str2id = -1;
  440. str3id = -1;
  441. str4id = -1;
  442. pcv->cState++;
  443. EnableWindow( GetDlgItem( hwnd, IDC_JOYCALBACK ), back );
  444. while( !done ) {
  445. done = TRUE;
  446. switch( pcv->cState ) {
  447. case JCS_XY_CENTER1:
  448. /*
  449. * init. range variables
  450. */
  451. pcv->jr.jpMin.dwX = (DWORD) -1;
  452. pcv->jr.jpMin.dwY = (DWORD) -1;
  453. pcv->jr.jpMin.dwZ = (DWORD) -1;
  454. pcv->jr.jpMin.dwR = (DWORD) -1;
  455. pcv->jr.jpMin.dwU = (DWORD) -1;
  456. pcv->jr.jpMin.dwV = (DWORD) -1;
  457. pcv->jr.jpMax.dwX = 0;
  458. pcv->jr.jpMax.dwY = 0;
  459. pcv->jr.jpMax.dwZ = 0;
  460. pcv->jr.jpMax.dwR = 0;
  461. pcv->jr.jpMax.dwU = 0;
  462. pcv->jr.jpMax.dwV = 0;
  463. /*
  464. * set strings to display
  465. */
  466. stridx = CALSTR1;
  467. if( pcfg->hws.dwFlags & JOY_HWS_ISYOKE ) {
  468. strid = IDS_JOYCALXY_CENTERYOKE;
  469. } else if( pcfg->hws.dwFlags & JOY_HWS_ISCARCTRL ) {
  470. strid = IDS_JOYCALXY_CENTERCAR;
  471. } else if( pcfg->hws.dwFlags & JOY_HWS_ISGAMEPAD ) {
  472. strid = IDS_JOYCALXY_CENTERGAMEPAD;
  473. } else {
  474. strid = IDS_JOYCALXY_CENTER;
  475. }
  476. enableCalWindows( pgv, pcfg, hwnd, JC_XY );
  477. break;
  478. case JCS_XY_MOVE:
  479. stridx = CALSTR2;
  480. if( pcfg->hws.dwFlags & JOY_HWS_ISYOKE ) {
  481. strid = IDS_JOYCALXY_MOVEYOKE;
  482. } else if( pcfg->hws.dwFlags & JOY_HWS_ISCARCTRL ) {
  483. strid = IDS_JOYCALXY_MOVECAR;
  484. } else if( pcfg->hws.dwFlags & JOY_HWS_ISGAMEPAD ) {
  485. strid = IDS_JOYCALXY_MOVEGAMEPAD;
  486. } else {
  487. strid = IDS_JOYCALXY_MOVE;
  488. }
  489. break;
  490. case JCS_XY_CENTER2:
  491. stridx = CALSTR3;
  492. if( pcfg->hws.dwFlags & JOY_HWS_ISYOKE ) {
  493. strid = IDS_JOYCALXY_CENTERYOKE2;
  494. } else if( pcfg->hws.dwFlags & JOY_HWS_ISCARCTRL ) {
  495. strid = IDS_JOYCALXY_CENTERCAR2;
  496. } else if( pcfg->hws.dwFlags & JOY_HWS_ISGAMEPAD ) {
  497. strid = IDS_JOYCALXY_CENTERGAMEPAD2;
  498. } else {
  499. strid = IDS_JOYCALXY_CENTER2;
  500. }
  501. break;
  502. case JCS_Z_MOVE:
  503. stridx = CALSTR4;
  504. if( !(pcfg->hws.dwFlags & JOY_HWS_HASZ) ) {
  505. pcv->cState = JCS_R_MOVE;
  506. done = FALSE;
  507. } else {
  508. enableCalWindows( pgv, pcfg, hwnd, JC_Z );
  509. strid = IDS_JOYCALZ_MOVE;
  510. str2id = getJoyName( pcfg, TRUE );
  511. }
  512. break;
  513. case JCS_Z_PLACEHOLDER:
  514. pcv->cState = JCS_R_MOVE;
  515. done = FALSE;
  516. break;
  517. case JCS_R_MOVE:
  518. stridx = CALSTR5;
  519. if( !(pcfg->hws.dwFlags & JOY_HWS_HASR) && !(pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  520. pcv->cState = JCS_U_MOVE;
  521. done = FALSE;
  522. } else {
  523. enableCalWindows( pgv, pcfg, hwnd, JC_R );
  524. strid = IDS_JOYCALRUDDER_MOVE;
  525. str2id = getJoyName( pcfg, TRUE );
  526. }
  527. break;
  528. case JCS_R_PLACEHOLDER:
  529. pcv->cState = JCS_U_MOVE;
  530. done = FALSE;
  531. break;
  532. case JCS_U_MOVE:
  533. stridx = CALSTR6;
  534. if( !(pcfg->hws.dwFlags & JOY_HWS_HASU) ) {
  535. pcv->cState = JCS_V_MOVE;
  536. done = FALSE;
  537. } else {
  538. enableCalWindows( pgv, pcfg, hwnd, JC_U );
  539. strid = IDS_JOYCALU_MOVE;
  540. str2id = getJoyName( pcfg, TRUE );
  541. }
  542. break;
  543. case JCS_U_PLACEHOLDER:
  544. pcv->cState = JCS_V_MOVE;
  545. done = FALSE;
  546. break;
  547. case JCS_V_MOVE:
  548. stridx = CALSTR7;
  549. if( !(pcfg->hws.dwFlags & JOY_HWS_HASV) ) {
  550. pcv->cState = JCS_POV_MOVEUP;
  551. done = FALSE;
  552. } else {
  553. enableCalWindows( pgv, pcfg, hwnd, JC_V );
  554. strid = IDS_JOYCALV_MOVE;
  555. str2id = getJoyName( pcfg, TRUE );
  556. }
  557. break;
  558. case JCS_V_PLACEHOLDER:
  559. pcv->cState = JCS_POV_MOVEUP;
  560. done = FALSE;
  561. break;
  562. case JCS_POV_MOVEUP:
  563. stridx = CALSTR8;
  564. if( !(pcfg->hws.dwFlags & JOY_HWS_HASPOV)) {
  565. pcv->cState = JCS_FINI;
  566. done = FALSE;
  567. } else {
  568. enableCalWindows( pgv, pcfg, hwnd, JC_POV_UP );
  569. strid = IDS_JOYCALPOV_MOVE;
  570. str2id = IDS_JOYCAL_UP;
  571. str3id = getJoyName( pcfg, TRUE );
  572. str4id = IDS_JOYCAL_UP;
  573. }
  574. break;
  575. case JCS_POV_MOVERIGHT:
  576. stridx = CALSTR9;
  577. enableCalWindows( pgv, pcfg, hwnd, JC_POV_RIGHT );
  578. strid = IDS_JOYCALPOV_MOVE;
  579. str2id = IDS_JOYCAL_RIGHT;
  580. str3id = getJoyName( pcfg, TRUE );
  581. str4id = IDS_JOYCAL_RIGHT;
  582. break;
  583. case JCS_POV_MOVEDOWN:
  584. stridx = CALSTR10;
  585. enableCalWindows( pgv, pcfg, hwnd, JC_POV_DOWN );
  586. strid = IDS_JOYCALPOV_MOVE;
  587. str2id = IDS_JOYCAL_DOWN;
  588. str3id = getJoyName( pcfg, TRUE );
  589. str4id = IDS_JOYCAL_DOWN;
  590. break;
  591. case JCS_POV_MOVELEFT:
  592. stridx = CALSTR11;
  593. enableCalWindows( pgv, pcfg, hwnd, JC_POV_LEFT );
  594. strid = IDS_JOYCALPOV_MOVE;
  595. str2id = IDS_JOYCAL_LEFT;
  596. str3id = getJoyName( pcfg, TRUE );
  597. str4id = IDS_JOYCAL_LEFT;
  598. break;
  599. case JCS_FINI:
  600. /*
  601. * see if everything that needs to be calibrated
  602. * was actually calibrated
  603. */
  604. if( !(pcfg->hwv.dwCalFlags & JOY_ISCAL_XY) ) {
  605. isdone = FALSE;
  606. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASZ) &&
  607. !(pcfg->hwv.dwCalFlags & JOY_ISCAL_Z) ) {
  608. isdone = FALSE;
  609. } else if( ((pcfg->hws.dwFlags & JOY_HWS_HASR) ||
  610. (pcfg->dwUsageSettings & JOY_US_HASRUDDER)) &&
  611. !(pcfg->hwv.dwCalFlags & JOY_ISCAL_R) ) {
  612. isdone = FALSE;
  613. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASPOV) &&
  614. !(pcfg->hwv.dwCalFlags & JOY_ISCAL_POV) ) {
  615. isdone = FALSE;
  616. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASU) &&
  617. !(pcfg->hwv.dwCalFlags & JOY_ISCAL_U) ) {
  618. isdone = FALSE;
  619. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASV) &&
  620. !(pcfg->hwv.dwCalFlags & JOY_ISCAL_V) ) {
  621. isdone = FALSE;
  622. } else {
  623. isdone = TRUE;
  624. }
  625. if( isdone ) {
  626. strid = IDS_JOYCAL_DONE;
  627. } else {
  628. strid = IDS_JOYCAL_NOTDONE;
  629. }
  630. str2id = getJoyName( pcfg, FALSE );
  631. str3id = getJoyName( pcfg, TRUE );
  632. stridx = CALSTR12;
  633. enableCalWindows( pgv, pcfg, hwnd, JC_FINI );
  634. rc = FALSE;
  635. break;
  636. }
  637. }
  638. /*
  639. * see if there is any OEM text specified
  640. */
  641. hinst = GetWindowInstance( hwnd );
  642. hwtext = GetDlgItem( hwnd, IDC_JOYCALMSG );
  643. if( pcfg->dwUsageSettings & JOY_US_ISOEM ) {
  644. LPJOYDATA pjd;
  645. pjd = pgv->pjd;
  646. type = pcfg->dwType - JOY_HW_LASTENTRY;
  647. if( pjd->oemList[type].cal_strs[ stridx ][0] != 0 ) {
  648. SetWindowText( hwtext, pjd->oemList[type].cal_strs[ stridx] );
  649. return rc;
  650. }
  651. }
  652. /*
  653. * no OEM text, use the defaults
  654. */
  655. if( LoadString( hinst, strid, str, sizeof( str ) ) ) {
  656. if( str2id != -1 ) {
  657. if( LoadString( hinst, str2id, str2, sizeof( str2 ) ) ) {
  658. if( str3id != -1 ) {
  659. if( LoadString( hinst, str3id, str3, sizeof( str3 ) ) ) {
  660. if( str4id != -1 ) {
  661. if( LoadString( hinst, str4id, str4, sizeof( str4 ) ) ) {
  662. // wsprintf( buff, str, str2, str3, str4 );
  663. LPSTR lpargs[] = {str2, str3, str4};
  664. FormatMessage(FORMAT_MESSAGE_FROM_STRING |
  665. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  666. (LPSTR) str,
  667. 0, 0,
  668. buff,
  669. sizeof(buff),
  670. (va_list *)lpargs);
  671. SetWindowText( hwtext, buff );
  672. }
  673. } else {
  674. wsprintf( buff, str, str2, str3 );
  675. SetWindowText( hwtext, buff );
  676. }
  677. }
  678. } else {
  679. wsprintf( buff, str, str2, str2 );
  680. SetWindowText( hwtext, buff );
  681. }
  682. }
  683. } else {
  684. SetWindowText( hwtext, str );
  685. }
  686. }
  687. return rc;
  688. } /* joyCalStateChange */
  689. /*
  690. * joyCalStateSkip - skip the current state, move to the next one
  691. */
  692. static void joyCalStateSkip( LPCALVARS pcv, HWND hwnd )
  693. {
  694. /*
  695. * if we're calibrating XY, skip to Z
  696. */
  697. if( pcv->cState <= JCS_XY_CENTER2 ) {
  698. pcv->cState = JCS_XY_CENTER2;
  699. /*
  700. * if we're calibrating Z, skip to R
  701. */
  702. } else if( pcv->cState < JCS_Z_PLACEHOLDER ) {
  703. pcv->cState = JCS_Z_PLACEHOLDER;
  704. /*
  705. * if we're calibrating R, skip to U
  706. */
  707. } else if( pcv->cState < JCS_R_PLACEHOLDER ) {
  708. pcv->cState = JCS_R_PLACEHOLDER;
  709. /*
  710. * if we're calibrating U, skip to V
  711. */
  712. } else if( pcv->cState < JCS_U_PLACEHOLDER ) {
  713. pcv->cState = JCS_U_PLACEHOLDER;
  714. /*
  715. * if we're calibrating V, skip to POV
  716. */
  717. } else if( pcv->cState < JCS_V_PLACEHOLDER ) {
  718. pcv->cState = JCS_V_PLACEHOLDER;
  719. /*
  720. * we must be calibration POV, skip to the end
  721. */
  722. } else {
  723. pcv->cState = JCS_POV_MOVELEFT;
  724. }
  725. /*
  726. * state changed, reset to the new one
  727. */
  728. CauseRedraw( &pcv->ji, FALSE );
  729. joyCalStateChange( pcv, hwnd, TRUE );
  730. } /* joyCalStateSkip */
  731. /*
  732. * resetCustomPOVFlags - set POV flags based on original values for custom joystick
  733. */
  734. static void resetCustomPOVFlags( LPGLOBALVARS pgv, LPJOYREGHWCONFIG pcfg )
  735. {
  736. if( pcfg->dwType == JOY_HW_CUSTOM ) {
  737. pcfg->hws.dwFlags &= ~(JOY_HWS_POVISPOLL|JOY_HWS_POVISBUTTONCOMBOS);
  738. if( pgv->bOrigPOVIsPoll ) {
  739. pcfg->hws.dwFlags |= JOY_HWS_POVISPOLL;
  740. }
  741. if( pgv->bOrigPOVIsButtonCombos ) {
  742. pcfg->hws.dwFlags |= JOY_HWS_POVISBUTTONCOMBOS;
  743. }
  744. }
  745. } /* resetCustomPOVFlags */
  746. /*
  747. * joyCalStateBack - move back to start the previous state
  748. */
  749. static void joyCalStateBack( LPCALVARS pcv, HWND hwnd )
  750. {
  751. BOOL back;
  752. LPJOYREGHWCONFIG pcfg;
  753. LPGLOBALVARS pgv;
  754. pgv = pcv->pgv;
  755. back = TRUE;
  756. pcfg = &pgv->joyHWCurr;
  757. /*
  758. * at the end, backup
  759. */
  760. if( pcv->cState == JCS_FINI ) {
  761. /*
  762. * if there is POV, back up to it
  763. */
  764. if( pcfg->hws.dwFlags & JOY_HWS_HASPOV ) {
  765. pcv->cState = JCS_V_PLACEHOLDER;
  766. resetCustomPOVFlags( pgv, pcfg );
  767. /*
  768. * if there is V, back up to it
  769. */
  770. } else if( pcfg->hws.dwFlags & JOY_HWS_HASV ) {
  771. pcv->cState = JCS_U_PLACEHOLDER;
  772. /*
  773. * if there is U, back up to it
  774. */
  775. } else if( pcfg->hws.dwFlags & JOY_HWS_HASU ) {
  776. pcv->cState = JCS_R_PLACEHOLDER;
  777. /*
  778. * if there is R, back up to it
  779. */
  780. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASR) ||
  781. (pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  782. pcv->cState = JCS_Z_PLACEHOLDER;
  783. /*
  784. * if there is Z, back up to it
  785. */
  786. } else if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  787. pcv->cState = JCS_XY_CENTER2;
  788. /*
  789. * no where else to go, back up to XY
  790. */
  791. } else {
  792. pcv->cState = JCS_INIT;
  793. back = FALSE;
  794. }
  795. /*
  796. * doing POV, so restart it
  797. */
  798. } else if( pcv->cState > JCS_POV_MOVEUP ) {
  799. pcv->cState = JCS_V_PLACEHOLDER;
  800. // pcfg->hws.dwFlags &= ~(JOY_HWS_POVISPOLL|JOY_HWS_POVISBUTTONCOMBOS);
  801. resetCustomPOVFlags( pgv, pcfg );
  802. /*
  803. * just starting POV, back up
  804. */
  805. } else if( pcv->cState == JCS_POV_MOVEUP ) {
  806. /*
  807. * if there is V, back up to it
  808. */
  809. if( pcfg->hws.dwFlags & JOY_HWS_HASV ) {
  810. pcv->cState = JCS_U_PLACEHOLDER;
  811. /*
  812. * if there is U, back up to it
  813. */
  814. } else if( pcfg->hws.dwFlags & JOY_HWS_HASU ) {
  815. pcv->cState = JCS_R_PLACEHOLDER;
  816. /*
  817. * if there is R, back up to it
  818. */
  819. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASR) ||
  820. (pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  821. pcv->cState = JCS_Z_PLACEHOLDER;
  822. /*
  823. * if there is Z, back up to it
  824. */
  825. } else if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  826. pcv->cState = JCS_XY_CENTER2;
  827. /*
  828. * no where else to go, back up to XY
  829. */
  830. } else {
  831. pcv->cState = JCS_INIT;
  832. back = FALSE;
  833. }
  834. /*
  835. * doing V, backup
  836. */
  837. } else if( pcv->cState == JCS_V_MOVE ) {
  838. /*
  839. * if there is U, back up to it
  840. */
  841. if( pcfg->hws.dwFlags & JOY_HWS_HASU ) {
  842. pcv->cState = JCS_R_PLACEHOLDER;
  843. /*
  844. * if there is R, back up to it
  845. */
  846. } else if( (pcfg->hws.dwFlags & JOY_HWS_HASR) ||
  847. (pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  848. pcv->cState = JCS_Z_PLACEHOLDER;
  849. /*
  850. * if there is Z, back up to it
  851. */
  852. } else if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  853. pcv->cState = JCS_XY_CENTER2;
  854. /*
  855. * no where else to go, back up to XY
  856. */
  857. } else {
  858. pcv->cState = JCS_INIT;
  859. back = FALSE;
  860. }
  861. /*
  862. * doing U, backup
  863. */
  864. } else if( pcv->cState == JCS_U_MOVE ) {
  865. /*
  866. * if there is R, back up to it
  867. */
  868. if( (pcfg->hws.dwFlags & JOY_HWS_HASR) ||
  869. (pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  870. pcv->cState = JCS_Z_PLACEHOLDER;
  871. /*
  872. * if there is Z, back up to it
  873. */
  874. } else if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  875. pcv->cState = JCS_XY_CENTER2;
  876. /*
  877. * no where else to go, back up to XY
  878. */
  879. } else {
  880. pcv->cState = JCS_INIT;
  881. back = FALSE;
  882. }
  883. /*
  884. * doing R, backup
  885. */
  886. } else if( pcv->cState == JCS_R_MOVE ) {
  887. /*
  888. * if there is Z, back up to it
  889. */
  890. if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  891. pcv->cState = JCS_XY_CENTER2;
  892. /*
  893. * no where else to go, back up to XY
  894. */
  895. } else {
  896. pcv->cState = JCS_INIT;
  897. back = FALSE;
  898. }
  899. /*
  900. * if we're doing Z or in the middle of XY, backup to XY
  901. */
  902. } else {
  903. pcv->cState = JCS_INIT;
  904. back = FALSE;
  905. }
  906. /*
  907. * state changed, reset to the new one
  908. */
  909. CauseRedraw( &pcv->ji, FALSE );
  910. joyCalStateChange( pcv, hwnd, back );
  911. } /* joyCalStateBack */
  912. /*
  913. * macro to get new max/min data for an axis
  914. */
  915. #define NEWMINMAX( a ) \
  916. if( pji->dw##a##pos > pcv->jr.jpMax.dw##a ) { \
  917. pcv->jr.jpMax.dw##a = pji->dw##a##pos; \
  918. } \
  919. if( pji->dw##a##pos < pcv->jr.jpMin.dw##a ) { \
  920. pcv->jr.jpMin.dw##a = pji->dw##a##pos; \
  921. } \
  922. /*
  923. * macro to do continuous calibration--changes jpi->dw*pos based on current
  924. * position and latest minimum/maximum values
  925. */
  926. #define CAL_MIN 50 // Pretend it's centered unless HW range is >= CAL_MIN
  927. #define SIMULATECALIBRATION(_pcv,_pji,_AXIS_) \
  928. { \
  929. NEWMINMAX(_AXIS_); \
  930. _pji->dw##_AXIS_##pos -= _pcv->jr.jpMin.dw##_AXIS_; \
  931. if (_pcv->jr.jpMax.dw##_AXIS_ - _pcv->jr.jpMin.dw##_AXIS_ < CAL_MIN) { \
  932. _pji->dw##_AXIS_##pos = (RANGE_MAX -RANGE_MIN)/2; \
  933. } else if ( RANGE_MAX == RANGE_MIN ) { \
  934. _pji->dw##_AXIS_##pos = (RANGE_MAX -RANGE_MIN)/2; \
  935. } else { \
  936. _pji->dw##_AXIS_##pos *= (RANGE_MAX-RANGE_MIN); \
  937. _pji->dw##_AXIS_##pos /= ( _pcv->jr.jpMax.dw##_AXIS_ - \
  938. _pcv->jr.jpMin.dw##_AXIS_ ); \
  939. } \
  940. _pji->dw##_AXIS_##pos += RANGE_MIN; \
  941. }
  942. /*
  943. * joyCollectCalInfo - record calibration info
  944. */
  945. static BOOL joyCollectCalInfo( LPCALVARS pcv, HWND hwnd, LPJOYINFOEX pji )
  946. {
  947. LPGLOBALVARS pgv;
  948. LPJOYREGHWCONFIG pcfg;
  949. pgv = pcv->pgv;
  950. switch( pcv->cState ) {
  951. /*
  952. * remember XY center
  953. */
  954. case JCS_XY_CENTER1:
  955. case JCS_XY_CENTER2:
  956. {
  957. JOYINFOEX jiex = *pji;
  958. SIMULATECALIBRATION( pcv, pji, X );
  959. SIMULATECALIBRATION( pcv, pji, Y );
  960. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWXY );
  961. *pji = jiex;
  962. break;
  963. }
  964. /*
  965. * remember max/min XY values
  966. */
  967. case JCS_XY_MOVE:
  968. {
  969. JOYINFOEX jiex = *pji;
  970. SIMULATECALIBRATION( pcv, pji, X );
  971. SIMULATECALIBRATION( pcv, pji, Y );
  972. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWXY );
  973. *pji = jiex;
  974. break;
  975. }
  976. /*
  977. * remember max/min Z value
  978. */
  979. case JCS_Z_MOVE:
  980. {
  981. JOYINFOEX jiex = *pji;
  982. SIMULATECALIBRATION( pcv, pji, Z );
  983. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWZ );
  984. *pji = jiex;
  985. break;
  986. }
  987. /*
  988. * remember max/min R value
  989. */
  990. case JCS_R_MOVE:
  991. {
  992. JOYINFOEX jiex = *pji;
  993. SIMULATECALIBRATION( pcv, pji, R );
  994. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWR );
  995. *pji = jiex;
  996. break;
  997. }
  998. /*
  999. * remember max/min U value
  1000. */
  1001. case JCS_U_MOVE:
  1002. {
  1003. JOYINFOEX jiex = *pji;
  1004. SIMULATECALIBRATION( pcv, pji, U );
  1005. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWU );
  1006. *pji = jiex;
  1007. break;
  1008. }
  1009. /*
  1010. * remember max/min V value
  1011. */
  1012. case JCS_V_MOVE:
  1013. {
  1014. JOYINFOEX jiex = *pji;
  1015. SIMULATECALIBRATION( pcv, pji, V );
  1016. DoJoyMove( pgv, hwnd, pji, &pcv->ji, JOYMOVE_DRAWV );
  1017. *pji = jiex;
  1018. break;
  1019. }
  1020. }
  1021. /*
  1022. * if a button was pressed, move to the next state
  1023. */
  1024. if( ((pcv->ji.dwButtons & ALL_BUTTONS) != (pji->dwButtons & ALL_BUTTONS)) &&
  1025. ((pji->dwButtons & JOY_BUTTON1) ||
  1026. (pji->dwButtons & JOY_BUTTON2) ||
  1027. (pji->dwButtons & JOY_BUTTON3) ||
  1028. (pji->dwButtons & JOY_BUTTON4) ) ) {
  1029. /*
  1030. * check and see if we are leaving one calibration to the next;
  1031. * if yes, take time to stop and remember what the user just did
  1032. */
  1033. pcfg = &pgv->joyHWCurr;
  1034. switch( pcv->cState ) {
  1035. case JCS_XY_CENTER1:
  1036. pcv->jr.jpCenter.dwX = pji->dwXpos;
  1037. pcv->jr.jpCenter.dwY = pji->dwYpos;
  1038. DPF( "Center 1: %d,%d\r\n", pji->dwXpos, pji->dwYpos );
  1039. break;
  1040. case JCS_XY_CENTER2:
  1041. DPF( "Center 2: %d,%d\r\n", pji->dwXpos, pji->dwYpos );
  1042. pcv->jr.jpCenter.dwX += pji->dwXpos;
  1043. pcv->jr.jpCenter.dwY += pji->dwYpos;
  1044. pcv->jr.jpCenter.dwX /= 2;
  1045. pcv->jr.jpCenter.dwY /= 2;
  1046. DPF( "Center Avg: %d,%d\r\n", pcv->jr.jpCenter.dwX, pcv->jr.jpCenter.dwY );
  1047. pcfg->hwv.jrvHardware.jpMin.dwX = pcv->jr.jpMin.dwX;
  1048. pcfg->hwv.jrvHardware.jpMin.dwY = pcv->jr.jpMin.dwY;
  1049. pcfg->hwv.jrvHardware.jpMax.dwX = pcv->jr.jpMax.dwX;
  1050. pcfg->hwv.jrvHardware.jpMax.dwY = pcv->jr.jpMax.dwY;
  1051. pcfg->hwv.jrvHardware.jpCenter.dwX = pcv->jr.jpCenter.dwX;
  1052. pcfg->hwv.jrvHardware.jpCenter.dwY = pcv->jr.jpCenter.dwY;
  1053. pcfg->hwv.dwCalFlags |= JOY_ISCAL_XY;
  1054. break;
  1055. case JCS_Z_MOVE:
  1056. pcfg->hwv.jrvHardware.jpMin.dwZ = pcv->jr.jpMin.dwZ;
  1057. pcfg->hwv.jrvHardware.jpMax.dwZ = pcv->jr.jpMax.dwZ;
  1058. pcfg->hwv.dwCalFlags |= JOY_ISCAL_Z;
  1059. break;
  1060. case JCS_R_MOVE:
  1061. pcfg->hwv.jrvHardware.jpMin.dwR = pcv->jr.jpMin.dwR;
  1062. pcfg->hwv.jrvHardware.jpMax.dwR = pcv->jr.jpMax.dwR;
  1063. pcfg->hwv.dwCalFlags |= JOY_ISCAL_R;
  1064. break;
  1065. case JCS_U_MOVE:
  1066. pcfg->hwv.jrvHardware.jpMin.dwU = pcv->jr.jpMin.dwU;
  1067. pcfg->hwv.jrvHardware.jpMax.dwU = pcv->jr.jpMax.dwU;
  1068. pcfg->hwv.dwCalFlags |= JOY_ISCAL_U;
  1069. break;
  1070. case JCS_V_MOVE:
  1071. pcfg->hwv.jrvHardware.jpMin.dwV = pcv->jr.jpMin.dwV;
  1072. pcfg->hwv.jrvHardware.jpMax.dwV = pcv->jr.jpMax.dwV;
  1073. pcfg->hwv.dwCalFlags |= JOY_ISCAL_V;
  1074. break;
  1075. }
  1076. pcv->ji.dwButtons = pji->dwButtons;
  1077. return joyCalStateChange( pcv, hwnd, TRUE );
  1078. }
  1079. pcv->ji.dwButtons = pji->dwButtons;
  1080. return TRUE;
  1081. } /* joyCollectCalInfo */
  1082. /*
  1083. * joyCalibrateInitDialog - init the calibration dialog
  1084. */
  1085. static BOOL joyCalibrateInitDialog( HWND hwnd, LPARAM lParam )
  1086. {
  1087. LPJOYREGHWCONFIG pcfg;
  1088. LPCALVARS pcv;
  1089. LPGLOBALVARS pgv;
  1090. /*
  1091. * set up calibration variables
  1092. */
  1093. pcv = DoAlloc( sizeof( CALVARS ) );
  1094. SetWindowLong( hwnd, DWL_USER, (LONG) pcv );
  1095. if( pcv == NULL ) {
  1096. return FALSE;
  1097. }
  1098. pgv = (LPGLOBALVARS) lParam;
  1099. pcv->pgv = pgv;
  1100. /*
  1101. * init state info
  1102. */
  1103. pcv->cState = JCS_INIT;
  1104. /*
  1105. * set dialog text based on OEM strings
  1106. */
  1107. SetOEMText( pgv, hwnd, FALSE );
  1108. /*
  1109. * customize dialog based on Z axis, R axis, and POV hat
  1110. */
  1111. pcfg = &pgv->joyHWCurr;
  1112. pcv->iAxisCount = 2;
  1113. if( pcfg->hws.dwFlags & JOY_HWS_HASZ ) {
  1114. pcv->iAxisCount++;
  1115. }
  1116. if( (pcfg->hws.dwFlags & JOY_HWS_HASR) || (pcfg->dwUsageSettings & JOY_US_HASRUDDER) ) {
  1117. pcv->iAxisCount++;
  1118. }
  1119. if( (pcfg->hws.dwFlags & JOY_HWS_HASPOV) &&
  1120. (pcfg->hws.dwFlags & JOY_HWS_POVISPOLL) ) {
  1121. pcv->iAxisCount++;
  1122. }
  1123. if( pcfg->hws.dwFlags & JOY_HWS_HASU ) {
  1124. pcv->iAxisCount++;
  1125. }
  1126. if( pcfg->hws.dwFlags & JOY_HWS_HASV ) {
  1127. pcv->iAxisCount++;
  1128. }
  1129. ShowControls( pcfg, hwnd );
  1130. /*
  1131. * if all axes are used and we have POV then it MUST be buttons
  1132. */
  1133. if( pcfg->hws.dwFlags & JOY_HWS_HASPOV ) {
  1134. if( pgv->dwMaxAxes == 4 && pcv->iAxisCount == 4 ) {
  1135. pcfg->hws.dwFlags |= JOY_HWS_POVISBUTTONCOMBOS;
  1136. }
  1137. }
  1138. /*
  1139. * other misc setup
  1140. */
  1141. pcv->bPOVdone = FALSE;
  1142. pcv->bHasTimer = SetTimer( hwnd, TIMER_ID, JOYPOLLTIME, NULL );
  1143. pcv->bUseTimer = TRUE;
  1144. if( !pcv->bHasTimer ) {
  1145. DPF( "No timer for joystick calibration!\r\n" );
  1146. return FALSE;
  1147. }
  1148. if( !joyCalStateChange( pcv, hwnd, FALSE ) ) {
  1149. DPF( "Could not initialize joystick calibration\r\n" );
  1150. return FALSE;
  1151. }
  1152. return TRUE;
  1153. } /* joyCalibrateInitDialog */
  1154. /*
  1155. * setJIFlagsForPOV - get joyinfo flags to allow a raw POV poll
  1156. */
  1157. static void setJIFlagsForPOV( LPCALVARS pcv, LPJOYREGHWCONFIG pcfg, DWORD *pflags )
  1158. {
  1159. /*
  1160. * for polled POV, we need to specifiy JOY_CAL_READ(3|4) to make
  1161. * the driver give us position values back instead of trying to
  1162. * give us a POV value back
  1163. */
  1164. if( pcfg->hws.dwFlags & JOY_HWS_HASPOV ) {
  1165. if( pcfg->hws.dwFlags & JOY_HWS_POVISPOLL ) {
  1166. if( pcv->iAxisCount == 6 ) {
  1167. (*pflags) |= JOY_CAL_READ6;
  1168. } else if( pcv->iAxisCount == 5 ) {
  1169. (*pflags) |= JOY_CAL_READ5;
  1170. } else if( pcv->iAxisCount == 4 ) {
  1171. (*pflags) |= JOY_CAL_READ4;
  1172. } else if( pcv->iAxisCount == 3 ) {
  1173. (*pflags) |= JOY_CAL_READ3;
  1174. }
  1175. /*
  1176. * if we don't have a 3rd or 4th axis on this joystick, try reading
  1177. * another axis anyway to see if the POV hat is on it
  1178. */
  1179. } else if( !(pcfg->hws.dwFlags & (JOY_HWS_POVISPOLL|JOY_HWS_POVISBUTTONCOMBOS)) ) {
  1180. if( pcv->iAxisCount == 5 ) {
  1181. (*pflags) |= JOY_CAL_READ6;
  1182. } else if( pcv->iAxisCount == 4 ) {
  1183. (*pflags) |= JOY_CAL_READ5;
  1184. } else if( pcv->iAxisCount == 3 ) {
  1185. (*pflags) |= JOY_CAL_READ4;
  1186. } else if( pcv->iAxisCount == 2 ) {
  1187. (*pflags) |= JOY_CAL_READ3;
  1188. }
  1189. }
  1190. }
  1191. } /* setJIFlagsForPOV */
  1192. /*
  1193. * tryPOV - try for a POV access
  1194. */
  1195. static BOOL tryPOV( LPCALVARS pcv, HWND hwnd )
  1196. {
  1197. int rc;
  1198. BOOL ispoll;
  1199. BOOL isb;
  1200. BOOL nowaypoll;
  1201. JOYINFOEX ji;
  1202. DWORD val;
  1203. LPJOYREGHWCONFIG pcfg;
  1204. LPGLOBALVARS pgv;
  1205. int i;
  1206. pgv = pcv->pgv;
  1207. /*
  1208. * reject call if not in a POV state
  1209. */
  1210. if( !(pcv->cState == JCS_POV_MOVEUP ||
  1211. pcv->cState == JCS_POV_MOVEDOWN ||
  1212. pcv->cState == JCS_POV_MOVELEFT ||
  1213. pcv->cState == JCS_POV_MOVERIGHT) ) {
  1214. return FALSE;
  1215. }
  1216. /*
  1217. * take a snapshot of the current joystick state
  1218. */
  1219. pcfg = &pgv->joyHWCurr;
  1220. nowaypoll = FALSE;
  1221. ji.dwSize = sizeof( ji );
  1222. while( 1 ) {
  1223. /*
  1224. * get joystick info
  1225. */
  1226. ji.dwFlags = JOY_CALIB_FLAGS;
  1227. setJIFlagsForPOV( pcv, pcfg, &ji.dwFlags );
  1228. rc = joyGetPosEx( pgv->iJoyId, &ji );
  1229. if( rc == JOYERR_NOERROR ) {
  1230. break;
  1231. }
  1232. if( !(pcfg->hws.dwFlags & JOY_HWS_POVISPOLL) &&
  1233. (ji.dwFlags & (JOY_CAL_READ3|JOY_CAL_READ4|JOY_CAL_READ5|JOY_CAL_READ6)) ) {
  1234. /*
  1235. * try again, but don't ask for extra axis
  1236. */
  1237. ji.dwFlags &= ~(JOY_CAL_READ6 | JOY_CAL_READ5 | JOY_CAL_READ4 | JOY_CAL_READ3);
  1238. rc = joyGetPosEx( pgv->iJoyId, &ji );
  1239. if( rc == JOYERR_NOERROR ) {
  1240. nowaypoll = TRUE; // pov can't possibly be polled
  1241. break;
  1242. } else {
  1243. if( !JoyError( hwnd ) ) {
  1244. return FALSE;
  1245. }
  1246. return TRUE; // have to wait for next "Select POV" to retry
  1247. }
  1248. } else {
  1249. if( !JoyError( hwnd ) ) {
  1250. return FALSE;
  1251. }
  1252. return TRUE; // have to wait for next "Select POV" to retry
  1253. }
  1254. }
  1255. /*
  1256. * here is where we determine if POV is polled or is button combos.
  1257. *
  1258. * See if we already know the answer (bits in joyHWCurr):
  1259. * if yes:
  1260. * we're done.
  1261. * if no:
  1262. * We see if there are currently multiple buttons down.
  1263. * if yes:
  1264. * POV is assumed to be button combos.
  1265. * if no:
  1266. * POV is assumed to be done with polling
  1267. */
  1268. ispoll = FALSE;
  1269. isb = FALSE;
  1270. if( pcfg->hws.dwFlags & JOY_HWS_POVISPOLL ) {
  1271. ispoll = TRUE;
  1272. } else if( pcfg->hws.dwFlags & JOY_HWS_POVISBUTTONCOMBOS ) {
  1273. isb = TRUE;
  1274. }
  1275. if( !isb && !ispoll ) {
  1276. /*
  1277. * the type is indeterminate, so we identify it
  1278. */
  1279. if( nowaypoll ||
  1280. ((ji.dwButtons != 0) && (ji.dwButtons != JOY_BUTTON1) &&
  1281. (ji.dwButtons != JOY_BUTTON2) && (ji.dwButtons != JOY_BUTTON3) &&
  1282. (ji.dwButtons != JOY_BUTTON4)) ) {
  1283. isb = TRUE;
  1284. pcfg->hws.dwFlags |= JOY_HWS_POVISBUTTONCOMBOS;
  1285. } else {
  1286. /*
  1287. * we always assume J2 Y for a polling POV if unspecified
  1288. */
  1289. ispoll = TRUE;
  1290. pcfg->hws.dwFlags |= JOY_HWS_POVISPOLL;
  1291. }
  1292. /*
  1293. * the driver needs to notified that we've made this decision
  1294. */
  1295. RegSaveCurrentJoyHW( pgv );
  1296. RegistryUpdated( pgv );
  1297. }
  1298. /*
  1299. * record the data value for this POV reading
  1300. */
  1301. if( isb ) {
  1302. val = ji.dwButtons;
  1303. } else {
  1304. if( !(pcfg->hws.dwFlags & JOY_HWS_HASZ) ) {
  1305. val = ji.dwZpos;
  1306. } else {
  1307. val = ji.dwRpos;
  1308. }
  1309. }
  1310. switch( pcv->cState ) {
  1311. case JCS_POV_MOVEUP:
  1312. pcv->pov[JOY_POVVAL_FORWARD] = val;
  1313. break;
  1314. case JCS_POV_MOVERIGHT:
  1315. pcv->pov[JOY_POVVAL_RIGHT] = val;
  1316. break;
  1317. case JCS_POV_MOVEDOWN:
  1318. pcv->pov[JOY_POVVAL_BACKWARD] = val;
  1319. break;
  1320. case JCS_POV_MOVELEFT:
  1321. pcv->pov[JOY_POVVAL_LEFT] = val;
  1322. /*
  1323. * since this was the last POV thing to calibrate, we need
  1324. * to save the calibration info
  1325. */
  1326. for( i=0;i<JOY_POV_NUMDIRS;i++ ) {
  1327. pcfg->hwv.dwPOVValues[i] = pcv->pov[i];
  1328. }
  1329. pcfg->hwv.dwCalFlags |= JOY_ISCAL_POV;
  1330. pcv->bPOVdone = TRUE;
  1331. break;
  1332. }
  1333. return joyCalStateChange( pcv, hwnd, TRUE );
  1334. } /* tryPOV */
  1335. /*
  1336. * FixCustomPOVType - fix custom POV type info if POV wasn't calibrated;
  1337. * called by test dlg to update config
  1338. */
  1339. void FixCustomPOVType( LPCALVARS pcv )
  1340. {
  1341. if( !pcv->bPOVdone ) {
  1342. resetCustomPOVFlags( pcv->pgv, &pcv->pgv->joyHWCurr );
  1343. }
  1344. } /* FixCustomPOVType */
  1345. /*
  1346. * CalibrateProc - calibrate a joystick
  1347. */
  1348. BOOL CALLBACK CalibrateProc( HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
  1349. {
  1350. BOOL rc;
  1351. switch( umsg ) {
  1352. case WM_TIMER:
  1353. {
  1354. LPCALVARS pcv;
  1355. pcv = (LPCALVARS) GetWindowLong( hwnd, DWL_USER );
  1356. if( pcv->bUseTimer ) {
  1357. JOYINFOEX ji;
  1358. MMRESULT rc;
  1359. LPJOYREGHWCONFIG pcfg;
  1360. LPGLOBALVARS pgv;
  1361. pgv = pcv->pgv;
  1362. pcv->bUseTimer = FALSE;
  1363. ji.dwSize = sizeof( ji );
  1364. while( 1 ) {
  1365. /*
  1366. * get current joystick info
  1367. */
  1368. ji.dwFlags = JOY_CALIB_FLAGS;
  1369. pcfg = &pgv->joyHWCurr;
  1370. setJIFlagsForPOV( pcv, pcfg, &ji.dwFlags );
  1371. rc = joyGetPosEx( pgv->iJoyId, &ji );
  1372. if( rc == JOYERR_NOERROR ) {
  1373. break;
  1374. }
  1375. /*
  1376. * didn't work, try without extra POV axis
  1377. */
  1378. if( !(pcfg->hws.dwFlags & JOY_HWS_POVISPOLL) &&
  1379. (ji.dwFlags & (JOY_CAL_READ3|JOY_CAL_READ4|JOY_CAL_READ5|JOY_CAL_READ6)) ) {
  1380. ji.dwFlags &= ~(JOY_CAL_READ6 | JOY_CAL_READ5 | JOY_CAL_READ4 | JOY_CAL_READ3);
  1381. rc = joyGetPosEx( pgv->iJoyId, &ji );
  1382. if( rc == JOYERR_NOERROR ) {
  1383. break;
  1384. }
  1385. }
  1386. if( !JoyError( hwnd ) ) {
  1387. /*
  1388. * return now if cancel selected; don't turn back
  1389. * on the timer
  1390. */
  1391. return FALSE;
  1392. }
  1393. continue;
  1394. }
  1395. if( rc == JOYERR_NOERROR ) {
  1396. joyCollectCalInfo( pcv, hwnd, &ji );
  1397. }
  1398. /*
  1399. * If we've started POV calibration, we need to look at the
  1400. * keyboard and ignore joystick, so don't turn the timer
  1401. * back on if we've started the POV calibration
  1402. */
  1403. if( pcv->cState < JCS_POV_MOVEUP ) {
  1404. pcv->bUseTimer = TRUE;
  1405. }
  1406. }
  1407. break;
  1408. }
  1409. case WM_DESTROY:
  1410. {
  1411. LPCALVARS pcv;
  1412. pcv = (LPCALVARS) GetWindowLong( hwnd, DWL_USER );
  1413. DoFree( pcv );
  1414. break;
  1415. }
  1416. case WM_INITDIALOG:
  1417. {
  1418. LPCALVARS pcv;
  1419. rc = joyCalibrateInitDialog( hwnd, lParam );
  1420. if( !rc ) {
  1421. pcv = (LPCALVARS) GetWindowLong( hwnd, DWL_USER );
  1422. if( pcv != NULL && pcv->bHasTimer ) {
  1423. KillTimer( hwnd, TIMER_ID );
  1424. pcv->bHasTimer = FALSE;
  1425. }
  1426. EndDialog( hwnd, 0 );
  1427. }
  1428. return FALSE;
  1429. }
  1430. case WM_PAINT:
  1431. {
  1432. LPCALVARS pcv;
  1433. pcv = (LPCALVARS) GetWindowLong( hwnd, DWL_USER );
  1434. CauseRedraw( &pcv->ji, FALSE );
  1435. return FALSE;
  1436. }
  1437. case WM_COMMAND:
  1438. {
  1439. int id;
  1440. LPCALVARS pcv;
  1441. pcv = (LPCALVARS) GetWindowLong( hwnd, DWL_USER );
  1442. id = GET_WM_COMMAND_ID(wParam, lParam);
  1443. switch( id ) {
  1444. case IDC_JOYTEST:
  1445. {
  1446. BOOL timeon;
  1447. timeon = pcv->bUseTimer;
  1448. pcv->bUseTimer = FALSE;
  1449. DoTest( pcv->pgv, hwnd, FixCustomPOVType, pcv );
  1450. pcv->bUseTimer = timeon;
  1451. break;
  1452. }
  1453. case IDCANCEL:
  1454. // fall through
  1455. case IDC_JOYCALDONE:
  1456. if( pcv->bHasTimer ) {
  1457. KillTimer( hwnd, TIMER_ID );
  1458. pcv->bHasTimer = FALSE;
  1459. }
  1460. {
  1461. LPJOYREGHWCONFIG pcfg;
  1462. pcfg = &pcv->pgv->joyHWCurr;
  1463. }
  1464. EndDialog( hwnd, (id == IDC_JOYCALDONE) );
  1465. break;
  1466. case IDC_JOYPICKPOV:
  1467. if( !tryPOV( pcv, hwnd ) ) {
  1468. HWND hwb;
  1469. hwb = GetDlgItem( hwnd, IDC_JOYPICKPOV );
  1470. ShowWindow( hwb, SW_HIDE );
  1471. EnableWindow( hwb, FALSE );
  1472. }
  1473. break;
  1474. case IDC_JOYCALNEXT:
  1475. pcv->bUseTimer = TRUE;
  1476. joyCalStateSkip( pcv, hwnd );
  1477. break;
  1478. case IDC_JOYCALBACK:
  1479. pcv->bUseTimer = TRUE;
  1480. joyCalStateBack( pcv, hwnd );
  1481. break;
  1482. default:
  1483. break;
  1484. }
  1485. break;
  1486. }
  1487. default:
  1488. break;
  1489. }
  1490. return FALSE;
  1491. } /* CalibrateProc */
  1492. /*
  1493. * DoCalibrate - do the calibration dialog
  1494. */
  1495. void DoCalibrate( LPGLOBALVARS pgv, HWND hwnd )
  1496. {
  1497. JOYREGHWCONFIG save_joycfg;
  1498. int rc;
  1499. int id;
  1500. /*
  1501. * save the current config, and then add the rudder if it is present
  1502. */
  1503. save_joycfg = pgv->joyHWCurr;
  1504. /*
  1505. * if this is a custom joystick, then don't assume anything
  1506. * about how the POV is set up
  1507. */
  1508. if( pgv->joyHWCurr.dwType == JOY_HW_CUSTOM ) {
  1509. pgv->bOrigPOVIsPoll = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_POVISPOLL);
  1510. pgv->bOrigPOVIsButtonCombos = (pgv->joyHWCurr.hws.dwFlags & JOY_HWS_POVISBUTTONCOMBOS);
  1511. pgv->joyHWCurr.hws.dwFlags &= ~(JOY_HWS_POVISPOLL|JOY_HWS_POVISBUTTONCOMBOS);
  1512. }
  1513. /*
  1514. * update the registry with our new joystick info
  1515. */
  1516. RegSaveCurrentJoyHW( pgv );
  1517. RegistryUpdated( pgv );
  1518. if( pgv->joyHWCurr.hws.dwFlags & (JOY_HWS_HASU|JOY_HWS_HASV) ) {
  1519. id = IDD_JOYCALIBRATE1;
  1520. } else {
  1521. id = IDD_JOYCALIBRATE;
  1522. }
  1523. rc = DialogBoxParam((HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ),
  1524. MAKEINTRESOURCE( id ), hwnd, CalibrateProc, (LONG) pgv );
  1525. /*
  1526. * update the registry with the new info or the old info
  1527. */
  1528. if( rc ) {
  1529. PropSheet_Changed( GetParent(hwnd), hwnd );
  1530. } else {
  1531. pgv->joyHWCurr = save_joycfg;
  1532. }
  1533. RegSaveCurrentJoyHW( pgv );
  1534. RegistryUpdated( pgv );
  1535. } /* DoCalibrate */