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