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 if (hAccel == 0 || msg == NULL ||
778 (msg->message != WM_KEYDOWN &&
779 msg->message != WM_KEYUP &&
780 msg->message != WM_SYSKEYDOWN &&
781 msg->message != WM_SYSKEYUP &&
782 msg->message != WM_CHAR)) {
783 WARN(accel, "erraneous input parameters\n");
784 SetLastError(ERROR_INVALID_PARAMETER);
788 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
789 "msg->hwnd=%04x, msg->message=%04x\n",
790 hAccel,hWnd,msg->hwnd,msg->message);
795 if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
796 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
798 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
799 WARN(accel, "couldn't translate accelerator key");
803 /**********************************************************************
804 * TranslateAccelerator16 (USER.178)
806 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
808 LPACCEL16 lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
812 if (hAccel == 0 || msg == NULL ||
813 (msg->message != WM_KEYDOWN &&
814 msg->message != WM_KEYUP &&
815 msg->message != WM_SYSKEYDOWN &&
816 msg->message != WM_SYSKEYUP &&
817 msg->message != WM_CHAR)) {
818 WARN(accel, "erraneous input parameters\n");
819 SetLastError(ERROR_INVALID_PARAMETER);
823 TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
824 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
825 STRUCT32_MSG16to32(msg,&msg32);
831 if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
832 lpAccelTbl[i].key,lpAccelTbl[i].cmd))
834 } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
835 WARN(accel, "couldn't translate accelerator key");
840 /**********************************************************************
841 * ScreenSwitchEnable (KEYBOARD.100)
843 VOID WINAPI ScreenSwitchEnable(WORD unused)
845 FIXME(keyboard,"(%04x): stub\n",unused);
848 /**********************************************************************
849 * OemKeyScan (KEYBOARD.128)(USER32.401)
851 DWORD WINAPI OemKeyScan(WORD wOemChar)
853 TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
858 /**********************************************************************
859 * VkKeyScanA (USER32.573)
861 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
862 * for the current keyboard.
863 * high-order byte yields :
867 * 3-5 Shift-key combinations that are not used for characters
870 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
871 * FIXME : works ok except for dead chars :
872 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
873 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
876 WORD WINAPI VkKeyScan32A(CHAR cChar)
883 /* char->keysym (same for ANSI chars) */
884 keysym=(unsigned char) cChar;/* (!) cChar is signed */
885 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
887 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
889 { /* It didn't work ... let's try with deadchar code. */
890 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
893 TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
894 cChar,keysym,keysym,keycode);
898 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
899 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
902 WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
904 case 1 : highbyte = 0x0100; break;
905 case 2 : highbyte = 0X0600; break;
906 default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
909 index : 0 adds 0x0000
910 index : 1 adds 0x0100 (shift)
911 index : ? adds 0x0200 (ctrl)
912 index : 2 adds 0x0600 (ctrl+alt)
913 index : ? adds 0x0700 (ctrl+alt+shift (used?))
916 TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
917 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
920 /******************************************************************************
921 * VkKeyScan [KEYBOARD.129]
923 WORD WINAPI VkKeyScan16(CHAR cChar)
925 return VkKeyScan32A(cChar);
928 /******************************************************************************
929 * VkKeyScanW (USER32.576)
931 WORD WINAPI VkKeyScan32W(WCHAR cChar)
933 return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
936 /******************************************************************************
937 * GetKeyboardType16 (KEYBOARD.130)
939 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
941 return GetKeyboardType32(nTypeFlag);
944 /******************************************************************************
945 * GetKeyboardType32 (USER32.255)
947 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
949 TRACE(keyboard,"(%d)\n",nTypeFlag);
952 case 0: /* Keyboard type */
953 return 4; /* AT-101 */
955 case 1: /* Keyboard Subtype */
956 return 0; /* There are no defined subtypes */
958 case 2: /* Number of F-keys */
959 return 12; /* We're doing an 101 for now, so return 12 F-keys */
962 WARN(keyboard, "Unknown type\n");
963 return 0; /* The book says 0 here, so 0 */
968 /******************************************************************************
969 * MapVirtualKey32A (USER32.383)
971 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
973 return MapVirtualKey16(code,maptype);
976 /******************************************************************************
977 * MapVirtualKey32W (USER32.385)
979 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
981 return MapVirtualKey16(code,maptype);
984 /******************************************************************************
985 * MapVirtualKey16 (KEYBOARD.131)
987 * MapVirtualKey translates keycodes from one format to another
989 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
991 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
993 TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
996 case 0: { /* vkey-code to scan-code */
997 /* let's do vkey -> keycode -> scan */
999 for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
1000 if ((keyc2vkey[keyc] & 0xFF)== wCode)
1001 returnMVK (keyc - 8);
1004 case 1: /* scan-code to vkey-code */
1005 /* let's do scan -> keycode -> vkey */
1007 returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
1009 case 2: { /* vkey-code to unshifted ANSI code */
1010 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1011 /* My Windows returns 'A'. */
1012 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1016 e.display = display;
1017 e.state = 0; /* unshifted */
1018 e.keycode = MapVirtualKey16( wCode, 0);
1019 if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1024 default: /* reserved */
1025 WARN(keyboard, "Unknown wMapType %d !\n",
1033 /****************************************************************************
1034 * GetKBCodePage16 (KEYBOARD.132)
1036 INT16 WINAPI GetKBCodePage16(void)
1038 TRACE(keyboard,"(void)\n");
1043 /****************************************************************************
1044 * GetKBCodePage32 (USER32.246)
1046 UINT32 WINAPI GetKBCodePage32(void)
1048 TRACE(keyboard,"(void)\n");
1052 /****************************************************************************
1053 * GetKeyNameText32A (USER32.247)
1055 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1057 return GetKeyNameText16(lParam,lpBuffer,nSize);
1060 /****************************************************************************
1061 * GetKeyNameText32W (USER32.248)
1063 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1065 LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1066 int res = GetKeyNameText32A(lParam,buf,nSize);
1068 lstrcpynAtoW(lpBuffer,buf,nSize);
1069 HeapFree( GetProcessHeap(), 0, buf );
1074 /****************************************************************************
1075 * GetKeyNameText16 (KEYBOARD.133)
1077 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1081 TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1086 /* for (i = 0 ; i != KeyTableSize ; i++)
1087 if (KeyTable[i].scancode == lParam) {
1088 lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1089 return strlen(lpBuffer);
1092 /* FIXME ! GetKeyNameText is still to do...
1099 /****************************************************************************
1100 * ToAscii (KEYBOARD.4)
1102 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState,
1103 LPVOID lpChar, UINT16 flags)
1105 return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1108 /****************************************************************************
1109 * ToAscii32 (USER32.546)
1111 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1112 LPWORD lpChar,UINT32 flags )
1116 static XComposeStatus cs;
1120 e.display = display;
1122 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1123 { /* this could be speeded up by making another table, an array of struct vkey,keycode
1124 * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)! DF */
1125 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... */
1127 if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12)))
1128 /* it's normal to have 2 shift, control, and alt ! */
1129 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1130 e.keycode,keyc,virtKey);
1134 if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01))
1136 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1137 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1138 if (virtKey==VK_DECIMAL)
1139 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1143 WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1144 return virtKey; /* whatever */
1147 if (lpKeyState[VK_SHIFT] & 0x80)
1148 e.state |= ShiftMask;
1149 TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1150 if (lpKeyState[VK_CAPITAL] & 0x01)
1151 e.state |= LockMask;
1152 if (lpKeyState[VK_CONTROL] & 0x80)
1153 if (lpKeyState[VK_MENU] & 0x80)
1154 e.state |= AltGrMask;
1156 e.state |= ControlMask;
1157 if (lpKeyState[VK_NUMLOCK] & 0x01)
1158 e.state |= NumLockMask;
1159 TRACE(key, "(%04X, %04X) : faked state = %X\n",
1160 virtKey, scanCode, e.state);
1161 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1166 ((char*)lpChar)[1] = '\0';
1169 /* symbolic ASCII is the same as defined in rfc1345 */
1170 #ifdef XK_dead_tilde
1171 case XK_dead_tilde :
1173 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1174 dead_char = '~'; /* '? */
1176 #ifdef XK_dead_acute
1177 case XK_dead_acute :
1179 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1180 dead_char = 0xb4; /* '' */
1182 #ifdef XK_dead_circumflex
1183 case XK_dead_circumflex :
1185 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1186 dead_char = '^'; /* '> */
1188 #ifdef XK_dead_grave
1189 case XK_dead_grave :
1191 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1192 dead_char = '`'; /* '! */
1194 #ifdef XK_dead_diaeresis
1195 case XK_dead_diaeresis :
1197 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1198 dead_char = 0xa8; /* ': */
1200 #ifdef XK_dead_cedilla
1201 case XK_dead_cedilla :
1202 dead_char = 0xb8; /* ', */
1205 #ifdef XK_dead_macron
1206 case XK_dead_macron :
1207 dead_char = '-'; /* 'm isn't defined on iso-8859-x */
1210 #ifdef XK_dead_breve
1211 case XK_dead_breve :
1212 dead_char = 0xa2; /* '( */
1215 #ifdef XK_dead_abovedot
1216 case XK_dead_abovedot :
1217 dead_char = 0xff; /* '. */
1220 #ifdef XK_dead_abovering
1221 case XK_dead_abovering :
1222 dead_char = '0'; /* '0 isn't defined on iso-8859-x */
1225 #ifdef XK_dead_doubleacute
1226 case XK_dead_doubleacute :
1227 dead_char = 0xbd; /* '" */
1230 #ifdef XK_dead_caron
1231 case XK_dead_caron :
1232 dead_char = 0xb7; /* '< */
1235 #ifdef XK_dead_ogonek
1236 case XK_dead_ogonek :
1237 dead_char = 0xb2; /* '; */
1240 /* FIXME: I don't know this three.
1244 case XK_dead_voiced_sound :
1247 case XK_dead_semivoiced_sound :
1254 *(char*)lpChar = dead_char;
1261 ksname = TSXKeysymToString(keysym);
1264 if ((keysym >> 8) != 0xff)
1266 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1268 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1269 virtKey, scanCode, e.keycode, e.state);
1273 TRACE(key, "ToAscii about to return %d with char %x\n",
1274 ret, *(char*)lpChar);
1279 /***********************************************************************
1280 * GetKeyboardLayout (USER32.250)
1282 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1284 FIXME(keyboard,"(%ld): stub\n",dwLayout);
1285 return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1288 /***********************************************************************
1289 * GetKeyboardLayoutList (USER32.251)
1292 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1294 FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1296 layouts[0] = GetKeyboardLayout(0);
1301 /***********************************************************************
1302 * RegisterHotKey (USER32.433)
1304 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1305 FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1306 hwnd,id,modifiers,vk
1311 /***********************************************************************
1312 * UnregisterHotKey (USER32.565)
1314 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1315 FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);