1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun *Permission is hereby granted, free of charge, to any person obtaining
5*4882a593Smuzhiyun * a copy of this software and associated documentation files (the
6*4882a593Smuzhiyun *"Software"), to deal in the Software without restriction, including
7*4882a593Smuzhiyun *without limitation the rights to use, copy, modify, merge, publish,
8*4882a593Smuzhiyun *distribute, sublicense, and/or sell copies of the Software, and to
9*4882a593Smuzhiyun *permit persons to whom the Software is furnished to do so, subject to
10*4882a593Smuzhiyun *the following conditions:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun *The above copyright notice and this permission notice shall be
13*4882a593Smuzhiyun *included in all copies or substantial portions of the Software.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*4882a593Smuzhiyun *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*4882a593Smuzhiyun *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18*4882a593Smuzhiyun *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19*4882a593Smuzhiyun *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20*4882a593Smuzhiyun *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21*4882a593Smuzhiyun *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun *Except as contained in this notice, the name of the XFree86 Project
24*4882a593Smuzhiyun *shall not be used in advertising or otherwise to promote the sale, use
25*4882a593Smuzhiyun *or other dealings in this Software without prior written authorization
26*4882a593Smuzhiyun *from the XFree86 Project.
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * Authors: Dakshinamurthy Karra
29*4882a593Smuzhiyun * Suhaib M Siddiqi
30*4882a593Smuzhiyun * Peter Busch
31*4882a593Smuzhiyun * Harold L Hunt II
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #ifdef HAVE_XWIN_CONFIG_H
35*4882a593Smuzhiyun #include <xwin-config.h>
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun #include "win.h"
38*4882a593Smuzhiyun #include "winkeybd.h"
39*4882a593Smuzhiyun #include "winconfig.h"
40*4882a593Smuzhiyun #include "winmsg.h"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #include "xkbsrv.h"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* C does not have a logical XOR operator, so we use a macro instead */
45*4882a593Smuzhiyun #define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b)))
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static Bool g_winKeyState[NUM_KEYCODES];
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Local prototypes
51*4882a593Smuzhiyun */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun static void
54*4882a593Smuzhiyun winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static void
57*4882a593Smuzhiyun winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * Translate a Windows WM_[SYS]KEY(UP/DOWN) message
61*4882a593Smuzhiyun * into an ASCII scan code.
62*4882a593Smuzhiyun *
63*4882a593Smuzhiyun * We do this ourselves, rather than letting Windows handle it,
64*4882a593Smuzhiyun * because Windows tends to munge the handling of special keys,
65*4882a593Smuzhiyun * like AltGr on European keyboards.
66*4882a593Smuzhiyun */
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun int
winTranslateKey(WPARAM wParam,LPARAM lParam)69*4882a593Smuzhiyun winTranslateKey(WPARAM wParam, LPARAM lParam)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
72*4882a593Smuzhiyun int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
73*4882a593Smuzhiyun int iParam = HIWORD(lParam);
74*4882a593Smuzhiyun int iParamScanCode = LOBYTE(iParam);
75*4882a593Smuzhiyun int iScanCode;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* WM_ key messages faked by Vista speech recognition (WSR) don't have a
80*4882a593Smuzhiyun * scan code.
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * Vocola 3 (Rick Mohr's supplement to WSR) uses
83*4882a593Smuzhiyun * System.Windows.Forms.SendKeys.SendWait(), which appears always to give a
84*4882a593Smuzhiyun * scan code of 1
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun if (iParamScanCode <= 1) {
87*4882a593Smuzhiyun if (VK_PRIOR <= wParam && wParam <= VK_DOWN)
88*4882a593Smuzhiyun /* Trigger special case table to translate to extended
89*4882a593Smuzhiyun * keycode, otherwise if num_lock is on, we can get keypad
90*4882a593Smuzhiyun * numbers instead of navigation keys. */
91*4882a593Smuzhiyun iParam |= KF_EXTENDED;
92*4882a593Smuzhiyun else
93*4882a593Smuzhiyun iParamScanCode = MapVirtualKeyEx(wParam,
94*4882a593Smuzhiyun /*MAPVK_VK_TO_VSC */ 0,
95*4882a593Smuzhiyun GetKeyboardLayout(0));
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Branch on special extended, special non-extended, or normal key */
99*4882a593Smuzhiyun if ((iParam & KF_EXTENDED) && iKeyFixupEx)
100*4882a593Smuzhiyun iScanCode = iKeyFixupEx;
101*4882a593Smuzhiyun else if (iKeyFixup)
102*4882a593Smuzhiyun iScanCode = iKeyFixup;
103*4882a593Smuzhiyun else if (wParam == 0 && iParamScanCode == 0x70)
104*4882a593Smuzhiyun iScanCode = KEY_HKTG;
105*4882a593Smuzhiyun else
106*4882a593Smuzhiyun switch (iParamScanCode) {
107*4882a593Smuzhiyun case 0x70:
108*4882a593Smuzhiyun iScanCode = KEY_HKTG;
109*4882a593Smuzhiyun break;
110*4882a593Smuzhiyun case 0x73:
111*4882a593Smuzhiyun iScanCode = KEY_BSlash2;
112*4882a593Smuzhiyun break;
113*4882a593Smuzhiyun default:
114*4882a593Smuzhiyun iScanCode = iParamScanCode;
115*4882a593Smuzhiyun break;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun return iScanCode;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* Ring the keyboard bell (system speaker on PCs) */
122*4882a593Smuzhiyun static void
winKeybdBell(int iPercent,DeviceIntPtr pDeviceInt,void * pCtrl,int iClass)123*4882a593Smuzhiyun winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun * We can't use Beep () here because it uses the PC speaker
127*4882a593Smuzhiyun * on NT/2000. MessageBeep (MB_OK) will play the default system
128*4882a593Smuzhiyun * sound on systems with a sound card or it will beep the PC speaker
129*4882a593Smuzhiyun * on systems that do not have a sound card.
130*4882a593Smuzhiyun */
131*4882a593Smuzhiyun if (iPercent > 0) MessageBeep(MB_OK);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Change some keyboard configuration parameters */
135*4882a593Smuzhiyun static void
winKeybdCtrl(DeviceIntPtr pDevice,KeybdCtrl * pCtrl)136*4882a593Smuzhiyun winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * See Porting Layer Definition - p. 18
142*4882a593Smuzhiyun * winKeybdProc is known as a DeviceProc.
143*4882a593Smuzhiyun */
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun int
winKeybdProc(DeviceIntPtr pDeviceInt,int iState)146*4882a593Smuzhiyun winKeybdProc(DeviceIntPtr pDeviceInt, int iState)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun DevicePtr pDevice = (DevicePtr) pDeviceInt;
149*4882a593Smuzhiyun XkbSrvInfoPtr xkbi;
150*4882a593Smuzhiyun XkbControlsPtr ctrl;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun switch (iState) {
153*4882a593Smuzhiyun case DEVICE_INIT:
154*4882a593Smuzhiyun winConfigKeyboard(pDeviceInt);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* FIXME: Maybe we should use winGetKbdLeds () here? */
157*4882a593Smuzhiyun defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
160*4882a593Smuzhiyun " Variant = \"%s\" Options = \"%s\"\n",
161*4882a593Smuzhiyun g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none",
162*4882a593Smuzhiyun g_winInfo.xkb.model ? g_winInfo.xkb.model : "none",
163*4882a593Smuzhiyun g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none",
164*4882a593Smuzhiyun g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none",
165*4882a593Smuzhiyun g_winInfo.xkb.options ? g_winInfo.xkb.options : "none");
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun InitKeyboardDeviceStruct(pDeviceInt,
168*4882a593Smuzhiyun &g_winInfo.xkb, winKeybdBell, winKeybdCtrl);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun xkbi = pDeviceInt->key->xkbInfo;
171*4882a593Smuzhiyun if ((xkbi != NULL) && (xkbi->desc != NULL)) {
172*4882a593Smuzhiyun ctrl = xkbi->desc->ctrls;
173*4882a593Smuzhiyun ctrl->repeat_delay = g_winInfo.keyboard.delay;
174*4882a593Smuzhiyun ctrl->repeat_interval = 1000 / g_winInfo.keyboard.rate;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun else {
177*4882a593Smuzhiyun winErrorFVerb(1,
178*4882a593Smuzhiyun "winKeybdProc - Error initializing keyboard AutoRepeat\n");
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun case DEVICE_ON:
184*4882a593Smuzhiyun pDevice->on = TRUE;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun // immediately copy the state of this keyboard device to the VCK
187*4882a593Smuzhiyun // (which otherwise happens lazily after the first keypress)
188*4882a593Smuzhiyun CopyKeyClass(pDeviceInt, inputInfo.keyboard);
189*4882a593Smuzhiyun break;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun case DEVICE_CLOSE:
192*4882a593Smuzhiyun case DEVICE_OFF:
193*4882a593Smuzhiyun pDevice->on = FALSE;
194*4882a593Smuzhiyun break;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun return Success;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * Detect current mode key states upon server startup.
202*4882a593Smuzhiyun *
203*4882a593Smuzhiyun * Simulate a press and release of any key that is currently
204*4882a593Smuzhiyun * toggled.
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun void
winInitializeModeKeyStates(void)208*4882a593Smuzhiyun winInitializeModeKeyStates(void)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun /* Restore NumLock */
211*4882a593Smuzhiyun if (GetKeyState(VK_NUMLOCK) & 0x0001) {
212*4882a593Smuzhiyun winSendKeyEvent(KEY_NumLock, TRUE);
213*4882a593Smuzhiyun winSendKeyEvent(KEY_NumLock, FALSE);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /* Restore CapsLock */
217*4882a593Smuzhiyun if (GetKeyState(VK_CAPITAL) & 0x0001) {
218*4882a593Smuzhiyun winSendKeyEvent(KEY_CapsLock, TRUE);
219*4882a593Smuzhiyun winSendKeyEvent(KEY_CapsLock, FALSE);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* Restore ScrollLock */
223*4882a593Smuzhiyun if (GetKeyState(VK_SCROLL) & 0x0001) {
224*4882a593Smuzhiyun winSendKeyEvent(KEY_ScrollLock, TRUE);
225*4882a593Smuzhiyun winSendKeyEvent(KEY_ScrollLock, FALSE);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* Restore KanaLock */
229*4882a593Smuzhiyun if (GetKeyState(VK_KANA) & 0x0001) {
230*4882a593Smuzhiyun winSendKeyEvent(KEY_HKTG, TRUE);
231*4882a593Smuzhiyun winSendKeyEvent(KEY_HKTG, FALSE);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /*
236*4882a593Smuzhiyun * Upon regaining the keyboard focus we must
237*4882a593Smuzhiyun * resynchronize our internal mode key states
238*4882a593Smuzhiyun * with the actual state of the keys.
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun void
winRestoreModeKeyStates(void)242*4882a593Smuzhiyun winRestoreModeKeyStates(void)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun DWORD dwKeyState;
245*4882a593Smuzhiyun BOOL processEvents = TRUE;
246*4882a593Smuzhiyun unsigned short internalKeyStates;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* X server is being initialized */
249*4882a593Smuzhiyun if (!inputInfo.keyboard || !inputInfo.keyboard->key)
250*4882a593Smuzhiyun return;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /* Only process events if the rootwindow is mapped. The keyboard events
253*4882a593Smuzhiyun * will cause segfaults otherwise */
254*4882a593Smuzhiyun if (screenInfo.screens[0]->root &&
255*4882a593Smuzhiyun screenInfo.screens[0]->root->mapped == FALSE)
256*4882a593Smuzhiyun processEvents = FALSE;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /* Force to process all pending events in the mi event queue */
259*4882a593Smuzhiyun if (processEvents)
260*4882a593Smuzhiyun mieqProcessInputEvents();
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /* Read the mode key states of our X server */
263*4882a593Smuzhiyun /* (stored in the virtual core keyboard) */
264*4882a593Smuzhiyun internalKeyStates =
265*4882a593Smuzhiyun XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state);
266*4882a593Smuzhiyun winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Check if modifier keys are pressed, and if so, fake a press */
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun BOOL lctrl = (GetAsyncKeyState(VK_LCONTROL) < 0);
272*4882a593Smuzhiyun BOOL rctrl = (GetAsyncKeyState(VK_RCONTROL) < 0);
273*4882a593Smuzhiyun BOOL lshift = (GetAsyncKeyState(VK_LSHIFT) < 0);
274*4882a593Smuzhiyun BOOL rshift = (GetAsyncKeyState(VK_RSHIFT) < 0);
275*4882a593Smuzhiyun BOOL alt = (GetAsyncKeyState(VK_LMENU) < 0);
276*4882a593Smuzhiyun BOOL altgr = (GetAsyncKeyState(VK_RMENU) < 0);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun If AltGr and CtrlL appear to be pressed, assume the
280*4882a593Smuzhiyun CtrL is a fake one
281*4882a593Smuzhiyun */
282*4882a593Smuzhiyun if (lctrl && altgr)
283*4882a593Smuzhiyun lctrl = FALSE;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (lctrl)
286*4882a593Smuzhiyun winSendKeyEvent(KEY_LCtrl, TRUE);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (rctrl)
289*4882a593Smuzhiyun winSendKeyEvent(KEY_RCtrl, TRUE);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (lshift)
292*4882a593Smuzhiyun winSendKeyEvent(KEY_ShiftL, TRUE);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (rshift)
295*4882a593Smuzhiyun winSendKeyEvent(KEY_ShiftL, TRUE);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun if (alt)
298*4882a593Smuzhiyun winSendKeyEvent(KEY_Alt, TRUE);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (altgr)
301*4882a593Smuzhiyun winSendKeyEvent(KEY_AltLang, TRUE);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /*
305*4882a593Smuzhiyun Check if latching modifier key states have changed, and if so,
306*4882a593Smuzhiyun fake a press and a release to toggle the modifier to the correct
307*4882a593Smuzhiyun state
308*4882a593Smuzhiyun */
309*4882a593Smuzhiyun dwKeyState = GetKeyState(VK_NUMLOCK) & 0x0001;
310*4882a593Smuzhiyun if (LOGICAL_XOR(internalKeyStates & NumLockMask, dwKeyState)) {
311*4882a593Smuzhiyun winSendKeyEvent(KEY_NumLock, TRUE);
312*4882a593Smuzhiyun winSendKeyEvent(KEY_NumLock, FALSE);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun dwKeyState = GetKeyState(VK_CAPITAL) & 0x0001;
316*4882a593Smuzhiyun if (LOGICAL_XOR(internalKeyStates & LockMask, dwKeyState)) {
317*4882a593Smuzhiyun winSendKeyEvent(KEY_CapsLock, TRUE);
318*4882a593Smuzhiyun winSendKeyEvent(KEY_CapsLock, FALSE);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun dwKeyState = GetKeyState(VK_SCROLL) & 0x0001;
322*4882a593Smuzhiyun if (LOGICAL_XOR(internalKeyStates & ScrollLockMask, dwKeyState)) {
323*4882a593Smuzhiyun winSendKeyEvent(KEY_ScrollLock, TRUE);
324*4882a593Smuzhiyun winSendKeyEvent(KEY_ScrollLock, FALSE);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun dwKeyState = GetKeyState(VK_KANA) & 0x0001;
328*4882a593Smuzhiyun if (LOGICAL_XOR(internalKeyStates & KanaMask, dwKeyState)) {
329*4882a593Smuzhiyun winSendKeyEvent(KEY_HKTG, TRUE);
330*4882a593Smuzhiyun winSendKeyEvent(KEY_HKTG, FALSE);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /*
334*4882a593Smuzhiyun For strict correctness, we should also press any non-modifier keys
335*4882a593Smuzhiyun which are already down when we gain focus, but nobody has complained
336*4882a593Smuzhiyun yet :-)
337*4882a593Smuzhiyun */
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * Look for the lovely fake Control_L press/release generated by Windows
342*4882a593Smuzhiyun * when AltGr is pressed/released on a non-U.S. keyboard.
343*4882a593Smuzhiyun */
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun Bool
winIsFakeCtrl_L(UINT message,WPARAM wParam,LPARAM lParam)346*4882a593Smuzhiyun winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun MSG msgNext;
349*4882a593Smuzhiyun LONG lTime;
350*4882a593Smuzhiyun Bool fReturn;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun static Bool lastWasControlL = FALSE;
353*4882a593Smuzhiyun static LONG lastTime;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /*
356*4882a593Smuzhiyun * Fake Ctrl_L presses will be followed by an Alt_R press
357*4882a593Smuzhiyun * with the same timestamp as the Ctrl_L press.
358*4882a593Smuzhiyun */
359*4882a593Smuzhiyun if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
360*4882a593Smuzhiyun && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
361*4882a593Smuzhiyun /* Got a Ctrl_L press */
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /* Get time of current message */
364*4882a593Smuzhiyun lTime = GetMessageTime();
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* Look for next press message */
367*4882a593Smuzhiyun fReturn = PeekMessage(&msgNext, NULL,
368*4882a593Smuzhiyun WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (fReturn && msgNext.message != WM_KEYDOWN &&
371*4882a593Smuzhiyun msgNext.message != WM_SYSKEYDOWN)
372*4882a593Smuzhiyun fReturn = 0;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (!fReturn) {
375*4882a593Smuzhiyun lastWasControlL = TRUE;
376*4882a593Smuzhiyun lastTime = lTime;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun else {
379*4882a593Smuzhiyun lastWasControlL = FALSE;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun /* Is next press an Alt_R with the same timestamp? */
383*4882a593Smuzhiyun if (fReturn && msgNext.wParam == VK_MENU
384*4882a593Smuzhiyun && msgNext.time == lTime
385*4882a593Smuzhiyun && (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
386*4882a593Smuzhiyun /*
387*4882a593Smuzhiyun * Next key press is Alt_R with same timestamp as current
388*4882a593Smuzhiyun * Ctrl_L message. Therefore, this Ctrl_L press is a fake
389*4882a593Smuzhiyun * event, so discard it.
390*4882a593Smuzhiyun */
391*4882a593Smuzhiyun return TRUE;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun /*
395*4882a593Smuzhiyun * Sometimes, the Alt_R press message is not yet posted when the
396*4882a593Smuzhiyun * fake Ctrl_L press message arrives (even though it has the
397*4882a593Smuzhiyun * same timestamp), so check for an Alt_R press message that has
398*4882a593Smuzhiyun * arrived since the last Ctrl_L message.
399*4882a593Smuzhiyun */
400*4882a593Smuzhiyun else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
401*4882a593Smuzhiyun && wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) {
402*4882a593Smuzhiyun /* Got a Alt_R press */
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (lastWasControlL) {
405*4882a593Smuzhiyun lTime = GetMessageTime();
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (lastTime == lTime) {
408*4882a593Smuzhiyun /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */
409*4882a593Smuzhiyun winSendKeyEvent(KEY_LCtrl, FALSE);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun lastWasControlL = FALSE;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun /*
415*4882a593Smuzhiyun * Fake Ctrl_L releases will be followed by an Alt_R release
416*4882a593Smuzhiyun * with the same timestamp as the Ctrl_L release.
417*4882a593Smuzhiyun */
418*4882a593Smuzhiyun else if ((message == WM_KEYUP || message == WM_SYSKEYUP)
419*4882a593Smuzhiyun && wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
420*4882a593Smuzhiyun /* Got a Ctrl_L release */
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* Get time of current message */
423*4882a593Smuzhiyun lTime = GetMessageTime();
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /* Look for next release message */
426*4882a593Smuzhiyun fReturn = PeekMessage(&msgNext, NULL,
427*4882a593Smuzhiyun WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun if (fReturn && msgNext.message != WM_KEYUP &&
430*4882a593Smuzhiyun msgNext.message != WM_SYSKEYUP)
431*4882a593Smuzhiyun fReturn = 0;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun lastWasControlL = FALSE;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* Is next press an Alt_R with the same timestamp? */
436*4882a593Smuzhiyun if (fReturn
437*4882a593Smuzhiyun && (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP)
438*4882a593Smuzhiyun && msgNext.wParam == VK_MENU
439*4882a593Smuzhiyun && msgNext.time == lTime
440*4882a593Smuzhiyun && (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
441*4882a593Smuzhiyun /*
442*4882a593Smuzhiyun * Next key release is Alt_R with same timestamp as current
443*4882a593Smuzhiyun * Ctrl_L message. Therefore, this Ctrl_L release is a fake
444*4882a593Smuzhiyun * event, so discard it.
445*4882a593Smuzhiyun */
446*4882a593Smuzhiyun return TRUE;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun else {
450*4882a593Smuzhiyun /* On any other press or release message, we don't have a
451*4882a593Smuzhiyun potentially fake Ctrl_L to worry about anymore... */
452*4882a593Smuzhiyun lastWasControlL = FALSE;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* Not a fake control left press/release */
456*4882a593Smuzhiyun return FALSE;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /*
460*4882a593Smuzhiyun * Lift any modifier keys that are pressed
461*4882a593Smuzhiyun */
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun void
winKeybdReleaseKeys(void)464*4882a593Smuzhiyun winKeybdReleaseKeys(void)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun int i;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun #ifdef HAS_DEVWINDOWS
469*4882a593Smuzhiyun /* Verify that the mi input system has been initialized */
470*4882a593Smuzhiyun if (g_fdMessageQueue == WIN_FD_INVALID)
471*4882a593Smuzhiyun return;
472*4882a593Smuzhiyun #endif
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /* Loop through all keys */
475*4882a593Smuzhiyun for (i = 0; i < NUM_KEYCODES; ++i) {
476*4882a593Smuzhiyun /* Pop key if pressed */
477*4882a593Smuzhiyun if (g_winKeyState[i])
478*4882a593Smuzhiyun winSendKeyEvent(i, FALSE);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /* Reset pressed flag for keys */
481*4882a593Smuzhiyun g_winKeyState[i] = FALSE;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun * Take a raw X key code and send an up or down event for it.
487*4882a593Smuzhiyun *
488*4882a593Smuzhiyun * Thanks to VNC for inspiration, though it is a simple function.
489*4882a593Smuzhiyun */
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun void
winSendKeyEvent(DWORD dwKey,Bool fDown)492*4882a593Smuzhiyun winSendKeyEvent(DWORD dwKey, Bool fDown)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun /*
495*4882a593Smuzhiyun * When alt-tabing between screens we can get phantom key up messages
496*4882a593Smuzhiyun * Here we only pass them through it we think we should!
497*4882a593Smuzhiyun */
498*4882a593Smuzhiyun if (g_winKeyState[dwKey] == FALSE && fDown == FALSE)
499*4882a593Smuzhiyun return;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun /* Update the keyState map */
502*4882a593Smuzhiyun g_winKeyState[dwKey] = fDown;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease,
505*4882a593Smuzhiyun dwKey + MIN_KEYCODE);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun BOOL
winCheckKeyPressed(WPARAM wParam,LPARAM lParam)511*4882a593Smuzhiyun winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun switch (wParam) {
514*4882a593Smuzhiyun case VK_CONTROL:
515*4882a593Smuzhiyun if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
516*4882a593Smuzhiyun return TRUE;
517*4882a593Smuzhiyun if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
518*4882a593Smuzhiyun return TRUE;
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun case VK_SHIFT:
521*4882a593Smuzhiyun if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
522*4882a593Smuzhiyun return TRUE;
523*4882a593Smuzhiyun if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
524*4882a593Smuzhiyun return TRUE;
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun default:
527*4882a593Smuzhiyun return TRUE;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun return FALSE;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun /* Only one shift release message is sent even if both are pressed.
533*4882a593Smuzhiyun * Fix this here
534*4882a593Smuzhiyun */
535*4882a593Smuzhiyun void
winFixShiftKeys(int iScanCode)536*4882a593Smuzhiyun winFixShiftKeys(int iScanCode)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun if (GetKeyState(VK_SHIFT) & 0x8000)
539*4882a593Smuzhiyun return;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
542*4882a593Smuzhiyun winSendKeyEvent(KEY_ShiftR, FALSE);
543*4882a593Smuzhiyun if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
544*4882a593Smuzhiyun winSendKeyEvent(KEY_ShiftL, FALSE);
545*4882a593Smuzhiyun }
546