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