105b261ecSmrg/* 205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 305b261ecSmrg * 405b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining 505b261ecSmrg * a copy of this software and associated documentation files (the 605b261ecSmrg *"Software"), to deal in the Software without restriction, including 705b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish, 805b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to 905b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to 1005b261ecSmrg *the following conditions: 1105b261ecSmrg * 1205b261ecSmrg *The above copyright notice and this permission notice shall be 1305b261ecSmrg *included in all copies or substantial portions of the Software. 1405b261ecSmrg * 1505b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1605b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1705b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1805b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 1905b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 2005b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2105b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2205b261ecSmrg * 2305b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project 2405b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use 2505b261ecSmrg *or other dealings in this Software without prior written authorization 2605b261ecSmrg *from the XFree86 Project. 2705b261ecSmrg * 2805b261ecSmrg * Authors: Dakshinamurthy Karra 2905b261ecSmrg * Suhaib M Siddiqi 3005b261ecSmrg * Peter Busch 3105b261ecSmrg * Harold L Hunt II 3205b261ecSmrg */ 3305b261ecSmrg 3405b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H 3505b261ecSmrg#include <xwin-config.h> 3605b261ecSmrg#endif 3705b261ecSmrg#include "win.h" 3805b261ecSmrg#include "winkeybd.h" 3905b261ecSmrg#include "winconfig.h" 4005b261ecSmrg#include "winmsg.h" 4105b261ecSmrg 426747b715Smrg#include "xkbsrv.h" 4305b261ecSmrg 4435c4bbdfSmrg/* C does not have a logical XOR operator, so we use a macro instead */ 4535c4bbdfSmrg#define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) 4635c4bbdfSmrg 4705b261ecSmrgstatic Bool g_winKeyState[NUM_KEYCODES]; 4805b261ecSmrg 4905b261ecSmrg/* 5005b261ecSmrg * Local prototypes 5105b261ecSmrg */ 5205b261ecSmrg 5305b261ecSmrgstatic void 5435c4bbdfSmrg winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass); 5505b261ecSmrg 5605b261ecSmrgstatic void 5735c4bbdfSmrg winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl); 5805b261ecSmrg 5935c4bbdfSmrg/* 6005b261ecSmrg * Translate a Windows WM_[SYS]KEY(UP/DOWN) message 6105b261ecSmrg * into an ASCII scan code. 6205b261ecSmrg * 6305b261ecSmrg * We do this ourselves, rather than letting Windows handle it, 6405b261ecSmrg * because Windows tends to munge the handling of special keys, 6505b261ecSmrg * like AltGr on European keyboards. 6605b261ecSmrg */ 6705b261ecSmrg 6835c4bbdfSmrgint 6935c4bbdfSmrgwinTranslateKey(WPARAM wParam, LPARAM lParam) 7005b261ecSmrg{ 7135c4bbdfSmrg int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1]; 7235c4bbdfSmrg int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2]; 7335c4bbdfSmrg int iParam = HIWORD(lParam); 7435c4bbdfSmrg int iParamScanCode = LOBYTE(iParam); 7535c4bbdfSmrg int iScanCode; 766747b715Smrg 7735c4bbdfSmrg winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam); 789ace9065Smrg 796747b715Smrg/* WM_ key messages faked by Vista speech recognition (WSR) don't have a 806747b715Smrg * scan code. 816747b715Smrg * 826747b715Smrg * Vocola 3 (Rick Mohr's supplement to WSR) uses 836747b715Smrg * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a 846747b715Smrg * scan code of 1 856747b715Smrg */ 8635c4bbdfSmrg if (iParamScanCode <= 1) { 8735c4bbdfSmrg if (VK_PRIOR <= wParam && wParam <= VK_DOWN) 8835c4bbdfSmrg /* Trigger special case table to translate to extended 8935c4bbdfSmrg * keycode, otherwise if num_lock is on, we can get keypad 9035c4bbdfSmrg * numbers instead of navigation keys. */ 9135c4bbdfSmrg iParam |= KF_EXTENDED; 9235c4bbdfSmrg else 9335c4bbdfSmrg iParamScanCode = MapVirtualKeyEx(wParam, 9435c4bbdfSmrg /*MAPVK_VK_TO_VSC */ 0, 9535c4bbdfSmrg GetKeyboardLayout(0)); 966747b715Smrg } 9705b261ecSmrg 9835c4bbdfSmrg /* Branch on special extended, special non-extended, or normal key */ 9935c4bbdfSmrg if ((iParam & KF_EXTENDED) && iKeyFixupEx) 10035c4bbdfSmrg iScanCode = iKeyFixupEx; 10135c4bbdfSmrg else if (iKeyFixup) 10235c4bbdfSmrg iScanCode = iKeyFixup; 10335c4bbdfSmrg else if (wParam == 0 && iParamScanCode == 0x70) 10435c4bbdfSmrg iScanCode = KEY_HKTG; 10535c4bbdfSmrg else 10635c4bbdfSmrg switch (iParamScanCode) { 10735c4bbdfSmrg case 0x70: 10835c4bbdfSmrg iScanCode = KEY_HKTG; 10935c4bbdfSmrg break; 11035c4bbdfSmrg case 0x73: 11135c4bbdfSmrg iScanCode = KEY_BSlash2; 11235c4bbdfSmrg break; 11335c4bbdfSmrg default: 11435c4bbdfSmrg iScanCode = iParamScanCode; 11535c4bbdfSmrg break; 11635c4bbdfSmrg } 11705b261ecSmrg 11835c4bbdfSmrg return iScanCode; 11935c4bbdfSmrg} 12005b261ecSmrg 12105b261ecSmrg/* Ring the keyboard bell (system speaker on PCs) */ 12205b261ecSmrgstatic void 12335c4bbdfSmrgwinKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass) 12405b261ecSmrg{ 12535c4bbdfSmrg /* 12635c4bbdfSmrg * We can't use Beep () here because it uses the PC speaker 12735c4bbdfSmrg * on NT/2000. MessageBeep (MB_OK) will play the default system 12835c4bbdfSmrg * sound on systems with a sound card or it will beep the PC speaker 12935c4bbdfSmrg * on systems that do not have a sound card. 13035c4bbdfSmrg */ 13135c4bbdfSmrg if (iPercent > 0) MessageBeep(MB_OK); 13205b261ecSmrg} 13305b261ecSmrg 13405b261ecSmrg/* Change some keyboard configuration parameters */ 13505b261ecSmrgstatic void 13635c4bbdfSmrgwinKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl) 13705b261ecSmrg{ 13805b261ecSmrg} 13905b261ecSmrg 14035c4bbdfSmrg/* 14105b261ecSmrg * See Porting Layer Definition - p. 18 14205b261ecSmrg * winKeybdProc is known as a DeviceProc. 14305b261ecSmrg */ 14405b261ecSmrg 14505b261ecSmrgint 14635c4bbdfSmrgwinKeybdProc(DeviceIntPtr pDeviceInt, int iState) 14705b261ecSmrg{ 14835c4bbdfSmrg DevicePtr pDevice = (DevicePtr) pDeviceInt; 14935c4bbdfSmrg XkbSrvInfoPtr xkbi; 15035c4bbdfSmrg XkbControlsPtr ctrl; 15105b261ecSmrg 15235c4bbdfSmrg switch (iState) { 15305b261ecSmrg case DEVICE_INIT: 15435c4bbdfSmrg winConfigKeyboard(pDeviceInt); 15535c4bbdfSmrg 15635c4bbdfSmrg /* FIXME: Maybe we should use winGetKbdLeds () here? */ 15735c4bbdfSmrg defaultKeyboardControl.leds = g_winInfo.keyboard.leds; 15835c4bbdfSmrg 15935c4bbdfSmrg winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\"" 16035c4bbdfSmrg " Variant = \"%s\" Options = \"%s\"\n", 16135c4bbdfSmrg g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none", 16235c4bbdfSmrg g_winInfo.xkb.model ? g_winInfo.xkb.model : "none", 16335c4bbdfSmrg g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none", 16435c4bbdfSmrg g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none", 16535c4bbdfSmrg g_winInfo.xkb.options ? g_winInfo.xkb.options : "none"); 16635c4bbdfSmrg 16735c4bbdfSmrg InitKeyboardDeviceStruct(pDeviceInt, 16835c4bbdfSmrg &g_winInfo.xkb, winKeybdBell, winKeybdCtrl); 16935c4bbdfSmrg 17035c4bbdfSmrg xkbi = pDeviceInt->key->xkbInfo; 17135c4bbdfSmrg if ((xkbi != NULL) && (xkbi->desc != NULL)) { 17235c4bbdfSmrg ctrl = xkbi->desc->ctrls; 17335c4bbdfSmrg ctrl->repeat_delay = g_winInfo.keyboard.delay; 17435c4bbdfSmrg ctrl->repeat_interval = 1000 / g_winInfo.keyboard.rate; 1756747b715Smrg } 17635c4bbdfSmrg else { 17735c4bbdfSmrg winErrorFVerb(1, 17835c4bbdfSmrg "winKeybdProc - Error initializing keyboard AutoRepeat\n"); 17905b261ecSmrg } 18005b261ecSmrg 18135c4bbdfSmrg break; 1826747b715Smrg 18335c4bbdfSmrg case DEVICE_ON: 18435c4bbdfSmrg pDevice->on = TRUE; 18535c4bbdfSmrg 18635c4bbdfSmrg // immediately copy the state of this keyboard device to the VCK 18735c4bbdfSmrg // (which otherwise happens lazily after the first keypress) 18835c4bbdfSmrg CopyKeyClass(pDeviceInt, inputInfo.keyboard); 18935c4bbdfSmrg break; 19005b261ecSmrg 19105b261ecSmrg case DEVICE_CLOSE: 19235c4bbdfSmrg case DEVICE_OFF: 19335c4bbdfSmrg pDevice->on = FALSE; 19435c4bbdfSmrg break; 19505b261ecSmrg } 19605b261ecSmrg 19735c4bbdfSmrg return Success; 19805b261ecSmrg} 19905b261ecSmrg 20005b261ecSmrg/* 20105b261ecSmrg * Detect current mode key states upon server startup. 20205b261ecSmrg * 20305b261ecSmrg * Simulate a press and release of any key that is currently 20405b261ecSmrg * toggled. 20505b261ecSmrg */ 20605b261ecSmrg 20705b261ecSmrgvoid 20835c4bbdfSmrgwinInitializeModeKeyStates(void) 20905b261ecSmrg{ 21035c4bbdfSmrg /* Restore NumLock */ 21135c4bbdfSmrg if (GetKeyState(VK_NUMLOCK) & 0x0001) { 21235c4bbdfSmrg winSendKeyEvent(KEY_NumLock, TRUE); 21335c4bbdfSmrg winSendKeyEvent(KEY_NumLock, FALSE); 21405b261ecSmrg } 21505b261ecSmrg 21635c4bbdfSmrg /* Restore CapsLock */ 21735c4bbdfSmrg if (GetKeyState(VK_CAPITAL) & 0x0001) { 21835c4bbdfSmrg winSendKeyEvent(KEY_CapsLock, TRUE); 21935c4bbdfSmrg winSendKeyEvent(KEY_CapsLock, FALSE); 22005b261ecSmrg } 22105b261ecSmrg 22235c4bbdfSmrg /* Restore ScrollLock */ 22335c4bbdfSmrg if (GetKeyState(VK_SCROLL) & 0x0001) { 22435c4bbdfSmrg winSendKeyEvent(KEY_ScrollLock, TRUE); 22535c4bbdfSmrg winSendKeyEvent(KEY_ScrollLock, FALSE); 22605b261ecSmrg } 22705b261ecSmrg 22835c4bbdfSmrg /* Restore KanaLock */ 22935c4bbdfSmrg if (GetKeyState(VK_KANA) & 0x0001) { 23035c4bbdfSmrg winSendKeyEvent(KEY_HKTG, TRUE); 23135c4bbdfSmrg winSendKeyEvent(KEY_HKTG, FALSE); 23205b261ecSmrg } 23305b261ecSmrg} 23405b261ecSmrg 23505b261ecSmrg/* 23605b261ecSmrg * Upon regaining the keyboard focus we must 23705b261ecSmrg * resynchronize our internal mode key states 23805b261ecSmrg * with the actual state of the keys. 23905b261ecSmrg */ 24005b261ecSmrg 24105b261ecSmrgvoid 24235c4bbdfSmrgwinRestoreModeKeyStates(void) 24305b261ecSmrg{ 24435c4bbdfSmrg DWORD dwKeyState; 24535c4bbdfSmrg BOOL processEvents = TRUE; 24635c4bbdfSmrg unsigned short internalKeyStates; 24735c4bbdfSmrg 24835c4bbdfSmrg /* X server is being initialized */ 2491b5d61b8Smrg if (!inputInfo.keyboard || !inputInfo.keyboard->key) 25035c4bbdfSmrg return; 25135c4bbdfSmrg 25235c4bbdfSmrg /* Only process events if the rootwindow is mapped. The keyboard events 25335c4bbdfSmrg * will cause segfaults otherwise */ 25435c4bbdfSmrg if (screenInfo.screens[0]->root && 25535c4bbdfSmrg screenInfo.screens[0]->root->mapped == FALSE) 25635c4bbdfSmrg processEvents = FALSE; 25735c4bbdfSmrg 25835c4bbdfSmrg /* Force to process all pending events in the mi event queue */ 25935c4bbdfSmrg if (processEvents) 26035c4bbdfSmrg mieqProcessInputEvents(); 26135c4bbdfSmrg 26235c4bbdfSmrg /* Read the mode key states of our X server */ 26335c4bbdfSmrg /* (stored in the virtual core keyboard) */ 26435c4bbdfSmrg internalKeyStates = 26535c4bbdfSmrg XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state); 26635c4bbdfSmrg winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates); 26735c4bbdfSmrg 26835c4bbdfSmrg /* Check if modifier keys are pressed, and if so, fake a press */ 26905b261ecSmrg { 27035c4bbdfSmrg 27135c4bbdfSmrg BOOL lctrl = (GetAsyncKeyState(VK_LCONTROL) < 0); 27235c4bbdfSmrg BOOL rctrl = (GetAsyncKeyState(VK_RCONTROL) < 0); 27335c4bbdfSmrg BOOL lshift = (GetAsyncKeyState(VK_LSHIFT) < 0); 27435c4bbdfSmrg BOOL rshift = (GetAsyncKeyState(VK_RSHIFT) < 0); 27535c4bbdfSmrg BOOL alt = (GetAsyncKeyState(VK_LMENU) < 0); 27635c4bbdfSmrg BOOL altgr = (GetAsyncKeyState(VK_RMENU) < 0); 27735c4bbdfSmrg 27835c4bbdfSmrg /* 27935c4bbdfSmrg If AltGr and CtrlL appear to be pressed, assume the 28035c4bbdfSmrg CtrL is a fake one 28135c4bbdfSmrg */ 28235c4bbdfSmrg if (lctrl && altgr) 28335c4bbdfSmrg lctrl = FALSE; 28435c4bbdfSmrg 28535c4bbdfSmrg if (lctrl) 28635c4bbdfSmrg winSendKeyEvent(KEY_LCtrl, TRUE); 28735c4bbdfSmrg 28835c4bbdfSmrg if (rctrl) 28935c4bbdfSmrg winSendKeyEvent(KEY_RCtrl, TRUE); 29035c4bbdfSmrg 29135c4bbdfSmrg if (lshift) 29235c4bbdfSmrg winSendKeyEvent(KEY_ShiftL, TRUE); 29335c4bbdfSmrg 29435c4bbdfSmrg if (rshift) 29535c4bbdfSmrg winSendKeyEvent(KEY_ShiftL, TRUE); 29635c4bbdfSmrg 29735c4bbdfSmrg if (alt) 29835c4bbdfSmrg winSendKeyEvent(KEY_Alt, TRUE); 29935c4bbdfSmrg 30035c4bbdfSmrg if (altgr) 30135c4bbdfSmrg winSendKeyEvent(KEY_AltLang, TRUE); 30205b261ecSmrg } 30305b261ecSmrg 30435c4bbdfSmrg /* 30535c4bbdfSmrg Check if latching modifier key states have changed, and if so, 30635c4bbdfSmrg fake a press and a release to toggle the modifier to the correct 30735c4bbdfSmrg state 30835c4bbdfSmrg */ 30935c4bbdfSmrg dwKeyState = GetKeyState(VK_NUMLOCK) & 0x0001; 31035c4bbdfSmrg if (LOGICAL_XOR(internalKeyStates & NumLockMask, dwKeyState)) { 31135c4bbdfSmrg winSendKeyEvent(KEY_NumLock, TRUE); 31235c4bbdfSmrg winSendKeyEvent(KEY_NumLock, FALSE); 31305b261ecSmrg } 31405b261ecSmrg 31535c4bbdfSmrg dwKeyState = GetKeyState(VK_CAPITAL) & 0x0001; 31635c4bbdfSmrg if (LOGICAL_XOR(internalKeyStates & LockMask, dwKeyState)) { 31735c4bbdfSmrg winSendKeyEvent(KEY_CapsLock, TRUE); 31835c4bbdfSmrg winSendKeyEvent(KEY_CapsLock, FALSE); 31905b261ecSmrg } 32005b261ecSmrg 32135c4bbdfSmrg dwKeyState = GetKeyState(VK_SCROLL) & 0x0001; 32235c4bbdfSmrg if (LOGICAL_XOR(internalKeyStates & ScrollLockMask, dwKeyState)) { 32335c4bbdfSmrg winSendKeyEvent(KEY_ScrollLock, TRUE); 32435c4bbdfSmrg winSendKeyEvent(KEY_ScrollLock, FALSE); 32535c4bbdfSmrg } 32635c4bbdfSmrg 32735c4bbdfSmrg dwKeyState = GetKeyState(VK_KANA) & 0x0001; 32835c4bbdfSmrg if (LOGICAL_XOR(internalKeyStates & KanaMask, dwKeyState)) { 32935c4bbdfSmrg winSendKeyEvent(KEY_HKTG, TRUE); 33035c4bbdfSmrg winSendKeyEvent(KEY_HKTG, FALSE); 33105b261ecSmrg } 33205b261ecSmrg 33335c4bbdfSmrg /* 33435c4bbdfSmrg For strict correctness, we should also press any non-modifier keys 33535c4bbdfSmrg which are already down when we gain focus, but nobody has complained 33635c4bbdfSmrg yet :-) 33735c4bbdfSmrg */ 33835c4bbdfSmrg} 33905b261ecSmrg 34005b261ecSmrg/* 34105b261ecSmrg * Look for the lovely fake Control_L press/release generated by Windows 34205b261ecSmrg * when AltGr is pressed/released on a non-U.S. keyboard. 34305b261ecSmrg */ 34405b261ecSmrg 34505b261ecSmrgBool 34635c4bbdfSmrgwinIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam) 34705b261ecSmrg{ 34835c4bbdfSmrg MSG msgNext; 34935c4bbdfSmrg LONG lTime; 35035c4bbdfSmrg Bool fReturn; 35135c4bbdfSmrg 35235c4bbdfSmrg static Bool lastWasControlL = FALSE; 35335c4bbdfSmrg static LONG lastTime; 35435c4bbdfSmrg 35535c4bbdfSmrg /* 35635c4bbdfSmrg * Fake Ctrl_L presses will be followed by an Alt_R press 35735c4bbdfSmrg * with the same timestamp as the Ctrl_L press. 35835c4bbdfSmrg */ 35935c4bbdfSmrg if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) 36035c4bbdfSmrg && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { 36135c4bbdfSmrg /* Got a Ctrl_L press */ 36235c4bbdfSmrg 36335c4bbdfSmrg /* Get time of current message */ 36435c4bbdfSmrg lTime = GetMessageTime(); 36535c4bbdfSmrg 36635c4bbdfSmrg /* Look for next press message */ 36735c4bbdfSmrg fReturn = PeekMessage(&msgNext, NULL, 36835c4bbdfSmrg WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE); 36935c4bbdfSmrg 37035c4bbdfSmrg if (fReturn && msgNext.message != WM_KEYDOWN && 37135c4bbdfSmrg msgNext.message != WM_SYSKEYDOWN) 37235c4bbdfSmrg fReturn = 0; 37335c4bbdfSmrg 37435c4bbdfSmrg if (!fReturn) { 37535c4bbdfSmrg lastWasControlL = TRUE; 37635c4bbdfSmrg lastTime = lTime; 37735c4bbdfSmrg } 37835c4bbdfSmrg else { 37935c4bbdfSmrg lastWasControlL = FALSE; 38035c4bbdfSmrg } 38105b261ecSmrg 38235c4bbdfSmrg /* Is next press an Alt_R with the same timestamp? */ 38335c4bbdfSmrg if (fReturn && msgNext.wParam == VK_MENU 38435c4bbdfSmrg && msgNext.time == lTime 38535c4bbdfSmrg && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { 38635c4bbdfSmrg /* 38735c4bbdfSmrg * Next key press is Alt_R with same timestamp as current 38835c4bbdfSmrg * Ctrl_L message. Therefore, this Ctrl_L press is a fake 38935c4bbdfSmrg * event, so discard it. 39035c4bbdfSmrg */ 39135c4bbdfSmrg return TRUE; 39235c4bbdfSmrg } 39335c4bbdfSmrg } 39435c4bbdfSmrg /* 39535c4bbdfSmrg * Sometimes, the Alt_R press message is not yet posted when the 39635c4bbdfSmrg * fake Ctrl_L press message arrives (even though it has the 39735c4bbdfSmrg * same timestamp), so check for an Alt_R press message that has 39835c4bbdfSmrg * arrived since the last Ctrl_L message. 39935c4bbdfSmrg */ 40035c4bbdfSmrg else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) 40135c4bbdfSmrg && wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) { 40235c4bbdfSmrg /* Got a Alt_R press */ 40335c4bbdfSmrg 40435c4bbdfSmrg if (lastWasControlL) { 40535c4bbdfSmrg lTime = GetMessageTime(); 40635c4bbdfSmrg 40735c4bbdfSmrg if (lastTime == lTime) { 40835c4bbdfSmrg /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */ 40935c4bbdfSmrg winSendKeyEvent(KEY_LCtrl, FALSE); 41035c4bbdfSmrg } 41135c4bbdfSmrg lastWasControlL = FALSE; 41235c4bbdfSmrg } 41335c4bbdfSmrg } 41435c4bbdfSmrg /* 41535c4bbdfSmrg * Fake Ctrl_L releases will be followed by an Alt_R release 41635c4bbdfSmrg * with the same timestamp as the Ctrl_L release. 41735c4bbdfSmrg */ 41835c4bbdfSmrg else if ((message == WM_KEYUP || message == WM_SYSKEYUP) 41935c4bbdfSmrg && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) { 42035c4bbdfSmrg /* Got a Ctrl_L release */ 42135c4bbdfSmrg 42235c4bbdfSmrg /* Get time of current message */ 42335c4bbdfSmrg lTime = GetMessageTime(); 42435c4bbdfSmrg 42535c4bbdfSmrg /* Look for next release message */ 42635c4bbdfSmrg fReturn = PeekMessage(&msgNext, NULL, 42735c4bbdfSmrg WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE); 42835c4bbdfSmrg 42935c4bbdfSmrg if (fReturn && msgNext.message != WM_KEYUP && 43035c4bbdfSmrg msgNext.message != WM_SYSKEYUP) 43135c4bbdfSmrg fReturn = 0; 43235c4bbdfSmrg 43335c4bbdfSmrg lastWasControlL = FALSE; 43435c4bbdfSmrg 43535c4bbdfSmrg /* Is next press an Alt_R with the same timestamp? */ 43635c4bbdfSmrg if (fReturn 43735c4bbdfSmrg && (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP) 43835c4bbdfSmrg && msgNext.wParam == VK_MENU 43935c4bbdfSmrg && msgNext.time == lTime 44035c4bbdfSmrg && (HIWORD(msgNext.lParam) & KF_EXTENDED)) { 44135c4bbdfSmrg /* 44235c4bbdfSmrg * Next key release is Alt_R with same timestamp as current 44335c4bbdfSmrg * Ctrl_L message. Therefore, this Ctrl_L release is a fake 44435c4bbdfSmrg * event, so discard it. 44535c4bbdfSmrg */ 44635c4bbdfSmrg return TRUE; 44735c4bbdfSmrg } 44835c4bbdfSmrg } 44935c4bbdfSmrg else { 45035c4bbdfSmrg /* On any other press or release message, we don't have a 45135c4bbdfSmrg potentially fake Ctrl_L to worry about anymore... */ 45235c4bbdfSmrg lastWasControlL = FALSE; 45305b261ecSmrg } 45405b261ecSmrg 45535c4bbdfSmrg /* Not a fake control left press/release */ 45635c4bbdfSmrg return FALSE; 45735c4bbdfSmrg} 45805b261ecSmrg 45905b261ecSmrg/* 46005b261ecSmrg * Lift any modifier keys that are pressed 46105b261ecSmrg */ 46205b261ecSmrg 46305b261ecSmrgvoid 46435c4bbdfSmrgwinKeybdReleaseKeys(void) 46505b261ecSmrg{ 46635c4bbdfSmrg int i; 46705b261ecSmrg 46805b261ecSmrg#ifdef HAS_DEVWINDOWS 46935c4bbdfSmrg /* Verify that the mi input system has been initialized */ 47035c4bbdfSmrg if (g_fdMessageQueue == WIN_FD_INVALID) 47135c4bbdfSmrg return; 47205b261ecSmrg#endif 47305b261ecSmrg 47435c4bbdfSmrg /* Loop through all keys */ 47535c4bbdfSmrg for (i = 0; i < NUM_KEYCODES; ++i) { 47635c4bbdfSmrg /* Pop key if pressed */ 47735c4bbdfSmrg if (g_winKeyState[i]) 47835c4bbdfSmrg winSendKeyEvent(i, FALSE); 47905b261ecSmrg 48035c4bbdfSmrg /* Reset pressed flag for keys */ 48135c4bbdfSmrg g_winKeyState[i] = FALSE; 48205b261ecSmrg } 48305b261ecSmrg} 48405b261ecSmrg 48505b261ecSmrg/* 48605b261ecSmrg * Take a raw X key code and send an up or down event for it. 48705b261ecSmrg * 48805b261ecSmrg * Thanks to VNC for inspiration, though it is a simple function. 48905b261ecSmrg */ 49005b261ecSmrg 49105b261ecSmrgvoid 49235c4bbdfSmrgwinSendKeyEvent(DWORD dwKey, Bool fDown) 49305b261ecSmrg{ 49435c4bbdfSmrg /* 49535c4bbdfSmrg * When alt-tabing between screens we can get phantom key up messages 49635c4bbdfSmrg * Here we only pass them through it we think we should! 49735c4bbdfSmrg */ 49835c4bbdfSmrg if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) 49935c4bbdfSmrg return; 50005b261ecSmrg 50135c4bbdfSmrg /* Update the keyState map */ 50235c4bbdfSmrg g_winKeyState[dwKey] = fDown; 50305b261ecSmrg 50435c4bbdfSmrg QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease, 50535c4bbdfSmrg dwKey + MIN_KEYCODE); 5066747b715Smrg 50735c4bbdfSmrg winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown); 50805b261ecSmrg} 50905b261ecSmrg 51035c4bbdfSmrgBOOL 51135c4bbdfSmrgwinCheckKeyPressed(WPARAM wParam, LPARAM lParam) 51205b261ecSmrg{ 51335c4bbdfSmrg switch (wParam) { 51405b261ecSmrg case VK_CONTROL: 51535c4bbdfSmrg if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl]) 51635c4bbdfSmrg return TRUE; 51735c4bbdfSmrg if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl]) 51835c4bbdfSmrg return TRUE; 51935c4bbdfSmrg break; 52005b261ecSmrg case VK_SHIFT: 52135c4bbdfSmrg if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR]) 52235c4bbdfSmrg return TRUE; 52335c4bbdfSmrg if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL]) 52435c4bbdfSmrg return TRUE; 52535c4bbdfSmrg break; 52605b261ecSmrg default: 52735c4bbdfSmrg return TRUE; 52835c4bbdfSmrg } 52935c4bbdfSmrg return FALSE; 53005b261ecSmrg} 53105b261ecSmrg 53235c4bbdfSmrg/* Only one shift release message is sent even if both are pressed. 53335c4bbdfSmrg * Fix this here 53405b261ecSmrg */ 53535c4bbdfSmrgvoid 53635c4bbdfSmrgwinFixShiftKeys(int iScanCode) 53705b261ecSmrg{ 53835c4bbdfSmrg if (GetKeyState(VK_SHIFT) & 0x8000) 53935c4bbdfSmrg return; 54005b261ecSmrg 54135c4bbdfSmrg if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR]) 54235c4bbdfSmrg winSendKeyEvent(KEY_ShiftR, FALSE); 54335c4bbdfSmrg if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL]) 54435c4bbdfSmrg winSendKeyEvent(KEY_ShiftL, FALSE); 54505b261ecSmrg} 546