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
33
/* $XFree86: xc/programs/Xserver/hw/xwin/winkeybd.c,v 1.12 2002/10/17 08:18:22 alanh Exp $ */
36
#ifdef HAVE_XWIN_CONFIG_H
37
#include <xwin-config.h>
41
#include "winconfig.h"
48
#include <X11/extensions/XKBsrv.h>
51
static Bool g_winKeyState[NUM_KEYCODES];
53
/* Stored to get internal mode key states. Must be read-only. */
54
static unsigned short const *g_winInternalModeKeyStatesPtr = NULL;
62
winGetKeyMappings (KeySymsPtr pKeySyms, CARD8 *pModMap);
65
winKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
66
pointer pCtrl, int iClass);
69
winKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl);
73
* Translate a Windows WM_[SYS]KEY(UP/DOWN) message
74
* into an ASCII scan code.
76
* We do this ourselves, rather than letting Windows handle it,
77
* because Windows tends to munge the handling of special keys,
78
* like AltGr on European keyboards.
82
winTranslateKey (WPARAM wParam, LPARAM lParam, int *piScanCode)
84
int iKeyFixup = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 1];
85
int iKeyFixupEx = g_iKeyMap[wParam * WIN_KEYMAP_COLS + 2];
86
int iParamScanCode = LOBYTE (HIWORD (lParam));
88
/* Branch on special extended, special non-extended, or normal key */
89
if ((HIWORD (lParam) & KF_EXTENDED) && iKeyFixupEx)
90
*piScanCode = iKeyFixupEx;
92
*piScanCode = iKeyFixup;
93
else if (wParam == 0 && iParamScanCode == 0x70)
94
*piScanCode = KEY_HKTG;
96
switch (iParamScanCode)
99
*piScanCode = KEY_HKTG;
102
*piScanCode = KEY_BSlash2;
105
*piScanCode = iParamScanCode;
112
* We call this function from winKeybdProc when we are
113
* initializing the keyboard.
117
winGetKeyMappings (KeySymsPtr pKeySyms, CARD8 *pModMap)
124
* Initialize all key states to up... which may not be true
125
* but it is close enough.
127
ZeroMemory (g_winKeyState, sizeof (g_winKeyState[0]) * NUM_KEYCODES);
129
/* MAP_LENGTH is defined in Xserver/include/input.h to be 256 */
130
for (i = 0; i < MAP_LENGTH; i++)
131
pModMap[i] = NoSymbol; /* make sure it is restored */
133
/* Loop through all valid entries in the key symbol table */
134
for (pKeySym = pMap, i = MIN_KEYCODE;
135
i < (MIN_KEYCODE + NUM_KEYCODES);
136
i++, pKeySym += GLYPHS_PER_KEY)
142
pModMap[i] = ShiftMask;
147
pModMap[i] = ControlMask;
151
pModMap[i] = LockMask;
156
pModMap[i] = AltMask;
160
pModMap[i] = NumLockMask;
164
pModMap[i] = ScrollLockMask;
170
pModMap[i] = Mod4Mask;
173
/* Hirigana/Katakana toggle */
176
pModMap[i] = KanaMask;
180
/* alternate toggle for multinational support */
182
pModMap[i] = AltLangMask;
187
pKeySyms->map = (KeySym *) pMap;
188
pKeySyms->mapWidth = GLYPHS_PER_KEY;
189
pKeySyms->minKeyCode = MIN_KEYCODE;
190
pKeySyms->maxKeyCode = MAX_KEYCODE;
194
/* Ring the keyboard bell (system speaker on PCs) */
196
winKeybdBell (int iPercent, DeviceIntPtr pDeviceInt,
197
pointer pCtrl, int iClass)
200
* We can't use Beep () here because it uses the PC speaker
201
* on NT/2000. MessageBeep (MB_OK) will play the default system
202
* sound on systems with a sound card or it will beep the PC speaker
203
* on systems that do not have a sound card.
209
/* Change some keyboard configuration parameters */
211
winKeybdCtrl (DeviceIntPtr pDevice, KeybdCtrl *pCtrl)
213
g_winInternalModeKeyStatesPtr = &(pDevice->key->state);
218
* See Porting Layer Definition - p. 18
219
* winKeybdProc is known as a DeviceProc.
223
winKeybdProc (DeviceIntPtr pDeviceInt, int iState)
226
CARD8 modMap[MAP_LENGTH];
227
DevicePtr pDevice = (DevicePtr) pDeviceInt;
229
XkbComponentNamesRec names;
237
winConfigKeyboard (pDeviceInt);
239
winGetKeyMappings (&keySyms, modMap);
242
/* FIXME: Maybe we should use winGetKbdLeds () here? */
243
defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
245
defaultKeyboardControl.leds = g_winInfo.keyboard.leds;
249
if (g_winInfo.xkb.disable)
252
InitKeyboardDeviceStruct (pDevice,
264
names.keymap = XkbInitialMap;
265
names.keycodes = NULL;
268
names.symbols = NULL;
269
names.geometry = NULL;
273
names.keymap = g_winInfo.xkb.keymap;
274
names.keycodes = g_winInfo.xkb.keycodes;
275
names.types = g_winInfo.xkb.types;
276
names.compat = g_winInfo.xkb.compat;
277
names.symbols = g_winInfo.xkb.symbols;
278
names.geometry = g_winInfo.xkb.geometry;
281
winErrorFVerb(2, "Rules = \"%s\" Model = \"%s\" Layout = \"%s\""
282
" Variant = \"%s\" Options = \"%s\"\n",
283
g_winInfo.xkb.rules, g_winInfo.xkb.model,
284
g_winInfo.xkb.layout, g_winInfo.xkb.variant,
285
g_winInfo.xkb.options);
287
XkbSetRulesDflts (g_winInfo.xkb.rules, g_winInfo.xkb.model,
288
g_winInfo.xkb.layout, g_winInfo.xkb.variant,
289
g_winInfo.xkb.options);
290
XkbInitKeyboardDeviceStruct (pDeviceInt, &names, &keySyms,
291
modMap, winKeybdBell, winKeybdCtrl);
296
if (!g_winInfo.xkb.disable)
298
xkbi = pDeviceInt->key->xkbInfo;
301
ctrl = xkbi->desc->ctrls;
302
ctrl->repeat_delay = g_winInfo.keyboard.delay;
303
ctrl->repeat_interval = 1000/g_winInfo.keyboard.rate;
307
winErrorFVerb (1, "winKeybdProc - Error initializing keyboard AutoRepeat (No XKB)\n");
312
g_winInternalModeKeyStatesPtr = &(pDeviceInt->key->state);
317
g_winInternalModeKeyStatesPtr = &(pDeviceInt->key->state);
323
g_winInternalModeKeyStatesPtr = NULL;
332
* Detect current mode key states upon server startup.
334
* Simulate a press and release of any key that is currently
339
winInitializeModeKeyStates (void)
341
/* Restore NumLock */
342
if (GetKeyState (VK_NUMLOCK) & 0x0001)
344
winSendKeyEvent (KEY_NumLock, TRUE);
345
winSendKeyEvent (KEY_NumLock, FALSE);
348
/* Restore CapsLock */
349
if (GetKeyState (VK_CAPITAL) & 0x0001)
351
winSendKeyEvent (KEY_CapsLock, TRUE);
352
winSendKeyEvent (KEY_CapsLock, FALSE);
355
/* Restore ScrollLock */
356
if (GetKeyState (VK_SCROLL) & 0x0001)
358
winSendKeyEvent (KEY_ScrollLock, TRUE);
359
winSendKeyEvent (KEY_ScrollLock, FALSE);
362
/* Restore KanaLock */
363
if (GetKeyState (VK_KANA) & 0x0001)
365
winSendKeyEvent (KEY_HKTG, TRUE);
366
winSendKeyEvent (KEY_HKTG, FALSE);
372
* Upon regaining the keyboard focus we must
373
* resynchronize our internal mode key states
374
* with the actual state of the keys.
378
winRestoreModeKeyStates ()
381
BOOL processEvents = TRUE;
382
unsigned short internalKeyStates;
384
/* X server is being initialized */
385
if (!g_winInternalModeKeyStatesPtr)
388
/* Only process events if the rootwindow is mapped. The keyboard events
389
* will cause segfaults otherwise */
390
if (WindowTable && WindowTable[0] && WindowTable[0]->mapped == FALSE)
391
processEvents = FALSE;
393
/* Force to process all pending events in the mi event queue */
395
mieqProcessInputEvents ();
397
/* Read the mode key states of our X server */
398
internalKeyStates = *g_winInternalModeKeyStatesPtr;
401
* NOTE: The C XOR operator, ^, will not work here because it is
402
* a bitwise operator, not a logical operator. C does not
403
* have a logical XOR operator, so we use a macro instead.
406
/* Has the key state changed? */
407
dwKeyState = GetKeyState (VK_NUMLOCK) & 0x0001;
408
if (WIN_XOR (internalKeyStates & NumLockMask, dwKeyState))
410
winSendKeyEvent (KEY_NumLock, TRUE);
411
winSendKeyEvent (KEY_NumLock, FALSE);
414
/* Has the key state changed? */
415
dwKeyState = GetKeyState (VK_CAPITAL) & 0x0001;
416
if (WIN_XOR (internalKeyStates & LockMask, dwKeyState))
418
winSendKeyEvent (KEY_CapsLock, TRUE);
419
winSendKeyEvent (KEY_CapsLock, FALSE);
422
/* Has the key state changed? */
423
dwKeyState = GetKeyState (VK_SCROLL) & 0x0001;
424
if (WIN_XOR (internalKeyStates & ScrollLockMask, dwKeyState))
426
winSendKeyEvent (KEY_ScrollLock, TRUE);
427
winSendKeyEvent (KEY_ScrollLock, FALSE);
430
/* Has the key state changed? */
431
dwKeyState = GetKeyState (VK_KANA) & 0x0001;
432
if (WIN_XOR (internalKeyStates & KanaMask, dwKeyState))
434
winSendKeyEvent (KEY_HKTG, TRUE);
435
winSendKeyEvent (KEY_HKTG, FALSE);
441
* Look for the lovely fake Control_L press/release generated by Windows
442
* when AltGr is pressed/released on a non-U.S. keyboard.
446
winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam)
453
* Fake Ctrl_L presses will be followed by an Alt_R keypress
454
* with the same timestamp as the Ctrl_L press.
456
if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
457
&& wParam == VK_CONTROL
458
&& (HIWORD (lParam) & KF_EXTENDED) == 0)
460
/* Got a Ctrl_L press */
462
/* Get time of current message */
463
lTime = GetMessageTime ();
465
/* Look for fake Ctrl_L preceeding an Alt_R press. */
466
fReturn = PeekMessage (&msgNext, NULL,
467
WM_KEYDOWN, WM_SYSKEYDOWN,
471
* Try again if the first call fails.
472
* NOTE: This usually happens when TweakUI is enabled.
476
/* Voodoo to make sure that the Alt_R message has posted */
479
/* Look for fake Ctrl_L preceeding an Alt_R press. */
480
fReturn = PeekMessage (&msgNext, NULL,
481
WM_KEYDOWN, WM_SYSKEYDOWN,
484
if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN)
487
/* Is next press an Alt_R with the same timestamp? */
488
if (fReturn && msgNext.wParam == VK_MENU
489
&& msgNext.time == lTime
490
&& (HIWORD (msgNext.lParam) & KF_EXTENDED))
493
* Next key press is Alt_R with same timestamp as current
494
* Ctrl_L message. Therefore, this Ctrl_L press is a fake
495
* event, so discard it.
502
* Fake Ctrl_L releases will be followed by an Alt_R release
503
* with the same timestamp as the Ctrl_L release.
505
if ((message == WM_KEYUP || message == WM_SYSKEYUP)
506
&& wParam == VK_CONTROL
507
&& (HIWORD (lParam) & KF_EXTENDED) == 0)
509
/* Got a Ctrl_L release */
511
/* Get time of current message */
512
lTime = GetMessageTime ();
514
/* Look for fake Ctrl_L release preceeding an Alt_R release. */
515
fReturn = PeekMessage (&msgNext, NULL,
516
WM_KEYUP, WM_SYSKEYUP,
520
* Try again if the first call fails.
521
* NOTE: This usually happens when TweakUI is enabled.
525
/* Voodoo to make sure that the Alt_R message has posted */
528
/* Look for fake Ctrl_L release preceeding an Alt_R release. */
529
fReturn = PeekMessage (&msgNext, NULL,
530
WM_KEYUP, WM_SYSKEYUP,
534
if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP)
537
/* Is next press an Alt_R with the same timestamp? */
539
&& (msgNext.message == WM_KEYUP
540
|| msgNext.message == WM_SYSKEYUP)
541
&& msgNext.wParam == VK_MENU
542
&& msgNext.time == lTime
543
&& (HIWORD (msgNext.lParam) & KF_EXTENDED))
546
* Next key release is Alt_R with same timestamp as current
547
* Ctrl_L message. Therefore, this Ctrl_L release is a fake
548
* event, so discard it.
554
/* Not a fake control left press/release */
560
* Lift any modifier keys that are pressed
564
winKeybdReleaseKeys ()
568
#ifdef HAS_DEVWINDOWS
569
/* Verify that the mi input system has been initialized */
570
if (g_fdMessageQueue == WIN_FD_INVALID)
574
/* Loop through all keys */
575
for (i = 0; i < NUM_KEYCODES; ++i)
577
/* Pop key if pressed */
578
if (g_winKeyState[i])
579
winSendKeyEvent (i, FALSE);
581
/* Reset pressed flag for keys */
582
g_winKeyState[i] = FALSE;
588
* Take a raw X key code and send an up or down event for it.
590
* Thanks to VNC for inspiration, though it is a simple function.
594
winSendKeyEvent (DWORD dwKey, Bool fDown)
596
xEvent xCurrentEvent;
599
* When alt-tabing between screens we can get phantom key up messages
600
* Here we only pass them through it we think we should!
602
if (g_winKeyState[dwKey] == FALSE && fDown == FALSE) return;
604
/* Update the keyState map */
605
g_winKeyState[dwKey] = fDown;
607
ZeroMemory (&xCurrentEvent, sizeof (xCurrentEvent));
609
xCurrentEvent.u.u.type = fDown ? KeyPress : KeyRelease;
610
xCurrentEvent.u.keyButtonPointer.time =
611
g_c32LastInputEventTime = GetTickCount ();
612
xCurrentEvent.u.u.detail = dwKey + MIN_KEYCODE;
613
mieqEnqueue (&xCurrentEvent);
616
BOOL winCheckKeyPressed(WPARAM wParam, LPARAM lParam)
621
if ((lParam & 0x1ff0000) == 0x11d0000 && g_winKeyState[KEY_RCtrl])
623
if ((lParam & 0x1ff0000) == 0x01d0000 && g_winKeyState[KEY_LCtrl])
627
if ((lParam & 0x1ff0000) == 0x0360000 && g_winKeyState[KEY_ShiftR])
629
if ((lParam & 0x1ff0000) == 0x02a0000 && g_winKeyState[KEY_ShiftL])
638
/* Only on shift release message is sent even if both are pressed.
641
void winFixShiftKeys (int iScanCode)
643
if (GetKeyState (VK_SHIFT) & 0x8000)
646
if (iScanCode == KEY_ShiftL && g_winKeyState[KEY_ShiftR])
647
winSendKeyEvent (KEY_ShiftR, FALSE);
648
if (iScanCode == KEY_ShiftR && g_winKeyState[KEY_ShiftL])
649
winSendKeyEvent (KEY_ShiftL, FALSE);