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