winkeybd.c revision 6747b715
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
436747b715Smrg#include "xkbsrv.h"
4405b261ecSmrg
4505b261ecSmrgstatic Bool g_winKeyState[NUM_KEYCODES];
4605b261ecSmrg
4705b261ecSmrg/*
4805b261ecSmrg * Local prototypes
4905b261ecSmrg */
5005b261ecSmrg
5105b261ecSmrgstatic void
5205b261ecSmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
5305b261ecSmrg	      pointer pCtrl, int iClass);
5405b261ecSmrg
5505b261ecSmrgstatic void
5605b261ecSmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl);
5705b261ecSmrg
5805b261ecSmrg
5905b261ecSmrg/*
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
6805b261ecSmrgvoid
6905b261ecSmrgwinTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode)
7005b261ecSmrg{
7105b261ecSmrg  int		iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
7205b261ecSmrg  int		iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
736747b715Smrg  int		iParam = HIWORD (lParam);
746747b715Smrg  int		iParamScanCode = LOBYTE (iParam);
756747b715Smrg
766747b715Smrg/* WM_ key messages faked by Vista speech recognition (WSR) don't have a
776747b715Smrg * scan code.
786747b715Smrg *
796747b715Smrg * Vocola 3 (Rick Mohr's supplement to WSR) uses
806747b715Smrg * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a
816747b715Smrg * scan code of 1
826747b715Smrg */
836747b715Smrg  if (iParamScanCode <= 1)
846747b715Smrg    {
856747b715Smrg      if (VK_PRIOR <= wParam && wParam <= VK_DOWN)
866747b715Smrg        /* Trigger special case table to translate to extended
876747b715Smrg         * keycode, otherwise if num_lock is on, we can get keypad
886747b715Smrg         * numbers instead of navigation keys. */
896747b715Smrg        iParam |= KF_EXTENDED;
906747b715Smrg      else
916747b715Smrg        iParamScanCode = MapVirtualKeyEx(wParam,
926747b715Smrg                         /*MAPVK_VK_TO_VSC*/0,
936747b715Smrg                         GetKeyboardLayout(0));
946747b715Smrg    }
9505b261ecSmrg
9605b261ecSmrg  /* Branch on special extended, special non-extended, or normal key */
976747b715Smrg  if ((iParam & KF_EXTENDED) && iKeyFixupEx)
9805b261ecSmrg    *piScanCode = iKeyFixupEx;
9905b261ecSmrg  else if (iKeyFixup)
10005b261ecSmrg    *piScanCode = iKeyFixup;
10105b261ecSmrg  else if (wParam == 0 && iParamScanCode == 0x70)
10205b261ecSmrg    *piScanCode = KEY_HKTG;
10305b261ecSmrg  else
10405b261ecSmrg    switch (iParamScanCode)
10505b261ecSmrg    {
10605b261ecSmrg      case 0x70:
10705b261ecSmrg        *piScanCode = KEY_HKTG;
10805b261ecSmrg        break;
10905b261ecSmrg      case 0x73:
11005b261ecSmrg        *piScanCode = KEY_BSlash2;
11105b261ecSmrg        break;
11205b261ecSmrg      default:
11305b261ecSmrg        *piScanCode = iParamScanCode;
11405b261ecSmrg        break;
11505b261ecSmrg    }
11605b261ecSmrg}
11705b261ecSmrg
11805b261ecSmrg
11905b261ecSmrg/* Ring the keyboard bell (system speaker on PCs) */
12005b261ecSmrgstatic void
12105b261ecSmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
12205b261ecSmrg	      pointer pCtrl, int iClass)
12305b261ecSmrg{
12405b261ecSmrg  /*
12505b261ecSmrg   * We can't use Beep () here because it uses the PC speaker
12605b261ecSmrg   * on NT/2000.  MessageBeep (MB_OK) will play the default system
12705b261ecSmrg   * sound on systems with a sound card or it will beep the PC speaker
12805b261ecSmrg   * on systems that do not have a sound card.
12905b261ecSmrg   */
13005b261ecSmrg  MessageBeep (MB_OK);
13105b261ecSmrg}
13205b261ecSmrg
13305b261ecSmrg
13405b261ecSmrg/* Change some keyboard configuration parameters */
13505b261ecSmrgstatic void
13605b261ecSmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl)
13705b261ecSmrg{
13805b261ecSmrg}
13905b261ecSmrg
14005b261ecSmrg
14105b261ecSmrg/*
14205b261ecSmrg * See Porting Layer Definition - p. 18
14305b261ecSmrg * winKeybdProc is known as a DeviceProc.
14405b261ecSmrg */
14505b261ecSmrg
14605b261ecSmrgint
14705b261ecSmrgwinKeybdProc (DeviceIntPtr pDeviceInt, int iState)
14805b261ecSmrg{
14905b261ecSmrg  DevicePtr		pDevice = (DevicePtr) pDeviceInt;
15005b261ecSmrg  XkbSrvInfoPtr       xkbi;
15105b261ecSmrg  XkbControlsPtr      ctrl;
15205b261ecSmrg
15305b261ecSmrg  switch (iState)
15405b261ecSmrg    {
15505b261ecSmrg    case DEVICE_INIT:
15605b261ecSmrg      winConfigKeyboard (pDeviceInt);
15705b261ecSmrg
15805b261ecSmrg      /* FIXME: Maybe we should use winGetKbdLeds () here? */
15905b261ecSmrg      defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
16005b261ecSmrg
1616747b715Smrg      winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
1626747b715Smrg                    " Variant = \"%s\" Options = \"%s\"\n",
1636747b715Smrg                    g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none",
1646747b715Smrg                    g_winInfo.xkb.model ? g_winInfo.xkb.model : "none",
1656747b715Smrg                    g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none",
1666747b715Smrg                    g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none",
1676747b715Smrg                    g_winInfo.xkb.options ? g_winInfo.xkb.options : "none");
1686747b715Smrg
1696747b715Smrg      InitKeyboardDeviceStruct (pDeviceInt,
1706747b715Smrg                                &g_winInfo.xkb,
1716747b715Smrg                                winKeybdBell,
1726747b715Smrg                                winKeybdCtrl);
1736747b715Smrg
1746747b715Smrg      xkbi = pDeviceInt->key->xkbInfo;
1756747b715Smrg      if ((xkbi != NULL) && (xkbi->desc != NULL))
1766747b715Smrg        {
1776747b715Smrg          ctrl = xkbi->desc->ctrls;
1786747b715Smrg          ctrl->repeat_delay = g_winInfo.keyboard.delay;
1796747b715Smrg          ctrl->repeat_interval = 1000/g_winInfo.keyboard.rate;
1806747b715Smrg        }
1816747b715Smrg      else
1826747b715Smrg        {
1836747b715Smrg          winErrorFVerb (1, "winKeybdProc - Error initializing keyboard AutoRepeat\n");
18405b261ecSmrg        }
18505b261ecSmrg
18605b261ecSmrg      break;
18705b261ecSmrg
18805b261ecSmrg    case DEVICE_ON:
18905b261ecSmrg      pDevice->on = TRUE;
1906747b715Smrg
1916747b715Smrg      // immediately copy the state of this keyboard device to the VCK
1926747b715Smrg      // (which otherwise happens lazily after the first keypress)
1936747b715Smrg      CopyKeyClass(pDeviceInt, inputInfo.keyboard);
19405b261ecSmrg      break;
19505b261ecSmrg
19605b261ecSmrg    case DEVICE_CLOSE:
19705b261ecSmrg    case DEVICE_OFF:
19805b261ecSmrg      pDevice->on = FALSE;
19905b261ecSmrg      break;
20005b261ecSmrg    }
20105b261ecSmrg
20205b261ecSmrg  return Success;
20305b261ecSmrg}
20405b261ecSmrg
20505b261ecSmrg
20605b261ecSmrg/*
20705b261ecSmrg * Detect current mode key states upon server startup.
20805b261ecSmrg *
20905b261ecSmrg * Simulate a press and release of any key that is currently
21005b261ecSmrg * toggled.
21105b261ecSmrg */
21205b261ecSmrg
21305b261ecSmrgvoid
21405b261ecSmrgwinInitializeModeKeyStates (void)
21505b261ecSmrg{
21605b261ecSmrg  /* Restore NumLock */
21705b261ecSmrg  if (GetKeyState (VK_NUMLOCK) & 0x0001)
21805b261ecSmrg    {
21905b261ecSmrg      winSendKeyEvent (KEY_NumLock, TRUE);
22005b261ecSmrg      winSendKeyEvent (KEY_NumLock, FALSE);
22105b261ecSmrg    }
22205b261ecSmrg
22305b261ecSmrg  /* Restore CapsLock */
22405b261ecSmrg  if (GetKeyState (VK_CAPITAL) & 0x0001)
22505b261ecSmrg    {
22605b261ecSmrg      winSendKeyEvent (KEY_CapsLock, TRUE);
22705b261ecSmrg      winSendKeyEvent (KEY_CapsLock, FALSE);
22805b261ecSmrg    }
22905b261ecSmrg
23005b261ecSmrg  /* Restore ScrollLock */
23105b261ecSmrg  if (GetKeyState (VK_SCROLL) & 0x0001)
23205b261ecSmrg    {
23305b261ecSmrg      winSendKeyEvent (KEY_ScrollLock, TRUE);
23405b261ecSmrg      winSendKeyEvent (KEY_ScrollLock, FALSE);
23505b261ecSmrg    }
23605b261ecSmrg
23705b261ecSmrg  /* Restore KanaLock */
23805b261ecSmrg  if (GetKeyState (VK_KANA) & 0x0001)
23905b261ecSmrg    {
24005b261ecSmrg      winSendKeyEvent (KEY_HKTG, TRUE);
24105b261ecSmrg      winSendKeyEvent (KEY_HKTG, FALSE);
24205b261ecSmrg    }
24305b261ecSmrg}
24405b261ecSmrg
24505b261ecSmrg
24605b261ecSmrg/*
24705b261ecSmrg * Upon regaining the keyboard focus we must
24805b261ecSmrg * resynchronize our internal mode key states
24905b261ecSmrg * with the actual state of the keys.
25005b261ecSmrg */
25105b261ecSmrg
25205b261ecSmrgvoid
2536747b715SmrgwinRestoreModeKeyStates (void)
25405b261ecSmrg{
25505b261ecSmrg  DWORD			dwKeyState;
25605b261ecSmrg  BOOL			processEvents = TRUE;
25705b261ecSmrg  unsigned short	internalKeyStates;
25805b261ecSmrg
25905b261ecSmrg  /* X server is being initialized */
2606747b715Smrg  if (!inputInfo.keyboard)
26105b261ecSmrg    return;
26205b261ecSmrg
26305b261ecSmrg  /* Only process events if the rootwindow is mapped. The keyboard events
26405b261ecSmrg   * will cause segfaults otherwise */
2656747b715Smrg  if (screenInfo.screens[0]->root && screenInfo.screens[0]->root->mapped == FALSE)
26605b261ecSmrg    processEvents = FALSE;
26705b261ecSmrg
26805b261ecSmrg  /* Force to process all pending events in the mi event queue */
26905b261ecSmrg  if (processEvents)
27005b261ecSmrg    mieqProcessInputEvents ();
27105b261ecSmrg
27205b261ecSmrg  /* Read the mode key states of our X server */
2736747b715Smrg  /* (stored in the virtual core keyboard) */
2746747b715Smrg  internalKeyStates = XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state);
2756747b715Smrg  winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates);
27605b261ecSmrg
27705b261ecSmrg  /*
27805b261ecSmrg   * NOTE: The C XOR operator, ^, will not work here because it is
27905b261ecSmrg   * a bitwise operator, not a logical operator.  C does not
28005b261ecSmrg   * have a logical XOR operator, so we use a macro instead.
28105b261ecSmrg   */
28205b261ecSmrg
28305b261ecSmrg  /* Has the key state changed? */
28405b261ecSmrg  dwKeyState = GetKeyState (VK_NUMLOCK) & 0x0001;
28505b261ecSmrg  if (WIN_XOR (internalKeyStates & NumLockMask, dwKeyState))
28605b261ecSmrg    {
28705b261ecSmrg      winSendKeyEvent (KEY_NumLock, TRUE);
28805b261ecSmrg      winSendKeyEvent (KEY_NumLock, FALSE);
28905b261ecSmrg    }
29005b261ecSmrg
29105b261ecSmrg  /* Has the key state changed? */
29205b261ecSmrg  dwKeyState = GetKeyState (VK_CAPITAL) & 0x0001;
29305b261ecSmrg  if (WIN_XOR (internalKeyStates & LockMask, dwKeyState))
29405b261ecSmrg    {
29505b261ecSmrg      winSendKeyEvent (KEY_CapsLock, TRUE);
29605b261ecSmrg      winSendKeyEvent (KEY_CapsLock, FALSE);
29705b261ecSmrg    }
29805b261ecSmrg
29905b261ecSmrg  /* Has the key state changed? */
30005b261ecSmrg  dwKeyState = GetKeyState (VK_SCROLL) & 0x0001;
30105b261ecSmrg  if (WIN_XOR (internalKeyStates & ScrollLockMask, dwKeyState))
30205b261ecSmrg    {
30305b261ecSmrg      winSendKeyEvent (KEY_ScrollLock, TRUE);
30405b261ecSmrg      winSendKeyEvent (KEY_ScrollLock, FALSE);
30505b261ecSmrg    }
30605b261ecSmrg
30705b261ecSmrg  /* Has the key state changed? */
30805b261ecSmrg  dwKeyState = GetKeyState (VK_KANA) & 0x0001;
30905b261ecSmrg  if (WIN_XOR (internalKeyStates & KanaMask, dwKeyState))
31005b261ecSmrg    {
31105b261ecSmrg      winSendKeyEvent (KEY_HKTG, TRUE);
31205b261ecSmrg      winSendKeyEvent (KEY_HKTG, FALSE);
31305b261ecSmrg    }
31405b261ecSmrg}
31505b261ecSmrg
31605b261ecSmrg
31705b261ecSmrg/*
31805b261ecSmrg * Look for the lovely fake Control_L press/release generated by Windows
31905b261ecSmrg * when AltGr is pressed/released on a non-U.S. keyboard.
32005b261ecSmrg */
32105b261ecSmrg
32205b261ecSmrgBool
32305b261ecSmrgwinIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam)
32405b261ecSmrg{
32505b261ecSmrg  MSG		msgNext;
32605b261ecSmrg  LONG		lTime;
32705b261ecSmrg  Bool		fReturn;
32805b261ecSmrg
32905b261ecSmrg  /*
33005b261ecSmrg   * Fake Ctrl_L presses will be followed by an Alt_R keypress
33105b261ecSmrg   * with the same timestamp as the Ctrl_L press.
33205b261ecSmrg   */
33305b261ecSmrg  if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
33405b261ecSmrg      && wParam == VK_CONTROL
33505b261ecSmrg      && (HIWORD (lParam) & KF_EXTENDED) == 0)
33605b261ecSmrg    {
33705b261ecSmrg      /* Got a Ctrl_L press */
33805b261ecSmrg
33905b261ecSmrg      /* Get time of current message */
34005b261ecSmrg      lTime = GetMessageTime ();
34105b261ecSmrg
34205b261ecSmrg      /* Look for fake Ctrl_L preceeding an Alt_R press. */
34305b261ecSmrg      fReturn = PeekMessage (&msgNext, NULL,
34405b261ecSmrg			     WM_KEYDOWN, WM_SYSKEYDOWN,
34505b261ecSmrg			     PM_NOREMOVE);
34605b261ecSmrg
34705b261ecSmrg      /*
34805b261ecSmrg       * Try again if the first call fails.
34905b261ecSmrg       * NOTE: This usually happens when TweakUI is enabled.
35005b261ecSmrg       */
35105b261ecSmrg      if (!fReturn)
35205b261ecSmrg	{
35305b261ecSmrg	  /* Voodoo to make sure that the Alt_R message has posted */
35405b261ecSmrg	  Sleep (0);
35505b261ecSmrg
35605b261ecSmrg	  /* Look for fake Ctrl_L preceeding an Alt_R press. */
35705b261ecSmrg	  fReturn = PeekMessage (&msgNext, NULL,
35805b261ecSmrg				 WM_KEYDOWN, WM_SYSKEYDOWN,
35905b261ecSmrg				 PM_NOREMOVE);
36005b261ecSmrg	}
36105b261ecSmrg      if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN)
36205b261ecSmrg          fReturn = 0;
36305b261ecSmrg
36405b261ecSmrg      /* Is next press an Alt_R with the same timestamp? */
36505b261ecSmrg      if (fReturn && msgNext.wParam == VK_MENU
36605b261ecSmrg	  && msgNext.time == lTime
36705b261ecSmrg	  && (HIWORD (msgNext.lParam) & KF_EXTENDED))
36805b261ecSmrg	{
36905b261ecSmrg	  /*
37005b261ecSmrg	   * Next key press is Alt_R with same timestamp as current
37105b261ecSmrg	   * Ctrl_L message.  Therefore, this Ctrl_L press is a fake
37205b261ecSmrg	   * event, so discard it.
37305b261ecSmrg	   */
37405b261ecSmrg	  return TRUE;
37505b261ecSmrg	}
37605b261ecSmrg    }
37705b261ecSmrg
37805b261ecSmrg  /*
37905b261ecSmrg   * Fake Ctrl_L releases will be followed by an Alt_R release
38005b261ecSmrg   * with the same timestamp as the Ctrl_L release.
38105b261ecSmrg   */
38205b261ecSmrg  if ((message == WM_KEYUP || message == WM_SYSKEYUP)
38305b261ecSmrg      && wParam == VK_CONTROL
38405b261ecSmrg      && (HIWORD (lParam) & KF_EXTENDED) == 0)
38505b261ecSmrg    {
38605b261ecSmrg      /* Got a Ctrl_L release */
38705b261ecSmrg
38805b261ecSmrg      /* Get time of current message */
38905b261ecSmrg      lTime = GetMessageTime ();
39005b261ecSmrg
39105b261ecSmrg      /* Look for fake Ctrl_L release preceeding an Alt_R release. */
39205b261ecSmrg      fReturn = PeekMessage (&msgNext, NULL,
39305b261ecSmrg			     WM_KEYUP, WM_SYSKEYUP,
39405b261ecSmrg			     PM_NOREMOVE);
39505b261ecSmrg
39605b261ecSmrg      /*
39705b261ecSmrg       * Try again if the first call fails.
39805b261ecSmrg       * NOTE: This usually happens when TweakUI is enabled.
39905b261ecSmrg       */
40005b261ecSmrg      if (!fReturn)
40105b261ecSmrg	{
40205b261ecSmrg	  /* Voodoo to make sure that the Alt_R message has posted */
40305b261ecSmrg	  Sleep (0);
40405b261ecSmrg
40505b261ecSmrg	  /* Look for fake Ctrl_L release preceeding an Alt_R release. */
40605b261ecSmrg	  fReturn = PeekMessage (&msgNext, NULL,
40705b261ecSmrg				 WM_KEYUP, WM_SYSKEYUP,
40805b261ecSmrg				 PM_NOREMOVE);
40905b261ecSmrg	}
41005b261ecSmrg
41105b261ecSmrg      if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP)
41205b261ecSmrg          fReturn = 0;
41305b261ecSmrg
41405b261ecSmrg      /* Is next press an Alt_R with the same timestamp? */
41505b261ecSmrg      if (fReturn
41605b261ecSmrg	  && (msgNext.message == WM_KEYUP
41705b261ecSmrg	      || msgNext.message == WM_SYSKEYUP)
41805b261ecSmrg	  && msgNext.wParam == VK_MENU
41905b261ecSmrg	  && msgNext.time == lTime
42005b261ecSmrg	  && (HIWORD (msgNext.lParam) & KF_EXTENDED))
42105b261ecSmrg	{
42205b261ecSmrg	  /*
42305b261ecSmrg	   * Next key release is Alt_R with same timestamp as current
42405b261ecSmrg	   * Ctrl_L message. Therefore, this Ctrl_L release is a fake
42505b261ecSmrg	   * event, so discard it.
42605b261ecSmrg	   */
42705b261ecSmrg	  return TRUE;
42805b261ecSmrg	}
42905b261ecSmrg    }
43005b261ecSmrg
43105b261ecSmrg  /* Not a fake control left press/release */
43205b261ecSmrg  return FALSE;
43305b261ecSmrg}
43405b261ecSmrg
43505b261ecSmrg
43605b261ecSmrg/*
43705b261ecSmrg * Lift any modifier keys that are pressed
43805b261ecSmrg */
43905b261ecSmrg
44005b261ecSmrgvoid
4416747b715SmrgwinKeybdReleaseKeys (void)
44205b261ecSmrg{
44305b261ecSmrg  int				i;
44405b261ecSmrg
44505b261ecSmrg#ifdef HAS_DEVWINDOWS
44605b261ecSmrg  /* Verify that the mi input system has been initialized */
44705b261ecSmrg  if (g_fdMessageQueue == WIN_FD_INVALID)
44805b261ecSmrg    return;
44905b261ecSmrg#endif
45005b261ecSmrg
45105b261ecSmrg  /* Loop through all keys */
45205b261ecSmrg  for (i = 0; i < NUM_KEYCODES; ++i)
45305b261ecSmrg    {
45405b261ecSmrg      /* Pop key if pressed */
45505b261ecSmrg      if (g_winKeyState[i])
45605b261ecSmrg	winSendKeyEvent (i, FALSE);
45705b261ecSmrg
45805b261ecSmrg      /* Reset pressed flag for keys */
45905b261ecSmrg      g_winKeyState[i] = FALSE;
46005b261ecSmrg    }
46105b261ecSmrg}
46205b261ecSmrg
46305b261ecSmrg
46405b261ecSmrg/*
46505b261ecSmrg * Take a raw X key code and send an up or down event for it.
46605b261ecSmrg *
46705b261ecSmrg * Thanks to VNC for inspiration, though it is a simple function.
46805b261ecSmrg */
46905b261ecSmrg
47005b261ecSmrgvoid
47105b261ecSmrgwinSendKeyEvent (DWORD dwKey, Bool fDown)
47205b261ecSmrg{
4736747b715Smrg  EventListPtr events;
4746747b715Smrg  int i, nevents;
47505b261ecSmrg
47605b261ecSmrg  /*
47705b261ecSmrg   * When alt-tabing between screens we can get phantom key up messages
47805b261ecSmrg   * Here we only pass them through it we think we should!
47905b261ecSmrg   */
48005b261ecSmrg  if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) return;
48105b261ecSmrg
48205b261ecSmrg  /* Update the keyState map */
48305b261ecSmrg  g_winKeyState[dwKey] = fDown;
48405b261ecSmrg
4856747b715Smrg  GetEventList(&events);
4866747b715Smrg  nevents = GetKeyboardEvents(events, g_pwinKeyboard, fDown ? KeyPress : KeyRelease, dwKey + MIN_KEYCODE);
4876747b715Smrg
4886747b715Smrg  for (i = 0; i < nevents; i++)
4896747b715Smrg    mieqEnqueue(g_pwinKeyboard, events[i].event);
4906747b715Smrg
4916747b715Smrg#if CYGDEBUG
4926747b715Smrg  ErrorF("winSendKeyEvent: dwKey: %d, fDown: %d, nEvents %d\n",
4936747b715Smrg          dwKey, fDown, nevents);
4946747b715Smrg#endif
49505b261ecSmrg}
49605b261ecSmrg
49705b261ecSmrgBOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
49805b261ecSmrg{
49905b261ecSmrg  switch (wParam)
50005b261ecSmrg  {
50105b261ecSmrg    case VK_CONTROL:
50205b261ecSmrg      if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
50305b261ecSmrg        return TRUE;
50405b261ecSmrg      if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
50505b261ecSmrg        return TRUE;
50605b261ecSmrg      break;
50705b261ecSmrg    case VK_SHIFT:
50805b261ecSmrg      if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
50905b261ecSmrg        return TRUE;
51005b261ecSmrg      if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
51105b261ecSmrg        return TRUE;
51205b261ecSmrg      break;
51305b261ecSmrg    default:
51405b261ecSmrg      return TRUE;
51505b261ecSmrg  }
51605b261ecSmrg  return FALSE;
51705b261ecSmrg}
51805b261ecSmrg
51905b261ecSmrg/* Only on shift release message is sent even if both are pressed.
52005b261ecSmrg * Fix this here
52105b261ecSmrg */
52205b261ecSmrgvoid winFixShiftKeys (int iScanCode)
52305b261ecSmrg{
52405b261ecSmrg  if (GetKeyState (VK_SHIFT) & 0x8000)
52505b261ecSmrg    return;
52605b261ecSmrg
52705b261ecSmrg  if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
52805b261ecSmrg    winSendKeyEvent (KEY_ShiftR, FALSE);
52905b261ecSmrg  if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
53005b261ecSmrg    winSendKeyEvent (KEY_ShiftL, FALSE);
53105b261ecSmrg}
532