2
*Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
4
*Permission is hereby granted, free of charge, to any person obtaining
5
* a copy of this software and associated documentation files (the
6
*"Software"), to deal in the Software without restriction, including
7
*without limitation the rights to use, copy, modify, merge, publish,
8
*distribute, sublicense, and/or sell copies of the Software, and to
9
*permit persons to whom the Software is furnished to do so, subject to
10
*the following conditions:
12
*The above copyright notice and this permission notice shall be
13
*included in all copies or substantial portions of the Software.
15
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
*NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
*Except as contained in this notice, the name of the XFree86 Project
24
*shall not be used in advertising or otherwise to promote the sale, use
25
*or other dealings in this Software without prior written authorization
26
*from the XFree86 Project.
28
* Authors: Dakshinamurthy Karra
34
#ifdef HAVE_XWIN_CONFIG_H
35
#include <xwin-config.h>
39
#include "winconfig.h"
44
/* C does not have a logical XOR operator, so we use a macro instead */
45
#define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b)))
47
static Bool g_winKeyState[NUM_KEYCODES];
54
winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass);
57
winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl);
60
* Translate a Windows WM_[SYS]KEY(UP/DOWN) message
61
* into an ASCII scan code.
63
* We do this ourselves, rather than letting Windows handle it,
64
* because Windows tends to munge the handling of special keys,
65
* like AltGr on European keyboards.
69
winTranslateKey(WPARAM wParam, LPARAM lParam)
71
int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
72
int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
73
int iParam = HIWORD(lParam);
74
int iParamScanCode = LOBYTE(iParam);
77
winDebug("winTranslateKey: wParam %08x lParam %08x\n", (int)wParam, (int)lParam);
79
/* WM_ key messages faked by Vista speech recognition (WSR) don't have a
82
* Vocola 3 (Rick Mohr's supplement to WSR) uses
83
* System.Windows.Forms.SendKeys.SendWait(), which appears always to give a
86
if (iParamScanCode <= 1) {
87
if (VK_PRIOR <= wParam && wParam <= VK_DOWN)
88
/* Trigger special case table to translate to extended
89
* keycode, otherwise if num_lock is on, we can get keypad
90
* numbers instead of navigation keys. */
91
iParam |= KF_EXTENDED;
93
iParamScanCode = MapVirtualKeyEx(wParam,
94
/*MAPVK_VK_TO_VSC */ 0,
95
GetKeyboardLayout(0));
98
/* Branch on special extended, special non-extended, or normal key */
99
if ((iParam & KF_EXTENDED) && iKeyFixupEx)
100
iScanCode = iKeyFixupEx;
102
iScanCode = iKeyFixup;
103
else if (wParam == 0 && iParamScanCode == 0x70)
104
iScanCode = KEY_HKTG;
106
switch (iParamScanCode) {
108
iScanCode = KEY_HKTG;
111
iScanCode = KEY_BSlash2;
114
iScanCode = iParamScanCode;
121
/* Ring the keyboard bell (system speaker on PCs) */
123
winKeybdBell(int iPercent, DeviceIntPtr pDeviceInt, void *pCtrl, int iClass)
126
* We can't use Beep () here because it uses the PC speaker
127
* on NT/2000. MessageBeep (MB_OK) will play the default system
128
* sound on systems with a sound card or it will beep the PC speaker
129
* on systems that do not have a sound card.
131
if (iPercent > 0) MessageBeep(MB_OK);
134
/* Change some keyboard configuration parameters */
136
winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl)
141
* See Porting Layer Definition - p. 18
142
* winKeybdProc is known as a DeviceProc.
146
winKeybdProc(DeviceIntPtr pDeviceInt, int iState)
148
DevicePtr pDevice = (DevicePtr) pDeviceInt;
154
winConfigKeyboard(pDeviceInt);
156
/* FIXME: Maybe we should use winGetKbdLeds () here? */
157
defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
159
winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
160
" Variant = \"%s\" Options = \"%s\"\n",
161
g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "none",
162
g_winInfo.xkb.model ? g_winInfo.xkb.model : "none",
163
g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "none",
164
g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "none",
165
g_winInfo.xkb.options ? g_winInfo.xkb.options : "none");
167
InitKeyboardDeviceStruct(pDeviceInt,
168
&g_winInfo.xkb, winKeybdBell, winKeybdCtrl);
170
xkbi = pDeviceInt->key->xkbInfo;
171
if ((xkbi != NULL) && (xkbi->desc != NULL)) {
172
ctrl = xkbi->desc->ctrls;
173
ctrl->repeat_delay = g_winInfo.keyboard.delay;
174
ctrl->repeat_interval = 1000 / g_winInfo.keyboard.rate;
178
"winKeybdProc - Error initializing keyboard AutoRepeat\n");
186
// immediately copy the state of this keyboard device to the VCK
187
// (which otherwise happens lazily after the first keypress)
188
CopyKeyClass(pDeviceInt, inputInfo.keyboard);
201
* Detect current mode key states upon server startup.
203
* Simulate a press and release of any key that is currently
208
winInitializeModeKeyStates(void)
210
/* Restore NumLock */
211
if (GetKeyState(VK_NUMLOCK) & 0x0001) {
212
winSendKeyEvent(KEY_NumLock, TRUE);
213
winSendKeyEvent(KEY_NumLock, FALSE);
216
/* Restore CapsLock */
217
if (GetKeyState(VK_CAPITAL) & 0x0001) {
218
winSendKeyEvent(KEY_CapsLock, TRUE);
219
winSendKeyEvent(KEY_CapsLock, FALSE);
222
/* Restore ScrollLock */
223
if (GetKeyState(VK_SCROLL) & 0x0001) {
224
winSendKeyEvent(KEY_ScrollLock, TRUE);
225
winSendKeyEvent(KEY_ScrollLock, FALSE);
228
/* Restore KanaLock */
229
if (GetKeyState(VK_KANA) & 0x0001) {
230
winSendKeyEvent(KEY_HKTG, TRUE);
231
winSendKeyEvent(KEY_HKTG, FALSE);
236
* Upon regaining the keyboard focus we must
237
* resynchronize our internal mode key states
238
* with the actual state of the keys.
242
winRestoreModeKeyStates(void)
245
BOOL processEvents = TRUE;
246
unsigned short internalKeyStates;
248
/* X server is being initialized */
249
if (!inputInfo.keyboard)
252
/* Only process events if the rootwindow is mapped. The keyboard events
253
* will cause segfaults otherwise */
254
if (screenInfo.screens[0]->root &&
255
screenInfo.screens[0]->root->mapped == FALSE)
256
processEvents = FALSE;
258
/* Force to process all pending events in the mi event queue */
260
mieqProcessInputEvents();
262
/* Read the mode key states of our X server */
263
/* (stored in the virtual core keyboard) */
265
XkbStateFieldFromRec(&inputInfo.keyboard->key->xkbInfo->state);
266
winDebug("winRestoreModeKeyStates: state %d\n", internalKeyStates);
268
/* Check if modifier keys are pressed, and if so, fake a press */
271
BOOL lctrl = (GetAsyncKeyState(VK_LCONTROL) < 0);
272
BOOL rctrl = (GetAsyncKeyState(VK_RCONTROL) < 0);
273
BOOL lshift = (GetAsyncKeyState(VK_LSHIFT) < 0);
274
BOOL rshift = (GetAsyncKeyState(VK_RSHIFT) < 0);
275
BOOL alt = (GetAsyncKeyState(VK_LMENU) < 0);
276
BOOL altgr = (GetAsyncKeyState(VK_RMENU) < 0);
279
If AltGr and CtrlL appear to be pressed, assume the
286
winSendKeyEvent(KEY_LCtrl, TRUE);
289
winSendKeyEvent(KEY_RCtrl, TRUE);
292
winSendKeyEvent(KEY_ShiftL, TRUE);
295
winSendKeyEvent(KEY_ShiftL, TRUE);
298
winSendKeyEvent(KEY_Alt, TRUE);
301
winSendKeyEvent(KEY_AltLang, TRUE);
305
Check if latching modifier key states have changed, and if so,
306
fake a press and a release to toggle the modifier to the correct
309
dwKeyState = GetKeyState(VK_NUMLOCK) & 0x0001;
310
if (LOGICAL_XOR(internalKeyStates & NumLockMask, dwKeyState)) {
311
winSendKeyEvent(KEY_NumLock, TRUE);
312
winSendKeyEvent(KEY_NumLock, FALSE);
315
dwKeyState = GetKeyState(VK_CAPITAL) & 0x0001;
316
if (LOGICAL_XOR(internalKeyStates & LockMask, dwKeyState)) {
317
winSendKeyEvent(KEY_CapsLock, TRUE);
318
winSendKeyEvent(KEY_CapsLock, FALSE);
321
dwKeyState = GetKeyState(VK_SCROLL) & 0x0001;
322
if (LOGICAL_XOR(internalKeyStates & ScrollLockMask, dwKeyState)) {
323
winSendKeyEvent(KEY_ScrollLock, TRUE);
324
winSendKeyEvent(KEY_ScrollLock, FALSE);
327
dwKeyState = GetKeyState(VK_KANA) & 0x0001;
328
if (LOGICAL_XOR(internalKeyStates & KanaMask, dwKeyState)) {
329
winSendKeyEvent(KEY_HKTG, TRUE);
330
winSendKeyEvent(KEY_HKTG, FALSE);
334
For strict correctness, we should also press any non-modifier keys
335
which are already down when we gain focus, but nobody has complained
341
* Look for the lovely fake Control_L press/release generated by Windows
342
* when AltGr is pressed/released on a non-U.S. keyboard.
346
winIsFakeCtrl_L(UINT message, WPARAM wParam, LPARAM lParam)
352
static Bool lastWasControlL = FALSE;
353
static LONG lastTime;
356
* Fake Ctrl_L presses will be followed by an Alt_R press
357
* with the same timestamp as the Ctrl_L press.
359
if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
360
&& wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
361
/* Got a Ctrl_L press */
363
/* Get time of current message */
364
lTime = GetMessageTime();
366
/* Look for next press message */
367
fReturn = PeekMessage(&msgNext, NULL,
368
WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE);
370
if (fReturn && msgNext.message != WM_KEYDOWN &&
371
msgNext.message != WM_SYSKEYDOWN)
375
lastWasControlL = TRUE;
379
lastWasControlL = FALSE;
382
/* Is next press an Alt_R with the same timestamp? */
383
if (fReturn && msgNext.wParam == VK_MENU
384
&& msgNext.time == lTime
385
&& (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
387
* Next key press is Alt_R with same timestamp as current
388
* Ctrl_L message. Therefore, this Ctrl_L press is a fake
389
* event, so discard it.
395
* Sometimes, the Alt_R press message is not yet posted when the
396
* fake Ctrl_L press message arrives (even though it has the
397
* same timestamp), so check for an Alt_R press message that has
398
* arrived since the last Ctrl_L message.
400
else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
401
&& wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) {
402
/* Got a Alt_R press */
404
if (lastWasControlL) {
405
lTime = GetMessageTime();
407
if (lastTime == lTime) {
408
/* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */
409
winSendKeyEvent(KEY_LCtrl, FALSE);
411
lastWasControlL = FALSE;
415
* Fake Ctrl_L releases will be followed by an Alt_R release
416
* with the same timestamp as the Ctrl_L release.
418
else if ((message == WM_KEYUP || message == WM_SYSKEYUP)
419
&& wParam == VK_CONTROL && (HIWORD(lParam) & KF_EXTENDED) == 0) {
420
/* Got a Ctrl_L release */
422
/* Get time of current message */
423
lTime = GetMessageTime();
425
/* Look for next release message */
426
fReturn = PeekMessage(&msgNext, NULL,
427
WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE);
429
if (fReturn && msgNext.message != WM_KEYUP &&
430
msgNext.message != WM_SYSKEYUP)
433
lastWasControlL = FALSE;
435
/* Is next press an Alt_R with the same timestamp? */
437
&& (msgNext.message == WM_KEYUP || msgNext.message == WM_SYSKEYUP)
438
&& msgNext.wParam == VK_MENU
439
&& msgNext.time == lTime
440
&& (HIWORD(msgNext.lParam) & KF_EXTENDED)) {
442
* Next key release is Alt_R with same timestamp as current
443
* Ctrl_L message. Therefore, this Ctrl_L release is a fake
444
* event, so discard it.
450
/* On any other press or release message, we don't have a
451
potentially fake Ctrl_L to worry about anymore... */
452
lastWasControlL = FALSE;
455
/* Not a fake control left press/release */
460
* Lift any modifier keys that are pressed
464
winKeybdReleaseKeys(void)
468
#ifdef HAS_DEVWINDOWS
469
/* Verify that the mi input system has been initialized */
470
if (g_fdMessageQueue == WIN_FD_INVALID)
474
/* Loop through all keys */
475
for (i = 0; i < NUM_KEYCODES; ++i) {
476
/* Pop key if pressed */
477
if (g_winKeyState[i])
478
winSendKeyEvent(i, FALSE);
480
/* Reset pressed flag for keys */
481
g_winKeyState[i] = FALSE;
486
* Take a raw X key code and send an up or down event for it.
488
* Thanks to VNC for inspiration, though it is a simple function.
492
winSendKeyEvent(DWORD dwKey, Bool fDown)
495
* When alt-tabing between screens we can get phantom key up messages
496
* Here we only pass them through it we think we should!
498
if (g_winKeyState[dwKey] == FALSE && fDown == FALSE)
501
/* Update the keyState map */
502
g_winKeyState[dwKey] = fDown;
504
QueueKeyboardEvents(g_pwinKeyboard, fDown ? KeyPress : KeyRelease,
505
dwKey + MIN_KEYCODE);
507
winDebug("winSendKeyEvent: dwKey: %u, fDown: %u\n", (unsigned int)dwKey, fDown);
511
winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
515
if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
517
if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
521
if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
523
if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
532
/* Only one shift release message is sent even if both are pressed.
536
winFixShiftKeys(int iScanCode)
538
if (GetKeyState(VK_SHIFT) & 0x8000)
541
if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
542
winSendKeyEvent(KEY_ShiftR, FALSE);
543
if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
544
winSendKeyEvent(KEY_ShiftL, FALSE);