Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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
13 /* GLOBALS ********************************************************************/
14
15 OSK_GLOBALS Globals;
16
17 /* Functions */
18 int OSK_SetImage(int IdDlgItem, int IdResource);
19 int OSK_DlgInitDialog(HWND hDlg);
20 int OSK_DlgClose(void);
21 int OSK_DlgTimer(void);
22 BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl);
23 BOOL OSK_ReleaseKey(WORD ScanCode);
24
25 INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
26 int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int);
27
28 /* FUNCTIONS ******************************************************************/
29
30 /***********************************************************************
31 *
32 * OSK_SetImage
33 *
34 * Set an image on a button
35 */
36 int OSK_SetImage(int IdDlgItem, int IdResource)
37 {
38 HICON hIcon;
39 HWND hWndItem;
40
41 hIcon = (HICON)LoadImage(Globals.hInstance, MAKEINTRESOURCE(IdResource),
42 IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
43 if (hIcon == NULL)
44 return FALSE;
45
46 hWndItem = GetDlgItem(Globals.hMainWnd, IdDlgItem);
47 if (hWndItem == NULL)
48 {
49 DestroyIcon(hIcon);
50 return FALSE;
51 }
52
53 SendMessage(hWndItem, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon);
54
55 /* The system automatically deletes these resources when the process that created them terminates (MSDN) */
56
57 return TRUE;
58 }
59
60
61 /***********************************************************************
62 *
63 * OSK_DlgInitDialog
64 *
65 * Handling of WM_INITDIALOG
66 */
67 int OSK_DlgInitDialog(HWND hDlg)
68 {
69 HMONITOR monitor;
70 MONITORINFO info;
71 POINT Pt;
72 RECT rcWindow;
73
74 /* Save handle */
75 Globals.hMainWnd = hDlg;
76
77 /* Get screen info */
78 memset(&Pt, 0, sizeof(Pt));
79 monitor = MonitorFromPoint(Pt, MONITOR_DEFAULTTOPRIMARY );
80 info.cbSize = sizeof(info);
81 GetMonitorInfoW(monitor, &info);
82
83 /* Move the dialog on the bottom of main screen */
84 GetWindowRect(hDlg, &rcWindow);
85 MoveWindow(hDlg,
86 (info.rcMonitor.left + info.rcMonitor.right) / 2 - // Center of screen
87 (rcWindow.right - rcWindow.left) / 2, // - half size of dialog
88 info.rcMonitor.bottom - // Bottom of screen
89 (rcWindow.bottom - rcWindow.top), // - size of window
90 rcWindow.right - rcWindow.left, // Width
91 rcWindow.bottom - rcWindow.top, // Height
92 TRUE);
93
94 /* Set icon on visual buttons */
95 OSK_SetImage(SCAN_CODE_15, IDI_BACK);
96 OSK_SetImage(SCAN_CODE_16, IDI_TAB);
97 OSK_SetImage(SCAN_CODE_30, IDI_CAPS_LOCK);
98 OSK_SetImage(SCAN_CODE_43, IDI_RETURN);
99 OSK_SetImage(SCAN_CODE_44, IDI_SHIFT);
100 OSK_SetImage(SCAN_CODE_57, IDI_SHIFT);
101 OSK_SetImage(SCAN_CODE_127, IDI_REACTOS);
102 OSK_SetImage(SCAN_CODE_128, IDI_REACTOS);
103 OSK_SetImage(SCAN_CODE_129, IDI_MENU);
104 OSK_SetImage(SCAN_CODE_80, IDI_HOME);
105 OSK_SetImage(SCAN_CODE_85, IDI_PG_UP);
106 OSK_SetImage(SCAN_CODE_86, IDI_PG_DOWN);
107 OSK_SetImage(SCAN_CODE_79, IDI_LEFT);
108 OSK_SetImage(SCAN_CODE_83, IDI_TOP);
109 OSK_SetImage(SCAN_CODE_84, IDI_BOTTOM);
110 OSK_SetImage(SCAN_CODE_89, IDI_RIGHT);
111
112 /* Create a green brush for leds */
113 Globals.hBrushGreenLed = CreateSolidBrush(RGB(0, 255, 0));
114
115 /* Set a timer for periodics tasks */
116 Globals.iTimer = SetTimer(hDlg, 0, 200, NULL);
117
118 return TRUE;
119 }
120
121 /***********************************************************************
122 *
123 * OSK_DlgClose
124 *
125 * Handling of WM_CLOSE
126 */
127 int OSK_DlgClose(void)
128 {
129 KillTimer(Globals.hMainWnd, Globals.iTimer);
130
131 /* Release Ctrl, Shift, Alt keys */
132 OSK_ReleaseKey(SCAN_CODE_44); // Left shift
133 OSK_ReleaseKey(SCAN_CODE_57); // Right shift
134 OSK_ReleaseKey(SCAN_CODE_58); // Left ctrl
135 OSK_ReleaseKey(SCAN_CODE_60); // Left alt
136 OSK_ReleaseKey(SCAN_CODE_62); // Right alt
137 OSK_ReleaseKey(SCAN_CODE_64); // Right ctrl
138
139 /* delete GDI objects */
140 if (Globals.hBrushGreenLed) DeleteObject(Globals.hBrushGreenLed);
141
142 return TRUE;
143 }
144
145 /***********************************************************************
146 *
147 * OSK_DlgTimer
148 *
149 * Handling of WM_TIMER
150 */
151 int OSK_DlgTimer(void)
152 {
153 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
154 HWND hWndActiveWindow;
155
156 hWndActiveWindow = GetForegroundWindow();
157 if (hWndActiveWindow != NULL && hWndActiveWindow != Globals.hMainWnd)
158 {
159 Globals.hActiveWnd = hWndActiveWindow;
160 }
161
162 /* Always redraw leds because it can be changed by the real keyboard) */
163 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_NUM), NULL, TRUE);
164 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_CAPS), NULL, TRUE);
165 InvalidateRect(GetDlgItem(Globals.hMainWnd, IDC_LED_SCROLL), NULL, TRUE);
166
167 return TRUE;
168 }
169
170 /***********************************************************************
171 *
172 * OSK_DlgCommand
173 *
174 * All handling of dialog command
175 */
176 BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl)
177 {
178 WORD ScanCode;
179 INPUT Input;
180 BOOL bExtendedKey;
181 BOOL bKeyDown;
182 BOOL bKeyUp;
183 LONG WindowStyle;
184
185 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
186 if (Globals.hActiveWnd)
187 {
188 MSG msg;
189
190 SetForegroundWindow(Globals.hActiveWnd);
191 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
192 {
193 TranslateMessage(&msg);
194 DispatchMessage(&msg);
195 }
196 }
197
198 /* KeyDown and/or KeyUp ? */
199 WindowStyle = GetWindowLong(hWndControl, GWL_STYLE);
200 if ((WindowStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
201 {
202 /* 2-states key like Shift, Alt, Ctrl, ... */
203 if (SendMessage(hWndControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
204 {
205 bKeyDown = TRUE;
206 bKeyUp = FALSE;
207 }
208 else
209 {
210 bKeyDown = FALSE;
211 bKeyUp = TRUE;
212 }
213 }
214 else
215 {
216 /* Other key */
217 bKeyDown = TRUE;
218 bKeyUp = TRUE;
219 }
220
221 /* Extended key ? */
222 ScanCode = wCommand;
223 if (ScanCode & 0x0200)
224 bExtendedKey = TRUE;
225 else
226 bExtendedKey = FALSE;
227 ScanCode &= 0xFF;
228
229 /* Press and release the key */
230 if (bKeyDown)
231 {
232 Input.type = INPUT_KEYBOARD;
233 Input.ki.wVk = 0;
234 Input.ki.wScan = ScanCode;
235 Input.ki.time = GetTickCount();
236 Input.ki.dwExtraInfo = GetMessageExtraInfo();
237 Input.ki.dwFlags = KEYEVENTF_SCANCODE;
238 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
239 SendInput(1, &Input, sizeof(Input));
240 }
241
242 if (bKeyUp)
243 {
244 Input.type = INPUT_KEYBOARD;
245 Input.ki.wVk = 0;
246 Input.ki.wScan = ScanCode;
247 Input.ki.time = GetTickCount();
248 Input.ki.dwExtraInfo = GetMessageExtraInfo();
249 Input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
250 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
251 SendInput(1, &Input, sizeof(Input));
252 }
253
254 return TRUE;
255 }
256
257 /***********************************************************************
258 *
259 * OSK_ReleaseKey
260 *
261 * Release the key of ID wCommand
262 */
263 BOOL OSK_ReleaseKey(WORD ScanCode)
264 {
265 INPUT Input;
266 BOOL bExtendedKey;
267 LONG WindowStyle;
268 HWND hWndControl;
269
270 /* Is it a 2-states key ? */
271 hWndControl = GetDlgItem(Globals.hMainWnd, ScanCode);
272 WindowStyle = GetWindowLong(hWndControl, GWL_STYLE);
273 if ((WindowStyle & BS_AUTOCHECKBOX) != BS_AUTOCHECKBOX) return FALSE;
274
275 /* Is the key down ? */
276 if (SendMessage(hWndControl, BM_GETCHECK, 0, 0) != BST_CHECKED) return TRUE;
277
278 /* Extended key ? */
279 if (ScanCode & 0x0200)
280 bExtendedKey = TRUE;
281 else
282 bExtendedKey = FALSE;
283 ScanCode &= 0xFF;
284
285 /* Release the key */
286 Input.type = INPUT_KEYBOARD;
287 Input.ki.wVk = 0;
288 Input.ki.wScan = ScanCode;
289 Input.ki.time = GetTickCount();
290 Input.ki.dwExtraInfo = GetMessageExtraInfo();
291 Input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
292 if (bExtendedKey) Input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
293 SendInput(1, &Input, sizeof(Input));
294
295 return TRUE;
296 }
297
298 /***********************************************************************
299 *
300 * OSK_DlgProc
301 */
302 INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
303 {
304 switch (msg)
305 {
306 case WM_INITDIALOG:
307 OSK_DlgInitDialog(hDlg);
308 return TRUE;
309
310 case WM_TIMER:
311 OSK_DlgTimer();
312 return TRUE;
313
314 case WM_CTLCOLORSTATIC:
315 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_NUM))
316 {
317 if (GetKeyState(VK_NUMLOCK) & 0x0001)
318 return (INT_PTR)Globals.hBrushGreenLed;
319 else
320 return (INT_PTR)GetStockObject(BLACK_BRUSH);
321 }
322 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_CAPS))
323 {
324 if (GetKeyState(VK_CAPITAL) & 0x0001)
325 return (INT_PTR)Globals.hBrushGreenLed;
326 else
327 return (INT_PTR)GetStockObject(BLACK_BRUSH);
328 }
329 if ((HWND)lParam == GetDlgItem(hDlg, IDC_LED_SCROLL))
330 {
331 if (GetKeyState(VK_SCROLL) & 0x0001)
332 return (INT_PTR)Globals.hBrushGreenLed;
333 else
334 return (INT_PTR)GetStockObject(BLACK_BRUSH);
335 }
336 break;
337
338 case WM_COMMAND:
339 if (wParam == IDCANCEL)
340 EndDialog(hDlg, FALSE);
341 else if (wParam != IDC_STATIC)
342 OSK_DlgCommand(wParam, (HWND) lParam);
343 break;
344
345 case WM_CLOSE:
346 OSK_DlgClose();
347 break;
348 }
349
350 return 0;
351 }
352
353 /***********************************************************************
354 *
355 * WinMain
356 */
357 int WINAPI _tWinMain(HINSTANCE hInstance,
358 HINSTANCE prev,
359 LPTSTR cmdline,
360 int show)
361 {
362 HANDLE hMutex;
363
364 UNREFERENCED_PARAMETER(prev);
365 UNREFERENCED_PARAMETER(cmdline);
366 UNREFERENCED_PARAMETER(show);
367
368 ZeroMemory(&Globals, sizeof(Globals));
369 Globals.hInstance = hInstance;
370
371 /* Rry to open a mutex for a single instance */
372 hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, "osk");
373
374 if (!hMutex)
375 {
376 /* Mutex doesn\92t exist. This is the first instance so create the mutex. */
377 hMutex = CreateMutexA(NULL, FALSE, "osk");
378
379 DialogBox(hInstance,
380 MAKEINTRESOURCE(MAIN_DIALOG),
381 GetDesktopWindow(),
382 OSK_DlgProc);
383
384 /* Delete the mutex */
385 if (hMutex) CloseHandle(hMutex);
386 }
387 else
388 {
389 /* Programme already launched */
390
391 /* Delete the mutex */
392 CloseHandle(hMutex);
393
394 ExitProcess(0);
395 }
396
397 return 0;
398 }
399
400 /* EOF */