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
9 /* INCLUDES *******************************************************************/
14 /* GLOBALS ********************************************************************/
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
);
26 INT_PTR APIENTRY
OSK_DlgProc(HWND hDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
27 int WINAPI
wWinMain(HINSTANCE
, HINSTANCE
, LPWSTR
, int);
29 /* FUNCTIONS ******************************************************************/
31 /***********************************************************************
35 * Set an image on a button
37 int OSK_SetImage(int IdDlgItem
, int IdResource
)
42 hIcon
= (HICON
)LoadImageW(Globals
.hInstance
, MAKEINTRESOURCEW(IdResource
),
43 IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
47 hWndItem
= GetDlgItem(Globals
.hMainWnd
, IdDlgItem
);
54 SendMessageW(hWndItem
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hIcon
);
56 /* The system automatically deletes these resources when the process that created them terminates (MSDN) */
61 /***********************************************************************
65 * Function handler for the warning dialog box on startup
67 INT_PTR CALLBACK
OSK_WarningProc(HWND hDlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
69 UNREFERENCED_PARAMETER(lParam
);
80 switch (LOWORD(wParam
))
82 case IDC_SHOWWARNINGCHECK
:
84 Globals
.bShowWarning
= !IsDlgButtonChecked(hDlg
, IDC_SHOWWARNINGCHECK
);
91 EndDialog(hDlg
, LOWORD(wParam
));
102 /***********************************************************************
106 * Initializes the "About" dialog box
110 WCHAR szTitle
[MAX_BUFF
];
111 WCHAR szAuthors
[MAX_BUFF
];
115 OSKIcon
= LoadImageW(Globals
.hInstance
, MAKEINTRESOURCEW(IDI_OSK
), IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
);
117 /* Load the strings into the "About" dialog */
118 LoadStringW(Globals
.hInstance
, STRING_OSK
, szTitle
, countof(szTitle
));
119 LoadStringW(Globals
.hInstance
, STRING_AUTHORS
, szAuthors
, countof(szAuthors
));
121 /* Finally, execute the "About" dialog by using the Shell routine */
122 ShellAboutW(Globals
.hMainWnd
, szTitle
, szAuthors
, OSKIcon
);
124 /* Once done, destroy the icon */
125 DestroyIcon(OSKIcon
);
129 /***********************************************************************
133 * Handling of WM_INITDIALOG
135 int OSK_DlgInitDialog(HWND hDlg
)
137 HICON hIcon
, hIconSm
;
144 Globals
.hMainWnd
= hDlg
;
146 /* Check the checked menu item before displaying the modal box */
147 if (Globals
.bIsEnhancedKeyboard
)
149 /* Enhanced keyboard dialog chosen, set the respective menu item as checked */
150 CheckMenuItem(GetMenu(hDlg
), IDM_ENHANCED_KB
, MF_BYCOMMAND
| MF_CHECKED
);
151 CheckMenuItem(GetMenu(hDlg
), IDM_STANDARD_KB
, MF_BYCOMMAND
| MF_UNCHECKED
);
155 /* Standard keyboard dialog chosen, set the respective menu item as checked */
156 CheckMenuItem(GetMenu(hDlg
), IDM_STANDARD_KB
, MF_BYCOMMAND
| MF_CHECKED
);
157 CheckMenuItem(GetMenu(hDlg
), IDM_ENHANCED_KB
, MF_BYCOMMAND
| MF_UNCHECKED
);
160 /* Check if the "Click Sound" option was chosen before (and if so, then tick the menu item) */
161 if (Globals
.bSoundClick
)
163 CheckMenuItem(GetMenu(hDlg
), IDM_CLICK_SOUND
, MF_BYCOMMAND
| MF_CHECKED
);
166 /* Set the application's icon */
167 hIcon
= LoadImageW(Globals
.hInstance
, MAKEINTRESOURCEW(IDI_OSK
), IMAGE_ICON
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
168 hIconSm
= CopyImage(hIcon
, IMAGE_ICON
, GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), LR_COPYFROMRESOURCE
);
169 if (hIcon
|| hIconSm
)
171 /* Set the window icons (they are deleted when the process terminates) */
172 SendMessageW(Globals
.hMainWnd
, WM_SETICON
, ICON_BIG
, (LPARAM
)hIcon
);
173 SendMessageW(Globals
.hMainWnd
, WM_SETICON
, ICON_SMALL
, (LPARAM
)hIconSm
);
176 /* Get screen info */
177 memset(&Pt
, 0, sizeof(Pt
));
178 monitor
= MonitorFromPoint(Pt
, MONITOR_DEFAULTTOPRIMARY
);
179 info
.cbSize
= sizeof(info
);
180 GetMonitorInfoW(monitor
, &info
);
182 /* Move the dialog on the bottom of main screen */
183 GetWindowRect(hDlg
, &rcWindow
);
185 (info
.rcMonitor
.left
+ info
.rcMonitor
.right
) / 2 - // Center of screen
186 (rcWindow
.right
- rcWindow
.left
) / 2, // - half size of dialog
187 info
.rcMonitor
.bottom
- // Bottom of screen
188 (rcWindow
.bottom
- rcWindow
.top
), // - size of window
189 rcWindow
.right
- rcWindow
.left
, // Width
190 rcWindow
.bottom
- rcWindow
.top
, // Height
193 /* Set icon on visual buttons */
194 OSK_SetImage(SCAN_CODE_15
, IDI_BACK
);
195 OSK_SetImage(SCAN_CODE_16
, IDI_TAB
);
196 OSK_SetImage(SCAN_CODE_30
, IDI_CAPS_LOCK
);
197 OSK_SetImage(SCAN_CODE_43
, IDI_RETURN
);
198 OSK_SetImage(SCAN_CODE_44
, IDI_SHIFT
);
199 OSK_SetImage(SCAN_CODE_57
, IDI_SHIFT
);
200 OSK_SetImage(SCAN_CODE_127
, IDI_REACTOS
);
201 OSK_SetImage(SCAN_CODE_128
, IDI_REACTOS
);
202 OSK_SetImage(SCAN_CODE_129
, IDI_MENU
);
203 OSK_SetImage(SCAN_CODE_80
, IDI_HOME
);
204 OSK_SetImage(SCAN_CODE_85
, IDI_PG_UP
);
205 OSK_SetImage(SCAN_CODE_86
, IDI_PG_DOWN
);
206 OSK_SetImage(SCAN_CODE_79
, IDI_LEFT
);
207 OSK_SetImage(SCAN_CODE_83
, IDI_TOP
);
208 OSK_SetImage(SCAN_CODE_84
, IDI_BOTTOM
);
209 OSK_SetImage(SCAN_CODE_89
, IDI_RIGHT
);
211 /* Create a green brush for leds */
212 Globals
.hBrushGreenLed
= CreateSolidBrush(RGB(0, 255, 0));
214 /* Set a timer for periodics tasks */
215 Globals
.iTimer
= SetTimer(hDlg
, 0, 200, NULL
);
220 /***********************************************************************
224 * Handling of WM_CLOSE
226 int OSK_DlgClose(void)
228 KillTimer(Globals
.hMainWnd
, Globals
.iTimer
);
230 /* Release Ctrl, Shift, Alt keys */
231 OSK_ReleaseKey(SCAN_CODE_44
); // Left shift
232 OSK_ReleaseKey(SCAN_CODE_57
); // Right shift
233 OSK_ReleaseKey(SCAN_CODE_58
); // Left ctrl
234 OSK_ReleaseKey(SCAN_CODE_60
); // Left alt
235 OSK_ReleaseKey(SCAN_CODE_62
); // Right alt
236 OSK_ReleaseKey(SCAN_CODE_64
); // Right ctrl
238 /* delete GDI objects */
239 if (Globals
.hBrushGreenLed
) DeleteObject(Globals
.hBrushGreenLed
);
241 /* Save the settings to the registry hive */
242 SaveDataToRegistry();
247 /***********************************************************************
251 * Handling of WM_TIMER
253 int OSK_DlgTimer(void)
255 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
256 HWND hWndActiveWindow
;
258 hWndActiveWindow
= GetForegroundWindow();
259 if (hWndActiveWindow
!= NULL
&& hWndActiveWindow
!= Globals
.hMainWnd
)
261 Globals
.hActiveWnd
= hWndActiveWindow
;
264 /* Always redraw leds because it can be changed by the real keyboard) */
265 InvalidateRect(GetDlgItem(Globals
.hMainWnd
, IDC_LED_NUM
), NULL
, TRUE
);
266 InvalidateRect(GetDlgItem(Globals
.hMainWnd
, IDC_LED_CAPS
), NULL
, TRUE
);
267 InvalidateRect(GetDlgItem(Globals
.hMainWnd
, IDC_LED_SCROLL
), NULL
, TRUE
);
272 /***********************************************************************
276 * All handling of dialog command
278 BOOL
OSK_DlgCommand(WPARAM wCommand
, HWND hWndControl
)
287 /* FIXME: To be deleted when ReactOS will support WS_EX_NOACTIVATE */
288 if (Globals
.hActiveWnd
)
292 SetForegroundWindow(Globals
.hActiveWnd
);
293 while (PeekMessageW(&msg
, 0, 0, 0, PM_REMOVE
))
295 TranslateMessage(&msg
);
296 DispatchMessageW(&msg
);
300 /* KeyDown and/or KeyUp ? */
301 WindowStyle
= GetWindowLongW(hWndControl
, GWL_STYLE
);
302 if ((WindowStyle
& BS_AUTOCHECKBOX
) == BS_AUTOCHECKBOX
)
304 /* 2-states key like Shift, Alt, Ctrl, ... */
305 if (SendMessageW(hWndControl
, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
325 if (ScanCode
& 0x0200)
328 bExtendedKey
= FALSE
;
331 /* Press and release the key */
334 Input
.type
= INPUT_KEYBOARD
;
336 Input
.ki
.wScan
= ScanCode
;
337 Input
.ki
.time
= GetTickCount();
338 Input
.ki
.dwExtraInfo
= GetMessageExtraInfo();
339 Input
.ki
.dwFlags
= KEYEVENTF_SCANCODE
;
340 if (bExtendedKey
) Input
.ki
.dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
341 SendInput(1, &Input
, sizeof(Input
));
346 Input
.type
= INPUT_KEYBOARD
;
348 Input
.ki
.wScan
= ScanCode
;
349 Input
.ki
.time
= GetTickCount();
350 Input
.ki
.dwExtraInfo
= GetMessageExtraInfo();
351 Input
.ki
.dwFlags
= KEYEVENTF_SCANCODE
| KEYEVENTF_KEYUP
;
352 if (bExtendedKey
) Input
.ki
.dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
353 SendInput(1, &Input
, sizeof(Input
));
356 /* Play the sound during clicking event (only if "Use Click Sound" menu option is ticked) */
357 if (Globals
.bSoundClick
)
359 PlaySoundW(MAKEINTRESOURCEW(IDI_SOUNDCLICK
), GetModuleHandle(NULL
), SND_RESOURCE
| SND_ASYNC
);
365 /***********************************************************************
369 * Release the key of ID wCommand
371 BOOL
OSK_ReleaseKey(WORD ScanCode
)
378 /* Is it a 2-states key ? */
379 hWndControl
= GetDlgItem(Globals
.hMainWnd
, ScanCode
);
380 WindowStyle
= GetWindowLongW(hWndControl
, GWL_STYLE
);
381 if ((WindowStyle
& BS_AUTOCHECKBOX
) != BS_AUTOCHECKBOX
) return FALSE
;
383 /* Is the key down ? */
384 if (SendMessageW(hWndControl
, BM_GETCHECK
, 0, 0) != BST_CHECKED
) return TRUE
;
387 if (ScanCode
& 0x0200)
390 bExtendedKey
= FALSE
;
393 /* Release the key */
394 Input
.type
= INPUT_KEYBOARD
;
396 Input
.ki
.wScan
= ScanCode
;
397 Input
.ki
.time
= GetTickCount();
398 Input
.ki
.dwExtraInfo
= GetMessageExtraInfo();
399 Input
.ki
.dwFlags
= KEYEVENTF_SCANCODE
| KEYEVENTF_KEYUP
;
400 if (bExtendedKey
) Input
.ki
.dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
401 SendInput(1, &Input
, sizeof(Input
));
406 /***********************************************************************
410 INT_PTR APIENTRY
OSK_DlgProc(HWND hDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
415 OSK_DlgInitDialog(hDlg
);
422 case WM_CTLCOLORSTATIC
:
423 if ((HWND
)lParam
== GetDlgItem(hDlg
, IDC_LED_NUM
))
425 if (GetKeyState(VK_NUMLOCK
) & 0x0001)
426 return (INT_PTR
)Globals
.hBrushGreenLed
;
428 return (INT_PTR
)GetStockObject(BLACK_BRUSH
);
430 if ((HWND
)lParam
== GetDlgItem(hDlg
, IDC_LED_CAPS
))
432 if (GetKeyState(VK_CAPITAL
) & 0x0001)
433 return (INT_PTR
)Globals
.hBrushGreenLed
;
435 return (INT_PTR
)GetStockObject(BLACK_BRUSH
);
437 if ((HWND
)lParam
== GetDlgItem(hDlg
, IDC_LED_SCROLL
))
439 if (GetKeyState(VK_SCROLL
) & 0x0001)
440 return (INT_PTR
)Globals
.hBrushGreenLed
;
442 return (INT_PTR
)GetStockObject(BLACK_BRUSH
);
447 switch (LOWORD(wParam
))
451 EndDialog(hDlg
, FALSE
);
457 EndDialog(hDlg
, FALSE
);
461 case IDM_ENHANCED_KB
:
463 if (!Globals
.bIsEnhancedKeyboard
)
466 The user attempted to switch to enhanced keyboard dialog type.
467 Set the member value as TRUE, destroy the dialog and save the data configuration into the registry.
469 Globals
.bIsEnhancedKeyboard
= TRUE
;
470 EndDialog(hDlg
, FALSE
);
471 SaveDataToRegistry();
473 /* Change the condition of enhanced keyboard item menu to checked */
474 CheckMenuItem(GetMenu(hDlg
), IDM_ENHANCED_KB
, MF_BYCOMMAND
| MF_CHECKED
);
475 CheckMenuItem(GetMenu(hDlg
), IDM_STANDARD_KB
, MF_BYCOMMAND
| MF_UNCHECKED
);
477 /* Finally, display the dialog modal box with the enhanced keyboard dialog */
478 DialogBoxW(Globals
.hInstance
,
479 MAKEINTRESOURCEW(MAIN_DIALOG_ENHANCED_KB
),
487 case IDM_STANDARD_KB
:
489 if (Globals
.bIsEnhancedKeyboard
)
492 The user attempted to switch to standard keyboard dialog type.
493 Set the member value as FALSE, destroy the dialog and save the data configuration into the registry.
495 Globals
.bIsEnhancedKeyboard
= FALSE
;
496 EndDialog(hDlg
, FALSE
);
497 SaveDataToRegistry();
499 /* Change the condition of standard keyboard item menu to checked */
500 CheckMenuItem(GetMenu(hDlg
), IDM_ENHANCED_KB
, MF_BYCOMMAND
| MF_UNCHECKED
);
501 CheckMenuItem(GetMenu(hDlg
), IDM_STANDARD_KB
, MF_BYCOMMAND
| MF_CHECKED
);
503 /* Finally, display the dialog modal box with the standard keyboard dialog */
504 DialogBoxW(Globals
.hInstance
,
505 MAKEINTRESOURCEW(MAIN_DIALOG_STANDARD_KB
),
513 case IDM_CLICK_SOUND
:
516 This case is triggered when the user attempts to click on the menu item. Before doing anything,
517 we must check the condition state of such menu item so that we can tick/untick the menu item accordingly.
519 if (!Globals
.bSoundClick
)
521 Globals
.bSoundClick
= TRUE
;
522 CheckMenuItem(GetMenu(hDlg
), IDM_CLICK_SOUND
, MF_BYCOMMAND
| MF_CHECKED
);
526 Globals
.bSoundClick
= FALSE
;
527 CheckMenuItem(GetMenu(hDlg
), IDM_CLICK_SOUND
, MF_BYCOMMAND
| MF_UNCHECKED
);
540 OSK_DlgCommand(wParam
, (HWND
)lParam
);
553 /***********************************************************************
557 int WINAPI
wWinMain(HINSTANCE hInstance
,
565 UNREFERENCED_PARAMETER(prev
);
566 UNREFERENCED_PARAMETER(cmdline
);
567 UNREFERENCED_PARAMETER(show
);
569 ZeroMemory(&Globals
, sizeof(Globals
));
570 Globals
.hInstance
= hInstance
;
572 /* Load the settings from the registry hive */
573 LoadDataFromRegistry();
575 /* If the member of the struct (bShowWarning) is set then display the dialog box */
576 if (Globals
.bShowWarning
)
578 DialogBoxW(Globals
.hInstance
, MAKEINTRESOURCEW(IDD_WARNINGDIALOG_OSK
), Globals
.hMainWnd
, OSK_WarningProc
);
581 /* Before initializing the dialog execution, check if the chosen keyboard type is standard or enhanced */
582 if (Globals
.bIsEnhancedKeyboard
)
584 LayoutResource
= MAIN_DIALOG_ENHANCED_KB
;
588 LayoutResource
= MAIN_DIALOG_STANDARD_KB
;
591 /* Rry to open a mutex for a single instance */
592 hMutex
= OpenMutexW(MUTEX_ALL_ACCESS
, FALSE
, L
"osk");
596 /* Mutex doesn\92t exist. This is the first instance so create the mutex. */
597 hMutex
= CreateMutexW(NULL
, FALSE
, L
"osk");
599 /* Create the modal box based on the configuration registry */
600 DialogBoxW(hInstance
,
601 MAKEINTRESOURCEW(LayoutResource
),
605 /* Delete the mutex */
606 if (hMutex
) CloseHandle(hMutex
);
610 /* Programme already launched */
612 /* Delete the mutex */