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