xref: /reactos/dll/cpl/main/keyboard.c (revision be014129)
1 /*
2  *  ReactOS
3  *  Copyright (C) 2004, 2007 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * PROJECT:         ReactOS Main Control Panel
21  * FILE:            dll/cpl/main/keyboard.c
22  * PURPOSE:         Keyboard Control Panel
23  * PROGRAMMER:      Eric Kohl
24  */
25 
26 #include "main.h"
27 
28 #define ID_BLINK_TIMER 345
29 
30 typedef struct _SPEED_DATA
31 {
32     INT nKeyboardDelay;
33     INT nOrigKeyboardDelay;
34     DWORD dwKeyboardSpeed;
35     DWORD dwOrigKeyboardSpeed;
36     UINT uCaretBlinkTime;
37     UINT uOrigCaretBlinkTime;
38     BOOL fShowCursor;
39     RECT rcCursor;
40 } SPEED_DATA, *PSPEED_DATA;
41 
42 /* Property page dialog callback */
43 static INT_PTR CALLBACK
44 KeyboardSpeedProc(IN HWND hwndDlg,
45                   IN UINT uMsg,
46                   IN WPARAM wParam,
47                   IN LPARAM lParam)
48 {
49     PSPEED_DATA pSpeedData;
50 
51     pSpeedData = (PSPEED_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
52 
53     switch (uMsg)
54     {
55         case WM_INITDIALOG:
56             pSpeedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SPEED_DATA));
57             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSpeedData);
58 
59             /* Get current keyboard delay */
60             if (!SystemParametersInfo(SPI_GETKEYBOARDDELAY,
61                                       sizeof(INT),
62                                       &pSpeedData->nKeyboardDelay,
63                                       0))
64             {
65                 pSpeedData->nKeyboardDelay = 2;
66             }
67 
68             pSpeedData->nOrigKeyboardDelay = pSpeedData->nKeyboardDelay;
69 
70             /* Get current keyboard delay */
71             if (!SystemParametersInfo(SPI_GETKEYBOARDSPEED,
72                                       sizeof(DWORD),
73                                       &pSpeedData->dwKeyboardSpeed,
74                                       0))
75             {
76                 pSpeedData->dwKeyboardSpeed = 31;
77             }
78 
79             pSpeedData->dwOrigKeyboardSpeed = pSpeedData->dwKeyboardSpeed;
80 
81             pSpeedData->fShowCursor = TRUE;
82             GetWindowRect(GetDlgItem(hwndDlg, IDC_TEXT_CURSOR_BLINK), &pSpeedData->rcCursor);
83             ScreenToClient(hwndDlg, (LPPOINT)&pSpeedData->rcCursor.left);
84             ScreenToClient(hwndDlg, (LPPOINT)&pSpeedData->rcCursor.right);
85 
86             /* Get the caret blink time and save its original value */
87             pSpeedData->uOrigCaretBlinkTime = GetCaretBlinkTime();
88             pSpeedData->uCaretBlinkTime = pSpeedData->uOrigCaretBlinkTime;
89 
90             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 3));
91             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(3 - pSpeedData->nKeyboardDelay));
92 
93             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 31));
94             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pSpeedData->dwKeyboardSpeed);
95 
96             SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 10));
97             SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(12 - (pSpeedData->uCaretBlinkTime / 100)));
98 
99             /* Start the blink timer */
100             SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
101             break;
102 
103         case WM_HSCROLL:
104             if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_REPEAT_DELAY))
105             {
106                 switch (LOWORD(wParam))
107                 {
108                         case TB_LINEUP:
109                         case TB_LINEDOWN:
110                         case TB_PAGEUP:
111                         case TB_PAGEDOWN:
112                         case TB_TOP:
113                         case TB_BOTTOM:
114                         case TB_ENDTRACK:
115                             pSpeedData->nKeyboardDelay = 3 - (INT)SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_GETPOS, 0, 0);
116                             SystemParametersInfo(SPI_SETKEYBOARDDELAY,
117                                                  pSpeedData->nKeyboardDelay,
118                                                  0,
119                                                  0);
120                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
121                             break;
122 
123                         case TB_THUMBTRACK:
124                             pSpeedData->nKeyboardDelay = 3 - (INT)HIWORD(wParam);
125                             SystemParametersInfo(SPI_SETKEYBOARDDELAY,
126                                                  pSpeedData->nKeyboardDelay,
127                                                  0,
128                                                  0);
129                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
130                             break;
131                 }
132             }
133             else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_REPEAT_RATE))
134             {
135                 switch (LOWORD(wParam))
136                 {
137                         case TB_LINEUP:
138                         case TB_LINEDOWN:
139                         case TB_PAGEUP:
140                         case TB_PAGEDOWN:
141                         case TB_TOP:
142                         case TB_BOTTOM:
143                         case TB_ENDTRACK:
144                             pSpeedData->dwKeyboardSpeed = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_GETPOS, 0, 0);
145                             SystemParametersInfo(SPI_SETKEYBOARDSPEED,
146                                                  pSpeedData->dwKeyboardSpeed,
147                                                  0,
148                                                  0);
149                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
150                             break;
151 
152                         case TB_THUMBTRACK:
153                             pSpeedData->dwKeyboardSpeed = (DWORD)HIWORD(wParam);
154                             SystemParametersInfo(SPI_SETKEYBOARDSPEED,
155                                                  pSpeedData->dwKeyboardSpeed,
156                                                  0,
157                                                  0);
158                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
159                             break;
160                 }
161             }
162             else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_CURSOR_BLINK))
163             {
164                 switch (LOWORD(wParam))
165                 {
166                         case TB_LINEUP:
167                         case TB_LINEDOWN:
168                         case TB_PAGEUP:
169                         case TB_PAGEDOWN:
170                         case TB_TOP:
171                         case TB_BOTTOM:
172                         case TB_ENDTRACK:
173                             pSpeedData->uCaretBlinkTime = (12 - (UINT)SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_GETPOS, 0, 0)) * 100;
174                             KillTimer(hwndDlg, ID_BLINK_TIMER);
175                             SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
176                             SetCaretBlinkTime(pSpeedData->uCaretBlinkTime);
177                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
178                             break;
179 
180                         case TB_THUMBTRACK:
181                             pSpeedData->uCaretBlinkTime = (12 - (UINT)HIWORD(wParam)) * 100;
182                             KillTimer(hwndDlg, ID_BLINK_TIMER);
183                             SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
184                             SetCaretBlinkTime(pSpeedData->uCaretBlinkTime);
185                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
186                             break;
187                 }
188             }
189             break;
190 
191         case WM_TIMER:
192             if (wParam == ID_BLINK_TIMER)
193             {
194                 if (pSpeedData->fShowCursor)
195                 {
196                     HDC hDC = GetDC(hwndDlg);
197                     HBRUSH hBrush = GetSysColorBrush(COLOR_BTNTEXT);
198                     FillRect(hDC, &pSpeedData->rcCursor, hBrush);
199                     ReleaseDC(hwndDlg, hDC);
200                 }
201                 else
202                 {
203                     InvalidateRect(hwndDlg, &pSpeedData->rcCursor, TRUE);
204                 }
205 
206                 pSpeedData->fShowCursor = !pSpeedData->fShowCursor;
207             }
208             break;
209 
210         case WM_NOTIFY:
211         {
212             LPNMHDR lpnm = (LPNMHDR)lParam;
213 
214             switch(lpnm->code)
215             {
216                 case PSN_APPLY:
217                     /* Set the new keyboard settings */
218                     SystemParametersInfo(SPI_SETKEYBOARDDELAY,
219                                          pSpeedData->nKeyboardDelay,
220                                          0,
221                                          0);
222                     SystemParametersInfo(SPI_SETKEYBOARDSPEED,
223                                          pSpeedData->dwKeyboardSpeed,
224                                          0,
225                                          SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
226                     return TRUE;
227 
228                 case PSN_RESET:
229                     /* Restore the original settings */
230                     SetCaretBlinkTime(pSpeedData->uOrigCaretBlinkTime);
231                     SystemParametersInfo(SPI_SETKEYBOARDDELAY,
232                                          pSpeedData->nOrigKeyboardDelay,
233                                          0,
234                                          0);
235                     SystemParametersInfo(SPI_SETKEYBOARDSPEED,
236                                          pSpeedData->dwOrigKeyboardSpeed,
237                                          0,
238                                          0);
239                     break;
240 
241                 default:
242                     break;
243             }
244         }
245         break;
246 
247         case WM_DESTROY:
248             KillTimer(hwndDlg, ID_BLINK_TIMER);
249             HeapFree(GetProcessHeap(), 0, pSpeedData);
250             break;
251     }
252 
253     return FALSE;
254 }
255 
256 
257 /* Property page dialog callback */
258 static INT_PTR CALLBACK
259 KeybHardwareProc(IN HWND hwndDlg,
260                  IN UINT uMsg,
261                  IN WPARAM wParam,
262                  IN LPARAM lParam)
263 {
264     GUID Guids[1];
265     Guids[0] = GUID_DEVCLASS_KEYBOARD;
266 
267     UNREFERENCED_PARAMETER(lParam);
268     UNREFERENCED_PARAMETER(wParam);
269 
270     switch(uMsg)
271     {
272         case WM_INITDIALOG:
273             /* Create the hardware page */
274             DeviceCreateHardwarePageEx(hwndDlg,
275                                        Guids,
276                                        sizeof(Guids) / sizeof(Guids[0]),
277                                        HWPD_STANDARDLIST);
278             break;
279     }
280 
281     return FALSE;
282 }
283 
284 static int CALLBACK
285 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
286 {
287     // NOTE: This callback is needed to set large icon correctly.
288     HICON hIcon;
289     switch (uMsg)
290     {
291         case PSCB_INITIALIZED:
292         {
293             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON_2));
294             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
295             break;
296         }
297     }
298     return 0;
299 }
300 
301 LONG APIENTRY
302 KeyboardApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam)
303 {
304     HPROPSHEETPAGE hpsp[MAX_CPL_PAGES];
305     PROPSHEETHEADER psh;
306     HPSXA hpsxa;
307     INT nPage = 0;
308     LONG ret;
309 
310     UNREFERENCED_PARAMETER(lParam);
311     UNREFERENCED_PARAMETER(wParam);
312     UNREFERENCED_PARAMETER(uMsg);
313     UNREFERENCED_PARAMETER(hwnd);
314 
315     if (uMsg == CPL_STARTWPARMSW && lParam != 0)
316         nPage = _wtoi((PWSTR)lParam);
317 
318     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
319     psh.dwSize = sizeof(PROPSHEETHEADER);
320     psh.dwFlags =  PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
321     psh.hwndParent = hwnd;
322     psh.hInstance = hApplet;
323     psh.pszIcon = MAKEINTRESOURCE(IDC_CPLICON_2);
324     psh.pszCaption = MAKEINTRESOURCE(IDS_CPLNAME_2);
325     psh.nStartPage = 0;
326     psh.phpage = hpsp;
327     psh.pfnCallback = PropSheetProc;
328 
329     /* Load additional pages provided by shell extensions */
330     hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Keyboard"), MAX_CPL_PAGES - psh.nPages);
331 
332     /* NOTE: The speed page (CPLPAGE_KEYBOARD_SPEED) cannot be replaced by
333              shell extensions since Win2k! */
334     InitPropSheetPage(&psh, IDD_KEYBSPEED, KeyboardSpeedProc);
335     InitPropSheetPage(&psh, IDD_HARDWARE, KeybHardwareProc);
336 
337     if (hpsxa != NULL)
338         SHAddFromPropSheetExtArray(hpsxa, PropSheetAddPage, (LPARAM)&psh);
339 
340     if (nPage != 0 && nPage <= psh.nPages)
341         psh.nStartPage = nPage;
342 
343     ret = (LONG)(PropertySheet(&psh) != -1);
344 
345     if (hpsxa != NULL)
346         SHDestroyPropSheetExtArray(hpsxa);
347 
348     return ret;
349 }
350 
351 /* EOF */
352