xref: /OK3568_Linux_fs/external/xserver/hw/xwin/winkeybd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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