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.

1573 lines
49 KiB

  1. //===========================================================================
  2. // TEST.CPP
  3. //
  4. // Functions:
  5. // Test_DlgProc()
  6. // DoJoyMove()
  7. // DoTestButtons()
  8. // DoTestPOV()
  9. // DrawCross()
  10. // DisplayAvailableButtons()
  11. // JoyError()
  12. // DisplayAvailablePOVs()
  13. // SetOEMWindowText()
  14. //
  15. //===========================================================================
  16. // This is necessary for UnregisterDeviceNotification!
  17. #if (WINVER < 0x0500)
  18. #undef WINVER
  19. #define WINVER 0x0500
  20. #endif
  21. #include "cplsvr1.h"
  22. #include <initguid.h>
  23. #include <winuser.h> // For RegisterDeviceNotification stuff!
  24. #include <dbt.h> // for DBT_ defines!!!
  25. #include <hidclass.h>
  26. #include "dicputil.h"
  27. #include "resource.h"
  28. #include "pov.h"
  29. #include "assert.h"
  30. #include <regstr.h> // for REGSTR_VAL_'s below
  31. #include <commctrl.h> // for CProgressCtrl!
  32. #include <shlwapi.h> // for Str... functions!
  33. #include <malloc.h> // _alloca
  34. #include "Gradient.h" // for Gradient Fill Slider!
  35. #ifndef LONG2POINT
  36. #define LONG2POINT(l, pt) ((pt).x = (SHORT)LOWORD(l), (pt).y = (SHORT)HIWORD(l))
  37. #endif // LONG2POINT
  38. // local functions for services exclusive to this module!
  39. static void DisplayAvailablePOVs ( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs );
  40. static void DisplayAvailableButtons( const HWND hWndToolTip, const HWND hDlg, const int nNumButtons );
  41. static void DisplayAvailableAxisTest(const HWND hWndToolTip, const HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2);
  42. static void DoTestButtons ( const HWND hDlg, PBYTE pbButtons, int nButtons );
  43. static short JoyError ( const HWND hDlg );
  44. static BOOL SetDeviceRanges ( const HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis );
  45. static DWORD DecodeAxisPOV( DWORD dwVal );
  46. // Local defines
  47. #define DELTA 5
  48. #define ID_JOY_TIMER 2002
  49. #define TIMER_INTERVAL 45 // time between polls in milliseconds
  50. #define MAX_SLIDER_POS 100
  51. #define MIN_SLIDER_POS 0
  52. #define FORCE_POV_REFRESH 254
  53. #define ACTIVE_COLOR RGB(255,0,0)
  54. #define INACTIVE_COLOR RGB(128,0,0)
  55. extern BOOL bDlgCentered;
  56. extern BYTE nStatic;
  57. extern CDIGameCntrlPropSheet_X *pdiCpl;
  58. extern HINSTANCE ghInst;
  59. BOOL bGradient;
  60. static HWND ProgWnd[NUM_WNDS];
  61. static CGradientProgressCtrl *pProgs[NUM_WNDS];
  62. static HPEN hTextPen;
  63. static HPEN hWinPen;
  64. LPDIJOYSTATE lpDIJoyState;
  65. extern HICON hIconArray[2];
  66. //===========================================================================
  67. // Test_DlgProc
  68. //
  69. // Parameters:
  70. // HWND hWnd - handle to dialog window
  71. // UINT uMsg - dialog message
  72. // WPARAM wParam - message specific data
  73. // LPARAM lParam - message specific data
  74. //
  75. // Returns: BOOL
  76. //
  77. //===========================================================================
  78. BOOL CALLBACK Test_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  79. {
  80. static LPDIRECTINPUTDEVICE2 pdiDevice2;
  81. static PVOID hNotifyDevNode;
  82. static HWND hWndToolTip;
  83. static BYTE nAxis;
  84. switch( uMsg ) {
  85. /*
  86. #ifdef _UNICODE
  87. case WM_DEVICECHANGE:
  88. if ((UINT)wParam == DBT_DEVICEREMOVECOMPLETE)
  89. {
  90. if (nStatic & CALIBRATING)
  91. break;
  92. pdiDevice2->Unacquire();
  93. if (FAILED(pdiDevice2->Acquire()))
  94. {
  95. KillTimer(hWnd, ID_JOY_TIMER);
  96. Error(hWnd, (short)IDS_JOYREADERROR, (short)IDS_JOYUNPLUGGED);
  97. // if you call this function you will hang up the system for 30 seconds or more!!!
  98. if (hNotifyDevNode)
  99. UnregisterDeviceNotification(hNotifyDevNode);
  100. ::PostMessage(GetParent(hWnd), WM_COMMAND, IDOK, 0);
  101. }
  102. }
  103. break;
  104. #endif
  105. */
  106. case WM_ACTIVATEAPP:
  107. if( wParam ) {
  108. pdiDevice2->Acquire();
  109. // Hack for bug #228798
  110. if( lpDIJoyState ) {
  111. // This is to refresh the cross hair...
  112. lpDIJoyState->lX+=1;
  113. DoJoyMove( hWnd, nAxis );
  114. // This is to refresh the POV
  115. if( pdiCpl->GetStateFlags()->nPOVs )
  116. DoTestPOV(FORCE_POV_REFRESH, lpDIJoyState->rgdwPOV, hWnd);
  117. }
  118. SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
  119. } else {
  120. KillTimer(hWnd, ID_JOY_TIMER);
  121. pdiDevice2->Unacquire();
  122. }
  123. break;
  124. case WM_LBUTTONDOWN:
  125. // Click Drag service for PropSheets!
  126. PostMessage(GetParent(hWnd), WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lParam);
  127. break;
  128. // OnHelp
  129. case WM_HELP:
  130. KillTimer(hWnd, ID_JOY_TIMER);
  131. OnHelp(lParam);
  132. SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
  133. return(TRUE);
  134. // OnContextMenu
  135. case WM_CONTEXTMENU:
  136. KillTimer(hWnd, ID_JOY_TIMER);
  137. OnContextMenu(wParam);
  138. SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
  139. return(TRUE);
  140. // OnInit
  141. case WM_INITDIALOG:
  142. // get ptr to our object
  143. if( !pdiCpl )
  144. pdiCpl = (CDIGameCntrlPropSheet_X*)((LPPROPSHEETPAGE)lParam)->lParam;
  145. hTextPen = hWinPen = NULL;
  146. // Establish if you have enough colours to display the gradient fill scroll bar!
  147. {
  148. HDC hDC = ::GetWindowDC(hWnd);
  149. if( hDC ) { // Prefix Whistler Bug#45099
  150. bGradient = (BOOL)(GetDeviceCaps(hDC, NUMCOLORS) < 0);
  151. ::ReleaseDC(hWnd, hDC);
  152. }
  153. }
  154. // load the up and down states!
  155. hIconArray[0] = (HICON)LoadImage(ghInst, (PTSTR)IDI_BUTTONON, IMAGE_ICON, 0, 0, NULL);
  156. assert (hIconArray[0]);
  157. hIconArray[1] = (HICON)LoadImage(ghInst, (PTSTR)IDI_BUTTONOFF, IMAGE_ICON, 0, 0, NULL);
  158. assert (hIconArray[1]);
  159. // initialize DirectInput
  160. if( FAILED(InitDInput(GetParent(hWnd), pdiCpl)) ) {
  161. Error(hWnd, (short)IDS_INTERNAL_ERROR, (short)IDS_NO_DIJOYCONFIG);
  162. // Fix #108983 NT, Remove Flash on Error condition.
  163. SetWindowPos(::GetParent(hWnd), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
  164. PostMessage(GetParent(hWnd), WM_SYSCOMMAND, SC_CLOSE, 0);
  165. return(FALSE);
  166. }
  167. // Get the device2 interface pointer
  168. pdiCpl->GetDevice(&pdiDevice2);
  169. nAxis = pdiCpl->GetStateFlags()->nAxis;
  170. // Set The scale for the Device Range!!!
  171. SetDeviceRanges(hWnd, pdiDevice2, nAxis);
  172. LPDIRECTINPUTJOYCONFIG pdiJoyConfig;
  173. pdiCpl->GetJoyConfig(&pdiJoyConfig);
  174. // Create the Pens for X/Y axis!
  175. CreatePens();
  176. // Create ToolTip window!
  177. hWndToolTip = CreateWindowEx( 0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_ALWAYSTIP,
  178. CW_USEDEFAULT, CW_USEDEFAULT, 10, 10, hWnd, NULL, ghInst, NULL);
  179. // Show the available Axis!
  180. DisplayAvailableAxisTest(hWndToolTip, hWnd, nAxis, pdiDevice2);
  181. DisplayAvailableButtons(hWndToolTip, hWnd, pdiCpl->GetStateFlags()->nButtons);
  182. DisplayAvailablePOVs(hWndToolTip, hWnd, pdiCpl->GetStateFlags()->nPOVs);
  183. lpDIJoyState = new (DIJOYSTATE);
  184. assert(lpDIJoyState);
  185. ZeroMemory(lpDIJoyState, sizeof(DIJOYSTATE));
  186. // Clear the Static vars in DoJoyMove!
  187. DoJoyMove(hWnd, nAxis);
  188. // Center the Dialog!
  189. // If it's not been centered!
  190. if( !bDlgCentered ) {
  191. SetTitle(hWnd);
  192. CenterDialog(hWnd);
  193. bDlgCentered = TRUE;
  194. }
  195. {
  196. // Get the Type name
  197. LPDIJOYCONFIG_DX5 lpDIJoyConfig = (LPDIJOYCONFIG_DX5)_alloca(sizeof(DIJOYCONFIG_DX5));
  198. ASSERT (lpDIJoyConfig);
  199. ZeroMemory(lpDIJoyConfig, sizeof(DIJOYCONFIG_DX5));
  200. lpDIJoyConfig->dwSize = sizeof(DIJOYCONFIG_DX5);
  201. if( SUCCEEDED(pdiJoyConfig->GetConfig(pdiCpl->GetID(), (LPDIJOYCONFIG)lpDIJoyConfig, DIJC_REGHWCONFIGTYPE)) ) {
  202. if( lpDIJoyConfig->hwc.dwUsageSettings & JOY_US_ISOEM ) {
  203. LPCTSTR pszLabels[] = {
  204. REGSTR_VAL_JOYOEMTESTMOVEDESC,
  205. REGSTR_VAL_JOYOEMTESTMOVECAP,
  206. REGSTR_VAL_JOYOEMTESTBUTTONCAP,
  207. REGSTR_VAL_JOYOEMPOVLABEL,
  208. REGSTR_VAL_JOYOEMTESTWINCAP};
  209. const short nControlIDs[] = {
  210. IDC_TEXT_AXESHELP,
  211. IDC_AXISGRP,
  212. IDC_GROUP_BUTTONS,
  213. IDC_GROUP_POV,
  214. 0};
  215. SetOEMWindowText(hWnd, nControlIDs, pszLabels, lpDIJoyConfig->wszType, pdiJoyConfig, (BYTE)(sizeof(nControlIDs)/sizeof(short))-1);
  216. }
  217. bPolledPOV = (lpDIJoyConfig->hwc.hws.dwFlags & JOY_HWS_HASPOV) && (lpDIJoyConfig->hwc.hws.dwFlags & JOY_HWS_POVISPOLL);
  218. CalibratePolledPOV( &lpDIJoyConfig->hwc );
  219. }
  220. #ifdef _UNICODE
  221. // Set up the Device Notification
  222. // Removed per Om...
  223. //RegisterForDevChange(hWnd, &hNotifyDevNode);
  224. #endif
  225. }
  226. break; // end of WM_INITDIALOG
  227. // OnTimer
  228. case WM_TIMER:
  229. if( SUCCEEDED(DIUtilPollJoystick(pdiDevice2, lpDIJoyState)) ) {
  230. if( nAxis )
  231. DoJoyMove( hWnd, nAxis );
  232. if( pdiCpl->GetStateFlags()->nButtons )
  233. DoTestButtons( hWnd, lpDIJoyState->rgbButtons, pdiCpl->GetStateFlags()->nButtons );
  234. if( pdiCpl->GetStateFlags()->nPOVs )
  235. DoTestPOV( pdiCpl->GetStateFlags()->nPOVs, lpDIJoyState->rgdwPOV, hWnd );
  236. } else {
  237. KillTimer(hWnd, ID_JOY_TIMER);
  238. pdiDevice2->Unacquire();
  239. if( JoyError( hWnd ) == IDRETRY ) {
  240. pdiDevice2->Acquire();
  241. SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
  242. } else {
  243. // Send a message back to the CPL to update list, as it may have changed!
  244. ::PostMessage(GetParent(hWnd), WM_COMMAND, IDOK, 0);
  245. }
  246. }
  247. break; // end of WM_TIMER
  248. // All this has to be done because WM_MOUSEMOVE doesn't get sent to static text!
  249. case WM_MOUSEMOVE:
  250. if( hWndToolTip ) {
  251. POINT pt;
  252. LONG2POINT(lParam, pt);
  253. HWND hChildWnd = ::ChildWindowFromPoint(hWnd, pt);
  254. static HWND hPrev;
  255. if( hChildWnd != hPrev && hChildWnd !=NULL ) {
  256. switch( GetDlgCtrlID(hChildWnd) ) {
  257. case IDC_JOYLIST1_LABEL:
  258. case IDC_JOYLIST2_LABEL:
  259. case IDC_JOYLIST3_LABEL:
  260. case IDC_JOYLIST4_LABEL:
  261. case IDC_JOYLIST5_LABEL:
  262. case IDC_JOYLIST6_LABEL:
  263. case IDC_JOYLIST7_LABEL:
  264. if( IsWindowVisible(hChildWnd) ) {
  265. MSG msg;
  266. //we need to fill out a message structure and pass it to the tooltip
  267. //with the TTM_RELAYEVENT message
  268. msg.hwnd = hWnd;
  269. msg.message = uMsg;
  270. msg.wParam = wParam;
  271. msg.lParam = lParam;
  272. msg.time = GetMessageTime();
  273. GetCursorPos(&msg.pt);
  274. ::SendMessage(hWndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
  275. }
  276. break;
  277. // We don't need to trap for anything else, as the rest are TTF_SUBCLASS'd
  278. default:
  279. break;
  280. }
  281. // store the last one so we don't have to do this again...
  282. hPrev = hChildWnd;
  283. }
  284. }
  285. break;
  286. // OnDestroy
  287. case WM_DESTROY:
  288. bDlgCentered = FALSE;
  289. KillTimer(hWnd, ID_JOY_TIMER);
  290. // Delete the button icons...
  291. DestroyIcon(hIconArray[0]);
  292. DestroyIcon(hIconArray[1]);
  293. // Kill pProgs
  294. if( bGradient ) {
  295. BYTE nAxisCounter = MAX_AXIS - 2;
  296. BYTE nTmpFlags = nAxis;
  297. // Clear the X and Y flags... they don't have progress controls
  298. // associated with them!
  299. nTmpFlags &= ~(HAS_X | HAS_Y);
  300. while( nTmpFlags ) {
  301. if( nTmpFlags & (HAS_Z<<nAxisCounter) ) {
  302. delete (pProgs[nAxisCounter]);
  303. pProgs[nAxisCounter] = 0;
  304. nTmpFlags &= ~(HAS_Z<<nAxisCounter);
  305. }
  306. nAxisCounter--;
  307. }
  308. }
  309. // Destroy the pens!
  310. if (hTextPen)
  311. DeleteObject(hTextPen);
  312. if( hWinPen )
  313. DeleteObject(hWinPen);
  314. if( lpDIJoyState ) {
  315. delete (lpDIJoyState);
  316. lpDIJoyState = NULL;
  317. }
  318. // Make sure you set this to NULL!
  319. pdiDevice2 = NULL;
  320. break; // end of WM_DESTROY
  321. // OnNotify
  322. case WM_NOTIFY:
  323. switch( ((NMHDR*)lParam)->code ) {
  324. case PSN_SETACTIVE:
  325. if( pdiDevice2 ) {
  326. pdiDevice2->Acquire();
  327. // if you have this, you are safe to start the timer!
  328. if( lpDIJoyState )
  329. SetTimer( hWnd, ID_JOY_TIMER, TIMER_INTERVAL, NULL);
  330. lpDIJoyState->lX+=1;
  331. DoJoyMove(hWnd, HAS_X | HAS_Y);
  332. }
  333. break;
  334. case PSN_KILLACTIVE:
  335. KillTimer(hWnd, ID_JOY_TIMER);
  336. pdiDevice2->Unacquire();
  337. break;
  338. }
  339. break; // end of WM_NOTIFY
  340. case WM_SYSCOLORCHANGE:
  341. {
  342. //Destroy old pens.
  343. if (hTextPen)
  344. {
  345. DeleteObject(hTextPen);
  346. hTextPen=NULL;
  347. }
  348. if(hWinPen)
  349. {
  350. DeleteObject(hWinPen);
  351. hWinPen=NULL;
  352. }
  353. //Recreate pens with new colors.
  354. CreatePens();
  355. //Change colors of slider bars.
  356. for(int i=0;i<NUM_WNDS;i++)
  357. {
  358. if(pProgs[i]) {
  359. pProgs[i]->SetBkColor(GetSysColor(COLOR_WINDOW));
  360. }
  361. }
  362. }
  363. break;
  364. }
  365. return(FALSE);
  366. } //*** end Test_DlgProc()
  367. //===========================================================================
  368. // DoJoyMove( HWND hDlg, LPDIJOYSTATE pDIJoyState, int nDrawFlags )
  369. //
  370. // Reports to hDlg state information from pDIJoyState, dwDrawFlags, and pJoyRange;
  371. //
  372. // Parameters:
  373. // HWND hDlg - Handle to Dialog
  374. // LPDIJOYSTATE pDIJoyState - State information about the device
  375. // LPJOYRANGE pJoyRange
  376. //
  377. // Returns: nichts
  378. //
  379. //===========================================================================
  380. void DoJoyMove( const HWND hDlg, BYTE nDrawFlags )
  381. {
  382. if( !::IsWindow(hDlg) ) {
  383. #ifdef _DEBUG
  384. OutputDebugString(TEXT("DoJoyMove: hDlg: Not a valid window!\n"));
  385. #endif
  386. return;
  387. }
  388. if( nDrawFlags == 0 ) {
  389. #ifdef _DEBUG
  390. OutputDebugString(TEXT("DoJoyMove: nDrawFlags is Zero!\n"));
  391. #endif
  392. return;
  393. }
  394. // draw the cross in the XY box if needed
  395. if( (nDrawFlags & HAS_X) || (nDrawFlags & HAS_Y) ) {
  396. static POINTS ptOld = {DELTA,DELTA};
  397. HWND hCtrl = GetDlgItem( hDlg, IDC_JOYLIST1 );
  398. assert(hCtrl);
  399. //RedrawWindow(hCtrl, NULL, NULL, RDW_INVALIDATE | RDW_ERASENOW);
  400. RECT rc;
  401. GetClientRect(hCtrl, &rc);
  402. // The Real Max is rc.bottom-DELTA!
  403. rc.bottom -= DELTA;
  404. // Check for ranges - Y Axis
  405. if( lpDIJoyState->lY > rc.bottom ) {
  406. #ifdef _DEBUG
  407. OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved Y pos > Max Y pos!\n"));
  408. #endif
  409. lpDIJoyState->lY = rc.bottom;
  410. } else if( lpDIJoyState->lY < DELTA ) {
  411. #ifdef _DEBUG
  412. OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved Y pos < Min Y pos!\n"));
  413. #endif
  414. lpDIJoyState->lY = DELTA;
  415. }
  416. // Check for ranges - X Axis
  417. if( lpDIJoyState->lX > rc.right ) {
  418. #ifdef _DEBUG
  419. OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved X pos > Max X pos!\n"));
  420. #endif
  421. lpDIJoyState->lX = rc.right;
  422. } else if( lpDIJoyState->lX < DELTA ) {
  423. #ifdef _DEBUG
  424. OutputDebugString(TEXT("GCDEF: DoJoyMove: retrieved X pos < Min X pos!\n"));
  425. #endif
  426. lpDIJoyState->lX = DELTA;
  427. }
  428. // out with the old...
  429. if( (ptOld.x != (short)lpDIJoyState->lX) || (ptOld.y != (short)lpDIJoyState->lY) ) {
  430. // Sorry... no drawing outside of your RECT!
  431. if( (ptOld.x > (rc.right-DELTA)) || (ptOld.y > rc.bottom) ) {
  432. ptOld.x = ptOld.y = DELTA;
  433. return;
  434. }
  435. DrawCross(hCtrl, &ptOld, COLOR_WINDOW );
  436. ptOld.x = (short)lpDIJoyState->lX;
  437. ptOld.y = (short)lpDIJoyState->lY;
  438. // in with the new...
  439. DrawCross( hCtrl, &ptOld, COLOR_WINDOWTEXT );
  440. }
  441. nDrawFlags &= ~(HAS_X | HAS_Y);
  442. }
  443. // draw Z bar if needed
  444. if( nDrawFlags ) {
  445. if( nDrawFlags & HAS_Z ) {
  446. static BYTE nOldZ; // = MAX_SLIDER_POS+1;
  447. if( lpDIJoyState->lZ != nOldZ ) {
  448. if( bGradient )
  449. pProgs[Z_INDEX]->SetPos(lpDIJoyState->lZ);
  450. ::PostMessage(ProgWnd[Z_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lZ - MAX_SLIDER_POS), 0L);
  451. nOldZ = (BYTE)lpDIJoyState->lZ;
  452. }
  453. nDrawFlags &= ~HAS_Z;
  454. }
  455. } else return;
  456. // draw Slider0 bar if needed
  457. if( nDrawFlags ) {
  458. if( nDrawFlags & HAS_SLIDER0 ) {
  459. // Any value > 100, as that's the largest one we'll ever recieve!
  460. static BYTE nOldS0; // = MAX_SLIDER_POS+1;
  461. if( lpDIJoyState->rglSlider[0] != nOldS0 ) {
  462. nOldS0 = (BYTE)lpDIJoyState->rglSlider[0];
  463. if( bGradient )
  464. pProgs[S0_INDEX]->SetPos(lpDIJoyState->rglSlider[0]);
  465. ::PostMessage(ProgWnd[S0_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->rglSlider[0]-MAX_SLIDER_POS), 0L);
  466. }
  467. nDrawFlags &= ~HAS_SLIDER0;
  468. }
  469. } else return;
  470. // draw Rx bar if needed
  471. if( nDrawFlags ) {
  472. if( nDrawFlags & HAS_RX ) {
  473. static BYTE nOldRx; // = MAX_SLIDER_POS+1;
  474. if( lpDIJoyState->lRx != nOldRx ) {
  475. nOldRx = (BYTE)lpDIJoyState->lRx;
  476. if( bGradient )
  477. pProgs[RX_INDEX]->SetPos(lpDIJoyState->lRx);
  478. ::PostMessage(ProgWnd[RX_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRx - MAX_SLIDER_POS), 0L);
  479. }
  480. nDrawFlags &= ~HAS_RX;
  481. }
  482. } else return;
  483. // draw Ry bar if needed
  484. if( nDrawFlags ) {
  485. if( nDrawFlags & HAS_RY ) {
  486. static BYTE nOldRy; // = MAX_SLIDER_POS+1;
  487. if( lpDIJoyState->lRy != nOldRy ) {
  488. nOldRy = (BYTE)lpDIJoyState->lRy;
  489. if( bGradient )
  490. pProgs[RY_INDEX]->SetPos(lpDIJoyState->lRy);
  491. ::PostMessage(ProgWnd[RY_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRy - MAX_SLIDER_POS), 0L);
  492. }
  493. nDrawFlags &= ~HAS_RY;
  494. }
  495. } else return;
  496. // draw Rz bar if needed
  497. if( nDrawFlags ) {
  498. if( nDrawFlags & HAS_RZ ) {
  499. static BYTE nOldRz; // = MAX_SLIDER_POS+1;
  500. if( lpDIJoyState->lRz != nOldRz ) {
  501. nOldRz = (BYTE)lpDIJoyState->lRz;
  502. if( bGradient )
  503. pProgs[RZ_INDEX]->SetPos(lpDIJoyState->lRz);
  504. ::PostMessage(ProgWnd[RZ_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->lRz - MAX_SLIDER_POS), 0L);
  505. }
  506. nDrawFlags &= ~HAS_RZ;
  507. }
  508. } else return;
  509. // draw Slider1 bar if needed
  510. if( nDrawFlags ) {
  511. if( nDrawFlags & HAS_SLIDER1 ) {
  512. static BYTE nOldS1; // = MAX_SLIDER_POS+1;
  513. if( lpDIJoyState->rglSlider[1] != nOldS1 ) {
  514. nOldS1 = (BYTE)lpDIJoyState->rglSlider[1];
  515. if( bGradient )
  516. pProgs[S1_INDEX]->SetPos(lpDIJoyState->rglSlider[1]);
  517. ::PostMessage(ProgWnd[S1_INDEX], PBM_SETPOS, (WPARAM)abs(lpDIJoyState->rglSlider[1] - MAX_SLIDER_POS), 0L);
  518. }
  519. }
  520. }
  521. } // *** end of DoJoyMove
  522. //===========================================================================
  523. // DoTestButtons( HWND hDlg, PBYTE pbButtons, short nButtons )
  524. //
  525. // Lites whatever button(s) that may be pressed.
  526. //
  527. // Parameters:
  528. // HWND hDlg - Handle to Dialog
  529. // PBYTE pbButtons - Pointer to byte array of buttons and their states
  530. // int dwButtons - Number of buttons on device (per STATEFLAGS struct)
  531. //
  532. // Returns: nichts
  533. //
  534. //===========================================================================
  535. static void DoTestButtons( const HWND hDlg, PBYTE pbButtons, int nButtons )
  536. {
  537. // validate pointer(s)
  538. if( (IsBadReadPtr((void*)pbButtons, sizeof(BYTE))) ) {
  539. #ifdef _DEBUG
  540. OutputDebugString(TEXT("DoTestButtons: Bad Read Pointer argument!\n"));
  541. #endif
  542. return;
  543. }
  544. if( (IsBadWritePtr((void*)pbButtons, sizeof(BYTE))) ) {
  545. #ifdef _DEBUG
  546. OutputDebugString(TEXT("DoTestButtons: Bad Write Pointer argument!\n"));
  547. #endif
  548. return;
  549. }
  550. // Don't worry about the Zero Button condition!
  551. // It's being done in the timer!
  552. static BYTE bLookup[MAX_BUTTONS] = {NULL};
  553. BYTE i = 0;
  554. // Loop threw the buttons looking only at the ones we know we have!
  555. while( nButtons && (nButtons & (HAS_BUTTON1<<i)) ) {
  556. // check for a button press
  557. if( pbButtons[i] != bLookup[i] ) {
  558. // update the button with the proper bitmap
  559. HWND hCtrl = GetDlgItem(hDlg, IDC_TESTJOYBTNICON1+i);
  560. // Set the Extra Info
  561. SetWindowLongPtr(hCtrl, GWLP_USERDATA, (LONG_PTR)(pbButtons[i] & 0x80) ? 1 : 0);
  562. RedrawWindow(hCtrl, NULL, NULL, RDW_INVALIDATE | RDW_ERASENOW);
  563. // update the lookup table
  564. bLookup[i] = pbButtons[i];
  565. }
  566. // strip the button!
  567. nButtons &= ~(HAS_BUTTON1<<i++);
  568. }
  569. } // end of DoTestButtons
  570. //===========================================================================
  571. // DoTestPOV( PDWORD pdwPOV )
  572. //
  573. // Routes a call to SetDegrees to set the degrees to pdwPOV
  574. //
  575. // Parameters:
  576. // PDWORD pdwPOV - degrees at which to display the POV arrow
  577. //
  578. // Returns: nichts
  579. //
  580. //===========================================================================
  581. void DoTestPOV( BYTE nPov, PDWORD pdwPOV, HWND hDlg )
  582. {
  583. // Assume all POV's to be centred at start
  584. // JOY_POVCENTERED is defined as 0xffffffff
  585. static short dwOldPOV[MAX_POVS] = {-1,-1,-1,-1};
  586. BYTE nPovCounter = MAX_POVS-1;
  587. BYTE nPovs = 0;
  588. BOOL bChanged = FALSE;
  589. if( nPov == FORCE_POV_REFRESH ) {
  590. nPovs = 1;
  591. bChanged = TRUE;
  592. } else {
  593. // You Never have to worry about nPov being Zero,
  594. // it is checked before entering this function!
  595. do {
  596. // Be aware that nPov is not just a number... it's a bit mask!
  597. if( nPov & (HAS_POV1<<nPovCounter) ) {
  598. DWORD dwPov = (nPov & HAS_CALIBRATED) ? pdwPOV[nPovCounter] : pdwPOV[nPovCounter];
  599. if( dwOldPOV[nPovCounter] != (int)dwPov ) {
  600. dwOldPOV[nPovCounter] = (dwPov > 36001) ? -1 : (int)dwPov;
  601. bChanged = TRUE;
  602. }
  603. nPovs++;
  604. nPov &= ~(HAS_POV1<<nPovCounter);
  605. }
  606. } while( nPovCounter-- && nPov );
  607. }
  608. if( bChanged ) {
  609. SetDegrees(nPovs, dwOldPOV, GetDlgItem(hDlg, IDC_JOYPOV));
  610. }
  611. } // *** end of DoTestPOV
  612. //===========================================================================
  613. // DrawCross( HWND hwnd, LPPOINTS pPoint, short nFlag)
  614. //
  615. // Draws a cross on hwnd at pPoint of type nFlag
  616. //
  617. // Parameters:
  618. // HWND hwnd
  619. // LPPOINTS pPoint
  620. // int nFlag
  621. //
  622. // Returns: nichts
  623. //
  624. //===========================================================================
  625. static void DrawCross(const HWND hwnd, LPPOINTS pPoint, short nFlag)
  626. {
  627. assert(hwnd);
  628. HDC hdc = GetDC( hwnd );
  629. HPEN holdpen = (struct HPEN__ *) SelectObject( hdc, (nFlag == COLOR_WINDOW) ? hWinPen : hTextPen );
  630. MoveToEx( hdc, pPoint->x-(DELTA-1), pPoint->y, NULL);
  631. LineTo( hdc, pPoint->x+DELTA, pPoint->y );
  632. MoveToEx( hdc, pPoint->x, pPoint->y-(DELTA-1), NULL );
  633. LineTo( hdc, pPoint->x, pPoint->y+DELTA );
  634. SelectObject( hdc, holdpen );
  635. ReleaseDC( hwnd, hdc );
  636. } // *** end of DrawCross
  637. void CreatePens( void )
  638. {
  639. // We always create both at the same time so checking one is sufficient!
  640. if( hTextPen == NULL ) {
  641. LOGPEN LogPen;
  642. LogPen.lopnStyle = PS_SOLID;
  643. LogPen.lopnWidth.x = LogPen.lopnWidth.y = 0;
  644. LogPen.lopnColor = GetSysColor( COLOR_WINDOW );
  645. hWinPen = CreatePenIndirect(&LogPen);
  646. LogPen.lopnColor = GetSysColor( COLOR_WINDOWTEXT );
  647. hTextPen = CreatePenIndirect(&LogPen);
  648. }
  649. }
  650. //===========================================================================
  651. // DisplayAvailableButtons(HWND hWnd, int nNumButtons)
  652. //
  653. // Removes buttons not found on the device!
  654. //
  655. //
  656. // Parameters:
  657. // HWND hDlg - Dialog handle
  658. // int nNumButtons - Number of buttons to display
  659. //
  660. // Returns:
  661. //
  662. //===========================================================================
  663. void DisplayAvailableButtons(const HWND hWndToolTip, const HWND hDlg, const int nButtonFlags)
  664. {
  665. LPTOOLINFO pToolInfo;
  666. LPTSTR lpStr;
  667. if( nButtonFlags ) {
  668. if( hWndToolTip ) {
  669. pToolInfo = new (TOOLINFO);
  670. ASSERT (pToolInfo);
  671. lpStr = new (TCHAR[STR_LEN_32]);
  672. ASSERT(lpStr);
  673. ZeroMemory(pToolInfo, sizeof(TOOLINFO));
  674. pToolInfo->cbSize = sizeof(TOOLINFO);
  675. pToolInfo->uFlags = 0;
  676. pToolInfo->hwnd = hDlg;
  677. ::SendDlgItemMessage(hDlg, IDC_GROUP_BUTTONS, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)lpStr);
  678. pToolInfo->lpszText = lpStr;
  679. }
  680. }
  681. HWND hCtrl;
  682. // Show the ones we have...
  683. // Destroy the ones we don't!
  684. BYTE i = MAX_BUTTONS;
  685. do {
  686. hCtrl = GetDlgItem(hDlg, IDC_TESTJOYBTNICON1+(--i));
  687. if( (nButtonFlags & HAS_BUTTON1<<i) && pToolInfo ) {
  688. // Add the Control to the tool!
  689. pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  690. pToolInfo->uId = (ULONG_PTR) hCtrl;
  691. // Add the control!
  692. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  693. continue;
  694. }
  695. DestroyWindow(hCtrl);
  696. } while( i );
  697. if( nButtonFlags ) {
  698. if( lpStr )
  699. delete[] (lpStr);
  700. if( pToolInfo )
  701. delete (pToolInfo);
  702. } else {
  703. // don't forget to remove the groupe!
  704. hCtrl = GetDlgItem(hDlg, IDC_GROUP_BUTTONS);
  705. DestroyWindow(hCtrl);
  706. }
  707. } //*** end DisplayAvailableButtons()
  708. //===========================================================================
  709. // JoyError(HWND hwnd)
  710. //
  711. // Displays the "Device Not Connected"
  712. //
  713. // Parameters:
  714. // HWND hwnd - window handle
  715. //
  716. // Returns: rc - User selection from MessageBox
  717. //
  718. //===========================================================================
  719. short JoyError( const HWND hwnd )
  720. {
  721. assert(hwnd);
  722. LPTSTR lptszTitle = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32]));
  723. assert (lptszTitle);
  724. short rc;
  725. if( LoadString(ghInst, IDS_JOYREADERROR, lptszTitle, STR_LEN_32) ) {
  726. LPTSTR lptszMsg = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_128]));
  727. assert(lptszMsg);
  728. if( LoadString(ghInst, IDS_JOYUNPLUGGED, lptszMsg, STR_LEN_128) ) {
  729. rc = (short)MessageBox( hwnd, lptszMsg, lptszTitle, MB_RETRYCANCEL | MB_ICONERROR );
  730. if( rc == IDCANCEL ) {
  731. // terminate the dialog if we give up
  732. PostMessage( GetParent(hwnd), WM_COMMAND, IDCANCEL, 0 );
  733. }
  734. }
  735. }
  736. return(rc);
  737. } // *** end of JoyError
  738. //===========================================================================
  739. // DisplayAvailablePOVs( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs )
  740. //
  741. // Displays POV window if there are any associated with the device.
  742. //
  743. // Parameters:
  744. // HWND hDlg - window handle
  745. // short nPOVs - number of POVs
  746. //
  747. // Returns: nichts
  748. //
  749. //===========================================================================
  750. static void DisplayAvailablePOVs ( const HWND hWndToolTip, const HWND hDlg, BYTE nPOVs )
  751. {
  752. HWND hwndPOV = GetDlgItem(hDlg, IDC_JOYPOV);
  753. SetWindowPos( hwndPOV, NULL, NULL, NULL, NULL, NULL,
  754. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((nPOVs) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  755. SetWindowPos( GetDlgItem( hDlg, IDC_GROUP_POV ), NULL, NULL, NULL, NULL, NULL,
  756. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | ((nPOVs) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  757. if( nPOVs ) {
  758. // Disable RTL flag
  759. SetWindowLongPtr(hwndPOV, GWL_EXSTYLE, GetWindowLongPtr(hwndPOV,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL );
  760. if( hWndToolTip ) {
  761. LPTOOLINFO pToolInfo = (LPTOOLINFO)_alloca(sizeof(TOOLINFO));
  762. ASSERT (pToolInfo);
  763. LPTSTR lpStr = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_32]));
  764. ASSERT (lpStr);
  765. if( pToolInfo && lpStr ) {
  766. ZeroMemory(pToolInfo, sizeof(TOOLINFO));
  767. pToolInfo->cbSize = sizeof(TOOLINFO);
  768. pToolInfo->uFlags = 0;
  769. pToolInfo->hwnd = hDlg;
  770. ::SendDlgItemMessage(hDlg, IDC_GROUP_POV, WM_GETTEXT, (WPARAM)STR_LEN_32, (LPARAM)lpStr);
  771. pToolInfo->lpszText = lpStr;
  772. pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  773. pToolInfo->uId = (ULONG_PTR)hwndPOV;
  774. // Add the control!
  775. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  776. }
  777. }
  778. }
  779. } // *** end of DisplayAvailablePOVs
  780. //===========================================================================
  781. // SetOEMWindowText( HWND hDlg, short *nControlIDs, LPTSTR *pszLabels, BYTE nCount )
  782. //
  783. // Retrieves text from registry keys and Displays it in a Dialog Control or title!
  784. //
  785. // Parameters:
  786. // HWND hDlg - Handle to dialog where strings are to be sent
  787. // nControlIDs - Pointer to array of Dialog Item ID's
  788. // Zero may be used if you want the Title!
  789. // pszLabels - Pointer to array of Registry Keys to read
  790. // nCount - Number of ellements in the array
  791. //
  792. // Returns: nichts
  793. //
  794. //===========================================================================
  795. void SetOEMWindowText ( const HWND hDlg, const short *nControlIDs, LPCTSTR *pszLabels, LPCWSTR wszType, LPDIRECTINPUTJOYCONFIG pdiJoyConfig, BYTE nCount )
  796. {
  797. if( nCount == 0 ) {
  798. #ifdef _DEBUG
  799. OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: nCount is Zero!\n"));
  800. #endif
  801. return;
  802. }
  803. // validate nControlIDs pointer
  804. if( IsBadReadPtr((void*)nControlIDs, sizeof(short)) ) {
  805. #ifdef _DEBUG
  806. OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: nControlIDs is not a valid Read Pointer!\n"));
  807. #endif
  808. return;
  809. }
  810. // validate pointers
  811. if( IsBadReadPtr((void*)pszLabels, sizeof(TCHAR)) ) {
  812. #ifdef _DEBUG
  813. OutputDebugString(TEXT("JOY.CPL: Test.cpp: SetOEMWindowText: pszLabels is not a valid Read Pointer!\n"));
  814. #endif
  815. return;
  816. }
  817. HKEY hKey;
  818. pdiJoyConfig->Acquire();
  819. // Open the TypeKey
  820. if( FAILED(pdiJoyConfig->OpenTypeKey( wszType, KEY_ALL_ACCESS, &hKey)) ) {
  821. #ifdef _DEBUG
  822. OutputDebugString(TEXT("Test.cpp: SetOEMWindowText: OpenTypeKey FAILED!\n"));
  823. #endif
  824. return;
  825. }
  826. DWORD dwCount = MAX_STR_LEN;
  827. LPTSTR pszBuff = (LPTSTR)_alloca(sizeof(TCHAR[MAX_STR_LEN]));
  828. assert(pszBuff);
  829. DWORD dwType = REG_SZ;
  830. do {
  831. if( RegQueryValueEx( hKey, pszLabels[nCount], NULL, &dwType, (CONST LPBYTE)pszBuff, &dwCount ) == ERROR_SUCCESS ) {
  832. // This is because RegQueryValueEx returns dwCount size as the size
  833. // of the terminating char if the label is found w/o a string!
  834. if( dwCount > sizeof(TCHAR) ) {
  835. if( nControlIDs[nCount] )
  836. ::SendMessage(GetDlgItem(hDlg, nControlIDs[nCount]), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pszBuff);
  837. else
  838. ::SendMessage(GetParent(hDlg), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)pszBuff);
  839. }
  840. #ifdef _DEBUG
  841. else OutputDebugString(TEXT("Test.cpp: SetOEMWindowText: ReqQueryValueEx failed to find Registry string!\n"));
  842. #endif
  843. }
  844. dwCount = MAX_STR_LEN;
  845. } while( nCount-- );
  846. RegCloseKey(hKey);
  847. } // *** end of SetOEMWindowText
  848. //===========================================================================
  849. // DisplayAvailableAxisTest(HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2)
  850. //
  851. // Displays the number and names of the device Axis in the provided dialog.
  852. // This EXPECTS that the controls are not visible by default!
  853. //
  854. // Parameters:
  855. // HWND hDlg - Dialog handle
  856. // BYTE nAxisFlags - Flags for number of Axis to display
  857. //
  858. // Returns:
  859. //
  860. //===========================================================================
  861. void DisplayAvailableAxisTest(const HWND hWndToolTip, const HWND hDlg, BYTE nAxisFlags, LPDIRECTINPUTDEVICE2 pdiDevice2)
  862. {
  863. if( nAxisFlags == 0 ) {
  864. DestroyWindow(GetDlgItem(hDlg, IDC_AXISGRP));
  865. #ifdef _DEBUG
  866. OutputDebugString(TEXT("GCDEF.DLL: DisplayAvailableAxis: Number of Axis is 0!\n"));
  867. #endif
  868. return;
  869. }
  870. LPDIDEVICEOBJECTINSTANCE_DX3 pDevObjInst = new (DIDEVICEOBJECTINSTANCE_DX3);
  871. assert (pDevObjInst);
  872. pDevObjInst->dwSize = sizeof(DIDEVICEOBJECTINSTANCE_DX3);
  873. LPTOOLINFO pToolInfo;
  874. if( hWndToolTip ) {
  875. pToolInfo = new (TOOLINFO);
  876. ASSERT (pToolInfo);
  877. ZeroMemory(pToolInfo, sizeof(TOOLINFO));
  878. pToolInfo->cbSize = sizeof(TOOLINFO);
  879. pToolInfo->uFlags = 0;
  880. pToolInfo->hwnd = hDlg;
  881. }
  882. HWND hCtrl;
  883. // X and Y use the same control so they are isolated!
  884. if( (nAxisFlags & HAS_X) || (nAxisFlags & HAS_Y) ) {
  885. HWND hwndXY = GetDlgItem(hDlg, IDC_JOYLIST1);
  886. // Show the Window
  887. SetWindowPos( hwndXY, NULL, NULL, NULL, NULL, NULL,
  888. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  889. // Disable RTL flag
  890. SetWindowLongPtr(hwndXY, GWL_EXSTYLE, GetWindowLongPtr(hwndXY,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL );
  891. hCtrl = GetDlgItem(hDlg, IDC_JOYLIST1_LABEL);
  892. // Show it's text
  893. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
  894. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  895. LPTSTR ptszBuff = (LPTSTR)_alloca(sizeof(TCHAR[STR_LEN_64]));
  896. assert (ptszBuff);
  897. ZeroMemory(ptszBuff, sizeof(TCHAR[STR_LEN_64]));
  898. // Set it's text
  899. if( nAxisFlags & HAS_X ) {
  900. if( SUCCEEDED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, DIJOFS_X, DIPH_BYOFFSET)) )
  901. {
  902. int nLen=lstrlen(pDevObjInst->tszName)+1;
  903. if(nLen>STR_LEN_64)
  904. nLen=STR_LEN_64;
  905. StrCpyN(ptszBuff, pDevObjInst->tszName, nLen);
  906. }
  907. // Remove the HAS_X flag
  908. nAxisFlags &= ~HAS_X;
  909. }
  910. if( nAxisFlags & HAS_Y ) {
  911. if( FAILED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, DIJOFS_Y, DIPH_BYOFFSET)) ) {
  912. #ifdef _DEBUG
  913. OutputDebugString(TEXT("GCDEF.DLL: DisplayAvailableAxis: GetObjectInfo Failed to find DIJOFS_Y!\n"));
  914. #endif
  915. }
  916. if( ptszBuff && lstrlen(ptszBuff) ) {
  917. int nLen=STR_LEN_64-lstrlen(ptszBuff);
  918. StrNCat(ptszBuff, TEXT(" / "), nLen);
  919. }
  920. int nLen=STR_LEN_64-lstrlen(ptszBuff);
  921. StrNCat(ptszBuff, pDevObjInst->tszName, nLen);
  922. // Remove the HAS_Y flag
  923. nAxisFlags &= ~HAS_Y;
  924. }
  925. ::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)ptszBuff);
  926. // CreateWindow could have failed... if so, no tooltips!
  927. if( hWndToolTip ) {
  928. GetWindowRect(hCtrl, &pToolInfo->rect);
  929. ScreenToClient(GetParent(hDlg), (LPPOINT)&pToolInfo->rect);
  930. ScreenToClient(GetParent(hDlg), ((LPPOINT)&pToolInfo->rect)+1);
  931. pToolInfo->lpszText = ptszBuff;
  932. // Add the Label...
  933. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  934. // Add the Control!
  935. pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  936. pToolInfo->uId = (ULONG_PTR)hwndXY;
  937. // Add the control!
  938. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  939. }
  940. }
  941. // if you have additional axis, keep going!
  942. if( nAxisFlags ) {
  943. // Array of supported axis!
  944. DWORD dwOffsetArray[] = {DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1)};
  945. BYTE nAxisCounter = MAX_AXIS - 2;
  946. // Go 'till you run out of axis!
  947. do {
  948. if( nAxisFlags & (HAS_Z<<nAxisCounter) ) {
  949. // Create and Assign to the global list!
  950. ProgWnd[nAxisCounter] = GetDlgItem(hDlg, nAxisCounter+IDC_JOYLIST2);
  951. ASSERT (ProgWnd[nAxisCounter]);
  952. // Create Gradient Class
  953. if( bGradient ) {
  954. pProgs[nAxisCounter] = new (CGradientProgressCtrl);
  955. assert (pProgs[nAxisCounter]);
  956. // Subclass the Progress Control Window
  957. pProgs[nAxisCounter]->SubclassWindow(ProgWnd[nAxisCounter]);
  958. } else {
  959. // Set the colour
  960. // PBM_SETBARCOLOR is WM_USER+9
  961. ::PostMessage(ProgWnd[nAxisCounter], WM_USER+9, 0, (LPARAM)ACTIVE_COLOR);
  962. }
  963. // Show the control... ProgWnd[nAxisCounter]
  964. SetWindowPos( ProgWnd[nAxisCounter], NULL, NULL, NULL, NULL, NULL,
  965. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  966. hCtrl = GetDlgItem(hDlg, nAxisCounter+IDC_JOYLIST2_LABEL);
  967. // Now, Show it's text
  968. SetWindowPos( hCtrl, NULL, NULL, NULL, NULL, NULL,
  969. SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  970. // Get it's text
  971. if( SUCCEEDED(pdiDevice2->GetObjectInfo((LPDIDEVICEOBJECTINSTANCE)pDevObjInst, dwOffsetArray[nAxisCounter], DIPH_BYOFFSET)) ) {
  972. TCHAR tszAxisName[20];
  973. int nLen=lstrlen(pDevObjInst->tszName)+1;
  974. if(nLen>20)
  975. nLen=20;
  976. StrCpyN(tszAxisName, pDevObjInst->tszName, nLen);
  977. if( lstrlen( tszAxisName ) > 4 ) {
  978. tszAxisName[4] = L'.';
  979. tszAxisName[5] = L'.';
  980. tszAxisName[6] = 0;
  981. }
  982. ::SendMessage(hCtrl, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)tszAxisName);
  983. // Just in case CreateWindow failed!!!
  984. if( hWndToolTip ) {
  985. GetWindowRect(hCtrl, &pToolInfo->rect);
  986. ScreenToClient(GetParent(hDlg), (LPPOINT)&pToolInfo->rect);
  987. ScreenToClient(GetParent(hDlg), ((LPPOINT)&pToolInfo->rect)+1);
  988. pToolInfo->uFlags = 0;
  989. pToolInfo->lpszText = pDevObjInst->tszName;
  990. // Add the Label...
  991. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  992. // Add the Control!
  993. pToolInfo->uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  994. pToolInfo->uId = (ULONG_PTR) ProgWnd[nAxisCounter];
  995. // Now, Add the control!
  996. ::SendMessage(hWndToolTip, TTM_ADDTOOL, 0, (LPARAM)pToolInfo);
  997. }
  998. }
  999. // Remove the flag you just hit!
  1000. nAxisFlags &= ~(HAS_Z<<nAxisCounter);
  1001. }
  1002. } while( nAxisCounter-- && nAxisFlags );
  1003. }
  1004. if( hWndToolTip ) {
  1005. if( pToolInfo )
  1006. delete (pToolInfo);
  1007. }
  1008. if( pDevObjInst )
  1009. delete (pDevObjInst);
  1010. } //*** end of DisplayAvailableAxisTest
  1011. //===========================================================================
  1012. // BOOL SetDeviceRanges( HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis)
  1013. //
  1014. // Parameters:
  1015. // HWND hDlg - Handle of Dialog containing controls to scale to
  1016. // LPDIRECTINPUTDEVICE2 pdiDevice2 - Device2 Interface pointer
  1017. // BYTE nAxis - Bit mask of axis ranges to set
  1018. //
  1019. // Returns: FALSE if failed
  1020. //
  1021. //===========================================================================
  1022. BOOL SetDeviceRanges( const HWND hDlg, LPDIRECTINPUTDEVICE2 pdiDevice2, BYTE nAxis)
  1023. {
  1024. if( !::IsWindow(hDlg) ) {
  1025. #ifdef _DEBUG
  1026. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: hDlg: Not a valid window!\n"));
  1027. #endif
  1028. return(FALSE);
  1029. }
  1030. // validate pDIDevice2 pointer
  1031. if( IsBadReadPtr((void*)pdiDevice2, sizeof(IDirectInputDevice2)) ) {
  1032. #ifdef _DEBUG
  1033. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: pdiDevice2: Bad Read Pointer argument!\n"));
  1034. #endif
  1035. return(FALSE);
  1036. }
  1037. if( !nAxis ) {
  1038. #ifdef _DEBUG
  1039. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: nAxis is Zero!\n"));
  1040. #endif
  1041. return(FALSE);
  1042. }
  1043. LPDIPROPRANGE pDIPropRange = (LPDIPROPRANGE)_alloca(sizeof(DIPROPRANGE));
  1044. assert (pDIPropRange);
  1045. if( !pDIPropRange ) {
  1046. #ifdef _DEBUG
  1047. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: Failed to malloc DIPROPDRANGE!\n"));
  1048. #endif
  1049. return(FALSE);
  1050. }
  1051. pDIPropRange->diph.dwSize = sizeof(DIPROPRANGE);
  1052. pDIPropRange->diph.dwHeaderSize = sizeof(DIPROPHEADER);
  1053. pDIPropRange->diph.dwHow = DIPH_BYOFFSET;
  1054. BOOL bRet = TRUE;
  1055. HWND hCtrl;
  1056. RECT rc;
  1057. // since X and Y share the same window..
  1058. if( (nAxis & HAS_X) || (nAxis & HAS_Y) ) {
  1059. hCtrl = GetDlgItem(hDlg, IDC_JOYLIST1);
  1060. assert (hCtrl);
  1061. GetClientRect( hCtrl, &rc );
  1062. // Check if it's X
  1063. if( nAxis & HAS_X ) {
  1064. pDIPropRange->diph.dwObj = DIJOFS_X;
  1065. pDIPropRange->lMin = DELTA;
  1066. pDIPropRange->lMax = rc.right-DELTA;
  1067. if( FAILED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)) ) {
  1068. #ifdef _DEBUG
  1069. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: SetProperty Failed to return X axis Ranges!\n"));
  1070. #endif
  1071. bRet = FALSE;
  1072. }
  1073. // strip off the bits you just used
  1074. nAxis &= ~HAS_X;
  1075. }
  1076. // Check if it's Y
  1077. if( nAxis & HAS_Y ) {
  1078. pDIPropRange->diph.dwObj = DIJOFS_Y;
  1079. pDIPropRange->lMin = DELTA;
  1080. pDIPropRange->lMax = rc.bottom-DELTA;
  1081. if( FAILED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)) ) {
  1082. #ifdef _DEBUG
  1083. OutputDebugString(TEXT("GCDEF: SetDeviceRanges: SetProperty Failed to return Y axis Ranges!\n"));
  1084. #endif
  1085. bRet = FALSE;
  1086. }
  1087. // strip off the bits you just used
  1088. nAxis &= ~HAS_Y;
  1089. }
  1090. }
  1091. // you've got axes > X & Y...
  1092. if( nAxis ) {
  1093. const DWORD dwOfset[] = {DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1)};
  1094. // Minus 2 is because we've already done X/Y!
  1095. // the third decrement is for the Zero based dwOffset!
  1096. BYTE nAxisCounter = MAX_AXIS-3;
  1097. // These aren't random!
  1098. // These are the default ranges for the CProgressCtrl!!!
  1099. pDIPropRange->lMin = MIN_SLIDER_POS;
  1100. pDIPropRange->lMax = MAX_SLIDER_POS;
  1101. do {
  1102. if( nAxis & (HAS_Z<<nAxisCounter) ) {
  1103. pDIPropRange->diph.dwObj = dwOfset[nAxisCounter];
  1104. VERIFY(SUCCEEDED(pdiDevice2->SetProperty(DIPROP_RANGE, &pDIPropRange->diph)));
  1105. // Remove the flag you just hit!
  1106. nAxis &= ~(HAS_Z<<nAxisCounter);
  1107. }
  1108. nAxisCounter--;
  1109. } while( nAxis );
  1110. }
  1111. return(bRet);
  1112. }
  1113. #ifdef _UNICODE
  1114. ///////////////////////////////////////////////////////////////////////////////
  1115. // FUNCTION: RegisterForDevChange ( HWND hDlg, PVOID *hNoditfyDevNode )
  1116. //
  1117. // PARAMETERS:
  1118. //
  1119. //
  1120. // PURPOSE:
  1121. //
  1122. // RETURN:
  1123. ///////////////////////////////////////////////////////////////////////////////
  1124. void RegisterForDevChange(HWND hDlg, PVOID *hNotifyDevNode)
  1125. {
  1126. DEV_BROADCAST_DEVICEINTERFACE *pFilterData = (DEV_BROADCAST_DEVICEINTERFACE *)_alloca(sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  1127. ASSERT (pFilterData);
  1128. ZeroMemory(pFilterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  1129. pFilterData->dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  1130. pFilterData->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  1131. pFilterData->dbcc_classguid = GUID_CLASS_INPUT;
  1132. *hNotifyDevNode = RegisterDeviceNotification(hDlg, pFilterData, DEVICE_NOTIFY_WINDOW_HANDLE);
  1133. }
  1134. ///////////////////////////////////////////////////////////////////////////////
  1135. // FUNCTION: DecodeAxisPOV ( DWORD dwVal )
  1136. //
  1137. // PARAMETERS:
  1138. //
  1139. //
  1140. // PURPOSE:
  1141. //
  1142. // RETURN:
  1143. ///////////////////////////////////////////////////////////////////////////////
  1144. static DWORD DecodeAxisPOV( DWORD dwVal )
  1145. {
  1146. DWORD dwResult;
  1147. if( bPolledPOV ) {
  1148. /*
  1149. * figure out which direction this value indicates...
  1150. */
  1151. if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_FORWARD])
  1152. &&(dwVal < myPOV[POV_MAX][JOY_POVVAL_FORWARD]) )
  1153. {
  1154. dwResult = JOY_POVFORWARD;
  1155. }
  1156. else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_BACKWARD])
  1157. &&(dwVal < myPOV[POV_MAX][JOY_POVVAL_BACKWARD]) )
  1158. {
  1159. dwResult = JOY_POVBACKWARD;
  1160. }
  1161. else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_LEFT])
  1162. &&(dwVal < myPOV[POV_MAX][JOY_POVVAL_LEFT]) )
  1163. {
  1164. dwResult = JOY_POVLEFT;
  1165. }
  1166. else if( (dwVal > myPOV[POV_MIN][JOY_POVVAL_RIGHT])
  1167. &&(dwVal < myPOV[POV_MAX][JOY_POVVAL_RIGHT]) )
  1168. {
  1169. dwResult = JOY_POVRIGHT;
  1170. }
  1171. else
  1172. {
  1173. dwResult = JOY_POVCENTERED;
  1174. }
  1175. } else {
  1176. dwResult = dwVal;
  1177. }
  1178. #if 0
  1179. {
  1180. TCHAR buf[100];
  1181. if( bPolledPOV ) {
  1182. wsprintf(buf, TEXT("calibrated pov: %d\r\n"), dwResult);
  1183. } else {
  1184. wsprintf(buf, TEXT("uncalibrated pov: %d\r\n"), dwResult);
  1185. }
  1186. OutputDebugString(buf);
  1187. }
  1188. #endif
  1189. return dwResult;
  1190. }
  1191. /*
  1192. * doPOVCal - compute calibration for POV for a direction
  1193. */
  1194. static void __inline doPOVCal( LPJOYREGHWCONFIG pHWCfg, DWORD dwDir, LPDWORD dwOrder )
  1195. {
  1196. DWORD dwVal;
  1197. int nDir;
  1198. for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
  1199. {
  1200. if( dwOrder[nDir] == dwDir )
  1201. {
  1202. break;
  1203. }
  1204. }
  1205. if( nDir == 0 )
  1206. {
  1207. dwVal = 1;
  1208. }
  1209. else
  1210. {
  1211. dwVal = (pHWCfg->hwv.dwPOVValues[dwDir] + pHWCfg->hwv.dwPOVValues[dwOrder[nDir-1]])/2;
  1212. }
  1213. myPOV[POV_MIN][dwDir] = dwVal;
  1214. if( nDir == JOY_POV_NUMDIRS-1 ) {
  1215. dwVal = pHWCfg->hwv.dwPOVValues[dwDir]/10l;
  1216. dwVal += pHWCfg->hwv.dwPOVValues[dwDir];
  1217. } else {
  1218. dwVal = (pHWCfg->hwv.dwPOVValues[dwOrder[nDir+1]] + pHWCfg->hwv.dwPOVValues[dwDir])/2;
  1219. }
  1220. myPOV[POV_MAX][dwDir] = dwVal;
  1221. } /* doPOVCal */
  1222. ///////////////////////////////////////////////////////////////////////////////
  1223. // FUNCTION: CalibratePolledPOV( LPJOYREGHWCONFIG pHWCfg )
  1224. //
  1225. // PARAMETERS:
  1226. //
  1227. //
  1228. // PURPOSE:
  1229. //
  1230. // RETURN:
  1231. ///////////////////////////////////////////////////////////////////////////////
  1232. void CalibratePolledPOV( LPJOYREGHWCONFIG pHWCfg )
  1233. {
  1234. DWORD dwOrder[JOY_POV_NUMDIRS];
  1235. DWORD dwTmp[JOY_POV_NUMDIRS];
  1236. DWORD dwVal;
  1237. int nDir,nDir2;
  1238. /*
  1239. * calibrate POV for polling based ones
  1240. */
  1241. for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
  1242. {
  1243. dwTmp[nDir] = pHWCfg->hwv.dwPOVValues[nDir];
  1244. dwOrder[nDir] = nDir;
  1245. }
  1246. /*
  1247. * sort (did you ever think you'd see a bubble sort again?)
  1248. */
  1249. for( nDir=0;nDir<JOY_POV_NUMDIRS;nDir++ )
  1250. {
  1251. for( nDir2=nDir; nDir2<JOY_POV_NUMDIRS; nDir2++ )
  1252. {
  1253. if( dwTmp[nDir] > dwTmp[nDir2] )
  1254. {
  1255. dwVal = dwTmp[nDir];
  1256. dwTmp[nDir] = dwTmp[nDir2];
  1257. dwTmp[nDir2] = dwVal;
  1258. dwVal = dwOrder[nDir];
  1259. dwOrder[nDir] = dwOrder[nDir2];
  1260. dwOrder[nDir2] = dwVal;
  1261. }
  1262. }
  1263. }
  1264. for( nDir=0; nDir<JOY_POV_NUMDIRS; nDir++ )
  1265. {
  1266. doPOVCal( pHWCfg, nDir, dwOrder );
  1267. }
  1268. myPOV[POV_MIN][JOY_POV_NUMDIRS] = 0;
  1269. myPOV[POV_MAX][JOY_POV_NUMDIRS] = 0;
  1270. } /* CalibratePolledPOV */
  1271. #endif