xref: /reactos/base/applications/osk/main.c (revision 84ccccab)
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�t 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 */
401