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
UpdateCaretBlinkTimeReg(_In_ UINT uCaretBlinkTime)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
KeyboardSpeedProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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
KeybHardwareProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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
PropSheetProc(HWND hwndDlg,UINT uMsg,LPARAM lParam)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
KeyboardApplet(HWND hwnd,UINT uMsg,LPARAM wParam,LPARAM lParam)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