winkeybd.c revision 05b261ec
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 3505b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H 3605b261ecSmrg#include <xwin-config.h> 3705b261ecSmrg#endif 3805b261ecSmrg#include "win.h" 3905b261ecSmrg#include "winkeybd.h" 4005b261ecSmrg#include "winconfig.h" 4105b261ecSmrg#include "winmsg.h" 4205b261ecSmrg 4305b261ecSmrg#ifdef XKB 4405b261ecSmrg#ifndef XKB_IN_SERVER 4505b261ecSmrg#define XKB_IN_SERVER 4605b261ecSmrg#endif 4705b261ecSmrg#include <xkbsrv.h> 4805b261ecSmrg#endif 4905b261ecSmrg 5005b261ecSmrgstatic Bool g_winKeyState[NUM_KEYCODES]; 5105b261ecSmrg 5205b261ecSmrg/* Stored to get internal mode key states. Must be read-only. */ 5305b261ecSmrgstatic unsigned short const *g_winInternalModeKeyStatesPtr = NULL; 5405b261ecSmrg 5505b261ecSmrg 5605b261ecSmrg/* 5705b261ecSmrg * Local prototypes 5805b261ecSmrg */ 5905b261ecSmrg 6005b261ecSmrgstatic void 6105b261ecSmrgwinGetKeyMappings (KeySymsPtr pKeySyms, CARD8 *pModMap); 6205b261ecSmrg 6305b261ecSmrgstatic void 6405b261ecSmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt, 6505b261ecSmrg pointer pCtrl, int iClass); 6605b261ecSmrg 6705b261ecSmrgstatic void 6805b261ecSmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl); 6905b261ecSmrg 7005b261ecSmrg 7105b261ecSmrg/* 7205b261ecSmrg * Translate a Windows WM_[SYS]KEY(UP/DOWN) message 7305b261ecSmrg * into an ASCII scan code. 7405b261ecSmrg * 7505b261ecSmrg * We do this ourselves, rather than letting Windows handle it, 7605b261ecSmrg * because Windows tends to munge the handling of special keys, 7705b261ecSmrg * like AltGr on European keyboards. 7805b261ecSmrg */ 7905b261ecSmrg 8005b261ecSmrgvoid 8105b261ecSmrgwinTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode) 8205b261ecSmrg{ 8305b261ecSmrg int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1]; 8405b261ecSmrg int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2]; 8505b261ecSmrg int iParamScanCode = LOBYTE (HIWORD (lParam)); 8605b261ecSmrg 8705b261ecSmrg /* Branch on special extended, special non-extended, or normal key */ 8805b261ecSmrg if ((HIWORD (lParam) & KF_EXTENDED) && iKeyFixupEx) 8905b261ecSmrg *piScanCode = iKeyFixupEx; 9005b261ecSmrg else if (iKeyFixup) 9105b261ecSmrg *piScanCode = iKeyFixup; 9205b261ecSmrg else if (wParam == 0 && iParamScanCode == 0x70) 9305b261ecSmrg *piScanCode = KEY_HKTG; 9405b261ecSmrg else 9505b261ecSmrg switch (iParamScanCode) 9605b261ecSmrg { 9705b261ecSmrg case 0x70: 9805b261ecSmrg *piScanCode = KEY_HKTG; 9905b261ecSmrg break; 10005b261ecSmrg case 0x73: 10105b261ecSmrg *piScanCode = KEY_BSlash2; 10205b261ecSmrg break; 10305b261ecSmrg default: 10405b261ecSmrg *piScanCode = iParamScanCode; 10505b261ecSmrg break; 10605b261ecSmrg } 10705b261ecSmrg} 10805b261ecSmrg 10905b261ecSmrg 11005b261ecSmrg/* 11105b261ecSmrg * We call this function from winKeybdProc when we are 11205b261ecSmrg * initializing the keyboard. 11305b261ecSmrg */ 11405b261ecSmrg 11505b261ecSmrgstatic void 11605b261ecSmrgwinGetKeyMappings (KeySymsPtr pKeySyms, CARD8 *pModMap) 11705b261ecSmrg{ 11805b261ecSmrg int i; 11905b261ecSmrg KeySym *pMap = map; 12005b261ecSmrg KeySym *pKeySym; 12105b261ecSmrg 12205b261ecSmrg /* 12305b261ecSmrg * Initialize all key states to up... which may not be true 12405b261ecSmrg * but it is close enough. 12505b261ecSmrg */ 12605b261ecSmrg ZeroMemory (g_winKeyState, sizeof (g_winKeyState[0]) * NUM_KEYCODES); 12705b261ecSmrg 12805b261ecSmrg /* MAP_LENGTH is defined in Xserver/include/input.h to be 256 */ 12905b261ecSmrg for (i = 0; i < MAP_LENGTH; i++) 13005b261ecSmrg pModMap[i] = NoSymbol; /* make sure it is restored */ 13105b261ecSmrg 13205b261ecSmrg /* Loop through all valid entries in the key symbol table */ 13305b261ecSmrg for (pKeySym = pMap, i = MIN_KEYCODE; 13405b261ecSmrg i < (MIN_KEYCODE + NUM_KEYCODES); 13505b261ecSmrg i++, pKeySym += GLYPHS_PER_KEY) 13605b261ecSmrg { 13705b261ecSmrg switch (*pKeySym) 13805b261ecSmrg { 13905b261ecSmrg case XK_Shift_L: 14005b261ecSmrg case XK_Shift_R: 14105b261ecSmrg pModMap[i] = ShiftMask; 14205b261ecSmrg break; 14305b261ecSmrg 14405b261ecSmrg case XK_Control_L: 14505b261ecSmrg case XK_Control_R: 14605b261ecSmrg pModMap[i] = ControlMask; 14705b261ecSmrg break; 14805b261ecSmrg 14905b261ecSmrg case XK_Caps_Lock: 15005b261ecSmrg pModMap[i] = LockMask; 15105b261ecSmrg break; 15205b261ecSmrg 15305b261ecSmrg case XK_Alt_L: 15405b261ecSmrg case XK_Alt_R: 15505b261ecSmrg pModMap[i] = AltMask; 15605b261ecSmrg break; 15705b261ecSmrg 15805b261ecSmrg case XK_Num_Lock: 15905b261ecSmrg pModMap[i] = NumLockMask; 16005b261ecSmrg break; 16105b261ecSmrg 16205b261ecSmrg case XK_Scroll_Lock: 16305b261ecSmrg pModMap[i] = ScrollLockMask; 16405b261ecSmrg break; 16505b261ecSmrg 16605b261ecSmrg#if 0 16705b261ecSmrg case XK_Super_L: 16805b261ecSmrg case XK_Super_R: 16905b261ecSmrg pModMap[i] = Mod4Mask; 17005b261ecSmrg break; 17105b261ecSmrg#else 17205b261ecSmrg /* Hirigana/Katakana toggle */ 17305b261ecSmrg case XK_Kana_Lock: 17405b261ecSmrg case XK_Kana_Shift: 17505b261ecSmrg pModMap[i] = KanaMask; 17605b261ecSmrg break; 17705b261ecSmrg#endif 17805b261ecSmrg 17905b261ecSmrg /* alternate toggle for multinational support */ 18005b261ecSmrg case XK_Mode_switch: 18105b261ecSmrg pModMap[i] = AltLangMask; 18205b261ecSmrg break; 18305b261ecSmrg } 18405b261ecSmrg } 18505b261ecSmrg 18605b261ecSmrg pKeySyms->map = (KeySym *) pMap; 18705b261ecSmrg pKeySyms->mapWidth = GLYPHS_PER_KEY; 18805b261ecSmrg pKeySyms->minKeyCode = MIN_KEYCODE; 18905b261ecSmrg pKeySyms->maxKeyCode = MAX_KEYCODE; 19005b261ecSmrg} 19105b261ecSmrg 19205b261ecSmrg 19305b261ecSmrg/* Ring the keyboard bell (system speaker on PCs) */ 19405b261ecSmrgstatic void 19505b261ecSmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt, 19605b261ecSmrg pointer pCtrl, int iClass) 19705b261ecSmrg{ 19805b261ecSmrg /* 19905b261ecSmrg * We can't use Beep () here because it uses the PC speaker 20005b261ecSmrg * on NT/2000. MessageBeep (MB_OK) will play the default system 20105b261ecSmrg * sound on systems with a sound card or it will beep the PC speaker 20205b261ecSmrg * on systems that do not have a sound card. 20305b261ecSmrg */ 20405b261ecSmrg MessageBeep (MB_OK); 20505b261ecSmrg} 20605b261ecSmrg 20705b261ecSmrg 20805b261ecSmrg/* Change some keyboard configuration parameters */ 20905b261ecSmrgstatic void 21005b261ecSmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl) 21105b261ecSmrg{ 21205b261ecSmrg g_winInternalModeKeyStatesPtr = &(pDevice->key->state); 21305b261ecSmrg} 21405b261ecSmrg 21505b261ecSmrg 21605b261ecSmrg/* 21705b261ecSmrg * See Porting Layer Definition - p. 18 21805b261ecSmrg * winKeybdProc is known as a DeviceProc. 21905b261ecSmrg */ 22005b261ecSmrg 22105b261ecSmrgint 22205b261ecSmrgwinKeybdProc (DeviceIntPtr pDeviceInt, int iState) 22305b261ecSmrg{ 22405b261ecSmrg KeySymsRec keySyms; 22505b261ecSmrg CARD8 modMap[MAP_LENGTH]; 22605b261ecSmrg DevicePtr pDevice = (DevicePtr) pDeviceInt; 22705b261ecSmrg#ifdef XKB 22805b261ecSmrg XkbComponentNamesRec names; 22905b261ecSmrg XkbSrvInfoPtr xkbi; 23005b261ecSmrg XkbControlsPtr ctrl; 23105b261ecSmrg#endif 23205b261ecSmrg 23305b261ecSmrg switch (iState) 23405b261ecSmrg { 23505b261ecSmrg case DEVICE_INIT: 23605b261ecSmrg winConfigKeyboard (pDeviceInt); 23705b261ecSmrg 23805b261ecSmrg winGetKeyMappings (&keySyms, modMap); 23905b261ecSmrg 24005b261ecSmrg#ifdef XKB 24105b261ecSmrg /* FIXME: Maybe we should use winGetKbdLeds () here? */ 24205b261ecSmrg defaultKeyboardControl.leds = g_winInfo.keyboard.leds; 24305b261ecSmrg#else 24405b261ecSmrg defaultKeyboardControl.leds = g_winInfo.keyboard.leds; 24505b261ecSmrg#endif 24605b261ecSmrg 24705b261ecSmrg#ifdef XKB 24805b261ecSmrg if (g_winInfo.xkb.disable) 24905b261ecSmrg { 25005b261ecSmrg#endif 25105b261ecSmrg InitKeyboardDeviceStruct (pDevice, 25205b261ecSmrg &keySyms, 25305b261ecSmrg modMap, 25405b261ecSmrg winKeybdBell, 25505b261ecSmrg winKeybdCtrl); 25605b261ecSmrg#ifdef XKB 25705b261ecSmrg } 25805b261ecSmrg else 25905b261ecSmrg { 26005b261ecSmrg 26105b261ecSmrg names.keymap = g_winInfo.xkb.keymap; 26205b261ecSmrg names.keycodes = g_winInfo.xkb.keycodes; 26305b261ecSmrg names.types = g_winInfo.xkb.types; 26405b261ecSmrg names.compat = g_winInfo.xkb.compat; 26505b261ecSmrg names.symbols = g_winInfo.xkb.symbols; 26605b261ecSmrg names.geometry = g_winInfo.xkb.geometry; 26705b261ecSmrg 26805b261ecSmrg winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\"" 26905b261ecSmrg " Variant = \"%s\" Options = \"%s\"\n", 27005b261ecSmrg g_winInfo.xkb.rules, g_winInfo.xkb.model, 27105b261ecSmrg g_winInfo.xkb.layout, g_winInfo.xkb.variant, 27205b261ecSmrg g_winInfo.xkb.options); 27305b261ecSmrg 27405b261ecSmrg XkbSetRulesDflts (g_winInfo.xkb.rules, g_winInfo.xkb.model, 27505b261ecSmrg g_winInfo.xkb.layout, g_winInfo.xkb.variant, 27605b261ecSmrg g_winInfo.xkb.options); 27705b261ecSmrg XkbInitKeyboardDeviceStruct (pDeviceInt, &names, &keySyms, 27805b261ecSmrg modMap, winKeybdBell, winKeybdCtrl); 27905b261ecSmrg } 28005b261ecSmrg#endif 28105b261ecSmrg 28205b261ecSmrg#ifdef XKB 28305b261ecSmrg if (!g_winInfo.xkb.disable) 28405b261ecSmrg { 28505b261ecSmrg xkbi = pDeviceInt->key->xkbInfo; 28605b261ecSmrg if (xkbi != NULL) 28705b261ecSmrg { 28805b261ecSmrg ctrl = xkbi->desc->ctrls; 28905b261ecSmrg ctrl->repeat_delay = g_winInfo.keyboard.delay; 29005b261ecSmrg ctrl->repeat_interval = 1000/g_winInfo.keyboard.rate; 29105b261ecSmrg } 29205b261ecSmrg else 29305b261ecSmrg { 29405b261ecSmrg winErrorFVerb (1, "winKeybdProc - Error initializing keyboard AutoRepeat (No XKB)\n"); 29505b261ecSmrg } 29605b261ecSmrg } 29705b261ecSmrg#endif 29805b261ecSmrg 29905b261ecSmrg g_winInternalModeKeyStatesPtr = &(pDeviceInt->key->state); 30005b261ecSmrg break; 30105b261ecSmrg 30205b261ecSmrg case DEVICE_ON: 30305b261ecSmrg pDevice->on = TRUE; 30405b261ecSmrg g_winInternalModeKeyStatesPtr = &(pDeviceInt->key->state); 30505b261ecSmrg break; 30605b261ecSmrg 30705b261ecSmrg case DEVICE_CLOSE: 30805b261ecSmrg case DEVICE_OFF: 30905b261ecSmrg pDevice->on = FALSE; 31005b261ecSmrg g_winInternalModeKeyStatesPtr = NULL; 31105b261ecSmrg break; 31205b261ecSmrg } 31305b261ecSmrg 31405b261ecSmrg return Success; 31505b261ecSmrg} 31605b261ecSmrg 31705b261ecSmrg 31805b261ecSmrg/* 31905b261ecSmrg * Detect current mode key states upon server startup. 32005b261ecSmrg * 32105b261ecSmrg * Simulate a press and release of any key that is currently 32205b261ecSmrg * toggled. 32305b261ecSmrg */ 32405b261ecSmrg 32505b261ecSmrgvoid 32605b261ecSmrgwinInitializeModeKeyStates (void) 32705b261ecSmrg{ 32805b261ecSmrg /* Restore NumLock */ 32905b261ecSmrg if (GetKeyState (VK_NUMLOCK) & 0x0001) 33005b261ecSmrg { 33105b261ecSmrg winSendKeyEvent (KEY_NumLock, TRUE); 33205b261ecSmrg winSendKeyEvent (KEY_NumLock, FALSE); 33305b261ecSmrg } 33405b261ecSmrg 33505b261ecSmrg /* Restore CapsLock */ 33605b261ecSmrg if (GetKeyState (VK_CAPITAL) & 0x0001) 33705b261ecSmrg { 33805b261ecSmrg winSendKeyEvent (KEY_CapsLock, TRUE); 33905b261ecSmrg winSendKeyEvent (KEY_CapsLock, FALSE); 34005b261ecSmrg } 34105b261ecSmrg 34205b261ecSmrg /* Restore ScrollLock */ 34305b261ecSmrg if (GetKeyState (VK_SCROLL) & 0x0001) 34405b261ecSmrg { 34505b261ecSmrg winSendKeyEvent (KEY_ScrollLock, TRUE); 34605b261ecSmrg winSendKeyEvent (KEY_ScrollLock, FALSE); 34705b261ecSmrg } 34805b261ecSmrg 34905b261ecSmrg /* Restore KanaLock */ 35005b261ecSmrg if (GetKeyState (VK_KANA) & 0x0001) 35105b261ecSmrg { 35205b261ecSmrg winSendKeyEvent (KEY_HKTG, TRUE); 35305b261ecSmrg winSendKeyEvent (KEY_HKTG, FALSE); 35405b261ecSmrg } 35505b261ecSmrg} 35605b261ecSmrg 35705b261ecSmrg 35805b261ecSmrg/* 35905b261ecSmrg * Upon regaining the keyboard focus we must 36005b261ecSmrg * resynchronize our internal mode key states 36105b261ecSmrg * with the actual state of the keys. 36205b261ecSmrg */ 36305b261ecSmrg 36405b261ecSmrgvoid 36505b261ecSmrgwinRestoreModeKeyStates () 36605b261ecSmrg{ 36705b261ecSmrg DWORD dwKeyState; 36805b261ecSmrg BOOL processEvents = TRUE; 36905b261ecSmrg unsigned short internalKeyStates; 37005b261ecSmrg 37105b261ecSmrg /* X server is being initialized */ 37205b261ecSmrg if (!g_winInternalModeKeyStatesPtr) 37305b261ecSmrg return; 37405b261ecSmrg 37505b261ecSmrg /* Only process events if the rootwindow is mapped. The keyboard events 37605b261ecSmrg * will cause segfaults otherwise */ 37705b261ecSmrg if (WindowTable && WindowTable[0] && WindowTable[0]->mapped == FALSE) 37805b261ecSmrg processEvents = FALSE; 37905b261ecSmrg 38005b261ecSmrg /* Force to process all pending events in the mi event queue */ 38105b261ecSmrg if (processEvents) 38205b261ecSmrg mieqProcessInputEvents (); 38305b261ecSmrg 38405b261ecSmrg /* Read the mode key states of our X server */ 38505b261ecSmrg internalKeyStates = *g_winInternalModeKeyStatesPtr; 38605b261ecSmrg 38705b261ecSmrg /* 38805b261ecSmrg * NOTE: The C XOR operator, ^, will not work here because it is 38905b261ecSmrg * a bitwise operator, not a logical operator. C does not 39005b261ecSmrg * have a logical XOR operator, so we use a macro instead. 39105b261ecSmrg */ 39205b261ecSmrg 39305b261ecSmrg /* Has the key state changed? */ 39405b261ecSmrg dwKeyState = GetKeyState (VK_NUMLOCK) & 0x0001; 39505b261ecSmrg if (WIN_XOR (internalKeyStates & NumLockMask, dwKeyState)) 39605b261ecSmrg { 39705b261ecSmrg winSendKeyEvent (KEY_NumLock, TRUE); 39805b261ecSmrg winSendKeyEvent (KEY_NumLock, FALSE); 39905b261ecSmrg } 40005b261ecSmrg 40105b261ecSmrg /* Has the key state changed? */ 40205b261ecSmrg dwKeyState = GetKeyState (VK_CAPITAL) & 0x0001; 40305b261ecSmrg if (WIN_XOR (internalKeyStates & LockMask, dwKeyState)) 40405b261ecSmrg { 40505b261ecSmrg winSendKeyEvent (KEY_CapsLock, TRUE); 40605b261ecSmrg winSendKeyEvent (KEY_CapsLock, FALSE); 40705b261ecSmrg } 40805b261ecSmrg 40905b261ecSmrg /* Has the key state changed? */ 41005b261ecSmrg dwKeyState = GetKeyState (VK_SCROLL) & 0x0001; 41105b261ecSmrg if (WIN_XOR (internalKeyStates & ScrollLockMask, dwKeyState)) 41205b261ecSmrg { 41305b261ecSmrg winSendKeyEvent (KEY_ScrollLock, TRUE); 41405b261ecSmrg winSendKeyEvent (KEY_ScrollLock, FALSE); 41505b261ecSmrg } 41605b261ecSmrg 41705b261ecSmrg /* Has the key state changed? */ 41805b261ecSmrg dwKeyState = GetKeyState (VK_KANA) & 0x0001; 41905b261ecSmrg if (WIN_XOR (internalKeyStates & KanaMask, dwKeyState)) 42005b261ecSmrg { 42105b261ecSmrg winSendKeyEvent (KEY_HKTG, TRUE); 42205b261ecSmrg winSendKeyEvent (KEY_HKTG, FALSE); 42305b261ecSmrg } 42405b261ecSmrg} 42505b261ecSmrg 42605b261ecSmrg 42705b261ecSmrg/* 42805b261ecSmrg * Look for the lovely fake Control_L press/release generated by Windows 42905b261ecSmrg * when AltGr is pressed/released on a non-U.S. keyboard. 43005b261ecSmrg */ 43105b261ecSmrg 43205b261ecSmrgBool 43305b261ecSmrgwinIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) 43405b261ecSmrg{ 43505b261ecSmrg MSG msgNext; 43605b261ecSmrg LONG lTime; 43705b261ecSmrg Bool fReturn; 43805b261ecSmrg 43905b261ecSmrg /* 44005b261ecSmrg * Fake Ctrl_L presses will be followed by an Alt_R keypress 44105b261ecSmrg * with the same timestamp as the Ctrl_L press. 44205b261ecSmrg */ 44305b261ecSmrg if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) 44405b261ecSmrg && wParam == VK_CONTROL 44505b261ecSmrg && (HIWORD (lParam) & KF_EXTENDED) == 0) 44605b261ecSmrg { 44705b261ecSmrg /* Got a Ctrl_L press */ 44805b261ecSmrg 44905b261ecSmrg /* Get time of current message */ 45005b261ecSmrg lTime = GetMessageTime (); 45105b261ecSmrg 45205b261ecSmrg /* Look for fake Ctrl_L preceeding an Alt_R press. */ 45305b261ecSmrg fReturn = PeekMessage (&msgNext, NULL, 45405b261ecSmrg WM_KEYDOWN, WM_SYSKEYDOWN, 45505b261ecSmrg PM_NOREMOVE); 45605b261ecSmrg 45705b261ecSmrg /* 45805b261ecSmrg * Try again if the first call fails. 45905b261ecSmrg * NOTE: This usually happens when TweakUI is enabled. 46005b261ecSmrg */ 46105b261ecSmrg if (!fReturn) 46205b261ecSmrg { 46305b261ecSmrg /* Voodoo to make sure that the Alt_R message has posted */ 46405b261ecSmrg Sleep (0); 46505b261ecSmrg 46605b261ecSmrg /* Look for fake Ctrl_L preceeding an Alt_R press. */ 46705b261ecSmrg fReturn = PeekMessage (&msgNext, NULL, 46805b261ecSmrg WM_KEYDOWN, WM_SYSKEYDOWN, 46905b261ecSmrg PM_NOREMOVE); 47005b261ecSmrg } 47105b261ecSmrg if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN) 47205b261ecSmrg fReturn = 0; 47305b261ecSmrg 47405b261ecSmrg /* Is next press an Alt_R with the same timestamp? */ 47505b261ecSmrg if (fReturn && msgNext.wParam == VK_MENU 47605b261ecSmrg && msgNext.time == lTime 47705b261ecSmrg && (HIWORD (msgNext.lParam) & KF_EXTENDED)) 47805b261ecSmrg { 47905b261ecSmrg /* 48005b261ecSmrg * Next key press is Alt_R with same timestamp as current 48105b261ecSmrg * Ctrl_L message. Therefore, this Ctrl_L press is a fake 48205b261ecSmrg * event, so discard it. 48305b261ecSmrg */ 48405b261ecSmrg return TRUE; 48505b261ecSmrg } 48605b261ecSmrg } 48705b261ecSmrg 48805b261ecSmrg /* 48905b261ecSmrg * Fake Ctrl_L releases will be followed by an Alt_R release 49005b261ecSmrg * with the same timestamp as the Ctrl_L release. 49105b261ecSmrg */ 49205b261ecSmrg if ((message == WM_KEYUP || message == WM_SYSKEYUP) 49305b261ecSmrg && wParam == VK_CONTROL 49405b261ecSmrg && (HIWORD (lParam) & KF_EXTENDED) == 0) 49505b261ecSmrg { 49605b261ecSmrg /* Got a Ctrl_L release */ 49705b261ecSmrg 49805b261ecSmrg /* Get time of current message */ 49905b261ecSmrg lTime = GetMessageTime (); 50005b261ecSmrg 50105b261ecSmrg /* Look for fake Ctrl_L release preceeding an Alt_R release. */ 50205b261ecSmrg fReturn = PeekMessage (&msgNext, NULL, 50305b261ecSmrg WM_KEYUP, WM_SYSKEYUP, 50405b261ecSmrg PM_NOREMOVE); 50505b261ecSmrg 50605b261ecSmrg /* 50705b261ecSmrg * Try again if the first call fails. 50805b261ecSmrg * NOTE: This usually happens when TweakUI is enabled. 50905b261ecSmrg */ 51005b261ecSmrg if (!fReturn) 51105b261ecSmrg { 51205b261ecSmrg /* Voodoo to make sure that the Alt_R message has posted */ 51305b261ecSmrg Sleep (0); 51405b261ecSmrg 51505b261ecSmrg /* Look for fake Ctrl_L release preceeding an Alt_R release. */ 51605b261ecSmrg fReturn = PeekMessage (&msgNext, NULL, 51705b261ecSmrg WM_KEYUP, WM_SYSKEYUP, 51805b261ecSmrg PM_NOREMOVE); 51905b261ecSmrg } 52005b261ecSmrg 52105b261ecSmrg if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP) 52205b261ecSmrg fReturn = 0; 52305b261ecSmrg 52405b261ecSmrg /* Is next press an Alt_R with the same timestamp? */ 52505b261ecSmrg if (fReturn 52605b261ecSmrg && (msgNext.message == WM_KEYUP 52705b261ecSmrg || msgNext.message == WM_SYSKEYUP) 52805b261ecSmrg && msgNext.wParam == VK_MENU 52905b261ecSmrg && msgNext.time == lTime 53005b261ecSmrg && (HIWORD (msgNext.lParam) & KF_EXTENDED)) 53105b261ecSmrg { 53205b261ecSmrg /* 53305b261ecSmrg * Next key release is Alt_R with same timestamp as current 53405b261ecSmrg * Ctrl_L message. Therefore, this Ctrl_L release is a fake 53505b261ecSmrg * event, so discard it. 53605b261ecSmrg */ 53705b261ecSmrg return TRUE; 53805b261ecSmrg } 53905b261ecSmrg } 54005b261ecSmrg 54105b261ecSmrg /* Not a fake control left press/release */ 54205b261ecSmrg return FALSE; 54305b261ecSmrg} 54405b261ecSmrg 54505b261ecSmrg 54605b261ecSmrg/* 54705b261ecSmrg * Lift any modifier keys that are pressed 54805b261ecSmrg */ 54905b261ecSmrg 55005b261ecSmrgvoid 55105b261ecSmrgwinKeybdReleaseKeys () 55205b261ecSmrg{ 55305b261ecSmrg int i; 55405b261ecSmrg 55505b261ecSmrg#ifdef HAS_DEVWINDOWS 55605b261ecSmrg /* Verify that the mi input system has been initialized */ 55705b261ecSmrg if (g_fdMessageQueue == WIN_FD_INVALID) 55805b261ecSmrg return; 55905b261ecSmrg#endif 56005b261ecSmrg 56105b261ecSmrg /* Loop through all keys */ 56205b261ecSmrg for (i = 0; i < NUM_KEYCODES; ++i) 56305b261ecSmrg { 56405b261ecSmrg /* Pop key if pressed */ 56505b261ecSmrg if (g_winKeyState[i]) 56605b261ecSmrg winSendKeyEvent (i, FALSE); 56705b261ecSmrg 56805b261ecSmrg /* Reset pressed flag for keys */ 56905b261ecSmrg g_winKeyState[i] = FALSE; 57005b261ecSmrg } 57105b261ecSmrg} 57205b261ecSmrg 57305b261ecSmrg 57405b261ecSmrg/* 57505b261ecSmrg * Take a raw X key code and send an up or down event for it. 57605b261ecSmrg * 57705b261ecSmrg * Thanks to VNC for inspiration, though it is a simple function. 57805b261ecSmrg */ 57905b261ecSmrg 58005b261ecSmrgvoid 58105b261ecSmrgwinSendKeyEvent (DWORD dwKey, Bool fDown) 58205b261ecSmrg{ 58305b261ecSmrg xEvent xCurrentEvent; 58405b261ecSmrg 58505b261ecSmrg /* 58605b261ecSmrg * When alt-tabing between screens we can get phantom key up messages 58705b261ecSmrg * Here we only pass them through it we think we should! 58805b261ecSmrg */ 58905b261ecSmrg if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) return; 59005b261ecSmrg 59105b261ecSmrg /* Update the keyState map */ 59205b261ecSmrg g_winKeyState[dwKey] = fDown; 59305b261ecSmrg 59405b261ecSmrg ZeroMemory (&xCurrentEvent, sizeof (xCurrentEvent)); 59505b261ecSmrg 59605b261ecSmrg xCurrentEvent.u.u.type = fDown ? KeyPress : KeyRelease; 59705b261ecSmrg xCurrentEvent.u.keyButtonPointer.time = 59805b261ecSmrg g_c32LastInputEventTime = GetTickCount (); 59905b261ecSmrg xCurrentEvent.u.u.detail = dwKey + MIN_KEYCODE; 60005b261ecSmrg mieqEnqueue (&xCurrentEvent); 60105b261ecSmrg} 60205b261ecSmrg 60305b261ecSmrgBOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam) 60405b261ecSmrg{ 60505b261ecSmrg switch (wParam) 60605b261ecSmrg { 60705b261ecSmrg case VK_CONTROL: 60805b261ecSmrg if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl]) 60905b261ecSmrg return TRUE; 61005b261ecSmrg if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl]) 61105b261ecSmrg return TRUE; 61205b261ecSmrg break; 61305b261ecSmrg case VK_SHIFT: 61405b261ecSmrg if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR]) 61505b261ecSmrg return TRUE; 61605b261ecSmrg if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL]) 61705b261ecSmrg return TRUE; 61805b261ecSmrg break; 61905b261ecSmrg default: 62005b261ecSmrg return TRUE; 62105b261ecSmrg } 62205b261ecSmrg return FALSE; 62305b261ecSmrg} 62405b261ecSmrg 62505b261ecSmrg/* Only on shift release message is sent even if both are pressed. 62605b261ecSmrg * Fix this here 62705b261ecSmrg */ 62805b261ecSmrgvoid winFixShiftKeys (int iScanCode) 62905b261ecSmrg{ 63005b261ecSmrg if (GetKeyState (VK_SHIFT) & 0x8000) 63105b261ecSmrg return; 63205b261ecSmrg 63305b261ecSmrg if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR]) 63405b261ecSmrg winSendKeyEvent (KEY_ShiftR, FALSE); 63505b261ecSmrg if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL]) 63605b261ecSmrg winSendKeyEvent (KEY_ShiftL, FALSE); 63705b261ecSmrg} 638