1706f2543Smrg/* 2706f2543Smrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3706f2543Smrg * 4706f2543Smrg *Permission is hereby granted, free of charge, to any person obtaining 5706f2543Smrg * a copy of this software and associated documentation files (the 6706f2543Smrg *"Software"), to deal in the Software without restriction, including 7706f2543Smrg *without limitation the rights to use, copy, modify, merge, publish, 8706f2543Smrg *distribute, sublicense, and/or sell copies of the Software, and to 9706f2543Smrg *permit persons to whom the Software is furnished to do so, subject to 10706f2543Smrg *the following conditions: 11706f2543Smrg * 12706f2543Smrg *The above copyright notice and this permission notice shall be 13706f2543Smrg *included in all copies or substantial portions of the Software. 14706f2543Smrg * 15706f2543Smrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16706f2543Smrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17706f2543Smrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18706f2543Smrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 19706f2543Smrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20706f2543Smrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21706f2543Smrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22706f2543Smrg * 23706f2543Smrg *Except as contained in this notice, the name of the XFree86 Project 24706f2543Smrg *shall not be used in advertising or otherwise to promote the sale, use 25706f2543Smrg *or other dealings in this Software without prior written authorization 26706f2543Smrg *from the XFree86 Project. 27706f2543Smrg * 28706f2543Smrg * Authors: Dakshinamurthy Karra 29706f2543Smrg * Suhaib M Siddiqi 30706f2543Smrg * Peter Busch 31706f2543Smrg * Harold L Hunt II 32706f2543Smrg */ 33706f2543Smrg 34706f2543Smrg 35706f2543Smrg#ifdef HAVE_XWIN_CONFIG_H 36706f2543Smrg#include <xwin-config.h> 37706f2543Smrg#endif 38706f2543Smrg#include "win.h" 39706f2543Smrg#include "winkeybd.h" 40706f2543Smrg#include "winconfig.h" 41706f2543Smrg#include "winmsg.h" 42706f2543Smrg 43706f2543Smrg#include "xkbsrv.h" 44706f2543Smrg 45706f2543Smrgstatic Bool g_winKeyState[NUM_KEYCODES]; 46706f2543Smrg 47706f2543Smrg/* 48706f2543Smrg * Local prototypes 49706f2543Smrg */ 50706f2543Smrg 51706f2543Smrgstatic void 52706f2543SmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt, 53706f2543Smrg pointer pCtrl, int iClass); 54706f2543Smrg 55706f2543Smrgstatic void 56706f2543SmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl); 57706f2543Smrg 58706f2543Smrg 59706f2543Smrg/* 60706f2543Smrg * Translate a Windows WM_[SYS]KEY(UP/DOWN) message 61706f2543Smrg * into an ASCII scan code. 62706f2543Smrg * 63706f2543Smrg * We do this ourselves, rather than letting Windows handle it, 64706f2543Smrg * because Windows tends to munge the handling of special keys, 65706f2543Smrg * like AltGr on European keyboards. 66706f2543Smrg */ 67706f2543Smrg 68706f2543Smrgvoid 69706f2543SmrgwinTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode) 70706f2543Smrg{ 71706f2543Smrg int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1]; 72706f2543Smrg int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2]; 73706f2543Smrg int iParam = HIWORD (lParam); 74706f2543Smrg int iParamScanCode = LOBYTE (iParam); 75706f2543Smrg 76706f2543Smrg winDebug("winTranslateKey: wParam %08x lParam %08x\n", wParam, lParam); 77706f2543Smrg 78706f2543Smrg/* WM_ key messages faked by Vista speech recognition (WSR) don't have a 79706f2543Smrg * scan code. 80706f2543Smrg * 81706f2543Smrg * Vocola 3 (Rick Mohr's supplement to WSR) uses 82706f2543Smrg * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a 83706f2543Smrg * scan code of 1 84706f2543Smrg */ 85706f2543Smrg if (iParamScanCode <= 1) 86706f2543Smrg { 87706f2543Smrg if (VK_PRIOR <= wParam && wParam <= VK_DOWN) 88706f2543Smrg /* Trigger special case table to translate to extended 89706f2543Smrg * keycode, otherwise if num_lock is on, we can get keypad 90706f2543Smrg * numbers instead of navigation keys. */ 91706f2543Smrg iParam |= KF_EXTENDED; 92706f2543Smrg else 93706f2543Smrg iParamScanCode = MapVirtualKeyEx(wParam, 94706f2543Smrg /*MAPVK_VK_TO_VSC*/0, 95706f2543Smrg GetKeyboardLayout(0)); 96706f2543Smrg } 97706f2543Smrg 98706f2543Smrg /* Branch on special extended, special non-extended, or normal key */ 99706f2543Smrg if ((iParam & KF_EXTENDED) && iKeyFixupEx) 100706f2543Smrg *piScanCode = iKeyFixupEx; 101706f2543Smrg else if (iKeyFixup) 102706f2543Smrg *piScanCode = iKeyFixup; 103706f2543Smrg else if (wParam == 0 && iParamScanCode == 0x70) 104706f2543Smrg *piScanCode = KEY_HKTG; 105706f2543Smrg else 106706f2543Smrg switch (iParamScanCode) 107706f2543Smrg { 108706f2543Smrg case 0x70: 109706f2543Smrg *piScanCode = KEY_HKTG; 110706f2543Smrg break; 111706f2543Smrg case 0x73: 112706f2543Smrg *piScanCode = KEY_BSlash2; 113706f2543Smrg break; 114706f2543Smrg default: 115706f2543Smrg *piScanCode = iParamScanCode; 116706f2543Smrg break; 117706f2543Smrg } 118706f2543Smrg} 119706f2543Smrg 120706f2543Smrg 121706f2543Smrg/* Ring the keyboard bell (system speaker on PCs) */ 122706f2543Smrgstatic void 123706f2543SmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt, 124706f2543Smrg pointer pCtrl, int iClass) 125706f2543Smrg{ 126706f2543Smrg /* 127706f2543Smrg * We can't use Beep () here because it uses the PC speaker 128706f2543Smrg * on NT/2000. MessageBeep (MB_OK) will play the default system 129706f2543Smrg * sound on systems with a sound card or it will beep the PC speaker 130706f2543Smrg * on systems that do not have a sound card. 131706f2543Smrg */ 132706f2543Smrg MessageBeep (MB_OK); 133706f2543Smrg} 134706f2543Smrg 135706f2543Smrg 136706f2543Smrg/* Change some keyboard configuration parameters */ 137706f2543Smrgstatic void 138706f2543SmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl) 139706f2543Smrg{ 140706f2543Smrg} 141706f2543Smrg 142706f2543Smrg 143706f2543Smrg/* 144706f2543Smrg * See Porting Layer Definition - p. 18 145706f2543Smrg * winKeybdProc is known as a DeviceProc. 146706f2543Smrg */ 147706f2543Smrg 148706f2543Smrgint 149706f2543SmrgwinKeybdProc (DeviceIntPtr pDeviceInt, int iState) 150706f2543Smrg{ 151706f2543Smrg DevicePtr pDevice = (DevicePtr) pDeviceInt; 152706f2543Smrg XkbSrvInfoPtr xkbi; 153706f2543Smrg XkbControlsPtr ctrl; 154706f2543Smrg 155706f2543Smrg switch (iState) 156706f2543Smrg { 157706f2543Smrg case DEVICE_INIT: 158706f2543Smrg winConfigKeyboard (pDeviceInt); 159706f2543Smrg 160706f2543Smrg /* FIXME: Maybe we should use winGetKbdLeds () here? */ 161706f2543Smrg defaultKeyboardControl.leds = g_winInfo.keyboard.leds; 162706f2543Smrg 163706f2543Smrg winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\"" 164706f2543Smrg " Variant = \"%s\" Options = \"%s\"\n", 165706f2543Smrg g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none", 166706f2543Smrg g_winInfo.xkb.model ? g_winInfo.xkb.model : "none", 167706f2543Smrg g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none", 168706f2543Smrg g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none", 169706f2543Smrg g_winInfo.xkb.options ? g_winInfo.xkb.options : "none"); 170706f2543Smrg 171706f2543Smrg InitKeyboardDeviceStruct (pDeviceInt, 172706f2543Smrg &g_winInfo.xkb, 173706f2543Smrg winKeybdBell, 174706f2543Smrg winKeybdCtrl); 175706f2543Smrg 176706f2543Smrg xkbi = pDeviceInt->key->xkbInfo; 177706f2543Smrg if ((xkbi != NULL) && (xkbi->desc != NULL)) 178706f2543Smrg { 179706f2543Smrg ctrl = xkbi->desc->ctrls; 180706f2543Smrg ctrl->repeat_delay = g_winInfo.keyboard.delay; 181706f2543Smrg ctrl->repeat_interval = 1000/g_winInfo.keyboard.rate; 182706f2543Smrg } 183706f2543Smrg else 184706f2543Smrg { 185706f2543Smrg winErrorFVerb (1, "winKeybdProc - Error initializing keyboard AutoRepeat\n"); 186706f2543Smrg } 187706f2543Smrg 188706f2543Smrg break; 189706f2543Smrg 190706f2543Smrg case DEVICE_ON: 191706f2543Smrg pDevice->on = TRUE; 192706f2543Smrg 193706f2543Smrg // immediately copy the state of this keyboard device to the VCK 194706f2543Smrg // (which otherwise happens lazily after the first keypress) 195706f2543Smrg CopyKeyClass(pDeviceInt, inputInfo.keyboard); 196706f2543Smrg break; 197706f2543Smrg 198706f2543Smrg case DEVICE_CLOSE: 199706f2543Smrg case DEVICE_OFF: 200706f2543Smrg pDevice->on = FALSE; 201706f2543Smrg break; 202706f2543Smrg } 203706f2543Smrg 204706f2543Smrg return Success; 205706f2543Smrg} 206706f2543Smrg 207706f2543Smrg 208706f2543Smrg/* 209706f2543Smrg * Detect current mode key states upon server startup. 210706f2543Smrg * 211706f2543Smrg * Simulate a press and release of any key that is currently 212706f2543Smrg * toggled. 213706f2543Smrg */ 214706f2543Smrg 215706f2543Smrgvoid 216706f2543SmrgwinInitializeModeKeyStates (void) 217706f2543Smrg{ 218706f2543Smrg /* Restore NumLock */ 219706f2543Smrg if (GetKeyState (VK_NUMLOCK) & 0x0001) 220706f2543Smrg { 221706f2543Smrg winSendKeyEvent (KEY_NumLock, TRUE); 222706f2543Smrg winSendKeyEvent (KEY_NumLock, FALSE); 223706f2543Smrg } 224706f2543Smrg 225706f2543Smrg /* Restore CapsLock */ 226706f2543Smrg if (GetKeyState (VK_CAPITAL) & 0x0001) 227706f2543Smrg { 228706f2543Smrg winSendKeyEvent (KEY_CapsLock, TRUE); 229706f2543Smrg winSendKeyEvent (KEY_CapsLock, FALSE); 230706f2543Smrg } 231706f2543Smrg 232706f2543Smrg /* Restore ScrollLock */ 233706f2543Smrg if (GetKeyState (VK_SCROLL) & 0x0001) 234706f2543Smrg { 235706f2543Smrg winSendKeyEvent (KEY_ScrollLock, TRUE); 236706f2543Smrg winSendKeyEvent (KEY_ScrollLock, FALSE); 237706f2543Smrg } 238706f2543Smrg 239706f2543Smrg /* Restore KanaLock */ 240706f2543Smrg if (GetKeyState (VK_KANA) & 0x0001) 241706f2543Smrg { 242706f2543Smrg winSendKeyEvent (KEY_HKTG, TRUE); 243706f2543Smrg winSendKeyEvent (KEY_HKTG, FALSE); 244706f2543Smrg } 245706f2543Smrg} 246706f2543Smrg 247706f2543Smrg 248706f2543Smrg/* 249706f2543Smrg * Upon regaining the keyboard focus we must 250706f2543Smrg * resynchronize our internal mode key states 251706f2543Smrg * with the actual state of the keys. 252706f2543Smrg */ 253706f2543Smrg 254706f2543Smrgvoid 255706f2543SmrgwinRestoreModeKeyStates (void) 256706f2543Smrg{ 257706f2543Smrg DWORD dwKeyState; 258706f2543Smrg BOOL processEvents = TRUE; 259706f2543Smrg unsigned short internalKeyStates; 260706f2543Smrg 261706f2543Smrg /* X server is being initialized */ 262706f2543Smrg if (!inputInfo.keyboard) 263706f2543Smrg return; 264706f2543Smrg 265706f2543Smrg /* Only process events if the rootwindow is mapped. The keyboard events 266706f2543Smrg * will cause segfaults otherwise */ 267706f2543Smrg if (screenInfo.screens[0]->root && screenInfo.screens[0]->root->mapped == FALSE) 268706f2543Smrg processEvents = FALSE; 269706f2543Smrg 270706f2543Smrg /* Force to process all pending events in the mi event queue */ 271706f2543Smrg if (processEvents) 272706f2543Smrg mieqProcessInputEvents (); 273706f2543Smrg 274706f2543Smrg /* Read the mode key states of our X server */ 275706f2543Smrg /* (stored in the virtual core keyboard) */ 276706f2543Smrg internalKeyStates = XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state); 277706f2543Smrg winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates); 278706f2543Smrg 279706f2543Smrg /* 280706f2543Smrg * NOTE: The C XOR operator, ^, will not work here because it is 281706f2543Smrg * a bitwise operator, not a logical operator. C does not 282706f2543Smrg * have a logical XOR operator, so we use a macro instead. 283706f2543Smrg */ 284706f2543Smrg 285706f2543Smrg /* Has the key state changed? */ 286706f2543Smrg dwKeyState = GetKeyState (VK_NUMLOCK) & 0x0001; 287706f2543Smrg if (WIN_XOR (internalKeyStates & NumLockMask, dwKeyState)) 288706f2543Smrg { 289706f2543Smrg winSendKeyEvent (KEY_NumLock, TRUE); 290706f2543Smrg winSendKeyEvent (KEY_NumLock, FALSE); 291706f2543Smrg } 292706f2543Smrg 293706f2543Smrg /* Has the key state changed? */ 294706f2543Smrg dwKeyState = GetKeyState (VK_CAPITAL) & 0x0001; 295706f2543Smrg if (WIN_XOR (internalKeyStates & LockMask, dwKeyState)) 296706f2543Smrg { 297706f2543Smrg winSendKeyEvent (KEY_CapsLock, TRUE); 298706f2543Smrg winSendKeyEvent (KEY_CapsLock, FALSE); 299706f2543Smrg } 300706f2543Smrg 301706f2543Smrg /* Has the key state changed? */ 302706f2543Smrg dwKeyState = GetKeyState (VK_SCROLL) & 0x0001; 303706f2543Smrg if (WIN_XOR (internalKeyStates & ScrollLockMask, dwKeyState)) 304706f2543Smrg { 305706f2543Smrg winSendKeyEvent (KEY_ScrollLock, TRUE); 306706f2543Smrg winSendKeyEvent (KEY_ScrollLock, FALSE); 307706f2543Smrg } 308706f2543Smrg 309706f2543Smrg /* Has the key state changed? */ 310706f2543Smrg dwKeyState = GetKeyState (VK_KANA) & 0x0001; 311706f2543Smrg if (WIN_XOR (internalKeyStates & KanaMask, dwKeyState)) 312706f2543Smrg { 313706f2543Smrg winSendKeyEvent (KEY_HKTG, TRUE); 314706f2543Smrg winSendKeyEvent (KEY_HKTG, FALSE); 315706f2543Smrg } 316706f2543Smrg} 317706f2543Smrg 318706f2543Smrg 319706f2543Smrg/* 320706f2543Smrg * Look for the lovely fake Control_L press/release generated by Windows 321706f2543Smrg * when AltGr is pressed/released on a non-U.S. keyboard. 322706f2543Smrg */ 323706f2543Smrg 324706f2543SmrgBool 325706f2543SmrgwinIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) 326706f2543Smrg{ 327706f2543Smrg MSG msgNext; 328706f2543Smrg LONG lTime; 329706f2543Smrg Bool fReturn; 330706f2543Smrg 331706f2543Smrg /* 332706f2543Smrg * Fake Ctrl_L presses will be followed by an Alt_R keypress 333706f2543Smrg * with the same timestamp as the Ctrl_L press. 334706f2543Smrg */ 335706f2543Smrg if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) 336706f2543Smrg && wParam == VK_CONTROL 337706f2543Smrg && (HIWORD (lParam) & KF_EXTENDED) == 0) 338706f2543Smrg { 339706f2543Smrg /* Got a Ctrl_L press */ 340706f2543Smrg 341706f2543Smrg /* Get time of current message */ 342706f2543Smrg lTime = GetMessageTime (); 343706f2543Smrg 344706f2543Smrg /* Look for fake Ctrl_L preceeding an Alt_R press. */ 345706f2543Smrg fReturn = PeekMessage (&msgNext, NULL, 346706f2543Smrg WM_KEYDOWN, WM_SYSKEYDOWN, 347706f2543Smrg PM_NOREMOVE); 348706f2543Smrg 349706f2543Smrg /* 350706f2543Smrg * Try again if the first call fails. 351706f2543Smrg * NOTE: This usually happens when TweakUI is enabled. 352706f2543Smrg */ 353706f2543Smrg if (!fReturn) 354706f2543Smrg { 355706f2543Smrg /* Voodoo to make sure that the Alt_R message has posted */ 356706f2543Smrg Sleep (0); 357706f2543Smrg 358706f2543Smrg /* Look for fake Ctrl_L preceeding an Alt_R press. */ 359706f2543Smrg fReturn = PeekMessage (&msgNext, NULL, 360706f2543Smrg WM_KEYDOWN, WM_SYSKEYDOWN, 361706f2543Smrg PM_NOREMOVE); 362706f2543Smrg } 363706f2543Smrg if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN) 364706f2543Smrg fReturn = 0; 365706f2543Smrg 366706f2543Smrg /* Is next press an Alt_R with the same timestamp? */ 367706f2543Smrg if (fReturn && msgNext.wParam == VK_MENU 368706f2543Smrg && msgNext.time == lTime 369706f2543Smrg && (HIWORD (msgNext.lParam) & KF_EXTENDED)) 370706f2543Smrg { 371706f2543Smrg /* 372706f2543Smrg * Next key press is Alt_R with same timestamp as current 373706f2543Smrg * Ctrl_L message. Therefore, this Ctrl_L press is a fake 374706f2543Smrg * event, so discard it. 375706f2543Smrg */ 376706f2543Smrg return TRUE; 377706f2543Smrg } 378706f2543Smrg } 379706f2543Smrg 380706f2543Smrg /* 381706f2543Smrg * Fake Ctrl_L releases will be followed by an Alt_R release 382706f2543Smrg * with the same timestamp as the Ctrl_L release. 383706f2543Smrg */ 384706f2543Smrg if ((message == WM_KEYUP || message == WM_SYSKEYUP) 385706f2543Smrg && wParam == VK_CONTROL 386706f2543Smrg && (HIWORD (lParam) & KF_EXTENDED) == 0) 387706f2543Smrg { 388706f2543Smrg /* Got a Ctrl_L release */ 389706f2543Smrg 390706f2543Smrg /* Get time of current message */ 391706f2543Smrg lTime = GetMessageTime (); 392706f2543Smrg 393706f2543Smrg /* Look for fake Ctrl_L release preceeding an Alt_R release. */ 394706f2543Smrg fReturn = PeekMessage (&msgNext, NULL, 395706f2543Smrg WM_KEYUP, WM_SYSKEYUP, 396706f2543Smrg PM_NOREMOVE); 397706f2543Smrg 398706f2543Smrg /* 399706f2543Smrg * Try again if the first call fails. 400706f2543Smrg * NOTE: This usually happens when TweakUI is enabled. 401706f2543Smrg */ 402706f2543Smrg if (!fReturn) 403706f2543Smrg { 404706f2543Smrg /* Voodoo to make sure that the Alt_R message has posted */ 405706f2543Smrg Sleep (0); 406706f2543Smrg 407706f2543Smrg /* Look for fake Ctrl_L release preceeding an Alt_R release. */ 408706f2543Smrg fReturn = PeekMessage (&msgNext, NULL, 409706f2543Smrg WM_KEYUP, WM_SYSKEYUP, 410706f2543Smrg PM_NOREMOVE); 411706f2543Smrg } 412706f2543Smrg 413706f2543Smrg if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP) 414706f2543Smrg fReturn = 0; 415706f2543Smrg 416706f2543Smrg /* Is next press an Alt_R with the same timestamp? */ 417706f2543Smrg if (fReturn 418706f2543Smrg && (msgNext.message == WM_KEYUP 419706f2543Smrg || msgNext.message == WM_SYSKEYUP) 420706f2543Smrg && msgNext.wParam == VK_MENU 421706f2543Smrg && msgNext.time == lTime 422706f2543Smrg && (HIWORD (msgNext.lParam) & KF_EXTENDED)) 423706f2543Smrg { 424706f2543Smrg /* 425706f2543Smrg * Next key release is Alt_R with same timestamp as current 426706f2543Smrg * Ctrl_L message. Therefore, this Ctrl_L release is a fake 427706f2543Smrg * event, so discard it. 428706f2543Smrg */ 429706f2543Smrg return TRUE; 430706f2543Smrg } 431706f2543Smrg } 432706f2543Smrg 433706f2543Smrg /* Not a fake control left press/release */ 434706f2543Smrg return FALSE; 435706f2543Smrg} 436706f2543Smrg 437706f2543Smrg 438706f2543Smrg/* 439706f2543Smrg * Lift any modifier keys that are pressed 440706f2543Smrg */ 441706f2543Smrg 442706f2543Smrgvoid 443706f2543SmrgwinKeybdReleaseKeys (void) 444706f2543Smrg{ 445706f2543Smrg int i; 446706f2543Smrg 447706f2543Smrg#ifdef HAS_DEVWINDOWS 448706f2543Smrg /* Verify that the mi input system has been initialized */ 449706f2543Smrg if (g_fdMessageQueue == WIN_FD_INVALID) 450706f2543Smrg return; 451706f2543Smrg#endif 452706f2543Smrg 453706f2543Smrg /* Loop through all keys */ 454706f2543Smrg for (i = 0; i < NUM_KEYCODES; ++i) 455706f2543Smrg { 456706f2543Smrg /* Pop key if pressed */ 457706f2543Smrg if (g_winKeyState[i]) 458706f2543Smrg winSendKeyEvent (i, FALSE); 459706f2543Smrg 460706f2543Smrg /* Reset pressed flag for keys */ 461706f2543Smrg g_winKeyState[i] = FALSE; 462706f2543Smrg } 463706f2543Smrg} 464706f2543Smrg 465706f2543Smrg 466706f2543Smrg/* 467706f2543Smrg * Take a raw X key code and send an up or down event for it. 468706f2543Smrg * 469706f2543Smrg * Thanks to VNC for inspiration, though it is a simple function. 470706f2543Smrg */ 471706f2543Smrg 472706f2543Smrgvoid 473706f2543SmrgwinSendKeyEvent (DWORD dwKey, Bool fDown) 474706f2543Smrg{ 475706f2543Smrg EventListPtr events; 476706f2543Smrg int i, nevents; 477706f2543Smrg 478706f2543Smrg /* 479706f2543Smrg * When alt-tabing between screens we can get phantom key up messages 480706f2543Smrg * Here we only pass them through it we think we should! 481706f2543Smrg */ 482706f2543Smrg if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) return; 483706f2543Smrg 484706f2543Smrg /* Update the keyState map */ 485706f2543Smrg g_winKeyState[dwKey] = fDown; 486706f2543Smrg 487706f2543Smrg GetEventList(&events); 488706f2543Smrg nevents = GetKeyboardEvents(events, g_pwinKeyboard, fDown ? KeyPress : KeyRelease, dwKey + MIN_KEYCODE); 489706f2543Smrg 490706f2543Smrg for (i = 0; i < nevents; i++) 491706f2543Smrg mieqEnqueue(g_pwinKeyboard, (InternalEvent*)events[i].event); 492706f2543Smrg 493706f2543Smrg winDebug("winSendKeyEvent: dwKey: %d, fDown: %d, nEvents %d\n", 494706f2543Smrg dwKey, fDown, nevents); 495706f2543Smrg} 496706f2543Smrg 497706f2543SmrgBOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam) 498706f2543Smrg{ 499706f2543Smrg switch (wParam) 500706f2543Smrg { 501706f2543Smrg case VK_CONTROL: 502706f2543Smrg if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl]) 503706f2543Smrg return TRUE; 504706f2543Smrg if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl]) 505706f2543Smrg return TRUE; 506706f2543Smrg break; 507706f2543Smrg case VK_SHIFT: 508706f2543Smrg if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR]) 509706f2543Smrg return TRUE; 510706f2543Smrg if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL]) 511706f2543Smrg return TRUE; 512706f2543Smrg break; 513706f2543Smrg default: 514706f2543Smrg return TRUE; 515706f2543Smrg } 516706f2543Smrg return FALSE; 517706f2543Smrg} 518706f2543Smrg 519706f2543Smrg/* Only on shift release message is sent even if both are pressed. 520706f2543Smrg * Fix this here 521706f2543Smrg */ 522706f2543Smrgvoid winFixShiftKeys (int iScanCode) 523706f2543Smrg{ 524706f2543Smrg if (GetKeyState (VK_SHIFT) & 0x8000) 525706f2543Smrg return; 526706f2543Smrg 527706f2543Smrg if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR]) 528706f2543Smrg winSendKeyEvent (KEY_ShiftR, FALSE); 529706f2543Smrg if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL]) 530706f2543Smrg winSendKeyEvent (KEY_ShiftL, FALSE); 531706f2543Smrg} 532