winkeybd.c revision 35c4bbdf
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 */
24935c4bbdfSmrg    if (!inputInfo.keyboard)
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