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