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.

824 lines
27 KiB

  1. // **************************************************************************
  2. // Filterkeys dialogs
  3. // Process the filterkeys dialogs
  4. // **************************************************************************
  5. #include "Access.h"
  6. extern DWORD g_dwOrigFKFlags;
  7. extern BOOL g_bFKOn;
  8. #define SWAP(A, B) ( A ^= B, B ^= A, A ^= B )
  9. // Prototypes
  10. INT_PTR WINAPI BKDlg (HWND, UINT, WPARAM, LPARAM);
  11. INT_PTR WINAPI RKDlg (HWND, UINT, WPARAM, LPARAM);
  12. BOOL WINAPI NotificationDlg (HWND, UINT, WPARAM, LPARAM);
  13. BOOL SubclassFilterKeysTestBox (UINT uIdTestBox,HWND hDlg);
  14. BOOL SubclassRepeatKeysTestBox (UINT uIdTestBox,HWND hDlg);
  15. // All these are for subclassing, so that pressing TAB stops at the next
  16. // control after test areas. a-anilk
  17. LRESULT CALLBACK SubclassWndProcFKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  18. LRESULT CALLBACK SubclassWndProcFKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  19. LRESULT CALLBACK SubclassWndProcRKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  20. LRESULT CALLBACK SubclassWndProcRKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  21. // Times are in milliseconds
  22. #define DELAYSIZE 5
  23. UINT uDelayTable[] = { 300, 700, 1000, 1500, 2000 };
  24. // Times are in milliseconds
  25. #define RATESIZE 6
  26. UINT uRateTable[] = { 300, 500, 700, 1000, 1500, 2000 };
  27. // Times are in milliseconds
  28. #define BOUNCESIZE 5
  29. UINT uBounceTable[] = { 500, 700, 1000, 1500, 2000 };
  30. // Times are in milliseconds
  31. // TODO 5, 10, and 20 sec needs change to kernel code (SystemParametersInfo)
  32. #define ACCEPTSIZE 10
  33. UINT uAcceptTable[] = { 0, 300, 500, 700, 1000, 1400, 2000, 5000, 10000, 20000 };
  34. // these are wndprocs for subclassed windows to ignore repeated tab keys in
  35. // some situations.
  36. WNDPROC g_WndProcFKPrev = NULL;
  37. WNDPROC g_WndProcFKNext = NULL;
  38. WNDPROC g_WndProcRKPrev = NULL;
  39. WNDPROC g_WndProcRKNext = NULL;
  40. // other definitions for the keyboard
  41. // UP means key was up before this message, DOWN means key was down
  42. // PRESS means the key is being pressed, RELEASE means key being released
  43. #define KEY_UP 0
  44. #define KEY_DOWN 1
  45. #define KEY_PRESS 0
  46. #define KEY_RELEASE 1
  47. // Macros to look at the lParam of keyboard messages
  48. //
  49. #define SCAN_CODE(theParam) (LOBYTE (HIWORD(theParam)))
  50. #define EXTENDED(theParam) ( (HIWORD (theParam) & 0x0100) > 0)
  51. #define SYSKEY(theParam) ( (HIWORD (theParam) & 0x2000) > 0)
  52. #define MENUMODE(theParam) ( (HIWORD (theParam) & 0x1000) > 0)
  53. #define PREV_STATE(theParam) ( (HIWORD (theParam) & 0x4000) > 0)
  54. #define TRAN_STATE(theParam) ( (HIWORD (theParam) & 0x8000) > 0)
  55. #define MAKE(theParam) (TRAN_STATE(theParam) == KEY_PRESS)
  56. #define BREAK(theParam) (TRAN_STATE(theParam) == KEY_RELEASE)
  57. #define WASUP(theParam) (PREV_STATE(theParam) == KEY_UP)
  58. #define WASDOWN(theParam) (PREV_STATE(theParam) == KEY_DOWN)
  59. #define FIRSTHIT(theParam) (WASUP(theParam) && MAKE(theParam))
  60. // *************************************************************************
  61. // Process the scrolling messages from our trackbars.
  62. // GENERIC CODE - called for any TrackBar handler.
  63. // Passed in the hwnd, wParam, hwndScroll
  64. // we can do all handling and return the new trackbar value without
  65. // knowing what control it is.
  66. // Returns -1 to mean don't do anything
  67. // *************************************************************************
  68. int HandleScroll (HWND hwnd, WPARAM wParam, HWND hwndScroll) {
  69. int nCurSliderPos = (int) SendMessage(
  70. hwndScroll, TBM_GETPOS, 0, 0);
  71. int nMaxVal = (int) SendMessage(
  72. hwndScroll, TBM_GETRANGEMAX, 0, 0);
  73. int nMinVal = (int) SendMessage(
  74. hwndScroll, TBM_GETRANGEMIN, 0, 0);
  75. switch (LOWORD(wParam)) {
  76. case TB_LINEUP:
  77. case TB_LINEDOWN:
  78. case TB_THUMBTRACK:
  79. case TB_THUMBPOSITION:
  80. case SB_ENDSCROLL:
  81. break;
  82. case TB_BOTTOM:
  83. nCurSliderPos = nMaxVal;
  84. break;
  85. case TB_TOP:
  86. nCurSliderPos = nMinVal;
  87. break;
  88. }
  89. if (nCurSliderPos < nMinVal)
  90. {
  91. nCurSliderPos = nMinVal;
  92. }
  93. if (nCurSliderPos > nMaxVal)
  94. {
  95. nCurSliderPos = nMaxVal;
  96. }
  97. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM) hwnd, 0);
  98. return(nCurSliderPos);
  99. }
  100. // Helper functions
  101. __inline WriteFloat(LPTSTR pszBuf, UINT uVal, LPCTSTR pszUnits)
  102. {
  103. wsprintf(pszBuf, TEXT("%d.%d %s"), uVal/1000, (uVal % 1000)/100, pszUnits);
  104. }
  105. __inline void HandleSelection(HWND hwnd, UINT *puTable, DWORD *pdwNewValue)
  106. {
  107. LRESULT i = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
  108. *pdwNewValue = (i != CB_ERR)?puTable[i]:0;
  109. }
  110. int GetIndex(DWORD dwValue, UINT *puTable, int cSize)
  111. {
  112. int i;
  113. for (i = 0; i < cSize; i++)
  114. {
  115. if (puTable[i] >= dwValue)
  116. break;
  117. }
  118. if (i >= cSize)
  119. i = cSize - 1;
  120. return i;
  121. }
  122. void FillAndSetCombo(HWND hwnd, UINT *puTable, int cItems, int iCurPos, LPCTSTR pszUnits)
  123. {
  124. int i;
  125. TCHAR pszItem[100];
  126. SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
  127. for (i=0;i<cItems;i++)
  128. {
  129. WriteFloat(pszItem, puTable[i], pszUnits);
  130. SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)pszItem);
  131. }
  132. SendMessage(hwnd, CB_SETCURSEL, iCurPos, 0);
  133. }
  134. void TestFilterKeys (BOOL fTurnTestOn)
  135. {
  136. if (fTurnTestOn)
  137. {
  138. g_fk.dwFlags &= ~FKF_INDICATOR;
  139. g_fk.dwFlags |= FKF_FILTERKEYSON;
  140. }
  141. else
  142. {
  143. if (g_dwOrigFKFlags & FKF_FILTERKEYSON)
  144. {
  145. g_fk.dwFlags |= FKF_FILTERKEYSON;
  146. }
  147. else
  148. {
  149. g_fk.dwFlags &= ~FKF_FILTERKEYSON;
  150. }
  151. if (g_dwOrigFKFlags & FKF_INDICATOR)
  152. {
  153. g_fk.dwFlags |= FKF_INDICATOR;
  154. }
  155. else
  156. {
  157. g_fk.dwFlags &= ~FKF_INDICATOR;
  158. }
  159. }
  160. AccessSystemParametersInfo(SPI_SETFILTERKEYS, sizeof(g_fk), &g_fk, 0);
  161. }
  162. // ****************************************************************************
  163. // Main filter keys dialog handler
  164. // ****************************************************************************
  165. INT_PTR WINAPI FilterKeyDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  166. FILTERKEYS fk;
  167. BOOL fProcessed = TRUE;
  168. switch (uMsg) {
  169. case WM_INITDIALOG:
  170. // Setup hotkey
  171. CheckDlgButton(hwnd, IDC_FK_HOTKEY, (g_fk.dwFlags & FKF_HOTKEYACTIVE) ? TRUE : FALSE);
  172. // Setup the radio buttons for SLOW vs BOUNCE keys
  173. if (0 != g_fk.iBounceMSec) {
  174. // Bounce keys enabeled
  175. CheckRadioButton(hwnd, IDC_FK_BOUNCE, IDC_FK_REPEAT, IDC_FK_BOUNCE);
  176. EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), TRUE);
  177. EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), FALSE);
  178. }
  179. else
  180. {
  181. // Slow key enabled
  182. CheckRadioButton(hwnd, IDC_FK_BOUNCE, IDC_FK_REPEAT, IDC_FK_REPEAT);
  183. EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), FALSE);
  184. EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), TRUE);
  185. }
  186. CheckDlgButton(hwnd, IDC_FK_SOUND, (g_fk.dwFlags & FKF_CLICKON) ? TRUE : FALSE);
  187. CheckDlgButton(hwnd, IDC_FK_STATUS, (g_fk.dwFlags & FKF_INDICATOR) ? TRUE : FALSE);
  188. //
  189. // SteveDon 5/15/98
  190. // If the focus is in the TestBox and "Ignore Quick Keystrokes" is on,
  191. // you have to hold down tab to get out. But as soon as focus leaves,
  192. // Ignore Quick Keystrokes gets turned off and the tab keys ends up
  193. // autorepeating very quickly, which (usually) lands you back in the
  194. // TestBox.
  195. // Solution: ignore repeated tabs in this dialog.
  196. // Problem: keys don't go to the dialog, they go to the focused
  197. // control. So: we can try to ignore repeated tab keys for the controls
  198. // just after the test box and just before the test box, which means
  199. // that we need to subclass those window procs.
  200. if (!SubclassFilterKeysTestBox (IDC_FK_TESTBOX,hwnd))
  201. return (FALSE);
  202. break;
  203. case WM_HELP:
  204. WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
  205. break;
  206. case WM_CONTEXTMENU:
  207. WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
  208. break;
  209. case WM_COMMAND:
  210. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  211. case IDC_FK_HOTKEY:
  212. g_fk.dwFlags ^= FKF_HOTKEYACTIVE;
  213. break;
  214. case IDC_FK_REPEAT:
  215. g_fk.iBounceMSec = 0;
  216. if (g_fk.iDelayMSec == 0)
  217. {
  218. g_fk.iDelayMSec = g_nLastRepeatDelay;
  219. g_fk.iRepeatMSec = g_nLastRepeatRate;
  220. g_fk.iWaitMSec = g_nLastWait;
  221. }
  222. CheckRadioButton(hwnd, IDC_FK_REPEAT, IDC_FK_BOUNCE, IDC_FK_REPEAT);
  223. EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), FALSE);
  224. EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), TRUE);
  225. break;
  226. case IDC_FK_BOUNCE:
  227. g_fk.iDelayMSec = 0;
  228. g_fk.iRepeatMSec = 0;
  229. g_fk.iWaitMSec = 0;
  230. if (g_fk.iBounceMSec == 0)
  231. {
  232. g_fk.iBounceMSec = g_dwLastBounceKeySetting;
  233. }
  234. CheckRadioButton(hwnd, IDC_FK_REPEAT, IDC_FK_BOUNCE, IDC_FK_BOUNCE);
  235. EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), TRUE);
  236. EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), FALSE);
  237. break;
  238. // Settings dialogs
  239. case IDC_RK_SETTINGS: // This is RepeatKeys
  240. fk = g_fk;
  241. if (DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ADVCHARREPEAT), hwnd, RKDlg) == IDCANCEL) {
  242. g_fk = fk;
  243. }
  244. break;
  245. case IDC_BK_SETTINGS: // This is BounceKeys
  246. fk = g_fk;
  247. if (DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ADVKEYBOUNCE), hwnd, BKDlg) == IDCANCEL) {
  248. g_fk = fk;
  249. }
  250. break;
  251. case IDC_FK_SOUND:
  252. g_fk.dwFlags ^= FKF_CLICKON;
  253. break;
  254. case IDC_FK_STATUS:
  255. g_fk.dwFlags ^= FKF_INDICATOR;
  256. break;
  257. // The test edit box is a special control for us. When we get the
  258. // focus we turn on the current filterkeys settings, when we
  259. // leave the text box, we turn them back to what they were.
  260. case IDC_FK_TESTBOX:
  261. switch (HIWORD(wParam)) {
  262. case EN_SETFOCUS: TestFilterKeys(TRUE); break;
  263. case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
  264. }
  265. break;
  266. case IDOK:
  267. if (g_dwLastBounceKeySetting == 0)
  268. g_dwLastBounceKeySetting = uBounceTable[0];
  269. EndDialog(hwnd, IDOK);
  270. break;
  271. case IDCANCEL:
  272. EndDialog(hwnd, IDCANCEL);
  273. break;
  274. }
  275. break;
  276. default:
  277. fProcessed = FALSE; break;
  278. }
  279. return(fProcessed);
  280. }
  281. void PutNumInEdit (HWND hwndEdit, int nNum)
  282. {
  283. TCHAR szBuf[10], szBuf2[20];
  284. wsprintf(szBuf, __TEXT("%d.%d"), nNum / 1000, (nNum % 1000) / 100);
  285. GetNumberFormat(LOCALE_USER_DEFAULT, 0, szBuf, NULL, szBuf2, 20);
  286. SetWindowText(hwndEdit, szBuf2);
  287. }
  288. // **************************************************************************
  289. // BKDlg
  290. // Process the BounceKeys dialog.
  291. // **************************************************************************
  292. INT_PTR WINAPI BKDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  293. int i;
  294. BOOL fProcessed = TRUE;
  295. TCHAR pszSeconds[50];
  296. int ctch;
  297. switch (uMsg) {
  298. case WM_INITDIALOG:
  299. ctch = LoadString(g_hinst, IDS_SECONDS, pszSeconds, ARRAY_SIZE(pszSeconds));
  300. Assert(ctch);
  301. // Determine the bounce. Make sure its a valide value.
  302. if (g_dwLastBounceKeySetting == 0)
  303. g_dwLastBounceKeySetting = 500;
  304. if (g_fk.iBounceMSec == 0)
  305. g_fk.iBounceMSec = g_dwLastBounceKeySetting;
  306. i = GetIndex(g_fk.iBounceMSec, uBounceTable, BOUNCESIZE);
  307. FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_BK_BOUNCERATE), uBounceTable, BOUNCESIZE, i, pszSeconds);
  308. break;
  309. case WM_HELP: // F1
  310. WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
  311. break;
  312. case WM_CONTEXTMENU: // right mouse click
  313. WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
  314. break;
  315. case WM_COMMAND:
  316. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  317. // The test edit box is a special control for us. When we get the
  318. // focus we turn on the current filterkeys settings, when we
  319. // leave the text box, we turn them back to what they were.
  320. case IDC_BK_TESTBOX:
  321. switch (HIWORD(wParam)) {
  322. case EN_SETFOCUS: TestFilterKeys(TRUE); break;
  323. case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
  324. }
  325. break;
  326. case IDC_CMB_BK_BOUNCERATE:
  327. switch (HIWORD(wParam))
  328. {
  329. case CBN_SELCHANGE:
  330. HandleSelection(GetDlgItem(hwnd, IDC_CMB_BK_BOUNCERATE), uBounceTable, &g_fk.iBounceMSec);
  331. break;
  332. }
  333. break;
  334. case IDOK:
  335. // Save the last known valid setting.
  336. g_dwLastBounceKeySetting = g_fk.iBounceMSec;
  337. EndDialog(hwnd, IDOK);
  338. break;
  339. case IDCANCEL:
  340. EndDialog(hwnd, IDCANCEL);
  341. break;
  342. }
  343. break;
  344. default: fProcessed = FALSE; break;
  345. }
  346. return(fProcessed);
  347. }
  348. // **************************************************************************
  349. // RKDlg
  350. // Process the RepeatKeys dialog.
  351. // **************************************************************************
  352. INT_PTR WINAPI RKDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  353. int i;
  354. BOOL fProcessed = TRUE;
  355. static s_fRepeating = TRUE;
  356. static DWORD s_nLastRepeatDelayOld;
  357. static DWORD s_nLastRepeatRateOld;
  358. static DWORD s_nLastWaitOld;
  359. TCHAR pszItem[100];
  360. TCHAR pszSeconds[50];
  361. int ctch;
  362. LPARAM lParamT;
  363. switch(uMsg) {
  364. case WM_INITDIALOG:
  365. ctch = LoadString(g_hinst, IDS_SECONDS, pszSeconds, ARRAY_SIZE(pszSeconds));
  366. Assert(ctch);
  367. s_nLastRepeatDelayOld = g_nLastRepeatDelay;
  368. s_nLastRepeatRateOld = g_nLastRepeatRate;
  369. s_nLastWaitOld = g_nLastWait;
  370. s_fRepeating = (0 != g_fk.iDelayMSec);
  371. CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT,
  372. s_fRepeating ? IDC_RK_REPEAT : IDC_RK_NOREPEAT);
  373. if (!s_fRepeating) {
  374. // Set FilterKey values to LastRepeat values
  375. // so the sliders will still get initialized correctly
  376. g_fk.iDelayMSec = g_nLastRepeatDelay;
  377. g_fk.iRepeatMSec = g_nLastRepeatRate;
  378. }
  379. // Initialize the Acceptance combo box to last valid state
  380. i = GetIndex(g_fk.iWaitMSec, uAcceptTable, ACCEPTSIZE);
  381. FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_ACCEPTRATE), uAcceptTable, ACCEPTSIZE, i, pszSeconds);
  382. g_fk.iWaitMSec = uAcceptTable[i];
  383. // Initialize the Delay combo box
  384. i = GetIndex(g_fk.iDelayMSec, uDelayTable, DELAYSIZE);
  385. FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), uDelayTable, DELAYSIZE, i, pszSeconds);
  386. g_fk.iDelayMSec = uDelayTable[i];
  387. // Initialize the Repeat Rate Slider Note -1 is set via the checkbox.
  388. i = GetIndex(g_fk.iRepeatMSec, uRateTable, RATESIZE);
  389. FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), uRateTable, RATESIZE, i, pszSeconds);
  390. g_fk.iRepeatMSec = uRateTable[i];
  391. // Now cleanup from initialization. Disable controls
  392. // that usable... Swap back any params needed
  393. if (!s_fRepeating)
  394. {
  395. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), FALSE);
  396. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), FALSE);
  397. // If we're not repeating, now set the value to 0
  398. // which indicates max repeat rate.
  399. g_fk.iDelayMSec = 0;
  400. g_fk.iRepeatMSec = 0;
  401. }
  402. //
  403. // SteveDon 5/15/98
  404. // If the focus is in the TestBox and "Ignore Quick Keystrokes" is on,
  405. // you have to hold down tab to get out. But as soon as focus leaves,
  406. // Ignore Quick Keystrokes gets turned off and the tab keys ends up
  407. // autorepeating very quickly, which (usually) lands you back in the
  408. // TestBox.
  409. // Solution: ignore repeated tabs in this dialog.
  410. // Problem: keys don't go to the dialog, they go to the focused
  411. // control. So: we can try to ignore repeated tab keys for the controls
  412. // just after the test box and just before the test box, which means
  413. // that we need to subclass those window procs.
  414. if (!SubclassRepeatKeysTestBox (IDC_RK_TESTBOX,hwnd))
  415. return (FALSE);
  416. break;
  417. case WM_HELP: // F1
  418. WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
  419. break;
  420. case WM_CONTEXTMENU: // right mouse click
  421. WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
  422. break;
  423. case WM_COMMAND:
  424. switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  425. // Turn on repeat keys - We're disabling via CPL rather than any flags in the call
  426. case IDC_RK_REPEAT:
  427. if (!s_fRepeating) {
  428. g_fk.iDelayMSec = g_nLastRepeatDelay;
  429. g_fk.iRepeatMSec = g_nLastRepeatRate;
  430. }
  431. // Now that we have valid parameters, continue with setting the sliders.
  432. s_fRepeating = TRUE;
  433. CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT, IDC_RK_REPEAT);
  434. if (g_fk.iRepeatMSec == 0)
  435. g_fk.iRepeatMSec = uRateTable[0];
  436. if (g_fk.iDelayMSec == 0)
  437. g_fk.iDelayMSec = uDelayTable[0];
  438. i = GetIndex(g_fk.iRepeatMSec, uRateTable, RATESIZE);
  439. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), TRUE);
  440. SendDlgItemMessage(hwnd, IDC_CMB_RK_REPEATRATE, CB_SETCURSEL, i, 0);
  441. i = GetIndex(g_fk.iDelayMSec, uDelayTable, DELAYSIZE);
  442. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), TRUE);
  443. SendDlgItemMessage(hwnd, IDC_CMB_RK_DELAYRATE, CB_SETCURSEL, i, 0);
  444. break;
  445. // Turn OFF repeat keys
  446. case IDC_RK_NOREPEAT:
  447. s_fRepeating = FALSE;
  448. CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT, IDC_RK_NOREPEAT);
  449. g_fk.iDelayMSec = 0;
  450. g_fk.iRepeatMSec = 0;
  451. SendDlgItemMessage(hwnd, IDC_CMB_RK_DELAYRATE, CB_SETCURSEL, -1, 0);
  452. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), FALSE);
  453. SendDlgItemMessage(hwnd, IDC_CMB_RK_REPEATRATE, CB_SETCURSEL, -1, 0);
  454. EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), FALSE);
  455. break;
  456. // Process the test box - turnon filterkeys while inside it.
  457. case IDC_RK_TESTBOX:
  458. switch (HIWORD(wParam)) {
  459. case EN_SETFOCUS: TestFilterKeys(TRUE); break;
  460. case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
  461. }
  462. break;
  463. case IDC_CMB_RK_DELAYRATE:
  464. switch (HIWORD(wParam))
  465. {
  466. case CBN_SELCHANGE:
  467. HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), uDelayTable, &g_fk.iDelayMSec);
  468. break;
  469. }
  470. break;
  471. case IDC_CMB_RK_REPEATRATE:
  472. switch (HIWORD(wParam))
  473. {
  474. case CBN_SELCHANGE:
  475. HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), uRateTable, &g_fk.iRepeatMSec);
  476. break;
  477. }
  478. break;
  479. case IDC_CMB_RK_ACCEPTRATE:
  480. switch (HIWORD(wParam))
  481. {
  482. case CBN_SELCHANGE:
  483. HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_ACCEPTRATE), uAcceptTable, &g_fk.iWaitMSec);
  484. break;
  485. }
  486. break;
  487. case IDOK:
  488. // Save off repeating values to registry
  489. EndDialog(hwnd, IDOK);
  490. break;
  491. case IDCANCEL:
  492. g_nLastRepeatDelay = s_nLastRepeatDelayOld;
  493. g_nLastRepeatRate = s_nLastRepeatRateOld;
  494. g_nLastWait = s_nLastWaitOld;
  495. EndDialog(hwnd, IDCANCEL);
  496. break;
  497. }
  498. break;
  499. default:
  500. fProcessed = FALSE;
  501. break;
  502. }
  503. return(fProcessed);
  504. }
  505. // **************************************************************************
  506. // SubclassFilterKeysTestBox
  507. //
  508. // This takes the dialog ID of an edit field, and then finds the controls
  509. // near the edit field (the controls 2 windows before and 2 windows after the
  510. // edit control in the z-order). These are the nearest controls that get
  511. // keyboard messages. It subclasses both of these controls
  512. // so that they ignore any WM_KEYDOWN messages when the key being pressed is
  513. // the tab key and the key is already down (i.e. this is a repeated message)
  514. //
  515. // **************************************************************************
  516. BOOL SubclassFilterKeysTestBox (UINT uIdTestBox,HWND hDlg)
  517. {
  518. HWND hwndPrev,
  519. hwndNext,
  520. hwndTestBox;
  521. hwndTestBox = GetDlgItem (hDlg,uIdTestBox);
  522. // BE CAREFUL IF DIALOG CHANGES! Right now the
  523. // Previous Previous window is the "S&ettings" push button,
  524. // and the Next Next is the "&Beep when keys pressed..."
  525. // checkbox. If the order changes, this code might have to change too.
  526. // Could make it more general where it searches for controls before
  527. // and after that can get keyboard focus.
  528. hwndPrev = GetNextDlgTabItem (hDlg,hwndTestBox,TRUE);
  529. if (!hwndPrev)
  530. return FALSE;
  531. g_WndProcFKPrev = (WNDPROC) GetWindowLongPtr (hwndPrev, GWLP_WNDPROC);
  532. SetWindowLongPtr (hwndPrev,GWLP_WNDPROC,(LPARAM)SubclassWndProcFKPrev);
  533. hwndNext = GetNextDlgTabItem (hDlg,hwndTestBox,FALSE);
  534. if (!hwndNext)
  535. return FALSE;
  536. g_WndProcFKNext = (WNDPROC) GetWindowLongPtr (hwndNext, GWLP_WNDPROC);
  537. SetWindowLongPtr (hwndNext,GWLP_WNDPROC,(LPARAM)SubclassWndProcFKNext);
  538. return TRUE;
  539. }
  540. // **************************************************************************
  541. // SubclassWndProcFKPrev
  542. //
  543. // This is the WndProc used to ignore repeated presses of the tab key for
  544. // the first focusable control that precedes the test box.
  545. //
  546. // **************************************************************************
  547. LRESULT CALLBACK SubclassWndProcFKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  548. {
  549. switch (uMsg)
  550. {
  551. case WM_KEYDOWN:
  552. if ((int)wParam == VK_TAB)
  553. {
  554. if (WASDOWN (lParam))
  555. {
  556. return (0);
  557. }
  558. // if not a repeat, need to move the focus. For some reason,
  559. // just calling CallWindowProc won't do it for us.
  560. if (GetKeyState(VK_SHIFT) < 0)
  561. {
  562. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
  563. }
  564. else
  565. {
  566. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
  567. }
  568. }
  569. break;
  570. case WM_GETDLGCODE:
  571. return (DLGC_WANTTAB | CallWindowProc (g_WndProcFKPrev,hwnd,uMsg,wParam,lParam));
  572. break;
  573. }
  574. return (CallWindowProc(g_WndProcFKPrev,hwnd,uMsg,wParam,lParam));
  575. }
  576. // **************************************************************************
  577. // SubclassWndProcFKNext
  578. //
  579. // This is the WndProc used to ignore repeated presses of the tab key for
  580. // the first focusable control that follows the test box.
  581. //
  582. // **************************************************************************
  583. LRESULT CALLBACK SubclassWndProcFKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  584. {
  585. switch (uMsg)
  586. {
  587. case WM_KEYDOWN:
  588. if ((int)wParam == VK_TAB)
  589. {
  590. if (WASDOWN(lParam))
  591. {
  592. return (0);
  593. }
  594. // if not a repeat, need to move the focus. For some reason,
  595. // just calling CallWindowProc won't do it for us.
  596. if (GetKeyState(VK_SHIFT) < 0)
  597. {
  598. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
  599. }
  600. else
  601. {
  602. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
  603. }
  604. }
  605. break;
  606. case WM_GETDLGCODE:
  607. return (DLGC_WANTTAB | CallWindowProc (g_WndProcFKNext,hwnd,uMsg,wParam,lParam));
  608. break;
  609. }
  610. return (CallWindowProc(g_WndProcFKNext,hwnd,uMsg,wParam,lParam));
  611. }
  612. // **************************************************************************
  613. // SubclassRepeatKeysTestBox
  614. //
  615. // Same as SubclassFilterKeysTestBox, but keeps it's info in different
  616. // globals so that one doesn't overwrite the other.
  617. //
  618. // **************************************************************************
  619. BOOL SubclassRepeatKeysTestBox (UINT uIdTestBox,HWND hDlg)
  620. {
  621. HWND hwndPrev,
  622. hwndNext,
  623. hwndTestBox;
  624. hwndTestBox = GetDlgItem (hDlg,uIdTestBox);
  625. // BE CAREFUL IF DIALOG CHANGES! Right now the
  626. // Previous Previous window is the "S&ettings" push button,
  627. // and the Next Next is the "&Beep when keys pressed..."
  628. // checkbox. If the order changes, this code might have to change too.
  629. // Could make it more general where it searches for controls before
  630. // and after that can get keyboard focus.
  631. hwndPrev = GetNextDlgTabItem (hDlg,hwndTestBox,TRUE);
  632. g_WndProcRKPrev = (WNDPROC) GetWindowLongPtr (hwndPrev,GWLP_WNDPROC);
  633. SetWindowLongPtr (hwndPrev,GWLP_WNDPROC,(LPARAM)SubclassWndProcRKPrev);
  634. hwndNext = GetNextDlgTabItem (hDlg,hwndTestBox,FALSE);
  635. g_WndProcRKNext = (WNDPROC) GetWindowLongPtr (hwndNext,GWLP_WNDPROC);
  636. SetWindowLongPtr (hwndNext,GWLP_WNDPROC,(LPARAM)SubclassWndProcRKNext);
  637. return (TRUE);
  638. }
  639. // **************************************************************************
  640. // SubclassWndProcRKPrev
  641. //
  642. // **************************************************************************
  643. LRESULT CALLBACK SubclassWndProcRKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  644. {
  645. switch (uMsg)
  646. {
  647. case WM_KEYDOWN:
  648. if ((int)wParam == VK_TAB)
  649. {
  650. if (WASDOWN (lParam))
  651. {
  652. return (0);
  653. }
  654. // if not a repeat, need to move the focus. For some reason,
  655. // just calling CallWindowProc won't do it for us.
  656. if (GetKeyState(VK_SHIFT) < 0)
  657. {
  658. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
  659. }
  660. else
  661. {
  662. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
  663. }
  664. }
  665. break;
  666. case WM_GETDLGCODE:
  667. return (DLGC_WANTTAB | CallWindowProc (g_WndProcRKPrev,hwnd,uMsg,wParam,lParam));
  668. break;
  669. }
  670. return (CallWindowProc(g_WndProcRKPrev,hwnd,uMsg,wParam,lParam));
  671. }
  672. // **************************************************************************
  673. // SubclassWndProcRKNext
  674. //
  675. // **************************************************************************
  676. LRESULT CALLBACK SubclassWndProcRKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  677. {
  678. switch (uMsg)
  679. {
  680. case WM_KEYDOWN:
  681. if ((int)wParam == VK_TAB)
  682. {
  683. if (WASDOWN(lParam))
  684. {
  685. return (0);
  686. }
  687. // if not a repeat, need to move the focus. For some reason,
  688. // just calling CallWindowProc won't do it for us.
  689. if (GetKeyState(VK_SHIFT) < 0)
  690. {
  691. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
  692. }
  693. else
  694. {
  695. SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
  696. }
  697. }
  698. break;
  699. case WM_GETDLGCODE:
  700. return (DLGC_WANTTAB | CallWindowProc (g_WndProcRKNext,hwnd,uMsg,wParam,lParam));
  701. break;
  702. }
  703. return (CallWindowProc(g_WndProcRKNext,hwnd,uMsg,wParam,lParam));
  704. }
  705. ///////////////////////////////// End of File /////////////////////////////////