8e623661c083e13a4faa1e10464181f97fda3dc1
[reactos.git] / base / applications / osk / main.c
1 /*
2 * PROJECT: ReactOS On-Screen Keyboard
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/osk/main.c
5 * PURPOSE: On-screen keyboard.
6 * PROGRAMMERS: Denis ROBERT
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "osk.h"
12 #include "settings.h"
13
14 /* GLOBALS ********************************************************************/
15
16 OSK_GLOBALS Globals;
17
18 /* Functions */
19 int OSK_SetImage(int IdDlgItem, int IdResource);
20 int OSK_DlgInitDialog(HWND hDlg);
21 int OSK_DlgClose(void);
22 int OSK_DlgTimer(void);
23 BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl);
24 BOOL OSK_ReleaseKey(WORD ScanCode);
25
26 INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
27 int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
28
29 /* FUNCTIONS ******************************************************************/
30
31 /***********************************************************************
32 *
33 * OSK_SetImage
34 *
35 * Set an image on a button
36 */
37 int OSK_SetImage(int IdDlgItem, int IdResource)
38 {
39 HICON hIcon;
40 HWND hWndItem;
41
42 hIcon = (HICON)LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IdResource),
43 IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
44 if (hIcon == NULL)
45 return FALSE;
46
47 hWndItem = GetDlgItem(Globals.hMainWnd, IdDlgItem);
48 if (hWndItem == NULL)
49 {
50 DestroyIcon(hIcon);
51 return FALSE;
52 }
53
54 SendMessageW(hWndItem, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon);
55
56 /* The system automatically deletes these resources when the process that created them terminates (MSDN) */
57
58 return TRUE;
59 }
60
61 /***********************************************************************
62 *
63 * OSK_WarningProc
64 *
65 * Function handler for the warning dialog box on startup
66 */
67 INT_PTR CALLBACK OSK_WarningProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
68 {
69 UNREFERENCED_PARAMETER(lParam);
70
71 switch (Msg)
72 {
73 case WM_INITDIALOG:
74 {
75 return TRUE;
76 }
77
78 case WM_COMMAND:
79 {
80 switch (LOWORD(wParam))
81 {
82 case IDC_SHOWWARNINGCHECK:
83 {
84 Globals.bShowWarning = !IsDlgButtonChecked(hDlg, IDC_SHOWWARNINGCHECK);
85 return TRUE;
86 }
87
88 case IDOK:
89 case IDCANCEL:
90 {
91 EndDialog(hDlg, LOWORD(wParam));
92 return TRUE;
93 }
94 }
95 break;
96 }
97 }
98
99 return FALSE;
100 }
101
102
103 /***********************************************************************
104 *
105 * OSK_DlgInitDialog
106 *
107 * Handling of WM_INITDIALOG
108 */
109 int OSK_DlgInitDialog(HWND hDlg)
110 {
111 HICON hIcon, hIconSm;
112 HMONITOR monitor;
113 MONITORINFO info;
114 POINT Pt;
115 RECT rcWindow;
116
117 /* Save handle */
118 Globals.hMainWnd = hDlg;
119
120 /* Load the settings from the registry hive */
121 LoadDataFromRegistry();
122
123 /* Set the application's icon */
124 hIcon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_OSK), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
125 hIconSm = CopyImage(hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_COPYFROMRESOURCE);
126 if (hIcon || hIconSm)
127 {
128 /* Set the window icons (they are deleted when the process terminates) */
129 SendMessageW(Globals.hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
130 SendMessageW(Globals.hMainWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
131 }
132
133 /* Get screen info */
134 memset(&Pt, 0, sizeof(Pt));
135 monitor = MonitorFromPoint(Pt, MONITOR_DEFAULTTOPRIMARY);
136 info.cbSize = sizeof(info);
137 GetMonitorInfoW(monitor, &info);
138
139 /* Move the dialog on the bottom of main screen */
140 GetWindowRect(hDlg, &rcWindow);
141 MoveWindow(hDlg,
142 (info.rcMonitor.left + info.rcMonitor.right) / 2 - // Center of screen
143 (rcWindow.right - rcWindow.left) / 2, // - half size of dialog
144 info.rcMonitor.bottom - // Bottom of screen
145 (rcWindow.bottom - rcWindow.top), // - size of window
146 rcWindow.right - rcWindow.left, // Width
147 rcWindow.bottom - rcWindow.top, // Height
148 TRUE);
149
150 /* Set icon on visual buttons */
151 OSK_SetImage(SCAN_CODE_15, IDI_BACK);
152 OSK_SetImage(SCAN_CODE_16, IDI_TAB);
153 OSK_SetImage(SCAN_CODE_30, IDI_CAPS_LOCK);
154 OSK_SetImage(SCAN_CODE_43, IDI_RETURN);
155 OSK_SetImage(SCAN_CODE_44, IDI_SHIFT);
156 OSK_SetImage(SCAN_CODE_57, IDI_SHIFT);
157 OSK_SetImage(SCAN_CODE_127, IDI_REACTOS);
158 OSK_SetImage(SCAN_CODE_128, IDI_REACTOS);
159 OSK_SetImage(SCAN_CODE_129, IDI_MENU);
160 OSK_SetImage(SCAN_CODE_80, IDI_HOME);
161 OSK_SetImage(SCAN_CODE_85, IDI_PG_UP);
162 OSK_SetImage(SCAN_CODE_86, IDI_PG_DOWN);
163 OSK_SetImage(SCAN_CODE_79, IDI_LEFT);
164 OSK_SetImage(SCAN_CODE_83, IDI_TOP);
165 OSK_SetImage(SCAN_CODE_84, IDI_BOTTOM);
166 OSK_SetImage(SCAN_CODE_89, IDI_RIGHT);
167
168 /* Create a green brush for leds */
169 Globals.hBrushGreenLed = CreateSolidBrush(RGB(0, 255, 0));
170
171 /* Set a timer for periodics tasks */
172 Globals.iTimer = SetTimer(hDlg, 0, 200, NULL);
173
174 /* If the member of the struct (bShowWarning) is set then display the dialog box */
175 if (Globals.bShowWarning)
176 {
177 DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(IDD_WARNINGDIALOG_OSK), Globals.hMainWnd, OSK_WarningProc);
178 }
179
180 return TRUE;
181 }
182
183 /***********************************************************************
184 *
185 * OSK_DlgClose
186 *
187 * Handling of WM_CLOSE
188 */
189 int OSK_DlgClose(void)
190 {
191 KillTimer(Globals.hMainWnd, Globals.iTimer);
192
193 /* Release Ctrl, Shift, Alt keys */
194 OSK_ReleaseKey(SCAN_CODE_44); // Left shift
195 OSK_ReleaseKey(SCAN_CODE_57); // Right shift
196 OSK_ReleaseKey(SCAN_CODE_58); // Left ctrl
197 OSK_ReleaseKey(SCAN_CODE_60); // Left alt
198 OSK_ReleaseKey(SCAN_CODE_62); // Right alt
199 OSK_ReleaseKey(SCAN_CODE_64); // Right ctrl
200
201 /* delete GDI objects */
202 if (Globals.hBrushGreenLed) DeleteObject(Globals.hBrushGreenLed);
203
204 /* Save the settings to the registry hive */
205 SaveDataToRegistry();
206
207 return TRUE;
208 }
209
210 /***********************************************************************
211 *
212 * OSK_DlgTimer
213 *
214 * Handling of WM_TIMER
215 */
216 int OSK_DlgTimer(void)
217 {
218 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
219 HWND hWndActiveWindow;
220
221 hWndActiveWindow = GetForegroundWindow();
222 if (hWndActiveWindow != NULL && hWndActiveWindow != Globals.hMainWnd)
223 {
224 Globals.hActiveWnd = hWndActiveWindow;
225 }
226
227 /* Always redraw leds because it can be changed by the real keyboard) */
228 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_NUM), NULL, TRUE);
229 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_CAPS), NULL, TRUE);
230 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_SCROLL), NULL, TRUE);
231
232 return TRUE;
233 }
234
235 /***********************************************************************
236 *
237 * OSK_DlgCommand
238 *
239 * All handling of dialog command
240 */
241 BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl)
242 {
243 WORD ScanCode;
244 INPUT Input;
245 BOOL bExtendedKey;
246 BOOL bKeyDown;
247 BOOL bKeyUp;
248 LONG WindowStyle;
249
250 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
251 if (Globals.hActiveWnd)
252 {
253 MSG msg;
254
255 SetForegroundWindow(Globals.hActiveWnd);
256 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
257 {
258 TranslateMessage(&msg);
259 DispatchMessageW(&msg);
260 }
261 }
262
263 /* KeyDown and/or KeyUp ? */
264 WindowStyle = GetWindowLongW(hWndControl, GWL_STYLE);
265 if ((WindowStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
266 {
267 /* 2-states key like Shift, Alt, Ctrl, ... */
268 if (SendMessageW(hWndControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
269 {
270 bKeyDown = TRUE;
271 bKeyUp = FALSE;
272 }
273 else
274 {
275 bKeyDown = FALSE;
276 bKeyUp = TRUE;
277 }
278 }
279 else
280 {
281 /* Other key */
282 bKeyDown = TRUE;
283 bKeyUp = TRUE;
284 }
285
286 /* Extended key ? */
287 ScanCode = wCommand;
288 if (ScanCode & 0x0200)
289 bExtendedKey = TRUE;
290 else
291 bExtendedKey = FALSE;
292 ScanCode &= 0xFF;
293
294 /* Press and release the key */
295 if (bKeyDown)
296 {
297 Input.type = INPUT_KEYBOARD;
298 Input.ki.wVk = 0;
299 Input.ki.wScan = ScanCode;
300 Input.ki.time = GetTickCount();
301 Input.ki.dwExtraInfo = GetMessageExtraInfo();
302 Input.ki.dwFlags = KEYEVENTF_SCANCODE;
303 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
304 SendInput(1, &Input, sizeof(Input));
305 }
306
307 if (bKeyUp)
308 {
309 Input.type = INPUT_KEYBOARD;
310 Input.ki.wVk = 0;
311 Input.ki.wScan = ScanCode;
312 Input.ki.time = GetTickCount();
313 Input.ki.dwExtraInfo = GetMessageExtraInfo();
314 Input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
315 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
316 SendInput(1, &Input, sizeof(Input));
317 }
318
319 return TRUE;
320 }
321
322 /***********************************************************************
323 *
324 * OSK_ReleaseKey
325 *
326 * Release the key of ID wCommand
327 */
328 BOOL OSK_ReleaseKey(WORD ScanCode)
329 {
330 INPUT Input;
331 BOOL bExtendedKey;
332 LONG WindowStyle;
333 HWND hWndControl;
334
335 /* Is it a 2-states key ? */
336 hWndControl = GetDlgItem(Globals.hMainWnd, ScanCode);
337 WindowStyle = GetWindowLongW(hWndControl, GWL_STYLE);
338 if ((WindowStyle & BS_AUTOCHECKBOX) != BS_AUTOCHECKBOX) return FALSE;
339
340 /* Is the key down ? */
341 if (SendMessageW(hWndControl, BM_GETCHECK, 0, 0) != BST_CHECKED) return TRUE;
342
343 /* Extended key ? */
344 if (ScanCode & 0x0200)
345 bExtendedKey = TRUE;
346 else
347 bExtendedKey = FALSE;
348 ScanCode &= 0xFF;
349
350 /* Release the key */
351 Input.type = INPUT_KEYBOARD;
352 Input.ki.wVk = 0;
353 Input.ki.wScan = ScanCode;
354 Input.ki.time = GetTickCount();
355 Input.ki.dwExtraInfo = GetMessageExtraInfo();
356 Input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
357 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
358 SendInput(1, &Input, sizeof(Input));
359
360 return TRUE;
361 }
362
363 /***********************************************************************
364 *
365 * OSK_DlgProc
366 */
367 INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
368 {
369 switch (msg)
370 {
371 case WM_INITDIALOG:
372 OSK_DlgInitDialog(hDlg);
373 return TRUE;
374
375 case WM_TIMER:
376 OSK_DlgTimer();
377 return TRUE;
378
379 case WM_CTLCOLORSTATIC:
380 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_NUM))
381 {
382 if (GetKeyState(VK_NUMLOCK) & 0x0001)
383 return (INT_PTR)Globals.hBrushGreenLed;
384 else
385 return (INT_PTR)GetStockObject(BLACK_BRUSH);
386 }
387 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_CAPS))
388 {
389 if (GetKeyState(VK_CAPITAL) & 0x0001)
390 return (INT_PTR)Globals.hBrushGreenLed;
391 else
392 return (INT_PTR)GetStockObject(BLACK_BRUSH);
393 }
394 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_SCROLL))
395 {
396 if (GetKeyState(VK_SCROLL) & 0x0001)
397 return (INT_PTR)Globals.hBrushGreenLed;
398 else
399 return (INT_PTR)GetStockObject(BLACK_BRUSH);
400 }
401 break;
402
403 case WM_COMMAND:
404 if (wParam == IDCANCEL)
405 EndDialog(hDlg, FALSE);
406 else if (wParam != IDC_STATIC)
407 OSK_DlgCommand(wParam, (HWND) lParam);
408 break;
409
410 case WM_CLOSE:
411 OSK_DlgClose();
412 break;
413 }
414
415 return 0;
416 }
417
418 /***********************************************************************
419 *
420 * WinMain
421 */
422 int WINAPI wWinMain(HINSTANCE hInstance,
423 HINSTANCE prev,
424 LPWSTR cmdline,
425 int show)
426 {
427 HANDLE hMutex;
428
429 UNREFERENCED_PARAMETER(prev);
430 UNREFERENCED_PARAMETER(cmdline);
431 UNREFERENCED_PARAMETER(show);
432
433 ZeroMemory(&Globals, sizeof(Globals));
434 Globals.hInstance = hInstance;
435
436 /* Rry to open a mutex for a single instance */
437 hMutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, L"osk");
438
439 if (!hMutex)
440 {
441 /* Mutex doesn\92t exist. This is the first instance so create the mutex. */
442 hMutex = CreateMutexW(NULL, FALSE, L"osk");
443
444 DialogBoxW(hInstance,
445 MAKEINTRESOURCEW(MAIN_DIALOG),
446 GetDesktopWindow(),
447 OSK_DlgProc);
448
449 /* Delete the mutex */
450 if (hMutex) CloseHandle(hMutex);
451 }
452 else
453 {
454 /* Programme already launched */
455
456 /* Delete the mutex */
457 CloseHandle(hMutex);
458
459 ExitProcess(0);
460 }
461
462 return 0;
463 }
464
465 /* EOF */