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;
174 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
175 ksp = TSXGetKeyboardMapping(display, min_keycode,
176 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
177 /* We are only interested in keysyms_per_keycode.
178 There is no need to hold a local copy of the keysyms table */
180 mmp = TSXGetModifierMapping(display);
181 kcp = mmp->modifiermap;
182 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
186 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
191 for (k = 0; k < keysyms_per_keycode; k += 1)
192 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
195 TRACE(key, "AltGrMask is %x\n", AltGrMask);
197 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
199 NumLockMask = 1 << i;
200 TRACE(key, "NumLockMask is %x\n", NumLockMask);
204 TSXFreeModifiermap(mmp);
206 /* Now build two conversion arrays :
207 * keycode -> vkey + extended
208 * vkey + extended -> keycode */
210 e2.display = display;
213 OEMvkey = VK_OEM_7; /* next is available. */
214 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
216 e2.keycode = (KeyCode)keyc;
217 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
219 if (keysym) /* otherwise, keycode not used */
221 if ((keysym >> 8) == 0xFF) /* non-character key */
223 int key = keysym & 0xff;
225 if (key >= 0x08 && key <= 0x1B) /* special key */
226 vkey = special_key[key - 0x08];
227 else if (key >= 0x50 && key <= 0x57) /* cursor key */
228 vkey = cursor_key[key - 0x50];
229 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
230 vkey = misc_key[key - 0x60];
231 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
232 vkey = keypad_key[key - 0x7E];
233 else if (key >= 0xBE && key <= 0xCD) /* function key */
235 vkey = function_key[key - 0xBE];
236 vkey |= 0x100; /* set extended bit */
238 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
239 vkey = modifier_key[key - 0xE1];
240 else if (key == 0xFF) /* DEL key */
242 /* extended must also be set for ALT_R, CTRL_R,
243 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
244 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
245 /* FIXME should we set extended bit for NumLock ? My
246 * Windows does ... DF */
266 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
268 keysym = TSXLookupKeysym(&e2, i);
269 if ((keysym >= VK_0 && keysym <= VK_9)
270 || (keysym >= VK_A && keysym <= VK_Z)
271 || keysym == VK_SPACE)
275 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
277 keysym = TSXLookupKeysym(&e2, i);
280 case ';': case ':': vkey = VK_OEM_1; break;
281 case '/': case '?': vkey = VK_OEM_2; break;
282 case '`': case '~': vkey = VK_OEM_3; break;
283 case '[': vkey = VK_OEM_4; break;
284 case '\\': vkey = VK_OEM_5; break;
285 case ']': vkey = VK_OEM_6; break;
286 case '\'': case '\"': vkey = VK_OEM_7; break;
287 case ',': vkey = VK_OEM_COMMA; break;
288 case '.': vkey = VK_OEM_PERIOD; break;
289 case '-': vkey = VK_OEM_MINUS; break;
290 case '+': vkey = VK_OEM_PLUS; break;
296 /* Others keys: let's assign OEM virtual key codes in the allowed range,
297 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
300 case 0xc1 : OEMvkey=0xdb; break;
301 case 0xe5 : OEMvkey=0xe9; break;
302 case 0xf6 : OEMvkey=0xf5; WARN(keyboard,"No more OEM vkey available!\n");
307 if (TRACE_ON(keyboard))
309 dbg_decl_str(keyboard, 1024);
311 TRACE(keyboard, "OEM specific virtual key %X assigned "
312 "to keycode %X:\n", OEMvkey, e2.keycode);
313 for (i = 0; i < keysyms_per_keycode; i += 1)
317 keysym = TSXLookupKeysym(&e2, i);
318 ksname = TSXKeysymToString(keysym);
321 dsprintf(keyboard, "%lX (%s) ", keysym, ksname);
323 TRACE(keyboard, "(%s)\n", dbg_str(keyboard));
327 keyc2vkey[e2.keycode] = vkey;
332 static BOOL32 NumState=FALSE, CapsState=FALSE;
334 /**********************************************************************
335 * KEYBOARD_GenerateMsg
337 void KEYBOARD_GenerateMsg( WORD vkey, int Evtype, INT32 event_x, INT32 event_y,
338 DWORD event_time, KEYLP localkeylp )
340 BOOL32 * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
343 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
344 don't treat it. It's from the same key press. Then the state goes to ON.
345 And from there, a 'release' event will switch off the toggle key. */
347 TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,InputKeyStateTable[vkey]);
350 if ( InputKeyStateTable[vkey] & 0x1 ) /* it was ON */
352 if (Evtype!=KeyPress)
354 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
355 localkeylp.lp1.previous = 0; /* ? */
356 localkeylp.lp1.transition = 0;
357 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
358 event_x, event_y, event_time, 0 );
359 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
360 event_x, event_y, event_time, 0 );
362 InputKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
365 else /* it was OFF */
366 if (Evtype==KeyPress)
368 TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
369 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
370 event_x, event_y, event_time, 0 );
371 localkeylp.lp1.previous = 1;
372 localkeylp.lp1.transition = 1;
373 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
374 event_x, event_y, event_time, 0 );
375 *State=TRUE; /* Goes to intermediary state before going to ON */
376 InputKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
381 /***********************************************************************
382 * KEYBOARD_HandleEvent
384 * Handle a X key event
386 void KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
393 static BOOL32 force_extended = FALSE; /* hack for AltGr translation */
395 int ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
397 INT32 event_x = pWnd->rectWindow.left + event->x;
398 INT32 event_y = pWnd->rectWindow.top + event->y;
399 DWORD event_time = event->time - MSG_WineStartTicks;
401 TRACE(key, "EVENT_key : state = %X\n", event->state);
402 if (keysym == XK_Mode_switch)
404 TRACE(key, "Alt Gr key event received\n");
405 event->keycode = TSXKeysymToKeycode(event->display, XK_Control_L);
406 TRACE(key, "Control_L is keycode 0x%x\n", event->keycode);
407 KEYBOARD_HandleEvent( pWnd, event );
408 event->keycode = TSXKeysymToKeycode(event->display, XK_Alt_L);
409 TRACE(key, "Alt_L is keycode 0x%x\n", event->keycode);
410 force_extended = TRUE;
411 KEYBOARD_HandleEvent( pWnd, event );
412 force_extended = FALSE;
416 Str[ascii_chars] = '\0';
420 ksname = TSXKeysymToString(keysym);
423 TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
424 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
425 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
428 vkey = EVENT_event_to_vkey(event);
429 if (force_extended) vkey |= 0x100;
431 TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
432 event->keycode, vkey);
437 keylp.lp1.code = vkey2scode[vkey]; /* 5/29/97 chrisf@america.com */
438 keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
439 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
440 * don't remember where I read it - AK */
441 /* it's '1' under windows, when a dialog box appears
442 * and you press one of the underlined keys - DF*/
448 KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
452 TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
453 KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
455 TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
460 if (event->type == KeyPress)
462 keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
463 if (!(InputKeyStateTable[vkey] & 0x80))
464 InputKeyStateTable[vkey] ^= 0x01;
465 InputKeyStateTable[vkey] |= 0x80;
466 keylp.lp1.transition = 0;
467 message = (InputKeyStateTable[VK_MENU] & 0x80)
468 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
469 ? WM_SYSKEYDOWN : WM_KEYDOWN;
473 BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
474 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
475 && (force_extended == FALSE); /* for Alt from AltGr */
477 InputKeyStateTable[vkey] &= ~0x80;
478 keylp.lp1.previous = 1;
479 keylp.lp1.transition = 1;
480 message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
482 keylp.lp1.context = ( (event->state & Mod1Mask) ||
483 (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
484 if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
486 TRACE(keyboard,"Adjusting NumLock state. \n");
487 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
489 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
492 if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
494 TRACE(keyboard,"Adjusting Caps Lock state. State before %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
495 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
497 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
499 TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
501 /* End of intermediary states. */
505 TRACE(key," wParam=%04X, lParam=%08lX\n",
507 TRACE(key," InputKeyState=%X\n",
508 InputKeyStateTable[vkey]);
510 hardware_event( message, vkey, keylp.lp2,
511 event_x, event_y, event_time, 0 );
518 /**********************************************************************
519 * GetKeyState (USER.106)
521 WORD WINAPI GetKeyState16(INT16 vkey)
523 return GetKeyState32(vkey);
526 /**********************************************************************
527 * GetKeyState (USER32.249)
529 * An application calls the GetKeyState function in response to a
530 * keyboard-input message. This function retrieves the state of the key
531 * at the time the input message was generated. (SDK 3.1 Vol 2. p 390)
533 WORD WINAPI GetKeyState32(INT32 vkey)
539 case VK_LBUTTON : /* VK_LBUTTON is 1 */
540 retval = MouseButtonsStates[0] ? 0x8000 : 0;
542 case VK_MBUTTON : /* VK_MBUTTON is 4 */
543 retval = MouseButtonsStates[1] ? 0x8000 : 0;
545 case VK_RBUTTON : /* VK_RBUTTON is 2 */
546 retval = MouseButtonsStates[2] ? 0x8000 : 0;
549 if (vkey >= 'a' && vkey <= 'z')
551 retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
552 (WORD)(QueueKeyStateTable[vkey] & 0x01);
554 TRACE(key, "(0x%x) -> %x\n", vkey, retval);
558 /**********************************************************************
559 * GetKeyboardState (USER.222)(USER32.254)
561 * An application calls the GetKeyboardState function in response to a
562 * keyboard-input message. This function retrieves the state of the keyboard
563 * at the time the input message was generated. (SDK 3.1 Vol 2. p 387)
565 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
567 TRACE(key, "(%p)\n", lpKeyState);
568 if (lpKeyState != NULL) {
569 QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
570 QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
571 QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
572 memcpy(lpKeyState, QueueKeyStateTable, 256);
576 /**********************************************************************
577 * SetKeyboardState (USER.223)(USER32.484)
579 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
581 TRACE(key, "(%p)\n", lpKeyState);
582 if (lpKeyState != NULL) {
583 memcpy(QueueKeyStateTable, lpKeyState, 256);
584 MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
585 MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
586 MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
590 /**********************************************************************
591 * GetAsyncKeyState32 (USER32.207)
593 * Determine if a key is or was pressed. retval has high-order
594 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
597 * This uses the variable AsyncMouseButtonsStates and
598 * AsyncKeyStateTable (set in event.c) which have the mouse button
599 * number or key number (whichever is applicable) set to true if the
600 * mouse or key had been depressed since the last call to
603 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
609 retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) |
610 (MouseButtonsStates[0] ? 0x8000 : 0);
613 retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) |
614 (MouseButtonsStates[1] ? 0x8000 : 0);
617 retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) |
618 (MouseButtonsStates[2] ? 0x8000 : 0);
621 retval = AsyncKeyStateTable[nKey] |
622 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0);
626 /* all states to false */
627 memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
628 memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
630 TRACE(key, "(%x) -> %x\n", nKey, retval);
634 /**********************************************************************
635 * GetAsyncKeyState16 (USER.249)
637 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
639 return GetAsyncKeyState32(nKey);
642 /**********************************************************************
643 * KBD_translate_accelerator
645 * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP -messages
647 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
648 BYTE fVirt,WORD key,WORD cmd)
650 BOOL32 sendmsg = FALSE;
652 if(msg->wParam == key)
654 if (msg->message == WM_CHAR) {
655 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
657 TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
662 if(fVirt & FVIRTKEY) {
664 TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
665 msg->wParam,0xff & HIWORD(msg->lParam));
666 if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
667 if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
668 if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
669 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
672 TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
676 if (!(msg->lParam & 0x01000000)) /* no special_key */
678 if ((fVirt & FALT) && (msg->lParam & 0x20000000))
679 { /* ^^ ALT pressed */
680 TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
687 if (sendmsg) /* found an accelerator, but send a message... ? */
689 INT16 iSysStat,iStat,mesg=0;
692 if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
698 if (!IsWindowEnabled32(hWnd))
702 WND* wndPtr = WIN_FindWndPtr(hWnd);
704 hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
705 iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
706 cmd, MF_BYCOMMAND) : -1 ;
707 iStat = (hMenu) ? GetMenuState32(hMenu,
708 cmd, MF_BYCOMMAND) : -1 ;
712 if (iSysStat & (MF_DISABLED|MF_GRAYED))
721 if (IsIconic32(hWnd))
725 if (iStat & (MF_DISABLED|MF_GRAYED))
735 if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
737 TRACE(accel,", sending %s, wParam=%0x\n",
738 mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
740 SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
744 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
745 * #0: unknown (please report!)
746 * #1: for WM_KEYUP,WM_SYSKEYUP
747 * #2: mouse is captured
748 * #3: window is disabled
749 * #4: it's a disabled system menu option
750 * #5: it's a menu option, but window is iconic
751 * #6: it's a menu option, but disabled
753 TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
755 ERR(accel, " unknown reason - please report!");
763 /**********************************************************************
764 * TranslateAccelerator32 (USER32.551)(USER32.552)(USER32.553)
766 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
768 LPACCEL32 lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
771 if (hAccel == 0 || msg == NULL ||
772 (msg->message != WM_KEYDOWN &&
773 msg->message != WM_KEYUP &&
774 msg->message != WM_SYSKEYDOWN &&
775 msg->message != WM_SYSKEYUP &&
776 msg->message != WM_CHAR)) {
777 WARN(accel, "erraneous input parameters\n");
778 SetLastError(ERROR_INVALID_PARAMETER);
782 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
783 "msg->hwnd=%04x, msg->message=%04x\n",
784 hAccel,hWnd,msg->hwnd,msg->message);
789 if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
790 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
792 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
793 WARN(accel, "couldn't translate accelerator key");
797 /**********************************************************************
798 * TranslateAccelerator16 (USER.178)
800 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
802 LPACCEL16 lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
806 if (hAccel == 0 || msg == NULL ||
807 (msg->message != WM_KEYDOWN &&
808 msg->message != WM_KEYUP &&
809 msg->message != WM_SYSKEYDOWN &&
810 msg->message != WM_SYSKEYUP &&
811 msg->message != WM_CHAR)) {
812 WARN(accel, "erraneous input parameters\n");
813 SetLastError(ERROR_INVALID_PARAMETER);
817 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
818 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
819 STRUCT32_MSG16to32(msg,&msg32);
825 if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
826 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
828 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
829 WARN(accel, "couldn't translate accelerator key");
834 /**********************************************************************
835 * OemKeyScan (KEYBOARD.128)(USER32.401)
837 DWORD WINAPI OemKeyScan(WORD wOemChar)
839 TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
844 /**********************************************************************
845 * VkKeyScanA (USER32.573)
847 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
848 * for the current keyboard.
849 * high-order byte yields :
853 * 3-5 Shift-key combinations that are not used for characters
856 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
857 * FIXME : works ok except for dead chars :
858 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
859 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
862 WORD WINAPI VkKeyScan32A(CHAR cChar)
869 /* char->keysym (same for ANSI chars) */
870 keysym=(unsigned char) cChar;/* (!) cChar is signed */
871 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
873 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
875 { /* It didn't work ... let's try with deadchar code. */
876 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
879 TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
880 cChar,keysym,keysym,keycode);
884 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
885 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
888 WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
890 case 1 : highbyte = 0x0100; break;
891 case 2 : highbyte = 0X0600; break;
892 default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
895 index : 0 adds 0x0000
896 index : 1 adds 0x0100 (shift)
897 index : ? adds 0x0200 (ctrl)
898 index : 2 adds 0x0600 (ctrl+alt)
899 index : ? adds 0x0700 (ctrl+alt+shift (used?))
902 TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
903 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
906 /******************************************************************************
907 * VkKeyScan [KEYBOARD.129]
909 WORD WINAPI VkKeyScan16(CHAR cChar)
911 return VkKeyScan32A(cChar);
914 /******************************************************************************
915 * VkKeyScanW (USER32.576)
917 WORD WINAPI VkKeyScan32W(WCHAR cChar)
919 return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
922 /******************************************************************************
923 * GetKeyboardType16 (KEYBOARD.130)
925 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
927 return GetKeyboardType32(nTypeFlag);
930 /******************************************************************************
931 * GetKeyboardType32 (USER32.255)
933 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
935 TRACE(keyboard,"(%d)\n",nTypeFlag);
938 case 0: /* Keyboard type */
939 return 4; /* AT-101 */
941 case 1: /* Keyboard Subtype */
942 return 0; /* There are no defined subtypes */
944 case 2: /* Number of F-keys */
945 return 12; /* We're doing an 101 for now, so return 12 F-keys */
948 WARN(keyboard, "Unknown type\n");
949 return 0; /* The book says 0 here, so 0 */
954 /******************************************************************************
955 * MapVirtualKey32A (USER32.383)
957 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
959 return MapVirtualKey16(code,maptype);
962 /******************************************************************************
963 * MapVirtualKey32W (USER32.385)
965 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
967 return MapVirtualKey16(code,maptype);
970 /******************************************************************************
971 * MapVirtualKey16 (KEYBOARD.131)
973 * MapVirtualKey translates keycodes from one format to another
975 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
977 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
979 TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
982 case 0: { /* vkey-code to scan-code */
983 /* let's do vkey -> keycode -> scan */
985 for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
986 if ((keyc2vkey[keyc] & 0xFF)== wCode)
987 returnMVK (keyc - 8);
990 case 1: /* scan-code to vkey-code */
991 /* let's do scan -> keycode -> vkey */
993 returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
995 case 2: { /* vkey-code to unshifted ANSI code */
996 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
997 /* My Windows returns 'A'. */
998 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1002 e.display = display;
1003 e.state = 0; /* unshifted */
1004 e.keycode = MapVirtualKey16( wCode, 0);
1005 if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1010 default: /* reserved */
1011 WARN(keyboard, "Unknown wMapType %d !\n",
1019 /****************************************************************************
1020 * GetKBCodePage16 (KEYBOARD.132)
1022 INT16 WINAPI GetKBCodePage16(void)
1024 TRACE(keyboard,"(void)\n");
1029 /****************************************************************************
1030 * GetKBCodePage32 (USER32.246)
1032 UINT32 WINAPI GetKBCodePage32(void)
1034 TRACE(keyboard,"(void)\n");
1038 /****************************************************************************
1039 * GetKeyNameText32A (USER32.247)
1041 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1043 return GetKeyNameText16(lParam,lpBuffer,nSize);
1046 /****************************************************************************
1047 * GetKeyNameText32W (USER32.248)
1049 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1051 LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1052 int res = GetKeyNameText32A(lParam,buf,nSize);
1054 lstrcpynAtoW(lpBuffer,buf,nSize);
1055 HeapFree( GetProcessHeap(), 0, buf );
1060 /****************************************************************************
1061 * GetKeyNameText16 (KEYBOARD.133)
1063 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1067 TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1072 /* for (i = 0 ; i != KeyTableSize ; i++)
1073 if (KeyTable[i].scancode == lParam) {
1074 lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1075 return strlen(lpBuffer);
1078 /* FIXME ! GetKeyNameText is still to do...
1085 /****************************************************************************
1086 * ToAscii (KEYBOARD.4)
1088 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1089 LPVOID lpChar, UINT16 flags)
1091 return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1094 /****************************************************************************
1095 * ToAscii32 (USER32.546)
1097 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1098 LPWORD lpChar,UINT32 flags )
1102 static XComposeStatus cs;
1106 e.display = display;
1108 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1109 { /* this could be speeded up by making another table, an array of struct vkey,keycode
1110 * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)! DF */
1111 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... */
1113 if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12)))
1114 /* it's normal to have 2 shift, control, and alt ! */
1115 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1116 e.keycode,keyc,virtKey);
1120 if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01))
1122 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1123 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1124 if (virtKey==VK_DECIMAL)
1125 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1129 WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1130 return virtKey; /* whatever */
1133 if (lpKeyState[VK_SHIFT] & 0x80)
1134 e.state |= ShiftMask;
1135 TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1136 if (lpKeyState[VK_CAPITAL] & 0x01)
1137 e.state |= LockMask;
1138 if (lpKeyState[VK_CONTROL] & 0x80)
1139 if (lpKeyState[VK_MENU] & 0x80)
1140 e.state |= AltGrMask;
1142 e.state |= ControlMask;
1143 if (lpKeyState[VK_NUMLOCK] & 0x01)
1144 e.state |= NumLockMask;
1145 TRACE(key, "(%04X, %04X) : faked state = %X\n",
1146 virtKey, scanCode, e.state);
1147 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1152 ((char*)lpChar)[1] = '\0';
1155 /* symbolic ASCII is the same as defined in rfc1345 */
1156 #ifdef XK_dead_tilde
1157 case XK_dead_tilde :
1159 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1160 dead_char = '~'; /* '? */
1162 #ifdef XK_dead_acute
1163 case XK_dead_acute :
1165 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1166 dead_char = 0xb4; /* '' */
1168 #ifdef XK_dead_circumflex
1169 case XK_dead_circumflex :
1171 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1172 dead_char = '^'; /* '> */
1174 #ifdef XK_dead_grave
1175 case XK_dead_grave :
1177 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1178 dead_char = '`'; /* '! */
1180 #ifdef XK_dead_diaeresis
1181 case XK_dead_diaeresis :
1183 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1184 dead_char = 0xa8; /* ': */
1186 #ifdef XK_dead_cedilla
1187 case XK_dead_cedilla :
1188 dead_char = 0xb8; /* ', */
1191 #ifdef XK_dead_macron
1192 case XK_dead_macron :
1193 dead_char = '-'; /* 'm isn't defined on iso-8859-x */
1196 #ifdef XK_dead_breve
1197 case XK_dead_breve :
1198 dead_char = 0xa2; /* '( */
1201 #ifdef XK_dead_abovedot
1202 case XK_dead_abovedot :
1203 dead_char = 0xff; /* '. */
1206 #ifdef XK_dead_abovering
1207 case XK_dead_abovering :
1208 dead_char = '0'; /* '0 isn't defined on iso-8859-x */
1211 #ifdef XK_dead_doubleacute
1212 case XK_dead_doubleacute :
1213 dead_char = 0xbd; /* '" */
1216 #ifdef XK_dead_caron
1217 case XK_dead_caron :
1218 dead_char = 0xb7; /* '< */
1221 #ifdef XK_dead_ogonek
1222 case XK_dead_ogonek :
1223 dead_char = 0xb2; /* '; */
1226 /* FIXME: I don't know this three.
1230 case XK_dead_voiced_sound :
1233 case XK_dead_semivoiced_sound :
1240 *(char*)lpChar = dead_char;
1247 ksname = TSXKeysymToString(keysym);
1250 if ((keysym >> 8) != 0xff)
1252 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1254 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1255 virtKey, scanCode, e.keycode, e.state);
1259 TRACE(key, "ToAscii about to return %d with char %x\n",
1260 ret, *(char*)lpChar);
1265 /***********************************************************************
1266 * GetKeyboardLayout (USER32.250)
1268 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1270 FIXME(keyboard,"(%ld): stub\n",dwLayout);
1271 return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1274 /***********************************************************************
1275 * GetKeyboardLayoutList (USER32.251)
1278 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1280 FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1282 layouts[0] = GetKeyboardLayout(0);
1287 /***********************************************************************
1288 * RegisterHotKey (USER32.433)
1290 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1291 FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1292 hwnd,id,modifiers,vk
1297 /***********************************************************************
1298 * UnregisterHotKey (USER32.565)
1300 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1301 FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);