xref: /reactos/dll/cpl/access/keyboard.c (revision 40462c92)
1 /*
2  * PROJECT:         ReactOS Accessibility Control Panel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/cpl/access/keyboard.c
5  * PURPOSE:         Keyboard-related accessibility settings
6  * COPYRIGHT:       Copyright 2004 Johannes Anderwald (johannes.anderwald@reactos.org)
7  *                  Copyright 2007 Eric Kohl
8  */
9 
10 #include "access.h"
11 
12 #define BOUNCETICKS 5
13 static UINT nBounceArray[BOUNCETICKS] = {500, 700, 1000, 1500, 2000};
14 
15 #define DELAYTICKS 5
16 static UINT nDelayArray[DELAYTICKS] = {300, 700, 1000, 1500, 2000};
17 
18 #define REPEATTICKS 6
19 static UINT nRepeatArray[REPEATTICKS] = {300, 500, 700, 1000, 1500, 2000};
20 
21 #define WAITTICKS 10
22 static UINT nWaitArray[WAITTICKS] = {0, 300, 500, 700, 1000, 1500, 2000, 5000, 10000, 20000};
23 
24 
25 static VOID
26 EnableFilterKeysTest(PGLOBAL_DATA pGlobalData)
27 {
28     pGlobalData->filterKeys.dwFlags |= FKF_FILTERKEYSON;
29     pGlobalData->filterKeys.dwFlags &= ~FKF_INDICATOR;
30 
31     SystemParametersInfo(SPI_SETFILTERKEYS,
32                          sizeof(FILTERKEYS),
33                          &pGlobalData->filterKeys,
34                          0);
35 }
36 
37 
38 static VOID
39 DisableFilterKeysTest(PGLOBAL_DATA pGlobalData)
40 {
41     if (pGlobalData->oldFilterKeys.dwFlags & FKF_FILTERKEYSON)
42     {
43         pGlobalData->filterKeys.dwFlags |= FKF_FILTERKEYSON;
44     }
45     else
46     {
47         pGlobalData->filterKeys.dwFlags &= ~FKF_FILTERKEYSON;
48     }
49 
50     if (pGlobalData->oldFilterKeys.dwFlags & FKF_INDICATOR)
51     {
52         pGlobalData->filterKeys.dwFlags |= FKF_INDICATOR;
53     }
54     else
55     {
56         pGlobalData->filterKeys.dwFlags &= ~FKF_INDICATOR;
57     }
58 
59     SystemParametersInfo(SPI_SETFILTERKEYS,
60                          sizeof(FILTERKEYS),
61                          &pGlobalData->filterKeys,
62                          0);
63 }
64 
65 
66 /* Property page dialog callback */
67 INT_PTR CALLBACK
68 StickyKeysDlgProc(HWND hwndDlg,
69                   UINT uMsg,
70                   WPARAM wParam,
71                   LPARAM lParam)
72 {
73     PGLOBAL_DATA pGlobalData;
74 
75     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
76 
77     switch (uMsg)
78     {
79         case WM_INITDIALOG:
80             pGlobalData = (PGLOBAL_DATA)lParam;
81             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
82 
83             memcpy(&pGlobalData->oldStickyKeys,
84                    &pGlobalData->stickyKeys,
85                    sizeof(STICKYKEYS));
86 
87             CheckDlgButton(hwndDlg,
88                            IDC_STICKY_ACTIVATE_CHECK,
89                            pGlobalData->stickyKeys.dwFlags & SKF_HOTKEYACTIVE ? BST_CHECKED : BST_UNCHECKED);
90 
91             CheckDlgButton(hwndDlg,
92                            IDC_STICKY_LOCK_CHECK,
93                            pGlobalData->stickyKeys.dwFlags & SKF_TRISTATE ? BST_CHECKED : BST_UNCHECKED);
94 
95             CheckDlgButton(hwndDlg,
96                            IDC_STICKY_UNLOCK_CHECK,
97                            pGlobalData->stickyKeys.dwFlags & SKF_TWOKEYSOFF ? BST_CHECKED : BST_UNCHECKED);
98 
99             CheckDlgButton(hwndDlg,
100                            IDC_STICKY_SOUND_CHECK,
101                            pGlobalData->stickyKeys.dwFlags & SKF_AUDIBLEFEEDBACK ? BST_CHECKED : BST_UNCHECKED);
102 
103             CheckDlgButton(hwndDlg,
104                            IDC_STICKY_STATUS_CHECK,
105                            pGlobalData->stickyKeys.dwFlags & SKF_INDICATOR ? BST_CHECKED : BST_UNCHECKED);
106             break;
107 
108         case WM_COMMAND:
109             switch (LOWORD(wParam))
110             {
111                 case IDC_STICKY_ACTIVATE_CHECK:
112                     pGlobalData->stickyKeys.dwFlags ^= SKF_HOTKEYACTIVE;
113                     break;
114 
115                 case IDC_STICKY_LOCK_CHECK:
116                     pGlobalData->stickyKeys.dwFlags ^= SKF_TRISTATE;
117                     break;
118 
119                 case IDC_STICKY_UNLOCK_CHECK:
120                     pGlobalData->stickyKeys.dwFlags ^= SKF_TWOKEYSOFF;
121                     break;
122 
123                 case IDC_STICKY_SOUND_CHECK:
124                     pGlobalData->stickyKeys.dwFlags ^= SKF_AUDIBLEFEEDBACK;
125                     break;
126 
127                 case IDC_STICKY_STATUS_CHECK:
128                     pGlobalData->stickyKeys.dwFlags ^= SKF_INDICATOR;
129                     break;
130 
131                 case IDOK:
132                     EndDialog(hwndDlg,
133                               (pGlobalData->stickyKeys.dwFlags != pGlobalData->oldStickyKeys.dwFlags));
134                     break;
135 
136                 case IDCANCEL:
137                     EndDialog(hwndDlg, FALSE);
138                     break;
139 
140                 default:
141                     break;
142             }
143             break;
144     }
145 
146     return FALSE;
147 }
148 
149 
150 static VOID
151 AddComboBoxTime(HWND hwnd, INT nId, INT nTimeMs)
152 {
153     TCHAR szBuffer[32];
154     TCHAR szSeconds[20];
155 
156     if (LoadString(hApplet, IDS_SECONDS, szSeconds, 20) == 0)
157         lstrcpy(szSeconds, L"Seconds");
158 
159     _stprintf(szBuffer, _T("%d.%d %s"),
160               nTimeMs / 1000, (nTimeMs % 1000) / 100,
161               szSeconds);
162 
163     SendDlgItemMessage(hwnd, nId, CB_ADDSTRING, 0, (LPARAM)szBuffer);
164 }
165 
166 
167 INT_PTR CALLBACK
168 BounceKeysDlgProc(HWND hwndDlg,
169                   UINT uMsg,
170                   WPARAM wParam,
171                   LPARAM lParam)
172 {
173     PGLOBAL_DATA pGlobalData;
174     INT i, n;
175 
176     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
177 
178     switch (uMsg)
179     {
180         case WM_INITDIALOG:
181             pGlobalData = (PGLOBAL_DATA)lParam;
182             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
183 
184             /* Determine the current bounce time */
185             if (pGlobalData->filterKeys.iBounceMSec == 0)
186                 pGlobalData->filterKeys.iBounceMSec = nBounceArray[0];
187 
188             for (n = 0; n < BOUNCETICKS; n++)
189             {
190                  if (pGlobalData->filterKeys.iBounceMSec < nBounceArray[n])
191                      break;
192             }
193             n--;
194 
195             for (i = 0; i < BOUNCETICKS; i++)
196             {
197                  AddComboBoxTime(hwndDlg, IDC_BOUNCE_TIME_COMBO, nBounceArray[i]);
198             }
199 
200             SendDlgItemMessage(hwndDlg, IDC_BOUNCE_TIME_COMBO, CB_SETCURSEL, n, 0);
201             break;
202 
203         case WM_COMMAND:
204             switch (LOWORD(wParam))
205             {
206                 case IDC_BOUNCE_TIME_COMBO:
207                     if (HIWORD(wParam) == CBN_SELCHANGE)
208                     {
209                         i = SendDlgItemMessage(hwndDlg, IDC_BOUNCE_TIME_COMBO, CB_GETCURSEL, 0, 0);
210                         if (i != CB_ERR)
211                         {
212                             pGlobalData->filterKeys.iBounceMSec = nBounceArray[i];
213                         }
214                     }
215                     break;
216 
217                 case IDC_BOUNCE_TEST_EDIT:
218                     switch (HIWORD(wParam))
219                     {
220                         case EN_SETFOCUS:
221                             EnableFilterKeysTest(pGlobalData);
222                             break;
223 
224                         case EN_KILLFOCUS:
225                             DisableFilterKeysTest(pGlobalData);
226                             break;
227                     }
228                     break;
229 
230                 case IDOK:
231                     EndDialog(hwndDlg, TRUE);
232                     break;
233 
234                 case IDCANCEL:
235                     EndDialog(hwndDlg, FALSE);
236                     break;
237 
238                 default:
239                     break;
240             }
241             break;
242     }
243 
244     return FALSE;
245 }
246 
247 
248 INT_PTR CALLBACK
249 RepeatKeysDlgProc(HWND hwndDlg,
250                   UINT uMsg,
251                   WPARAM wParam,
252                   LPARAM lParam)
253 {
254     PGLOBAL_DATA pGlobalData;
255     INT i, n;
256 
257     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
258 
259     switch (uMsg)
260     {
261         case WM_INITDIALOG:
262             pGlobalData = (PGLOBAL_DATA)lParam;
263             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
264 
265             CheckRadioButton(hwndDlg,
266                              IDC_REPEAT_NOREPEAT_RADIO,
267                              IDC_REPEAT_REPEAT_RADIO,
268                              (pGlobalData->filterKeys.iDelayMSec == 0) ? IDC_REPEAT_NOREPEAT_RADIO : IDC_REPEAT_REPEAT_RADIO);
269 
270             /* Initialize the delay combobox */
271             for (n = 0; n < DELAYTICKS; n++)
272             {
273                  if (pGlobalData->filterKeys.iDelayMSec < nDelayArray[n])
274                      break;
275             }
276             n--;
277 
278             for (i = 0; i < DELAYTICKS; i++)
279             {
280                  AddComboBoxTime(hwndDlg, IDC_REPEAT_DELAY_COMBO, nDelayArray[i]);
281             }
282 
283             SendDlgItemMessage(hwndDlg, IDC_REPEAT_DELAY_COMBO, CB_SETCURSEL, n, 0);
284 
285             /* Initialize the repeat combobox */
286             for (n = 0; n < REPEATTICKS; n++)
287             {
288                  if (pGlobalData->filterKeys.iRepeatMSec < nRepeatArray[n])
289                      break;
290             }
291             n--;
292 
293             for (i = 0; i < REPEATTICKS; i++)
294             {
295                  AddComboBoxTime(hwndDlg, IDC_REPEAT_REPEAT_COMBO, nRepeatArray[i]);
296             }
297 
298             SendDlgItemMessage(hwndDlg, IDC_REPEAT_REPEAT_COMBO, CB_SETCURSEL, n, 0);
299 
300             /* Disable the delay and repeat comboboxes if needed */
301             if (pGlobalData->filterKeys.iDelayMSec == 0)
302             {
303                 EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_DELAY_COMBO), FALSE);
304                 EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_REPEAT_COMBO), FALSE);
305             }
306 
307             /* Initialize the wait combobox */
308             for (n = 0; n < WAITTICKS; n++)
309             {
310                  if (pGlobalData->filterKeys.iWaitMSec < nWaitArray[n])
311                      break;
312             }
313             n--;
314 
315             for (i = 0; i < WAITTICKS; i++)
316             {
317                  AddComboBoxTime(hwndDlg, IDC_REPEAT_WAIT_COMBO, nWaitArray[i]);
318             }
319 
320             SendDlgItemMessage(hwndDlg, IDC_REPEAT_WAIT_COMBO, CB_SETCURSEL, n, 0);
321             break;
322 
323         case WM_COMMAND:
324             switch (LOWORD(wParam))
325             {
326                 case IDC_REPEAT_NOREPEAT_RADIO:
327                     pGlobalData->filterKeys.iDelayMSec = 0;
328                     pGlobalData->filterKeys.iRepeatMSec = 0;
329                     EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_DELAY_COMBO), FALSE);
330                     EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_REPEAT_COMBO), FALSE);
331                     break;
332 
333                 case IDC_REPEAT_REPEAT_RADIO:
334                     EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_DELAY_COMBO), TRUE);
335                     EnableWindow(GetDlgItem(hwndDlg, IDC_REPEAT_REPEAT_COMBO), TRUE);
336                     break;
337 
338                 case IDC_REPEAT_DELAY_COMBO:
339                     if (HIWORD(wParam) == CBN_SELCHANGE)
340                     {
341                         i = SendDlgItemMessage(hwndDlg, IDC_REPEAT_DELAY_COMBO, CB_GETCURSEL, 0, 0);
342                         if (i != CB_ERR)
343                         {
344                             pGlobalData->filterKeys.iDelayMSec = nDelayArray[i];
345                         }
346                     }
347                     break;
348 
349                 case IDC_REPEAT_REPEAT_COMBO:
350                     if (HIWORD(wParam) == CBN_SELCHANGE)
351                     {
352                         i = SendDlgItemMessage(hwndDlg, IDC_REPEAT_REPEAT_COMBO, CB_GETCURSEL, 0, 0);
353                         if (i != CB_ERR)
354                         {
355                             pGlobalData->filterKeys.iRepeatMSec = nRepeatArray[i];
356                         }
357                     }
358                     break;
359 
360                 case IDC_REPEAT_WAIT_COMBO:
361                     if (HIWORD(wParam) == CBN_SELCHANGE)
362                     {
363                         i = SendDlgItemMessage(hwndDlg, IDC_REPEAT_WAIT_COMBO, CB_GETCURSEL, 0, 0);
364                         if (i != CB_ERR)
365                         {
366                             pGlobalData->filterKeys.iWaitMSec = nWaitArray[i];
367                         }
368                     }
369                     break;
370 
371                 case IDC_REPEAT_TEST_EDIT:
372                     switch (HIWORD(wParam))
373                     {
374                         case EN_SETFOCUS:
375                             EnableFilterKeysTest(pGlobalData);
376                             break;
377 
378                         case EN_KILLFOCUS:
379                             DisableFilterKeysTest(pGlobalData);
380                             break;
381                     }
382                     break;
383 
384                 case IDOK:
385                     EndDialog(hwndDlg, TRUE);
386                     break;
387 
388                 case IDCANCEL:
389                     EndDialog(hwndDlg, FALSE);
390                     break;
391 
392                 default:
393                     break;
394             }
395             break;
396     }
397 
398     return FALSE;
399 }
400 
401 
402 /* Property page dialog callback */
403 INT_PTR CALLBACK
404 FilterKeysDlgProc(HWND hwndDlg,
405                   UINT uMsg,
406                   WPARAM wParam,
407                   LPARAM lParam)
408 {
409     PGLOBAL_DATA pGlobalData;
410 
411     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
412 
413     switch (uMsg)
414     {
415         case WM_INITDIALOG:
416             pGlobalData = (PGLOBAL_DATA)lParam;
417             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
418 
419             memcpy(&pGlobalData->oldFilterKeys,
420                    &pGlobalData->filterKeys,
421                    sizeof(FILTERKEYS));
422 
423             CheckDlgButton(hwndDlg,
424                            IDC_FILTER_ACTIVATE_CHECK,
425                            pGlobalData->filterKeys.dwFlags & FKF_HOTKEYACTIVE ? BST_CHECKED : BST_UNCHECKED);
426 
427             if (pGlobalData->filterKeys.iBounceMSec != 0)
428             {
429                 CheckRadioButton(hwndDlg, IDC_FILTER_BOUNCE_RADIO, IDC_FILTER_REPEAT_RADIO, IDC_FILTER_BOUNCE_RADIO);
430                 EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_BOUNCE_BUTTON), TRUE);
431                 EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_REPEAT_BUTTON), FALSE);
432             }
433             else
434             {
435                 CheckRadioButton(hwndDlg, IDC_FILTER_BOUNCE_RADIO, IDC_FILTER_REPEAT_RADIO, IDC_FILTER_REPEAT_RADIO);
436                 EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_BOUNCE_BUTTON), FALSE);
437                 EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_REPEAT_BUTTON), TRUE);
438             }
439 
440             CheckDlgButton(hwndDlg,
441                            IDC_FILTER_SOUND_CHECK,
442                            pGlobalData->filterKeys.dwFlags & FKF_CLICKON ? BST_CHECKED : BST_UNCHECKED);
443 
444             CheckDlgButton(hwndDlg,
445                            IDC_FILTER_STATUS_CHECK,
446                            pGlobalData->filterKeys.dwFlags & FKF_INDICATOR ? BST_CHECKED : BST_UNCHECKED);
447             break;
448 
449         case WM_COMMAND:
450             switch (LOWORD(wParam))
451             {
452                 case IDC_FILTER_ACTIVATE_CHECK:
453                     pGlobalData->filterKeys.dwFlags ^= FKF_HOTKEYACTIVE;
454                     break;
455 
456                 case IDC_FILTER_BOUNCE_RADIO:
457                     EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_BOUNCE_BUTTON), TRUE);
458                     EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_REPEAT_BUTTON), FALSE);
459                     break;
460 
461                 case IDC_FILTER_REPEAT_RADIO:
462                     EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_BOUNCE_BUTTON), FALSE);
463                     EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER_REPEAT_BUTTON), TRUE);
464                     break;
465 
466                 case IDC_FILTER_BOUNCE_BUTTON:
467                     DialogBoxParam(hApplet,
468                                    MAKEINTRESOURCE(IDD_BOUNCEKEYSOPTIONS),
469                                    hwndDlg,
470                                    BounceKeysDlgProc,
471                                    (LPARAM)pGlobalData);
472                     break;
473 
474                 case IDC_FILTER_TEST_EDIT:
475                     switch (HIWORD(wParam))
476                     {
477                         case EN_SETFOCUS:
478                             EnableFilterKeysTest(pGlobalData);
479                             break;
480 
481                         case EN_KILLFOCUS:
482                             DisableFilterKeysTest(pGlobalData);
483                             break;
484                     }
485                     break;
486 
487                 case IDC_FILTER_SOUND_CHECK:
488                     pGlobalData->filterKeys.dwFlags ^= FKF_CLICKON;
489                     break;
490 
491                 case IDC_FILTER_REPEAT_BUTTON:
492                     DialogBoxParam(hApplet,
493                                    MAKEINTRESOURCE(IDD_REPEATKEYSOPTIONS),
494                                    hwndDlg,
495                                    RepeatKeysDlgProc,
496                                    (LPARAM)pGlobalData);
497                     break;
498 
499                 case IDC_FILTER_STATUS_CHECK:
500                     pGlobalData->filterKeys.dwFlags ^= FKF_INDICATOR;
501                     break;
502 
503                 case IDOK:
504                     EndDialog(hwndDlg,
505                               (pGlobalData->filterKeys.dwFlags != pGlobalData->oldFilterKeys.dwFlags));
506                     break;
507 
508                 case IDCANCEL:
509                     EndDialog(hwndDlg, FALSE);
510                     break;
511 
512                 default:
513                     break;
514             }
515             break;
516     }
517 
518     return FALSE;
519 }
520 
521 
522 /* Property page dialog callback */
523 INT_PTR CALLBACK
524 ToggleKeysDlgProc(HWND hwndDlg,
525                   UINT uMsg,
526                   WPARAM wParam,
527                   LPARAM lParam)
528 {
529     PGLOBAL_DATA pGlobalData;
530 
531     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
532 
533     switch (uMsg)
534     {
535         case WM_INITDIALOG:
536             pGlobalData = (PGLOBAL_DATA)lParam;
537             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
538 
539             memcpy(&pGlobalData->oldToggleKeys,
540                    &pGlobalData->toggleKeys,
541                    sizeof(TOGGLEKEYS));
542 
543             CheckDlgButton(hwndDlg,
544                            IDC_TOGGLE_ACTIVATE_CHECK,
545                            pGlobalData->toggleKeys.dwFlags & TKF_HOTKEYACTIVE ? BST_CHECKED : BST_UNCHECKED);
546             break;
547 
548         case WM_COMMAND:
549             switch (LOWORD(wParam))
550             {
551                 case IDC_TOGGLE_ACTIVATE_CHECK:
552                     pGlobalData->toggleKeys.dwFlags ^= TKF_HOTKEYACTIVE;
553                     break;
554 
555                 case IDOK:
556                     EndDialog(hwndDlg,
557                               (pGlobalData->toggleKeys.dwFlags != pGlobalData->oldToggleKeys.dwFlags));
558                     break;
559 
560                 case IDCANCEL:
561                     EndDialog(hwndDlg, FALSE);
562                     break;
563 
564                 default:
565                     break;
566             }
567             break;
568     }
569 
570     return FALSE;
571 }
572 
573 
574 /* Property page dialog callback */
575 INT_PTR CALLBACK
576 KeyboardPageProc(HWND hwndDlg,
577                  UINT uMsg,
578                  WPARAM wParam,
579                  LPARAM lParam)
580 {
581     PGLOBAL_DATA pGlobalData;
582     LPPSHNOTIFY lppsn;
583 
584     pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
585 
586     switch (uMsg)
587     {
588         case WM_INITDIALOG:
589             pGlobalData = (PGLOBAL_DATA)((LPPROPSHEETPAGE)lParam)->lParam;
590             if (pGlobalData == NULL)
591                 return FALSE;
592 
593             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
594 
595             CheckDlgButton(hwndDlg,
596                            IDC_STICKY_BOX,
597                            pGlobalData->stickyKeys.dwFlags & SKF_STICKYKEYSON ? BST_CHECKED : BST_UNCHECKED);
598 
599             CheckDlgButton(hwndDlg,
600                            IDC_FILTER_BOX,
601                            pGlobalData->filterKeys.dwFlags & FKF_FILTERKEYSON ? BST_CHECKED : BST_UNCHECKED);
602 
603             CheckDlgButton(hwndDlg,
604                            IDC_TOGGLE_BOX,
605                            pGlobalData->toggleKeys.dwFlags & TKF_TOGGLEKEYSON ? BST_CHECKED : BST_UNCHECKED);
606 
607             CheckDlgButton(hwndDlg,
608                            IDC_KEYBOARD_EXTRA,
609                            pGlobalData->bKeyboardPref ? BST_CHECKED : BST_UNCHECKED);
610             return TRUE;
611 
612         case WM_COMMAND:
613             switch (LOWORD(wParam))
614             {
615                 case IDC_STICKY_BOX:
616                     pGlobalData->stickyKeys.dwFlags ^= SKF_STICKYKEYSON;
617                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
618                     break;
619 
620                 case IDC_STICKY_BUTTON:
621                     if (DialogBoxParam(hApplet,
622                                        MAKEINTRESOURCE(IDD_STICKYKEYSOPTIONS),
623                                        hwndDlg,
624                                        StickyKeysDlgProc,
625                                        (LPARAM)pGlobalData))
626                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
627                     break;
628 
629                 case IDC_FILTER_BOX:
630                     pGlobalData->filterKeys.dwFlags ^= FKF_FILTERKEYSON;
631                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
632                     break;
633 
634                 case IDC_FILTER_BUTTON:
635                     if (DialogBoxParam(hApplet,
636                                        MAKEINTRESOURCE(IDD_FILTERKEYSOPTIONS),
637                                        hwndDlg,
638                                        FilterKeysDlgProc,
639                                        (LPARAM)pGlobalData))
640                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
641                     break;
642 
643                 case IDC_TOGGLE_BOX:
644                     pGlobalData->toggleKeys.dwFlags ^= TKF_TOGGLEKEYSON;
645                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
646                     break;
647 
648                 case IDC_TOGGLE_BUTTON:
649                     if (DialogBoxParam(hApplet,
650                                        MAKEINTRESOURCE(IDD_TOGGLEKEYSOPTIONS),
651                                        hwndDlg,
652                                        ToggleKeysDlgProc,
653                                        (LPARAM)pGlobalData))
654                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
655                     break;
656 
657                 case IDC_KEYBOARD_EXTRA:
658                     pGlobalData->bKeyboardPref = !pGlobalData->bKeyboardPref;
659                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
660                     break;
661 
662                 default:
663                     break;
664             }
665             break;
666 
667         case WM_NOTIFY:
668             lppsn = (LPPSHNOTIFY)lParam;
669             if (lppsn->hdr.code == PSN_APPLY)
670             {
671                 SystemParametersInfo(SPI_SETSTICKYKEYS,
672                                      sizeof(STICKYKEYS),
673                                      &pGlobalData->stickyKeys,
674                                      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE /*0*/);
675 
676                 SystemParametersInfo(SPI_SETFILTERKEYS,
677                                      sizeof(FILTERKEYS),
678                                      &pGlobalData->filterKeys,
679                                      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE /*0*/);
680 
681                 SystemParametersInfo(SPI_SETTOGGLEKEYS,
682                                      sizeof(TOGGLEKEYS),
683                                      &pGlobalData->toggleKeys,
684                                      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE /*0*/);
685 
686                 SystemParametersInfo(SPI_SETKEYBOARDPREF,
687                                      pGlobalData->bKeyboardPref,
688                                      NULL,
689                                      SPIF_UPDATEINIFILE | SPIF_SENDCHANGE /*0*/);
690 
691                 return TRUE;
692             }
693             break;
694     }
695 
696     return FALSE;
697 }
698