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 ';': vkey = VK_OEM_1; break;
281 case '/': vkey = VK_OEM_2; break;
282 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 '\'': 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 */
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 /* this allows support for dead keys */
402 if ((event->keycode >> 8) == 0x10)
403 event->keycode=(event->keycode & 0xff);
405 ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
407 TRACE(key, "EVENT_key : state = %X\n", event->state);
408 if (keysym == XK_Mode_switch)
410 TRACE(key, "Alt Gr key event received\n");
411 event->keycode = TSXKeysymToKeycode(event->display, XK_Control_L);
412 TRACE(key, "Control_L is keycode 0x%x\n", event->keycode);
413 KEYBOARD_HandleEvent( pWnd, event );
414 event->keycode = TSXKeysymToKeycode(event->display, XK_Alt_L);
415 TRACE(key, "Alt_L is keycode 0x%x\n", event->keycode);
416 force_extended = TRUE;
417 KEYBOARD_HandleEvent( pWnd, event );
418 force_extended = FALSE;
422 Str[ascii_chars] = '\0';
426 ksname = TSXKeysymToString(keysym);
429 TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
430 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
431 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
434 vkey = EVENT_event_to_vkey(event);
435 if (force_extended) vkey |= 0x100;
437 TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
438 event->keycode, vkey);
443 keylp.lp1.code = vkey2scode[vkey]; /* 5/29/97 chrisf@america.com */
444 keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
445 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
446 * don't remember where I read it - AK */
447 /* it's '1' under windows, when a dialog box appears
448 * and you press one of the underlined keys - DF*/
454 KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
458 TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
459 KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
461 TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
466 if (event->type == KeyPress)
468 keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
469 if (!(InputKeyStateTable[vkey] & 0x80))
470 InputKeyStateTable[vkey] ^= 0x01;
471 InputKeyStateTable[vkey] |= 0x80;
472 keylp.lp1.transition = 0;
473 message = (InputKeyStateTable[VK_MENU] & 0x80)
474 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
475 ? WM_SYSKEYDOWN : WM_KEYDOWN;
479 BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
480 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
481 && (force_extended == FALSE); /* for Alt from AltGr */
483 InputKeyStateTable[vkey] &= ~0x80;
484 keylp.lp1.previous = 1;
485 keylp.lp1.transition = 1;
486 message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
488 keylp.lp1.context = ( (event->state & Mod1Mask) ||
489 (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
490 if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
492 TRACE(keyboard,"Adjusting NumLock state. \n");
493 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
495 KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
498 if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
500 TRACE(keyboard,"Adjusting Caps Lock state. State before %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
501 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
503 KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
505 TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
507 /* End of intermediary states. */
511 TRACE(key," wParam=%04X, lParam=%08lX\n",
513 TRACE(key," InputKeyState=%X\n",
514 InputKeyStateTable[vkey]);
516 hardware_event( message, vkey, keylp.lp2,
517 event_x, event_y, event_time, 0 );
524 /**********************************************************************
525 * GetKeyState (USER.106)
527 WORD WINAPI GetKeyState16(INT16 vkey)
529 return GetKeyState32(vkey);
532 /**********************************************************************
533 * GetKeyState (USER32.249)
535 * An application calls the GetKeyState function in response to a
536 * keyboard-input message. This function retrieves the state of the key
537 * at the time the input message was generated. (SDK 3.1 Vol 2. p 390)
539 WORD WINAPI GetKeyState32(INT32 vkey)
545 case VK_LBUTTON : /* VK_LBUTTON is 1 */
546 retval = MouseButtonsStates[0] ? 0x8000 : 0;
548 case VK_MBUTTON : /* VK_MBUTTON is 4 */
549 retval = MouseButtonsStates[1] ? 0x8000 : 0;
551 case VK_RBUTTON : /* VK_RBUTTON is 2 */
552 retval = MouseButtonsStates[2] ? 0x8000 : 0;
555 if (vkey >= 'a' && vkey <= 'z')
557 retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
558 (WORD)(QueueKeyStateTable[vkey] & 0x01);
560 TRACE(key, "(0x%x) -> %x\n", vkey, retval);
564 /**********************************************************************
565 * GetKeyboardState (USER.222)(USER32.254)
567 * An application calls the GetKeyboardState function in response to a
568 * keyboard-input message. This function retrieves the state of the keyboard
569 * at the time the input message was generated. (SDK 3.1 Vol 2. p 387)
571 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
573 TRACE(key, "(%p)\n", lpKeyState);
574 if (lpKeyState != NULL) {
575 QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
576 QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
577 QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
578 memcpy(lpKeyState, QueueKeyStateTable, 256);
582 /**********************************************************************
583 * SetKeyboardState (USER.223)(USER32.484)
585 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
587 TRACE(key, "(%p)\n", lpKeyState);
588 if (lpKeyState != NULL) {
589 memcpy(QueueKeyStateTable, lpKeyState, 256);
590 MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
591 MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
592 MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
596 /**********************************************************************
597 * GetAsyncKeyState32 (USER32.207)
599 * Determine if a key is or was pressed. retval has high-order
600 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
603 * This uses the variable AsyncMouseButtonsStates and
604 * AsyncKeyStateTable (set in event.c) which have the mouse button
605 * number or key number (whichever is applicable) set to true if the
606 * mouse or key had been depressed since the last call to
609 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
615 retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) |
616 (MouseButtonsStates[0] ? 0x8000 : 0);
619 retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) |
620 (MouseButtonsStates[1] ? 0x8000 : 0);
623 retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) |
624 (MouseButtonsStates[2] ? 0x8000 : 0);
627 retval = AsyncKeyStateTable[nKey] |
628 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0);
632 /* all states to false */
633 memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
634 memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
636 TRACE(key, "(%x) -> %x\n", nKey, retval);
640 /**********************************************************************
641 * GetAsyncKeyState16 (USER.249)
643 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
645 return GetAsyncKeyState32(nKey);
648 /**********************************************************************
649 * KBD_translate_accelerator
651 * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP -messages
653 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
654 BYTE fVirt,WORD key,WORD cmd)
656 BOOL32 sendmsg = FALSE;
658 if(msg->wParam == key)
660 if (msg->message == WM_CHAR) {
661 if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
663 TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
668 if(fVirt & FVIRTKEY) {
670 TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
671 msg->wParam,0xff & HIWORD(msg->lParam));
672 if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
673 if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
674 if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
675 if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
678 TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
682 if (!(msg->lParam & 0x01000000)) /* no special_key */
684 if ((fVirt & FALT) && (msg->lParam & 0x20000000))
685 { /* ^^ ALT pressed */
686 TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
693 if (sendmsg) /* found an accelerator, but send a message... ? */
695 INT16 iSysStat,iStat,mesg=0;
698 if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
704 if (!IsWindowEnabled32(hWnd))
708 WND* wndPtr = WIN_FindWndPtr(hWnd);
710 hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
711 iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
712 cmd, MF_BYCOMMAND) : -1 ;
713 iStat = (hMenu) ? GetMenuState32(hMenu,
714 cmd, MF_BYCOMMAND) : -1 ;
718 if (iSysStat & (MF_DISABLED|MF_GRAYED))
727 if (IsIconic32(hWnd))
731 if (iStat & (MF_DISABLED|MF_GRAYED))
741 if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
743 TRACE(accel,", sending %s, wParam=%0x\n",
744 mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
746 SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
750 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
751 * #0: unknown (please report!)
752 * #1: for WM_KEYUP,WM_SYSKEYUP
753 * #2: mouse is captured
754 * #3: window is disabled
755 * #4: it's a disabled system menu option
756 * #5: it's a menu option, but window is iconic
757 * #6: it's a menu option, but disabled
759 TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
761 ERR(accel, " unknown reason - please report!");
769 /**********************************************************************
770 * TranslateAccelerator32 (USER32.551)(USER32.552)(USER32.553)
772 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
774 LPACCEL32 lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
777 TRACE(accel,"hwnd=0x%x hacc=0x%x msg=0x%x wp=0x%x lp=0x%lx\n", hWnd, hAccel, msg->message, msg->wParam, msg->lParam);
779 if (hAccel == 0 || msg == NULL ||
780 (msg->message != WM_KEYDOWN &&
781 msg->message != WM_KEYUP &&
782 msg->message != WM_SYSKEYDOWN &&
783 msg->message != WM_SYSKEYUP &&
784 msg->message != WM_CHAR)) {
785 WARN(accel, "erraneous input parameters\n");
786 SetLastError(ERROR_INVALID_PARAMETER);
790 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
791 "msg->hwnd=%04x, msg->message=%04x\n",
792 hAccel,hWnd,msg->hwnd,msg->message);
797 if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
798 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
800 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
801 WARN(accel, "couldn't translate accelerator key");
805 /**********************************************************************
806 * TranslateAccelerator16 (USER.178)
808 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
810 LPACCEL16 lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
814 if (hAccel == 0 || msg == NULL ||
815 (msg->message != WM_KEYDOWN &&
816 msg->message != WM_KEYUP &&
817 msg->message != WM_SYSKEYDOWN &&
818 msg->message != WM_SYSKEYUP &&
819 msg->message != WM_CHAR)) {
820 WARN(accel, "erraneous input parameters\n");
821 SetLastError(ERROR_INVALID_PARAMETER);
825 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
826 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
827 STRUCT32_MSG16to32(msg,&msg32);
833 if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
834 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
836 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
837 WARN(accel, "couldn't translate accelerator key");
842 /**********************************************************************
843 * ScreenSwitchEnable (KEYBOARD.100)
845 VOID WINAPI ScreenSwitchEnable(WORD unused)
847 FIXME(keyboard,"(%04x): stub\n",unused);
850 /**********************************************************************
851 * OemKeyScan (KEYBOARD.128)(USER32.401)
853 DWORD WINAPI OemKeyScan(WORD wOemChar)
855 TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
860 /**********************************************************************
861 * VkKeyScanA (USER32.573)
863 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
864 * for the current keyboard.
865 * high-order byte yields :
869 * 3-5 Shift-key combinations that are not used for characters
872 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
873 * FIXME : works ok except for dead chars :
874 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
875 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
878 WORD WINAPI VkKeyScan32A(CHAR cChar)
885 /* char->keysym (same for ANSI chars) */
886 keysym=(unsigned char) cChar;/* (!) cChar is signed */
887 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
889 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
891 { /* It didn't work ... let's try with deadchar code. */
892 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
895 TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
896 cChar,keysym,keysym,keycode);
900 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
901 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
904 WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
906 case 1 : highbyte = 0x0100; break;
907 case 2 : highbyte = 0X0600; break;
908 default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
911 index : 0 adds 0x0000
912 index : 1 adds 0x0100 (shift)
913 index : ? adds 0x0200 (ctrl)
914 index : 2 adds 0x0600 (ctrl+alt)
915 index : ? adds 0x0700 (ctrl+alt+shift (used?))
918 TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
919 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
922 /******************************************************************************
923 * VkKeyScan [KEYBOARD.129]
925 WORD WINAPI VkKeyScan16(CHAR cChar)
927 return VkKeyScan32A(cChar);
930 /******************************************************************************
931 * VkKeyScanW (USER32.576)
933 WORD WINAPI VkKeyScan32W(WCHAR cChar)
935 return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
938 /******************************************************************************
939 * GetKeyboardType16 (KEYBOARD.130)
941 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
943 return GetKeyboardType32(nTypeFlag);
946 /******************************************************************************
947 * GetKeyboardType32 (USER32.255)
949 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
951 TRACE(keyboard,"(%d)\n",nTypeFlag);
954 case 0: /* Keyboard type */
955 return 4; /* AT-101 */
957 case 1: /* Keyboard Subtype */
958 return 0; /* There are no defined subtypes */
960 case 2: /* Number of F-keys */
961 return 12; /* We're doing an 101 for now, so return 12 F-keys */
964 WARN(keyboard, "Unknown type\n");
965 return 0; /* The book says 0 here, so 0 */
970 /******************************************************************************
971 * MapVirtualKey32A (USER32.383)
973 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
975 return MapVirtualKey16(code,maptype);
978 /******************************************************************************
979 * MapVirtualKey32W (USER32.385)
981 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
983 return MapVirtualKey16(code,maptype);
986 /******************************************************************************
987 * MapVirtualKey16 (KEYBOARD.131)
989 * MapVirtualKey translates keycodes from one format to another
991 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
993 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
995 TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
998 case 0: { /* vkey-code to scan-code */
999 /* let's do vkey -> keycode -> scan */
1001 for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
1002 if ((keyc2vkey[keyc] & 0xFF)== wCode)
1003 returnMVK (keyc - 8);
1006 case 1: /* scan-code to vkey-code */
1007 /* let's do scan -> keycode -> vkey */
1009 returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
1011 case 2: { /* vkey-code to unshifted ANSI code */
1012 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1013 /* My Windows returns 'A'. */
1014 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1018 e.display = display;
1019 e.state = 0; /* unshifted */
1020 e.keycode = MapVirtualKey16( wCode, 0);
1021 if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1026 default: /* reserved */
1027 WARN(keyboard, "Unknown wMapType %d !\n",
1035 /****************************************************************************
1036 * GetKBCodePage16 (KEYBOARD.132)
1038 INT16 WINAPI GetKBCodePage16(void)
1040 TRACE(keyboard,"(void)\n");
1045 /****************************************************************************
1046 * GetKBCodePage32 (USER32.246)
1048 UINT32 WINAPI GetKBCodePage32(void)
1050 TRACE(keyboard,"(void)\n");
1054 /****************************************************************************
1055 * GetKeyNameText32A (USER32.247)
1057 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1059 return GetKeyNameText16(lParam,lpBuffer,nSize);
1062 /****************************************************************************
1063 * GetKeyNameText32W (USER32.248)
1065 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1067 LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1068 int res = GetKeyNameText32A(lParam,buf,nSize);
1070 lstrcpynAtoW(lpBuffer,buf,nSize);
1071 HeapFree( GetProcessHeap(), 0, buf );
1076 /****************************************************************************
1077 * GetKeyNameText16 (KEYBOARD.133)
1079 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1083 TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1088 /* for (i = 0 ; i != KeyTableSize ; i++)
1089 if (KeyTable[i].scancode == lParam) {
1090 lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1091 return strlen(lpBuffer);
1094 /* FIXME ! GetKeyNameText is still to do...
1101 /****************************************************************************
1102 * ToAscii (KEYBOARD.4)
1104 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1105 LPVOID lpChar, UINT16 flags)
1107 return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1110 /****************************************************************************
1111 * ToAscii32 (USER32.546)
1113 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1114 LPWORD lpChar,UINT32 flags )
1118 static XComposeStatus cs;
1122 e.display = display;
1124 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1125 { /* this could be speeded up by making another table, an array of struct vkey,keycode
1126 * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)! DF */
1127 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... */
1129 if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12)))
1130 /* it's normal to have 2 shift, control, and alt ! */
1131 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1132 e.keycode,keyc,virtKey);
1136 if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01))
1138 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1139 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1140 if (virtKey==VK_DECIMAL)
1141 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1145 WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1146 return virtKey; /* whatever */
1149 if (lpKeyState[VK_SHIFT] & 0x80)
1150 e.state |= ShiftMask;
1151 TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1152 if (lpKeyState[VK_CAPITAL] & 0x01)
1153 e.state |= LockMask;
1154 if (lpKeyState[VK_CONTROL] & 0x80)
1155 if (lpKeyState[VK_MENU] & 0x80)
1156 e.state |= AltGrMask;
1158 e.state |= ControlMask;
1159 if (lpKeyState[VK_NUMLOCK] & 0x01)
1160 e.state |= NumLockMask;
1161 TRACE(key, "(%04X, %04X) : faked state = %X\n",
1162 virtKey, scanCode, e.state);
1163 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1168 ((char*)lpChar)[1] = '\0';
1171 /* symbolic ASCII is the same as defined in rfc1345 */
1172 #ifdef XK_dead_tilde
1173 case XK_dead_tilde :
1175 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1176 dead_char = '~'; /* '? */
1178 #ifdef XK_dead_acute
1179 case XK_dead_acute :
1181 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1182 dead_char = 0xb4; /* '' */
1184 #ifdef XK_dead_circumflex
1185 case XK_dead_circumflex :
1187 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1188 dead_char = '^'; /* '> */
1190 #ifdef XK_dead_grave
1191 case XK_dead_grave :
1193 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1194 dead_char = '`'; /* '! */
1196 #ifdef XK_dead_diaeresis
1197 case XK_dead_diaeresis :
1199 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1200 dead_char = 0xa8; /* ': */
1202 #ifdef XK_dead_cedilla
1203 case XK_dead_cedilla :
1204 dead_char = 0xb8; /* ', */
1207 #ifdef XK_dead_macron
1208 case XK_dead_macron :
1209 dead_char = '-'; /* 'm isn't defined on iso-8859-x */
1212 #ifdef XK_dead_breve
1213 case XK_dead_breve :
1214 dead_char = 0xa2; /* '( */
1217 #ifdef XK_dead_abovedot
1218 case XK_dead_abovedot :
1219 dead_char = 0xff; /* '. */
1222 #ifdef XK_dead_abovering
1223 case XK_dead_abovering :
1224 dead_char = '0'; /* '0 isn't defined on iso-8859-x */
1227 #ifdef XK_dead_doubleacute
1228 case XK_dead_doubleacute :
1229 dead_char = 0xbd; /* '" */
1232 #ifdef XK_dead_caron
1233 case XK_dead_caron :
1234 dead_char = 0xb7; /* '< */
1237 #ifdef XK_dead_ogonek
1238 case XK_dead_ogonek :
1239 dead_char = 0xb2; /* '; */
1242 /* FIXME: I don't know this three.
1246 case XK_dead_voiced_sound :
1249 case XK_dead_semivoiced_sound :
1256 *(char*)lpChar = dead_char;
1263 ksname = TSXKeysymToString(keysym);
1266 if ((keysym >> 8) != 0xff)
1268 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1270 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1271 virtKey, scanCode, e.keycode, e.state);
1275 TRACE(key, "ToAscii about to return %d with char %x\n",
1276 ret, *(char*)lpChar);
1281 /***********************************************************************
1282 * GetKeyboardLayout (USER32.250)
1284 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1286 FIXME(keyboard,"(%ld): stub\n",dwLayout);
1287 return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1290 /***********************************************************************
1291 * GetKeyboardLayoutList (USER32.251)
1294 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1296 FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1298 layouts[0] = GetKeyboardLayout(0);
1303 /***********************************************************************
1304 * RegisterHotKey (USER32.433)
1306 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1307 FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1308 hwnd,id,modifiers,vk
1313 /***********************************************************************
1314 * UnregisterHotKey (USER32.565)
1316 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1317 FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);