1706f2543Smrg/*
2706f2543Smrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3706f2543Smrg *
4706f2543Smrg *Permission is hereby granted, free of charge, to any person obtaining
5706f2543Smrg * a copy of this software and associated documentation files (the
6706f2543Smrg *"Software"), to deal in the Software without restriction, including
7706f2543Smrg *without limitation the rights to use, copy, modify, merge, publish,
8706f2543Smrg *distribute, sublicense, and/or sell copies of the Software, and to
9706f2543Smrg *permit persons to whom the Software is furnished to do so, subject to
10706f2543Smrg *the following conditions:
11706f2543Smrg *
12706f2543Smrg *The above copyright notice and this permission notice shall be
13706f2543Smrg *included in all copies or substantial portions of the Software.
14706f2543Smrg *
15706f2543Smrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16706f2543Smrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17706f2543Smrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18706f2543Smrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19706f2543Smrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20706f2543Smrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21706f2543Smrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22706f2543Smrg *
23706f2543Smrg *Except as contained in this notice, the name of the XFree86 Project
24706f2543Smrg *shall not be used in advertising or otherwise to promote the sale, use
25706f2543Smrg *or other dealings in this Software without prior written authorization
26706f2543Smrg *from the XFree86 Project.
27706f2543Smrg *
28706f2543Smrg * Authors:	Dakshinamurthy Karra
29706f2543Smrg *		Suhaib M Siddiqi
30706f2543Smrg *		Peter Busch
31706f2543Smrg *		Harold L Hunt II
32706f2543Smrg */
33706f2543Smrg
34706f2543Smrg
35706f2543Smrg#ifdef HAVE_XWIN_CONFIG_H
36706f2543Smrg#include <xwin-config.h>
37706f2543Smrg#endif
38706f2543Smrg#include "win.h"
39706f2543Smrg#include "winkeybd.h"
40706f2543Smrg#include "winconfig.h"
41706f2543Smrg#include "winmsg.h"
42706f2543Smrg
43706f2543Smrg#include "xkbsrv.h"
44706f2543Smrg
45706f2543Smrgstatic Bool g_winKeyState[NUM_KEYCODES];
46706f2543Smrg
47706f2543Smrg/*
48706f2543Smrg * Local prototypes
49706f2543Smrg */
50706f2543Smrg
51706f2543Smrgstatic void
52706f2543SmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
53706f2543Smrg	      pointer pCtrl, int iClass);
54706f2543Smrg
55706f2543Smrgstatic void
56706f2543SmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl);
57706f2543Smrg
58706f2543Smrg
59706f2543Smrg/*
60706f2543Smrg * Translate a Windows WM_[SYS]KEY(UP/DOWN) message
61706f2543Smrg * into an ASCII scan code.
62706f2543Smrg *
63706f2543Smrg * We do this ourselves, rather than letting Windows handle it,
64706f2543Smrg * because Windows tends to munge the handling of special keys,
65706f2543Smrg * like AltGr on European keyboards.
66706f2543Smrg */
67706f2543Smrg
68706f2543Smrgvoid
69706f2543SmrgwinTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode)
70706f2543Smrg{
71706f2543Smrg  int		iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
72706f2543Smrg  int		iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
73706f2543Smrg  int		iParam = HIWORD (lParam);
74706f2543Smrg  int		iParamScanCode = LOBYTE (iParam);
75706f2543Smrg
76706f2543Smrg  winDebug("winTranslateKey: wParam %08x lParam %08x\n", wParam, lParam);
77706f2543Smrg
78706f2543Smrg/* WM_ key messages faked by Vista speech recognition (WSR) don't have a
79706f2543Smrg * scan code.
80706f2543Smrg *
81706f2543Smrg * Vocola 3 (Rick Mohr's supplement to WSR) uses
82706f2543Smrg * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a
83706f2543Smrg * scan code of 1
84706f2543Smrg */
85706f2543Smrg  if (iParamScanCode <= 1)
86706f2543Smrg    {
87706f2543Smrg      if (VK_PRIOR <= wParam && wParam <= VK_DOWN)
88706f2543Smrg        /* Trigger special case table to translate to extended
89706f2543Smrg         * keycode, otherwise if num_lock is on, we can get keypad
90706f2543Smrg         * numbers instead of navigation keys. */
91706f2543Smrg        iParam |= KF_EXTENDED;
92706f2543Smrg      else
93706f2543Smrg        iParamScanCode = MapVirtualKeyEx(wParam,
94706f2543Smrg                         /*MAPVK_VK_TO_VSC*/0,
95706f2543Smrg                         GetKeyboardLayout(0));
96706f2543Smrg    }
97706f2543Smrg
98706f2543Smrg  /* Branch on special extended, special non-extended, or normal key */
99706f2543Smrg  if ((iParam & KF_EXTENDED) && iKeyFixupEx)
100706f2543Smrg    *piScanCode = iKeyFixupEx;
101706f2543Smrg  else if (iKeyFixup)
102706f2543Smrg    *piScanCode = iKeyFixup;
103706f2543Smrg  else if (wParam == 0 && iParamScanCode == 0x70)
104706f2543Smrg    *piScanCode = KEY_HKTG;
105706f2543Smrg  else
106706f2543Smrg    switch (iParamScanCode)
107706f2543Smrg    {
108706f2543Smrg      case 0x70:
109706f2543Smrg        *piScanCode = KEY_HKTG;
110706f2543Smrg        break;
111706f2543Smrg      case 0x73:
112706f2543Smrg        *piScanCode = KEY_BSlash2;
113706f2543Smrg        break;
114706f2543Smrg      default:
115706f2543Smrg        *piScanCode = iParamScanCode;
116706f2543Smrg        break;
117706f2543Smrg    }
118706f2543Smrg}
119706f2543Smrg
120706f2543Smrg
121706f2543Smrg/* Ring the keyboard bell (system speaker on PCs) */
122706f2543Smrgstatic void
123706f2543SmrgwinKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
124706f2543Smrg	      pointer pCtrl, int iClass)
125706f2543Smrg{
126706f2543Smrg  /*
127706f2543Smrg   * We can't use Beep () here because it uses the PC speaker
128706f2543Smrg   * on NT/2000.  MessageBeep (MB_OK) will play the default system
129706f2543Smrg   * sound on systems with a sound card or it will beep the PC speaker
130706f2543Smrg   * on systems that do not have a sound card.
131706f2543Smrg   */
132706f2543Smrg  MessageBeep (MB_OK);
133706f2543Smrg}
134706f2543Smrg
135706f2543Smrg
136706f2543Smrg/* Change some keyboard configuration parameters */
137706f2543Smrgstatic void
138706f2543SmrgwinKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl)
139706f2543Smrg{
140706f2543Smrg}
141706f2543Smrg
142706f2543Smrg
143706f2543Smrg/*
144706f2543Smrg * See Porting Layer Definition - p. 18
145706f2543Smrg * winKeybdProc is known as a DeviceProc.
146706f2543Smrg */
147706f2543Smrg
148706f2543Smrgint
149706f2543SmrgwinKeybdProc (DeviceIntPtr pDeviceInt, int iState)
150706f2543Smrg{
151706f2543Smrg  DevicePtr		pDevice = (DevicePtr) pDeviceInt;
152706f2543Smrg  XkbSrvInfoPtr       xkbi;
153706f2543Smrg  XkbControlsPtr      ctrl;
154706f2543Smrg
155706f2543Smrg  switch (iState)
156706f2543Smrg    {
157706f2543Smrg    case DEVICE_INIT:
158706f2543Smrg      winConfigKeyboard (pDeviceInt);
159706f2543Smrg
160706f2543Smrg      /* FIXME: Maybe we should use winGetKbdLeds () here? */
161706f2543Smrg      defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
162706f2543Smrg
163706f2543Smrg      winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
164706f2543Smrg                    " Variant = \"%s\" Options = \"%s\"\n",
165706f2543Smrg                    g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none",
166706f2543Smrg                    g_winInfo.xkb.model ? g_winInfo.xkb.model : "none",
167706f2543Smrg                    g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none",
168706f2543Smrg                    g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none",
169706f2543Smrg                    g_winInfo.xkb.options ? g_winInfo.xkb.options : "none");
170706f2543Smrg
171706f2543Smrg      InitKeyboardDeviceStruct (pDeviceInt,
172706f2543Smrg                                &g_winInfo.xkb,
173706f2543Smrg                                winKeybdBell,
174706f2543Smrg                                winKeybdCtrl);
175706f2543Smrg
176706f2543Smrg      xkbi = pDeviceInt->key->xkbInfo;
177706f2543Smrg      if ((xkbi != NULL) && (xkbi->desc != NULL))
178706f2543Smrg        {
179706f2543Smrg          ctrl = xkbi->desc->ctrls;
180706f2543Smrg          ctrl->repeat_delay = g_winInfo.keyboard.delay;
181706f2543Smrg          ctrl->repeat_interval = 1000/g_winInfo.keyboard.rate;
182706f2543Smrg        }
183706f2543Smrg      else
184706f2543Smrg        {
185706f2543Smrg          winErrorFVerb (1, "winKeybdProc - Error initializing keyboard AutoRepeat\n");
186706f2543Smrg        }
187706f2543Smrg
188706f2543Smrg      break;
189706f2543Smrg
190706f2543Smrg    case DEVICE_ON:
191706f2543Smrg      pDevice->on = TRUE;
192706f2543Smrg
193706f2543Smrg      // immediately copy the state of this keyboard device to the VCK
194706f2543Smrg      // (which otherwise happens lazily after the first keypress)
195706f2543Smrg      CopyKeyClass(pDeviceInt, inputInfo.keyboard);
196706f2543Smrg      break;
197706f2543Smrg
198706f2543Smrg    case DEVICE_CLOSE:
199706f2543Smrg    case DEVICE_OFF:
200706f2543Smrg      pDevice->on = FALSE;
201706f2543Smrg      break;
202706f2543Smrg    }
203706f2543Smrg
204706f2543Smrg  return Success;
205706f2543Smrg}
206706f2543Smrg
207706f2543Smrg
208706f2543Smrg/*
209706f2543Smrg * Detect current mode key states upon server startup.
210706f2543Smrg *
211706f2543Smrg * Simulate a press and release of any key that is currently
212706f2543Smrg * toggled.
213706f2543Smrg */
214706f2543Smrg
215706f2543Smrgvoid
216706f2543SmrgwinInitializeModeKeyStates (void)
217706f2543Smrg{
218706f2543Smrg  /* Restore NumLock */
219706f2543Smrg  if (GetKeyState (VK_NUMLOCK) & 0x0001)
220706f2543Smrg    {
221706f2543Smrg      winSendKeyEvent (KEY_NumLock, TRUE);
222706f2543Smrg      winSendKeyEvent (KEY_NumLock, FALSE);
223706f2543Smrg    }
224706f2543Smrg
225706f2543Smrg  /* Restore CapsLock */
226706f2543Smrg  if (GetKeyState (VK_CAPITAL) & 0x0001)
227706f2543Smrg    {
228706f2543Smrg      winSendKeyEvent (KEY_CapsLock, TRUE);
229706f2543Smrg      winSendKeyEvent (KEY_CapsLock, FALSE);
230706f2543Smrg    }
231706f2543Smrg
232706f2543Smrg  /* Restore ScrollLock */
233706f2543Smrg  if (GetKeyState (VK_SCROLL) & 0x0001)
234706f2543Smrg    {
235706f2543Smrg      winSendKeyEvent (KEY_ScrollLock, TRUE);
236706f2543Smrg      winSendKeyEvent (KEY_ScrollLock, FALSE);
237706f2543Smrg    }
238706f2543Smrg
239706f2543Smrg  /* Restore KanaLock */
240706f2543Smrg  if (GetKeyState (VK_KANA) & 0x0001)
241706f2543Smrg    {
242706f2543Smrg      winSendKeyEvent (KEY_HKTG, TRUE);
243706f2543Smrg      winSendKeyEvent (KEY_HKTG, FALSE);
244706f2543Smrg    }
245706f2543Smrg}
246706f2543Smrg
247706f2543Smrg
248706f2543Smrg/*
249706f2543Smrg * Upon regaining the keyboard focus we must
250706f2543Smrg * resynchronize our internal mode key states
251706f2543Smrg * with the actual state of the keys.
252706f2543Smrg */
253706f2543Smrg
254706f2543Smrgvoid
255706f2543SmrgwinRestoreModeKeyStates (void)
256706f2543Smrg{
257706f2543Smrg  DWORD			dwKeyState;
258706f2543Smrg  BOOL			processEvents = TRUE;
259706f2543Smrg  unsigned short	internalKeyStates;
260706f2543Smrg
261706f2543Smrg  /* X server is being initialized */
262706f2543Smrg  if (!inputInfo.keyboard)
263706f2543Smrg    return;
264706f2543Smrg
265706f2543Smrg  /* Only process events if the rootwindow is mapped. The keyboard events
266706f2543Smrg   * will cause segfaults otherwise */
267706f2543Smrg  if (screenInfo.screens[0]->root && screenInfo.screens[0]->root->mapped == FALSE)
268706f2543Smrg    processEvents = FALSE;
269706f2543Smrg
270706f2543Smrg  /* Force to process all pending events in the mi event queue */
271706f2543Smrg  if (processEvents)
272706f2543Smrg    mieqProcessInputEvents ();
273706f2543Smrg
274706f2543Smrg  /* Read the mode key states of our X server */
275706f2543Smrg  /* (stored in the virtual core keyboard) */
276706f2543Smrg  internalKeyStates = XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state);
277706f2543Smrg  winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates);
278706f2543Smrg
279706f2543Smrg  /*
280706f2543Smrg   * NOTE: The C XOR operator, ^, will not work here because it is
281706f2543Smrg   * a bitwise operator, not a logical operator.  C does not
282706f2543Smrg   * have a logical XOR operator, so we use a macro instead.
283706f2543Smrg   */
284706f2543Smrg
285706f2543Smrg  /* Has the key state changed? */
286706f2543Smrg  dwKeyState = GetKeyState (VK_NUMLOCK) & 0x0001;
287706f2543Smrg  if (WIN_XOR (internalKeyStates & NumLockMask, dwKeyState))
288706f2543Smrg    {
289706f2543Smrg      winSendKeyEvent (KEY_NumLock, TRUE);
290706f2543Smrg      winSendKeyEvent (KEY_NumLock, FALSE);
291706f2543Smrg    }
292706f2543Smrg
293706f2543Smrg  /* Has the key state changed? */
294706f2543Smrg  dwKeyState = GetKeyState (VK_CAPITAL) & 0x0001;
295706f2543Smrg  if (WIN_XOR (internalKeyStates & LockMask, dwKeyState))
296706f2543Smrg    {
297706f2543Smrg      winSendKeyEvent (KEY_CapsLock, TRUE);
298706f2543Smrg      winSendKeyEvent (KEY_CapsLock, FALSE);
299706f2543Smrg    }
300706f2543Smrg
301706f2543Smrg  /* Has the key state changed? */
302706f2543Smrg  dwKeyState = GetKeyState (VK_SCROLL) & 0x0001;
303706f2543Smrg  if (WIN_XOR (internalKeyStates & ScrollLockMask, dwKeyState))
304706f2543Smrg    {
305706f2543Smrg      winSendKeyEvent (KEY_ScrollLock, TRUE);
306706f2543Smrg      winSendKeyEvent (KEY_ScrollLock, FALSE);
307706f2543Smrg    }
308706f2543Smrg
309706f2543Smrg  /* Has the key state changed? */
310706f2543Smrg  dwKeyState = GetKeyState (VK_KANA) & 0x0001;
311706f2543Smrg  if (WIN_XOR (internalKeyStates & KanaMask, dwKeyState))
312706f2543Smrg    {
313706f2543Smrg      winSendKeyEvent (KEY_HKTG, TRUE);
314706f2543Smrg      winSendKeyEvent (KEY_HKTG, FALSE);
315706f2543Smrg    }
316706f2543Smrg}
317706f2543Smrg
318706f2543Smrg
319706f2543Smrg/*
320706f2543Smrg * Look for the lovely fake Control_L press/release generated by Windows
321706f2543Smrg * when AltGr is pressed/released on a non-U.S. keyboard.
322706f2543Smrg */
323706f2543Smrg
324706f2543SmrgBool
325706f2543SmrgwinIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam)
326706f2543Smrg{
327706f2543Smrg  MSG		msgNext;
328706f2543Smrg  LONG		lTime;
329706f2543Smrg  Bool		fReturn;
330706f2543Smrg
331706f2543Smrg  /*
332706f2543Smrg   * Fake Ctrl_L presses will be followed by an Alt_R keypress
333706f2543Smrg   * with the same timestamp as the Ctrl_L press.
334706f2543Smrg   */
335706f2543Smrg  if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
336706f2543Smrg      && wParam == VK_CONTROL
337706f2543Smrg      && (HIWORD (lParam) & KF_EXTENDED) == 0)
338706f2543Smrg    {
339706f2543Smrg      /* Got a Ctrl_L press */
340706f2543Smrg
341706f2543Smrg      /* Get time of current message */
342706f2543Smrg      lTime = GetMessageTime ();
343706f2543Smrg
344706f2543Smrg      /* Look for fake Ctrl_L preceeding an Alt_R press. */
345706f2543Smrg      fReturn = PeekMessage (&msgNext, NULL,
346706f2543Smrg			     WM_KEYDOWN, WM_SYSKEYDOWN,
347706f2543Smrg			     PM_NOREMOVE);
348706f2543Smrg
349706f2543Smrg      /*
350706f2543Smrg       * Try again if the first call fails.
351706f2543Smrg       * NOTE: This usually happens when TweakUI is enabled.
352706f2543Smrg       */
353706f2543Smrg      if (!fReturn)
354706f2543Smrg	{
355706f2543Smrg	  /* Voodoo to make sure that the Alt_R message has posted */
356706f2543Smrg	  Sleep (0);
357706f2543Smrg
358706f2543Smrg	  /* Look for fake Ctrl_L preceeding an Alt_R press. */
359706f2543Smrg	  fReturn = PeekMessage (&msgNext, NULL,
360706f2543Smrg				 WM_KEYDOWN, WM_SYSKEYDOWN,
361706f2543Smrg				 PM_NOREMOVE);
362706f2543Smrg	}
363706f2543Smrg      if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN)
364706f2543Smrg          fReturn = 0;
365706f2543Smrg
366706f2543Smrg      /* Is next press an Alt_R with the same timestamp? */
367706f2543Smrg      if (fReturn && msgNext.wParam == VK_MENU
368706f2543Smrg	  && msgNext.time == lTime
369706f2543Smrg	  && (HIWORD (msgNext.lParam) & KF_EXTENDED))
370706f2543Smrg	{
371706f2543Smrg	  /*
372706f2543Smrg	   * Next key press is Alt_R with same timestamp as current
373706f2543Smrg	   * Ctrl_L message.  Therefore, this Ctrl_L press is a fake
374706f2543Smrg	   * event, so discard it.
375706f2543Smrg	   */
376706f2543Smrg	  return TRUE;
377706f2543Smrg	}
378706f2543Smrg    }
379706f2543Smrg
380706f2543Smrg  /*
381706f2543Smrg   * Fake Ctrl_L releases will be followed by an Alt_R release
382706f2543Smrg   * with the same timestamp as the Ctrl_L release.
383706f2543Smrg   */
384706f2543Smrg  if ((message == WM_KEYUP || message == WM_SYSKEYUP)
385706f2543Smrg      && wParam == VK_CONTROL
386706f2543Smrg      && (HIWORD (lParam) & KF_EXTENDED) == 0)
387706f2543Smrg    {
388706f2543Smrg      /* Got a Ctrl_L release */
389706f2543Smrg
390706f2543Smrg      /* Get time of current message */
391706f2543Smrg      lTime = GetMessageTime ();
392706f2543Smrg
393706f2543Smrg      /* Look for fake Ctrl_L release preceeding an Alt_R release. */
394706f2543Smrg      fReturn = PeekMessage (&msgNext, NULL,
395706f2543Smrg			     WM_KEYUP, WM_SYSKEYUP,
396706f2543Smrg			     PM_NOREMOVE);
397706f2543Smrg
398706f2543Smrg      /*
399706f2543Smrg       * Try again if the first call fails.
400706f2543Smrg       * NOTE: This usually happens when TweakUI is enabled.
401706f2543Smrg       */
402706f2543Smrg      if (!fReturn)
403706f2543Smrg	{
404706f2543Smrg	  /* Voodoo to make sure that the Alt_R message has posted */
405706f2543Smrg	  Sleep (0);
406706f2543Smrg
407706f2543Smrg	  /* Look for fake Ctrl_L release preceeding an Alt_R release. */
408706f2543Smrg	  fReturn = PeekMessage (&msgNext, NULL,
409706f2543Smrg				 WM_KEYUP, WM_SYSKEYUP,
410706f2543Smrg				 PM_NOREMOVE);
411706f2543Smrg	}
412706f2543Smrg
413706f2543Smrg      if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP)
414706f2543Smrg          fReturn = 0;
415706f2543Smrg
416706f2543Smrg      /* Is next press an Alt_R with the same timestamp? */
417706f2543Smrg      if (fReturn
418706f2543Smrg	  && (msgNext.message == WM_KEYUP
419706f2543Smrg	      || msgNext.message == WM_SYSKEYUP)
420706f2543Smrg	  && msgNext.wParam == VK_MENU
421706f2543Smrg	  && msgNext.time == lTime
422706f2543Smrg	  && (HIWORD (msgNext.lParam) & KF_EXTENDED))
423706f2543Smrg	{
424706f2543Smrg	  /*
425706f2543Smrg	   * Next key release is Alt_R with same timestamp as current
426706f2543Smrg	   * Ctrl_L message. Therefore, this Ctrl_L release is a fake
427706f2543Smrg	   * event, so discard it.
428706f2543Smrg	   */
429706f2543Smrg	  return TRUE;
430706f2543Smrg	}
431706f2543Smrg    }
432706f2543Smrg
433706f2543Smrg  /* Not a fake control left press/release */
434706f2543Smrg  return FALSE;
435706f2543Smrg}
436706f2543Smrg
437706f2543Smrg
438706f2543Smrg/*
439706f2543Smrg * Lift any modifier keys that are pressed
440706f2543Smrg */
441706f2543Smrg
442706f2543Smrgvoid
443706f2543SmrgwinKeybdReleaseKeys (void)
444706f2543Smrg{
445706f2543Smrg  int				i;
446706f2543Smrg
447706f2543Smrg#ifdef HAS_DEVWINDOWS
448706f2543Smrg  /* Verify that the mi input system has been initialized */
449706f2543Smrg  if (g_fdMessageQueue == WIN_FD_INVALID)
450706f2543Smrg    return;
451706f2543Smrg#endif
452706f2543Smrg
453706f2543Smrg  /* Loop through all keys */
454706f2543Smrg  for (i = 0; i < NUM_KEYCODES; ++i)
455706f2543Smrg    {
456706f2543Smrg      /* Pop key if pressed */
457706f2543Smrg      if (g_winKeyState[i])
458706f2543Smrg	winSendKeyEvent (i, FALSE);
459706f2543Smrg
460706f2543Smrg      /* Reset pressed flag for keys */
461706f2543Smrg      g_winKeyState[i] = FALSE;
462706f2543Smrg    }
463706f2543Smrg}
464706f2543Smrg
465706f2543Smrg
466706f2543Smrg/*
467706f2543Smrg * Take a raw X key code and send an up or down event for it.
468706f2543Smrg *
469706f2543Smrg * Thanks to VNC for inspiration, though it is a simple function.
470706f2543Smrg */
471706f2543Smrg
472706f2543Smrgvoid
473706f2543SmrgwinSendKeyEvent (DWORD dwKey, Bool fDown)
474706f2543Smrg{
475706f2543Smrg  EventListPtr events;
476706f2543Smrg  int i, nevents;
477706f2543Smrg
478706f2543Smrg  /*
479706f2543Smrg   * When alt-tabing between screens we can get phantom key up messages
480706f2543Smrg   * Here we only pass them through it we think we should!
481706f2543Smrg   */
482706f2543Smrg  if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) return;
483706f2543Smrg
484706f2543Smrg  /* Update the keyState map */
485706f2543Smrg  g_winKeyState[dwKey] = fDown;
486706f2543Smrg
487706f2543Smrg  GetEventList(&events);
488706f2543Smrg  nevents = GetKeyboardEvents(events, g_pwinKeyboard, fDown ? KeyPress : KeyRelease, dwKey + MIN_KEYCODE);
489706f2543Smrg
490706f2543Smrg  for (i = 0; i < nevents; i++)
491706f2543Smrg    mieqEnqueue(g_pwinKeyboard, (InternalEvent*)events[i].event);
492706f2543Smrg
493706f2543Smrg  winDebug("winSendKeyEvent: dwKey: %d, fDown: %d, nEvents %d\n",
494706f2543Smrg           dwKey, fDown, nevents);
495706f2543Smrg}
496706f2543Smrg
497706f2543SmrgBOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
498706f2543Smrg{
499706f2543Smrg  switch (wParam)
500706f2543Smrg  {
501706f2543Smrg    case VK_CONTROL:
502706f2543Smrg      if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
503706f2543Smrg        return TRUE;
504706f2543Smrg      if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
505706f2543Smrg        return TRUE;
506706f2543Smrg      break;
507706f2543Smrg    case VK_SHIFT:
508706f2543Smrg      if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
509706f2543Smrg        return TRUE;
510706f2543Smrg      if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
511706f2543Smrg        return TRUE;
512706f2543Smrg      break;
513706f2543Smrg    default:
514706f2543Smrg      return TRUE;
515706f2543Smrg  }
516706f2543Smrg  return FALSE;
517706f2543Smrg}
518706f2543Smrg
519706f2543Smrg/* Only on shift release message is sent even if both are pressed.
520706f2543Smrg * Fix this here
521706f2543Smrg */
522706f2543Smrgvoid winFixShiftKeys (int iScanCode)
523706f2543Smrg{
524706f2543Smrg  if (GetKeyState (VK_SHIFT) & 0x8000)
525706f2543Smrg    return;
526706f2543Smrg
527706f2543Smrg  if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
528706f2543Smrg    winSendKeyEvent (KEY_ShiftR, FALSE);
529706f2543Smrg  if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
530706f2543Smrg    winSendKeyEvent (KEY_ShiftL, FALSE);
531706f2543Smrg}
532