xref: /reactos/dll/cpl/main/keyboard.c (revision ccef43f3)
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 static VOID
43 UpdateCaretBlinkTimeReg(
44     _In_ UINT uCaretBlinkTime)
45 {
46     HKEY hKey;
47     WCHAR szBuffer[12];
48 
49     if (RegOpenKeyExW(HKEY_CURRENT_USER,
50                       L"Control Panel\\Desktop",
51                       0, KEY_SET_VALUE,
52                       &hKey) != ERROR_SUCCESS)
53     {
54          return;
55     }
56 
57     wsprintf(szBuffer, L"%d", uCaretBlinkTime);
58 
59     RegSetValueExW(hKey, L"CursorBlinkRate",
60                    0, REG_SZ,
61                    (CONST BYTE*)szBuffer,
62                    (wcslen(szBuffer) + 1) * sizeof(WCHAR));
63 
64     RegCloseKey(hKey);
65 }
66 
67 /* Property page dialog callback */
68 static INT_PTR CALLBACK
69 KeyboardSpeedProc(IN HWND hwndDlg,
70                   IN UINT uMsg,
71                   IN WPARAM wParam,
72                   IN LPARAM lParam)
73 {
74     PSPEED_DATA pSpeedData;
75 
76     pSpeedData = (PSPEED_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
77 
78     switch (uMsg)
79     {
80         case WM_INITDIALOG:
81             pSpeedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SPEED_DATA));
82             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pSpeedData);
83 
84             /* Get current keyboard delay */
85             if (!SystemParametersInfo(SPI_GETKEYBOARDDELAY,
86                                       sizeof(INT),
87                                       &pSpeedData->nKeyboardDelay,
88                                       0))
89             {
90                 pSpeedData->nKeyboardDelay = 2;
91             }
92 
93             pSpeedData->nOrigKeyboardDelay = pSpeedData->nKeyboardDelay;
94 
95             /* Get current keyboard delay */
96             if (!SystemParametersInfo(SPI_GETKEYBOARDSPEED,
97                                       sizeof(DWORD),
98                                       &pSpeedData->dwKeyboardSpeed,
99                                       0))
100             {
101                 pSpeedData->dwKeyboardSpeed = 31;
102             }
103 
104             pSpeedData->dwOrigKeyboardSpeed = pSpeedData->dwKeyboardSpeed;
105 
106             pSpeedData->fShowCursor = TRUE;
107             GetWindowRect(GetDlgItem(hwndDlg, IDC_TEXT_CURSOR_BLINK), &pSpeedData->rcCursor);
108             ScreenToClient(hwndDlg, (LPPOINT)&pSpeedData->rcCursor.left);
109             ScreenToClient(hwndDlg, (LPPOINT)&pSpeedData->rcCursor.right);
110 
111             /* Get the caret blink time and save its original value */
112             pSpeedData->uOrigCaretBlinkTime = GetCaretBlinkTime();
113             pSpeedData->uCaretBlinkTime = pSpeedData->uOrigCaretBlinkTime;
114 
115             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 3));
116             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(3 - pSpeedData->nKeyboardDelay));
117 
118             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 31));
119             SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pSpeedData->dwKeyboardSpeed);
120 
121             SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 10));
122             SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(12 - (pSpeedData->uCaretBlinkTime / 100)));
123 
124             /* Start the blink timer */
125             pSpeedData->uCaretBlinkTime = pSpeedData->uCaretBlinkTime >= 1200 ? -1 : pSpeedData->uCaretBlinkTime;
126             if ((INT)pSpeedData->uCaretBlinkTime > 0)
127             {
128                 SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
129             }
130             else
131             {
132                 PostMessage(hwndDlg, WM_TIMER, ID_BLINK_TIMER, 0);
133             }
134 
135             break;
136 
137         case WM_HSCROLL:
138             if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_REPEAT_DELAY))
139             {
140                 switch (LOWORD(wParam))
141                 {
142                         case TB_LINEUP:
143                         case TB_LINEDOWN:
144                         case TB_PAGEUP:
145                         case TB_PAGEDOWN:
146                         case TB_TOP:
147                         case TB_BOTTOM:
148                         case TB_ENDTRACK:
149                             pSpeedData->nKeyboardDelay = 3 - (INT)SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_DELAY, TBM_GETPOS, 0, 0);
150                             SystemParametersInfo(SPI_SETKEYBOARDDELAY,
151                                                  pSpeedData->nKeyboardDelay,
152                                                  0,
153                                                  0);
154                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
155                             break;
156 
157                         case TB_THUMBTRACK:
158                             pSpeedData->nKeyboardDelay = 3 - (INT)HIWORD(wParam);
159                             SystemParametersInfo(SPI_SETKEYBOARDDELAY,
160                                                  pSpeedData->nKeyboardDelay,
161                                                  0,
162                                                  0);
163                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
164                             break;
165                 }
166             }
167             else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_REPEAT_RATE))
168             {
169                 switch (LOWORD(wParam))
170                 {
171                         case TB_LINEUP:
172                         case TB_LINEDOWN:
173                         case TB_PAGEUP:
174                         case TB_PAGEDOWN:
175                         case TB_TOP:
176                         case TB_BOTTOM:
177                         case TB_ENDTRACK:
178                             pSpeedData->dwKeyboardSpeed = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SLIDER_REPEAT_RATE, TBM_GETPOS, 0, 0);
179                             SystemParametersInfo(SPI_SETKEYBOARDSPEED,
180                                                  pSpeedData->dwKeyboardSpeed,
181                                                  0,
182                                                  0);
183                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
184                             break;
185 
186                         case TB_THUMBTRACK:
187                             pSpeedData->dwKeyboardSpeed = (DWORD)HIWORD(wParam);
188                             SystemParametersInfo(SPI_SETKEYBOARDSPEED,
189                                                  pSpeedData->dwKeyboardSpeed,
190                                                  0,
191                                                  0);
192                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
193                             break;
194                 }
195             }
196             else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SLIDER_CURSOR_BLINK))
197             {
198                 switch (LOWORD(wParam))
199                 {
200                         case TB_LINEUP:
201                         case TB_LINEDOWN:
202                         case TB_PAGEUP:
203                         case TB_PAGEDOWN:
204                         case TB_TOP:
205                         case TB_BOTTOM:
206                         case TB_ENDTRACK:
207                             pSpeedData->uCaretBlinkTime = (12 - (UINT)SendDlgItemMessage(hwndDlg, IDC_SLIDER_CURSOR_BLINK, TBM_GETPOS, 0, 0)) * 100;
208                             KillTimer(hwndDlg, ID_BLINK_TIMER);
209                             pSpeedData->uCaretBlinkTime = pSpeedData->uCaretBlinkTime >= 1200 ? -1 : pSpeedData->uCaretBlinkTime;
210                             if ((INT)pSpeedData->uCaretBlinkTime > 0)
211                             {
212                                 SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
213                             }
214                             else if (pSpeedData->fShowCursor)
215                             {
216                                 SendMessage(hwndDlg, WM_TIMER, ID_BLINK_TIMER, 0);
217                             }
218                             SetCaretBlinkTime(pSpeedData->uCaretBlinkTime);
219                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
220                             break;
221 
222                         case TB_THUMBTRACK:
223                             pSpeedData->uCaretBlinkTime = (12 - (UINT)HIWORD(wParam)) * 100;
224                             KillTimer(hwndDlg, ID_BLINK_TIMER);
225                             pSpeedData->uCaretBlinkTime = pSpeedData->uCaretBlinkTime >= 1200 ? -1 : pSpeedData->uCaretBlinkTime;
226                             if ((INT)pSpeedData->uCaretBlinkTime > 0)
227                             {
228                                 SetTimer(hwndDlg, ID_BLINK_TIMER, pSpeedData->uCaretBlinkTime, NULL);
229                             }
230                             else if (pSpeedData->fShowCursor)
231                             {
232                                 SendMessage(hwndDlg, WM_TIMER, ID_BLINK_TIMER, 0);
233                             }
234                             SetCaretBlinkTime(pSpeedData->uCaretBlinkTime);
235                             PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
236                             break;
237                 }
238             }
239             break;
240 
241         case WM_TIMER:
242             if (wParam == ID_BLINK_TIMER)
243             {
244                 if (pSpeedData->fShowCursor)
245                 {
246                     HDC hDC = GetDC(hwndDlg);
247                     HBRUSH hBrush = GetSysColorBrush(COLOR_BTNTEXT);
248                     FillRect(hDC, &pSpeedData->rcCursor, hBrush);
249                     ReleaseDC(hwndDlg, hDC);
250                 }
251                 else
252                 {
253                     InvalidateRect(hwndDlg, &pSpeedData->rcCursor, TRUE);
254                 }
255 
256                 pSpeedData->fShowCursor = !pSpeedData->fShowCursor;
257             }
258             break;
259 
260         case WM_NOTIFY:
261         {
262             LPNMHDR lpnm = (LPNMHDR)lParam;
263 
264             switch(lpnm->code)
265             {
266                 case PSN_APPLY:
267                     /* Set the new keyboard settings */
268                     if (pSpeedData->uOrigCaretBlinkTime != pSpeedData->uCaretBlinkTime)
269                     {
270                         UpdateCaretBlinkTimeReg(pSpeedData->uCaretBlinkTime);
271                     }
272 
273                     SystemParametersInfo(SPI_SETKEYBOARDDELAY,
274                                          pSpeedData->nKeyboardDelay,
275                                          0,
276                                          0);
277                     SystemParametersInfo(SPI_SETKEYBOARDSPEED,
278                                          pSpeedData->dwKeyboardSpeed,
279                                          0,
280                                          SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
281                     return TRUE;
282 
283                 case PSN_RESET:
284                     /* Restore the original settings */
285                     SetCaretBlinkTime(pSpeedData->uOrigCaretBlinkTime);
286                     SystemParametersInfo(SPI_SETKEYBOARDDELAY,
287                                          pSpeedData->nOrigKeyboardDelay,
288                                          0,
289                                          0);
290                     SystemParametersInfo(SPI_SETKEYBOARDSPEED,
291                                          pSpeedData->dwOrigKeyboardSpeed,
292                                          0,
293                                          0);
294                     break;
295 
296                 default:
297                     break;
298             }
299         }
300         break;
301 
302         case WM_DESTROY:
303             KillTimer(hwndDlg, ID_BLINK_TIMER);
304             HeapFree(GetProcessHeap(), 0, pSpeedData);
305             break;
306     }
307 
308     return FALSE;
309 }
310 
311 
312 /* Property page dialog callback */
313 static INT_PTR CALLBACK
314 KeybHardwareProc(IN HWND hwndDlg,
315                  IN UINT uMsg,
316                  IN WPARAM wParam,
317                  IN LPARAM lParam)
318 {
319     GUID Guids[1];
320     Guids[0] = GUID_DEVCLASS_KEYBOARD;
321 
322     UNREFERENCED_PARAMETER(lParam);
323     UNREFERENCED_PARAMETER(wParam);
324 
325     switch(uMsg)
326     {
327         case WM_INITDIALOG:
328             /* Create the hardware page */
329             DeviceCreateHardwarePageEx(hwndDlg,
330                                        Guids,
331                                        sizeof(Guids) / sizeof(Guids[0]),
332                                        HWPD_STANDARDLIST);
333             break;
334     }
335 
336     return FALSE;
337 }
338 
339 static int CALLBACK
340 PropSheetProc(HWND hwndDlg, UINT uMsg, LPARAM lParam)
341 {
342     // NOTE: This callback is needed to set large icon correctly.
343     HICON hIcon;
344     switch (uMsg)
345     {
346         case PSCB_INITIALIZED:
347         {
348             hIcon = LoadIconW(hApplet, MAKEINTRESOURCEW(IDC_CPLICON_2));
349             SendMessageW(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
350             break;
351         }
352     }
353     return 0;
354 }
355 
356 LONG APIENTRY
357 KeyboardApplet(HWND hwnd, UINT uMsg, LPARAM wParam, LPARAM lParam)
358 {
359     HPROPSHEETPAGE hpsp[MAX_CPL_PAGES];
360     PROPSHEETHEADER psh;
361     HPSXA hpsxa;
362     INT nPage = 0;
363     LONG ret;
364 
365     UNREFERENCED_PARAMETER(lParam);
366     UNREFERENCED_PARAMETER(wParam);
367     UNREFERENCED_PARAMETER(uMsg);
368     UNREFERENCED_PARAMETER(hwnd);
369 
370     if (uMsg == CPL_STARTWPARMSW && lParam != 0)
371         nPage = _wtoi((PWSTR)lParam);
372 
373     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
374     psh.dwSize = sizeof(PROPSHEETHEADER);
375     psh.dwFlags =  PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK;
376     psh.hwndParent = hwnd;
377     psh.hInstance = hApplet;
378     psh.pszIcon = MAKEINTRESOURCE(IDC_CPLICON_2);
379     psh.pszCaption = MAKEINTRESOURCE(IDS_CPLNAME_2);
380     psh.nStartPage = 0;
381     psh.phpage = hpsp;
382     psh.pfnCallback = PropSheetProc;
383 
384     /* Load additional pages provided by shell extensions */
385     hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Keyboard"), MAX_CPL_PAGES - psh.nPages);
386 
387     /* NOTE: The speed page (CPLPAGE_KEYBOARD_SPEED) cannot be replaced by
388              shell extensions since Win2k! */
389     InitPropSheetPage(&psh, IDD_KEYBSPEED, KeyboardSpeedProc);
390     InitPropSheetPage(&psh, IDD_HARDWARE, KeybHardwareProc);
391 
392     if (hpsxa != NULL)
393         SHAddFromPropSheetExtArray(hpsxa, PropSheetAddPage, (LPARAM)&psh);
394 
395     if (nPage != 0 && nPage <= psh.nPages)
396         psh.nStartPage = nPage;
397 
398     ret = (LONG)(PropertySheet(&psh) != -1);
399 
400     if (hpsxa != NULL)
401         SHDestroyPropSheetExtArray(hpsxa);
402 
403     return ret;
404 }
405 
406 /* EOF */
407