2 * Keyboard related functions
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
14 #include <X11/keysym.h>
16 #include "ts_xresource.h"
18 #include <X11/Xatom.h>
27 #include "debugtools.h"
31 BOOL32 MouseButtonsStates[3];
32 BOOL32 AsyncMouseButtonsStates[3];
33 BYTE InputKeyStateTable[256];
34 BYTE QueueKeyStateTable[256];
35 BYTE AsyncKeyStateTable[256];
37 static int NumLockMask;
39 static int min_keycode, max_keycode;
40 static int keyc2vkey[256];
46 unsigned long count : 16;
47 unsigned long code : 8;
48 unsigned long extended : 1;
49 unsigned long unused : 2;
50 unsigned long win_internal : 2;
51 unsigned long context : 1;
52 unsigned long previous : 1;
53 unsigned long transition : 1;
58 /* Keyboard translation tables */
59 static const int special_key[] =
61 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
62 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
63 0, 0, 0, VK_ESCAPE /* FF18 */
66 static const int cursor_key[] =
68 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
69 VK_NEXT, VK_END /* FF50 */
72 static const int misc_key[] =
74 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
75 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
78 static const int keypad_key[] =
80 0, VK_NUMLOCK, /* FF7E */
81 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
82 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
83 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
84 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
85 VK_INSERT, VK_DELETE, /* FF98 */
86 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
87 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
88 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
89 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
90 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
91 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
94 static const int function_key[] =
96 VK_F1, VK_F2, /* FFBE */
97 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
98 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
101 static const int modifier_key[] =
103 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
104 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
108 * Table for vkey to scancode translation - 5/29/97 chrisf@america.com
110 const BYTE vkey2scode[512] = {
111 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0e,0x0f,0x00,0x00,0x00,0x1c,0x00,0x00,
112 0x2a,0x1d,0x38,0x00,0x3a,0x00,0x00,0x00, 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
113 0x39,0x49,0x51,0x4f,0x47,0x4b,0x48,0x4d, 0x50,0x00,0x00,0x00,0x00,0x52,0x53,0x00,
114 0x0b,0x02,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,
115 0x00,0x1e,0x30,0x2e,0x20,0x12,0x21,0x22, 0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,
116 0x19,0x10,0x13,0x1f,0x14,0x16,0x2f,0x11, 0x2d,0x15,0x2c,0x00,0x00,0x00,0x00,0x00,
117 0x0b,0x02,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0a,0x37,0x4e,0x00,0x4a,0x34,0x00,
118 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
119 0x00,0x46,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x29,0x0c,0x0d,0x1a,0x1b,0x2b,
123 0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
124 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x28,0x33,0x34,0x35,0x4c,
125 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
126 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x00,
129 0x00,0x1d,0x38,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130 0x00,0x49,0x51,0x4f,0x47,0x4b,0x48,0x4d, 0x50,0x00,0x00,0x00,0x00,0x52,0x53,0x00,
131 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
132 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,
135 0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42, 0x43,0x44,0x57,0x58,0x00,0x00,0x00,0x00,
136 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
137 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
138 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
139 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
140 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
141 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
142 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
143 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
146 static WORD EVENT_event_to_vkey( XKeyEvent *e)
150 TSXLookupString(e, NULL, 0, &keysym, NULL);
152 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (e->state & NumLockMask))
153 /* Only the Keypad keys 0-9 and . send different keysyms
154 * depending on the NumLock state */
155 return keypad_key[(keysym & 0xFF) - 0x7E];
157 return keyc2vkey[e->keycode];
160 /**********************************************************************
163 BOOL32 KEYBOARD_Init(void)
165 int i, keysyms_per_keycode;
167 XModifierKeymap *mmp;
173 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
174 ksp = TSXGetKeyboardMapping(display, min_keycode,
175 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
176 /* We are only interested in keysyms_per_keycode.
177 There is no need to hold a local copy of the keysyms table */
179 mmp = TSXGetModifierMapping(display);
180 kcp = mmp->modifiermap;
181 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
185 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
190 for (k = 0; k < keysyms_per_keycode; k += 1)
191 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
194 TRACE(key, "AltGrMask is %x\n", AltGrMask);
196 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
198 NumLockMask = 1 << i;
199 TRACE(key, "NumLockMask is %x\n", NumLockMask);
203 TSXFreeModifiermap(mmp);
205 /* Now build two conversion arrays :
206 * keycode -> vkey + extended
207 * vkey + extended -> keycode */
209 e2.display = display;
212 OEMvkey = VK_OEM_7; /* next is available. */
213 for (e2.keycode=min_keycode; e2.keycode<=max_keycode; e2.keycode++)
215 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
217 if (keysym) /* otherwise, keycode not used */
219 if ((keysym >> 8) == 0xFF) /* non-character key */
221 int key = keysym & 0xff;
223 if (key >= 0x08 && key <= 0x1B) /* special key */
224 vkey = special_key[key - 0x08];
225 else if (key >= 0x50 && key <= 0x57) /* cursor key */
226 vkey = cursor_key[key - 0x50];
227 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
228 vkey = misc_key[key - 0x60];
229 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
230 vkey = keypad_key[key - 0x7E];
231 else if (key >= 0xBE && key <= 0xCD) /* function key */
233 vkey = function_key[key - 0xBE];
234 vkey |= 0x100; /* set extended bit */
236 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
237 vkey = modifier_key[key - 0xE1];
238 else if (key == 0xFF) /* DEL key */
240 /* extended must also be set for ALT_R, CTRL_R,
241 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
242 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
243 /* FIXME should we set extended bit for NumLock ? My
244 * Windows does ... DF */
264 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
266 keysym = TSXLookupKeysym(&e2, i);
267 if ((keysym >= VK_0 && keysym <= VK_9)
268 || (keysym >= VK_A && keysym <= VK_Z)
269 || keysym == VK_SPACE)
273 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
275 keysym = TSXLookupKeysym(&e2, i);
278 case ';': case ':': vkey = VK_OEM_1; break;
279 case '/': case '?': vkey = VK_OEM_2; break;
280 case '`': case '~': vkey = VK_OEM_3; break;
281 case '[': vkey = VK_OEM_4; break;
282 case '\\': vkey = VK_OEM_5; break;
283 case ']': vkey = VK_OEM_6; break;
284 case '\'': case '\"': vkey = VK_OEM_7; break;
285 case ',': vkey = VK_OEM_COMMA; break;
286 case '.': vkey = VK_OEM_PERIOD; break;
287 case '-': vkey = VK_OEM_MINUS; break;
288 case '+': vkey = VK_OEM_PLUS; break;
294 /* Others keys: let's assign OEM virtual key codes in the allowed range,
295 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
298 case 0xc1 : OEMvkey=0xdb; break;
299 case 0xe5 : OEMvkey=0xe9; break;
300 case 0xf6 : OEMvkey=0xf5; WARN(keyboard,"No more OEM vkey available!\n");
305 if (TRACE_ON(keyboard))
307 dbg_decl_str(keyboard, 1024);
309 TRACE(keyboard, "OEM specific virtual key %X assigned "
310 "to keycode %X:\n", OEMvkey, e2.keycode);
311 for (i = 0; i < keysyms_per_keycode; i += 1)
315 keysym = TSXLookupKeysym(&e2, i);
316 ksname = TSXKeysymToString(keysym);
319 dsprintf(keyboard, "%lX (%s) ", keysym, ksname);
321 TRACE(keyboard, "(%s)\n", dbg_str(keyboard));
325 keyc2vkey[e2.keycode] = vkey;
330 static BOOL32 NumState=FALSE, CapsState=FALSE;
332 /**********************************************************************
333 * KEYBOARD_GenerateMsg
335 void KEYBOARD_GenerateMsg( WORD vkey, int Evtype, INT32 event_x, INT32 event_y,
336 DWORD event_time, KEYLP localkeylp )
338 BOOL32 * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
341 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
342 don't treat it. It's from the same key press. Then the state goes to ON.
343 And from there, a 'release' event will switch off the toggle key. */
345 TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,InputKeyStateTable[vkey]);
348 if ( InputKeyStateTable[vkey] & 0x1 ) /* it was ON */
350 if (Evtype!=KeyPress)
352 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
353 localkeylp.lp1.previous = 0; /* ? */
354 localkeylp.lp1.transition = 0;
355 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
356 event_x, event_y, event_time, 0 );
357 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
358 event_x, event_y, event_time, 0 );
360 InputKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
363 else /* it was OFF */
364 if (Evtype==KeyPress)
366 TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
367 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
368 event_x, event_y, event_time, 0 );
369 localkeylp.lp1.previous = 1;
370 localkeylp.lp1.transition = 1;
371 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
372 event_x, event_y, event_time, 0 );
373 *State=TRUE; /* Goes to intermediary state before going to ON */
374 InputKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
379 /***********************************************************************
380 * KEYBOARD_HandleEvent
382 * Handle a X key event
384 void KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
391 static BOOL32 force_extended = FALSE; /* hack for AltGr translation */
393 int ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
395 INT32 event_x = pWnd->rectWindow.left + event->x;
396 INT32 event_y = pWnd->rectWindow.top + event->y;
397 DWORD event_time = event->time - MSG_WineStartTicks;
399 TRACE(key, "EVENT_key : state = %X\n", event->state);
400 if (keysym == XK_Mode_switch)
402 TRACE(key, "Alt Gr key event received\n");
403 event->keycode = TSXKeysymToKeycode(event->display, XK_Control_L);
404 TRACE(key, "Control_L is keycode 0x%x\n", event->keycode);
405 KEYBOARD_HandleEvent( pWnd, event );
406 event->keycode = TSXKeysymToKeycode(event->display, XK_Alt_L);
407 TRACE(key, "Alt_L is keycode 0x%x\n", event->keycode);
408 force_extended = TRUE;
409 KEYBOARD_HandleEvent( pWnd, event );
410 force_extended = FALSE;
414 Str[ascii_chars] = '\0';
418 ksname = TSXKeysymToString(keysym);
421 TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
422 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
423 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
426 vkey = EVENT_event_to_vkey(event);
427 if (force_extended) vkey |= 0x100;
429 TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
430 event->keycode, vkey);
435 keylp.lp1.code = vkey2scode[vkey]; /* 5/29/97 chrisf@america.com */
436 keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
437 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
438 * don't remember where I read it - AK */
439 /* it's '1' under windows, when a dialog box appears
440 * and you press one of the underlined keys - DF*/
446 KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
450 TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
451 KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
453 TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
458 if (event->type == KeyPress)
460 keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
461 if (!(InputKeyStateTable[vkey] & 0x80))
462 InputKeyStateTable[vkey] ^= 0x01;
463 InputKeyStateTable[vkey] |= 0x80;
464 keylp.lp1.transition = 0;
465 message = (InputKeyStateTable[VK_MENU] & 0x80)
466 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
467 ? WM_SYSKEYDOWN : WM_KEYDOWN;
471 BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
472 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
473 && (force_extended == FALSE); /* for Alt from AltGr */
475 InputKeyStateTable[vkey] &= ~0x80;
476 keylp.lp1.previous = 1;
477 keylp.lp1.transition = 1;
478 message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
480 keylp.lp1.context = ( (event->state & Mod1Mask) ||
481 (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
482 if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
484 TRACE(keyboard,"Adjusting NumLock state. \n");
485 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
487 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
490 if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
492 TRACE(keyboard,"Adjusting Caps Lock state. State before %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
493 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
495 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
497 TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
499 /* End of intermediary states. */
503 TRACE(key," wParam=%04X, lParam=%08lX\n",
505 TRACE(key," InputKeyState=%X\n",
506 InputKeyStateTable[vkey]);
508 hardware_event( message, vkey, keylp.lp2,
509 event_x, event_y, event_time, 0 );
516 /**********************************************************************
517 * GetKeyState (USER.106)
519 WORD WINAPI GetKeyState16(INT16 vkey)
521 return GetKeyState32(vkey);
524 /**********************************************************************
525 * GetKeyState (USER32.249)
527 * An application calls the GetKeyState function in response to a
528 * keyboard-input message. This function retrieves the state of the key
529 * at the time the input message was generated. (SDK 3.1 Vol 2. p 390)
531 WORD WINAPI GetKeyState32(INT32 vkey)
537 case VK_LBUTTON : /* VK_LBUTTON is 1 */
538 retval = MouseButtonsStates[0] ? 0x8000 : 0;
540 case VK_MBUTTON : /* VK_MBUTTON is 4 */
541 retval = MouseButtonsStates[1] ? 0x8000 : 0;
543 case VK_RBUTTON : /* VK_RBUTTON is 2 */
544 retval = MouseButtonsStates[2] ? 0x8000 : 0;
547 if (vkey >= 'a' && vkey <= 'z')
549 retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
550 (WORD)(QueueKeyStateTable[vkey] & 0x01);
552 TRACE(key, "(0x%x) -> %x\n", vkey, retval);
556 /**********************************************************************
557 * GetKeyboardState (USER.222)(USER32.254)
559 * An application calls the GetKeyboardState function in response to a
560 * keyboard-input message. This function retrieves the state of the keyboard
561 * at the time the input message was generated. (SDK 3.1 Vol 2. p 387)
563 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
565 TRACE(key, "(%p)\n", lpKeyState);
566 if (lpKeyState != NULL) {
567 QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
568 QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
569 QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
570 memcpy(lpKeyState, QueueKeyStateTable, 256);
574 /**********************************************************************
575 * SetKeyboardState (USER.223)(USER32.484)
577 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
579 TRACE(key, "(%p)\n", lpKeyState);
580 if (lpKeyState != NULL) {
581 memcpy(QueueKeyStateTable, lpKeyState, 256);
582 MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
583 MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
584 MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
588 /**********************************************************************
589 * GetAsyncKeyState32 (USER32.207)
591 * Determine if a key is or was pressed. retval has high-order
592 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
595 * This uses the variable AsyncMouseButtonsStates and
596 * AsyncKeyStateTable (set in event.c) which have the mouse button
597 * number or key number (whichever is applicable) set to true if the
598 * mouse or key had been depressed since the last call to
601 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
607 retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) |
608 (MouseButtonsStates[0] ? 0x8000 : 0);
611 retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) |
612 (MouseButtonsStates[1] ? 0x8000 : 0);
615 retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) |
616 (MouseButtonsStates[2] ? 0x8000 : 0);
619 retval = AsyncKeyStateTable[nKey] |
620 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0);
624 /* all states to false */
625 memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
626 memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
628 TRACE(key, "(%x) -> %x\n", nKey, retval);
632 /**********************************************************************
633 * GetAsyncKeyState16 (USER.249)
635 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
637 return GetAsyncKeyState32(nKey);
640 /**********************************************************************
641 * KBD_translate_accelerator
643 * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP -messages
645 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
646 BYTE fVirt,WORD key,WORD cmd)
648 BOOL32 sendmsg = FALSE;
650 if(msg->wParam == key)
652 if (msg->message == WM_CHAR) {
653 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
655 TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
660 if(fVirt & FVIRTKEY) {
662 TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
663 msg->wParam,0xff & HIWORD(msg->lParam));
664 if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
665 if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
666 if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
667 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
670 TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
674 if (!(msg->lParam & 0x01000000)) /* no special_key */
676 if ((fVirt & FALT) && (msg->lParam & 0x20000000))
677 { /* ^^ ALT pressed */
678 TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
685 if (sendmsg) /* found an accelerator, but send a message... ? */
687 INT16 iSysStat,iStat,mesg=0;
690 if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
696 if (!IsWindowEnabled32(hWnd))
700 WND* wndPtr = WIN_FindWndPtr(hWnd);
702 hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
703 iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
704 cmd, MF_BYCOMMAND) : -1 ;
705 iStat = (hMenu) ? GetMenuState32(hMenu,
706 cmd, MF_BYCOMMAND) : -1 ;
710 if (iSysStat & (MF_DISABLED|MF_GRAYED))
719 if (IsIconic32(hWnd))
723 if (iStat & (MF_DISABLED|MF_GRAYED))
733 if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
735 TRACE(accel,", sending %s, wParam=%0x\n",
736 mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
738 SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
742 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
743 * #0: unknown (please report!)
744 * #1: for WM_KEYUP,WM_SYSKEYUP
745 * #2: mouse is captured
746 * #3: window is disabled
747 * #4: it's a disabled system menu option
748 * #5: it's a menu option, but window is iconic
749 * #6: it's a menu option, but disabled
751 TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
753 ERR(accel, " unknown reason - please report!");
761 /**********************************************************************
762 * TranslateAccelerator32 (USER32.551)(USER32.552)(USER32.553)
764 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
766 LPACCEL32 lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
769 if (hAccel == 0 || msg == NULL ||
770 (msg->message != WM_KEYDOWN &&
771 msg->message != WM_KEYUP &&
772 msg->message != WM_SYSKEYDOWN &&
773 msg->message != WM_SYSKEYUP &&
774 msg->message != WM_CHAR)) {
775 WARN(accel, "erraneous input parameters\n");
776 SetLastError(ERROR_INVALID_PARAMETER);
780 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
781 "msg->hwnd=%04x, msg->message=%04x\n",
782 hAccel,hWnd,msg->hwnd,msg->message);
787 if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
788 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
790 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
791 WARN(accel, "couldn't translate accelerator key");
795 /**********************************************************************
796 * TranslateAccelerator16 (USER.178)
798 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
800 LPACCEL16 lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
804 if (hAccel == 0 || msg == NULL ||
805 (msg->message != WM_KEYDOWN &&
806 msg->message != WM_KEYUP &&
807 msg->message != WM_SYSKEYDOWN &&
808 msg->message != WM_SYSKEYUP &&
809 msg->message != WM_CHAR)) {
810 WARN(accel, "erraneous input parameters\n");
811 SetLastError(ERROR_INVALID_PARAMETER);
815 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
816 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
817 STRUCT32_MSG16to32(msg,&msg32);
823 if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
824 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
826 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
827 WARN(accel, "couldn't translate accelerator key");
832 /**********************************************************************
833 * OemKeyScan (KEYBOARD.128)(USER32.401)
835 DWORD WINAPI OemKeyScan(WORD wOemChar)
837 TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
842 /**********************************************************************
843 * VkKeyScanA (USER32.573)
845 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
846 * for the current keyboard.
847 * high-order byte yields :
851 * 3-5 Shift-key combinations that are not used for characters
854 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
855 * FIXME : works ok except for dead chars :
856 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
857 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
860 WORD WINAPI VkKeyScan32A(CHAR cChar)
867 /* char->keysym (same for ANSI chars) */
868 keysym=(unsigned char) cChar;/* (!) cChar is signed */
869 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
871 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
873 { /* It didn't work ... let's try with deadchar code. */
874 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
877 TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
878 cChar,keysym,keysym,keycode);
882 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
883 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
886 WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
888 case 1 : highbyte = 0x0100; break;
889 case 2 : highbyte = 0X0600; break;
890 default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
893 index : 0 adds 0x0000
894 index : 1 adds 0x0100 (shift)
895 index : ? adds 0x0200 (ctrl)
896 index : 2 adds 0x0600 (ctrl+alt)
897 index : ? adds 0x0700 (ctrl+alt+shift (used?))
900 TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
901 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
904 /******************************************************************************
905 * VkKeyScan [KEYBOARD.129]
907 WORD WINAPI VkKeyScan16(CHAR cChar)
909 return VkKeyScan32A(cChar);
912 /******************************************************************************
913 * VkKeyScanW (USER32.576)
915 WORD WINAPI VkKeyScan32W(WCHAR cChar)
917 return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
920 /******************************************************************************
921 * GetKeyboardType16 (KEYBOARD.130)
923 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
925 return GetKeyboardType32(nTypeFlag);
928 /******************************************************************************
929 * GetKeyboardType32 (USER32.255)
931 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
933 TRACE(keyboard,"(%d)\n",nTypeFlag);
936 case 0: /* Keyboard type */
937 return 4; /* AT-101 */
939 case 1: /* Keyboard Subtype */
940 return 0; /* There are no defined subtypes */
942 case 2: /* Number of F-keys */
943 return 12; /* We're doing an 101 for now, so return 12 F-keys */
946 WARN(keyboard, "Unknown type\n");
947 return 0; /* The book says 0 here, so 0 */
952 /******************************************************************************
953 * MapVirtualKey32A (USER32.383)
955 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
957 return MapVirtualKey16(code,maptype);
960 /******************************************************************************
961 * MapVirtualKey32W (USER32.385)
963 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
965 return MapVirtualKey16(code,maptype);
968 /******************************************************************************
969 * MapVirtualKey16 (KEYBOARD.131)
971 * MapVirtualKey translates keycodes from one format to another
973 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
975 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
977 TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
980 case 0: { /* vkey-code to scan-code */
981 /* let's do vkey -> keycode -> scan */
983 for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
984 if ((keyc2vkey[keyc] & 0xFF)== wCode)
985 returnMVK (keyc - 8);
988 case 1: /* scan-code to vkey-code */
989 /* let's do scan -> keycode -> vkey */
991 returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
993 case 2: { /* vkey-code to unshifted ANSI code */
994 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
995 /* My Windows returns 'A'. */
996 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1000 e.display = display;
1001 e.state = 0; /* unshifted */
1002 e.keycode = MapVirtualKey16( wCode, 0);
1003 if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1008 default: /* reserved */
1009 WARN(keyboard, "Unknown wMapType %d !\n",
1017 /****************************************************************************
1018 * GetKBCodePage16 (KEYBOARD.132)
1020 INT16 WINAPI GetKBCodePage16(void)
1022 TRACE(keyboard,"(void)\n");
1027 /****************************************************************************
1028 * GetKBCodePage32 (USER32.246)
1030 UINT32 WINAPI GetKBCodePage32(void)
1032 TRACE(keyboard,"(void)\n");
1036 /****************************************************************************
1037 * GetKeyNameText32A (USER32.247)
1039 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1041 return GetKeyNameText16(lParam,lpBuffer,nSize);
1044 /****************************************************************************
1045 * GetKeyNameText32W (USER32.248)
1047 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1049 LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1050 int res = GetKeyNameText32A(lParam,buf,nSize);
1052 lstrcpynAtoW(lpBuffer,buf,nSize);
1053 HeapFree( GetProcessHeap(), 0, buf );
1058 /****************************************************************************
1059 * GetKeyNameText16 (KEYBOARD.133)
1061 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1065 TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1070 /* for (i = 0 ; i != KeyTableSize ; i++)
1071 if (KeyTable[i].scancode == lParam) {
1072 lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1073 return strlen(lpBuffer);
1076 /* FIXME ! GetKeyNameText is still to do...
1083 /****************************************************************************
1084 * ToAscii (KEYBOARD.4)
1086 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1087 LPVOID lpChar, UINT16 flags)
1089 return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1092 /****************************************************************************
1093 * ToAscii32 (USER32.546)
1095 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1096 LPWORD lpChar,UINT32 flags )
1100 static XComposeStatus cs;
1104 e.display = display;
1106 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1107 { /* this could be speeded up by making another table, an array of struct vkey,keycode
1108 * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)! DF */
1109 if ((keyc2vkey[keyc] & 0xFF)== virtKey) /* no need to make a more precise test (with the extended bit correctly set above virtKey ... VK* are different enough... */
1111 if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12)))
1112 /* it's normal to have 2 shift, control, and alt ! */
1113 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1114 e.keycode,keyc,virtKey);
1118 if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01))
1120 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1121 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1122 if (virtKey==VK_DECIMAL)
1123 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1127 WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1128 return virtKey; /* whatever */
1131 if (lpKeyState[VK_SHIFT] & 0x80)
1132 e.state |= ShiftMask;
1133 TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1134 if (lpKeyState[VK_CAPITAL] & 0x01)
1135 e.state |= LockMask;
1136 if (lpKeyState[VK_CONTROL] & 0x80)
1137 if (lpKeyState[VK_MENU] & 0x80)
1138 e.state |= AltGrMask;
1140 e.state |= ControlMask;
1141 if (lpKeyState[VK_NUMLOCK] & 0x01)
1142 e.state |= NumLockMask;
1143 TRACE(key, "(%04X, %04X) : faked state = %X\n",
1144 virtKey, scanCode, e.state);
1145 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1150 ((char*)lpChar)[1] = '\0';
1153 /* symbolic ASCII is the same as defined in rfc1345 */
1154 #ifdef XK_dead_tilde
1155 case XK_dead_tilde :
1157 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1158 dead_char = '~'; /* '? */
1160 #ifdef XK_dead_acute
1161 case XK_dead_acute :
1163 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1164 dead_char = 0xb4; /* '' */
1166 #ifdef XK_dead_circumflex
1167 case XK_dead_circumflex :
1169 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1170 dead_char = '^'; /* '> */
1172 #ifdef XK_dead_grave
1173 case XK_dead_grave :
1175 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1176 dead_char = '`'; /* '! */
1178 #ifdef XK_dead_diaeresis
1179 case XK_dead_diaeresis :
1181 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1182 dead_char = 0xa8; /* ': */
1184 #ifdef XK_dead_cedilla
1185 case XK_dead_cedilla :
1186 dead_char = 0xb8; /* ', */
1189 #ifdef XK_dead_macron
1190 case XK_dead_macron :
1191 dead_char = '-'; /* 'm isn't defined on iso-8859-x */
1194 #ifdef XK_dead_breve
1195 case XK_dead_breve :
1196 dead_char = 0xa2; /* '( */
1199 #ifdef XK_dead_abovedot
1200 case XK_dead_abovedot :
1201 dead_char = 0xff; /* '. */
1204 #ifdef XK_dead_abovering
1205 case XK_dead_abovering :
1206 dead_char = '0'; /* '0 isn't defined on iso-8859-x */
1209 #ifdef XK_dead_doubleacute
1210 case XK_dead_doubleacute :
1211 dead_char = 0xbd; /* '" */
1214 #ifdef XK_dead_caron
1215 case XK_dead_caron :
1216 dead_char = 0xb7; /* '< */
1219 #ifdef XK_dead_ogonek
1220 case XK_dead_ogonek :
1221 dead_char = 0xb2; /* '; */
1224 /* FIXME: I don't know this three.
1228 case XK_dead_voiced_sound :
1231 case XK_dead_semivoiced_sound :
1238 *(char*)lpChar = dead_char;
1245 ksname = TSXKeysymToString(keysym);
1248 if ((keysym >> 8) != 0xff)
1250 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1252 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1253 virtKey, scanCode, e.keycode, e.state);
1257 TRACE(key, "ToAscii about to return %d with char %x\n",
1258 ret, *(char*)lpChar);
1263 /***********************************************************************
1264 * GetKeyboardLayout (USER32.250)
1266 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1268 FIXME(keyboard,"(%ld): stub\n",dwLayout);
1269 return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1272 /***********************************************************************
1273 * GetKeyboardLayoutList (USER32.251)
1276 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1278 FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1280 layouts[0] = GetKeyboardLayout(0);
1285 /***********************************************************************
1286 * RegisterHotKey (USER32.433)
1288 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1289 FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1290 hwnd,id,modifiers,vk
1295 /***********************************************************************
1296 * UnregisterHotKey (USER32.565)
1298 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1299 FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);