4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
15 #include <X11/keysym.h>
17 #include "ts_xresource.h"
19 #include <X11/Xatom.h>
28 #include "debugtools.h"
32 static LPKEYBD_EVENT_PROC DefKeybEventProc
= NULL
;
33 static LPBYTE pKeyStateTable
= NULL
;
35 int min_keycode
, max_keycode
, keysyms_per_keycode
;
38 static int NumLockMask
, AltGrMask
; /* mask in the XKeyEvent state */
39 static int kcControl
, kcAlt
, kcShift
, kcNumLock
, kcCapsLock
; /* keycodes */
41 /* Keyboard translation tables */
42 static const int special_key
[] =
44 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
45 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
46 0, 0, 0, VK_ESCAPE
/* FF18 */
49 static const int cursor_key
[] =
51 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, VK_DOWN
, VK_PRIOR
,
52 VK_NEXT
, VK_END
/* FF50 */
55 static const int misc_key
[] =
57 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0, 0, 0, 0, /* FF60 */
58 VK_CANCEL
, VK_HELP
, VK_CANCEL
, VK_MENU
/* FF68 */
61 static const int keypad_key
[] =
63 0, VK_NUMLOCK
, /* FF7E */
64 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
65 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
66 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
67 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
, 0,
68 VK_INSERT
, VK_DELETE
, /* FF98 */
69 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
70 0, 0, VK_MULTIPLY
, VK_ADD
, VK_SEPARATOR
, VK_SUBTRACT
,
71 VK_DECIMAL
, VK_DIVIDE
, /* FFA8 */
72 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, VK_NUMPAD4
,
73 VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
, /* FFB0 */
74 VK_NUMPAD8
, VK_NUMPAD9
/* FFB8 */
77 static const int function_key
[] =
79 VK_F1
, VK_F2
, /* FFBE */
80 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
81 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
/* FFC8 */
84 static const int modifier_key
[] =
86 VK_SHIFT
, VK_SHIFT
, VK_CONTROL
, VK_CONTROL
, VK_CAPITAL
, 0, /* FFE1 */
87 VK_MENU
, VK_MENU
, VK_MENU
, VK_MENU
/* FFE7 */
90 /* Returns the Windows virtual key code associated with the X event <e> */
91 static WORD
EVENT_event_to_vkey( XKeyEvent
*e
)
95 TSXLookupString(e
, NULL
, 0, &keysym
, NULL
);
97 if ((keysym
>= 0xFFAE) && (keysym
<= 0xFFB9) && (e
->state
& NumLockMask
))
98 /* Only the Keypad keys 0-9 and . send different keysyms
99 * depending on the NumLock state */
100 return keypad_key
[(keysym
& 0xFF) - 0x7E];
102 return keyc2vkey
[e
->keycode
];
105 /**********************************************************************
108 static void KEYBOARD_Init(void)
112 XModifierKeymap
*mmp
;
119 TSXDisplayKeycodes(display
, &min_keycode
, &max_keycode
);
120 ksp
= TSXGetKeyboardMapping(display
, min_keycode
,
121 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
122 /* We are only interested in keysyms_per_keycode.
123 There is no need to hold a local copy of the keysyms table */
125 mmp
= TSXGetModifierMapping(display
);
126 kcp
= mmp
->modifiermap
;
127 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
131 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
136 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
137 if (TSXKeycodeToKeysym(display
, *kcp
, k
) == XK_Mode_switch
)
140 TRACE(key
, "AltGrMask is %x\n", AltGrMask
);
142 else if (TSXKeycodeToKeysym(display
, *kcp
, k
) == XK_Num_Lock
)
144 NumLockMask
= 1 << i
;
145 TRACE(key
, "NumLockMask is %x\n", NumLockMask
);
149 TSXFreeModifiermap(mmp
);
151 /* Now build two conversion arrays :
152 * keycode -> vkey + extended
153 * vkey + extended -> keycode */
155 e2
.display
= display
;
158 OEMvkey
= VK_OEM_7
; /* next is available. */
159 for (keyc
= min_keycode
; keyc
<= max_keycode
; keyc
++)
161 e2
.keycode
= (KeyCode
)keyc
;
162 TSXLookupString(&e2
, NULL
, 0, &keysym
, NULL
);
164 if (keysym
) /* otherwise, keycode not used */
166 if ((keysym
>> 8) == 0xFF) /* non-character key */
168 int key
= keysym
& 0xff;
170 if (key
>= 0x08 && key
<= 0x1B) /* special key */
171 vkey
= special_key
[key
- 0x08];
172 else if (key
>= 0x50 && key
<= 0x57) /* cursor key */
173 vkey
= cursor_key
[key
- 0x50];
174 else if (key
>= 0x60 && key
<= 0x6B) /* miscellaneous key */
175 vkey
= misc_key
[key
- 0x60];
176 else if (key
>= 0x7E && key
<= 0xB9) /* keypad key */
177 vkey
= keypad_key
[key
- 0x7E];
178 else if (key
>= 0xBE && key
<= 0xCD) /* function key */
180 vkey
= function_key
[key
- 0xBE];
181 vkey
|= 0x100; /* set extended bit */
183 else if (key
>= 0xE1 && key
<= 0xEA) /* modifier key */
184 vkey
= modifier_key
[key
- 0xE1];
185 else if (key
== 0xFF) /* DEL key */
187 /* extended must also be set for ALT_R, CTRL_R,
188 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
189 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
190 /* FIXME should we set extended bit for NumLock ? My
191 * Windows does ... DF */
211 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
213 keysym
= TSXLookupKeysym(&e2
, i
);
214 if ((keysym
>= VK_0
&& keysym
<= VK_9
)
215 || (keysym
>= VK_A
&& keysym
<= VK_Z
)
216 || keysym
== VK_SPACE
)
220 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
222 keysym
= TSXLookupKeysym(&e2
, i
);
225 case ';': vkey
= VK_OEM_1
; break;
226 case '/': vkey
= VK_OEM_2
; break;
227 case '`': vkey
= VK_OEM_3
; break;
228 case '[': vkey
= VK_OEM_4
; break;
229 case '\\': vkey
= VK_OEM_5
; break;
230 case ']': vkey
= VK_OEM_6
; break;
231 case '\'': vkey
= VK_OEM_7
; break;
232 case ',': vkey
= VK_OEM_COMMA
; break;
233 case '.': vkey
= VK_OEM_PERIOD
; break;
234 case '-': vkey
= VK_OEM_MINUS
; break;
235 case '+': vkey
= VK_OEM_PLUS
; break;
241 /* Others keys: let's assign OEM virtual key codes in the allowed range,
242 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
245 case 0xc1 : OEMvkey
=0xdb; break;
246 case 0xe5 : OEMvkey
=0xe9; break;
247 case 0xf6 : OEMvkey
=0xf5; WARN(keyboard
,"No more OEM vkey available!\n");
252 if (TRACE_ON(keyboard
))
254 dbg_decl_str(keyboard
, 1024);
256 TRACE(keyboard
, "OEM specific virtual key %X assigned "
257 "to keycode %X:\n", OEMvkey
, e2
.keycode
);
258 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
262 keysym
= TSXLookupKeysym(&e2
, i
);
263 ksname
= TSXKeysymToString(keysym
);
266 dsprintf(keyboard
, "%lX (%s) ", keysym
, ksname
);
268 TRACE(keyboard
, "(%s)\n", dbg_str(keyboard
));
272 keyc2vkey
[e2
.keycode
] = vkey
;
274 /* Now store one keycode for each modifier. Used to simulate keypresses. */
275 kcControl
= TSXKeysymToKeycode(display
, XK_Control_L
);
276 kcAlt
= TSXKeysymToKeycode(display
, XK_Alt_L
);
277 kcShift
= TSXKeysymToKeycode(display
, XK_Shift_L
);
278 kcNumLock
= TSXKeysymToKeycode(display
, XK_Num_Lock
);
279 kcCapsLock
= TSXKeysymToKeycode(display
, XK_Caps_Lock
);
282 /***********************************************************************
283 * KEYBOARD_Inquire (KEYBOARD.1)
285 WORD WINAPI
KEYBOARD_Inquire(LPKBINFO kbInfo
)
287 kbInfo
->Begin_First_Range
= 0;
288 kbInfo
->End_First_Range
= 0;
289 kbInfo
->Begin_Second_Range
= 0;
290 kbInfo
->End_Second_Range
= 0;
291 kbInfo
->StateSize
= 16;
293 return sizeof(KBINFO
);
296 /***********************************************************************
297 * KEYBOARD_Enable (KEYBOARD.2)
299 VOID WINAPI
KEYBOARD_Enable( LPKEYBD_EVENT_PROC lpKeybEventProc
,
302 static BOOL32 initDone
= FALSE
;
304 DefKeybEventProc
= lpKeybEventProc
;
305 pKeyStateTable
= lpKeyState
;
307 /* all states to false */
308 memset( lpKeyState
, 0, sizeof(lpKeyState
) );
310 if (!initDone
) KEYBOARD_Init();
314 /***********************************************************************
315 * KEYBOARD_Disable (KEYBOARD.3)
317 VOID WINAPI
KEYBOARD_Disable(VOID
)
319 DefKeybEventProc
= NULL
;
320 pKeyStateTable
= NULL
;
323 /***********************************************************************
326 void KEYBOARD_SendEvent( BYTE bVk
, BYTE bScan
, DWORD dwFlags
,
327 DWORD posX
, DWORD posY
, DWORD time
)
331 if ( !DefKeybEventProc
) return;
333 TRACE( event
, "(%d,%d,%04lX)\n", bVk
, bScan
, dwFlags
);
335 wke
.magic
= WINE_KEYBDEVENT_MAGIC
;
340 DefKeybEventProc( bVk
, bScan
, dwFlags
, (DWORD
)&wke
);
344 static BOOL32 NumState
=FALSE
, CapsState
=FALSE
;
346 /**********************************************************************
347 * KEYBOARD_GenerateMsg
349 * Generate Down+Up messages when NumLock or CapsLock is pressed.
351 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
354 void KEYBOARD_GenerateMsg( WORD vkey
, int Evtype
, INT32 event_x
, INT32 event_y
,
357 BOOL32
* State
= (vkey
==VK_NUMLOCK
? &NumState
: &CapsState
);
360 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
361 don't treat it. It's from the same key press. Then the state goes to ON.
362 And from there, a 'release' event will switch off the toggle key. */
364 TRACE(keyboard
,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey
,pKeyStateTable
[vkey
]);
367 if ( pKeyStateTable
[vkey
] & 0x1 ) /* it was ON */
369 if (Evtype
!=KeyPress
)
371 TRACE(keyboard
,"ON + KeyRelease => generating DOWN and UP messages.\n");
372 KEYBOARD_SendEvent( vkey
, 0, 0,
373 event_x
, event_y
, event_time
);
374 KEYBOARD_SendEvent( vkey
, 0, KEYEVENTF_KEYUP
,
375 event_x
, event_y
, event_time
);
377 pKeyStateTable
[vkey
] &= ~0x01; /* Toggle state to off. */
380 else /* it was OFF */
381 if (Evtype
==KeyPress
)
383 TRACE(keyboard
,"OFF + Keypress => generating DOWN and UP messages.\n");
384 KEYBOARD_SendEvent( vkey
, 0, 0,
385 event_x
, event_y
, event_time
);
386 KEYBOARD_SendEvent( vkey
, 0, KEYEVENTF_KEYUP
,
387 event_x
, event_y
, event_time
);
388 *State
=TRUE
; /* Goes to intermediary state before going to ON */
389 pKeyStateTable
[vkey
] |= 0x01; /* Toggle state to on. */
394 /***********************************************************************
395 * KEYBOARD_UpdateOneState
397 * Updates internal state for <vkey>, depending on key <state> under X
400 void KEYBOARD_UpdateOneState ( int vkey
, int state
)
402 /* Do something if internal table state != X state for keycode */
403 if (((pKeyStateTable
[vkey
] & 0x80)!=0) != state
)
405 TRACE(keyboard
,"Adjusting state for vkey %#.2x. State before %#.2x \n",
406 vkey
, pKeyStateTable
[vkey
]);
408 /* Fake key being pressed inside wine */
409 KEYBOARD_SendEvent( vkey
, 0, state
? 0 : KEYEVENTF_KEYUP
,
410 0, 0, GetTickCount() );
412 TRACE(keyboard
,"State after %#.2x \n",pKeyStateTable
[vkey
]);
416 /***********************************************************************
417 * KEYBOARD_UpdateState
419 * Update modifiers state (Ctrl, Alt, Shift)
420 * when window is activated (called by EVENT_FocusIn in event.c)
422 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
423 * from wine to another application and back.
424 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
427 void KEYBOARD_UpdateState ( void )
429 /* extract a bit from the char[32] bit suite */
430 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
432 char keys_return
[32];
434 TRACE(keyboard
,"called\n");
435 if (!TSXQueryKeymap(display
, keys_return
)) {
436 ERR(keyboard
,"Error getting keymap !");
440 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
441 KEYBOARD_UpdateOneState(VK_MENU
, KeyState(kcAlt
));
442 KEYBOARD_UpdateOneState(VK_CONTROL
, KeyState(kcControl
));
443 KEYBOARD_UpdateOneState(VK_SHIFT
, KeyState(kcShift
));
447 /***********************************************************************
448 * KEYBOARD_HandleEvent
450 * Handle a X key event
452 void KEYBOARD_HandleEvent( WND
*pWnd
, XKeyEvent
*event
)
457 WORD vkey
= 0, bScan
;
459 static BOOL32 force_extended
= FALSE
; /* hack for AltGr translation */
463 INT32 event_x
= (pWnd
? pWnd
->rectWindow
.left
: 0) + event
->x
;
464 INT32 event_y
= (pWnd
? pWnd
->rectWindow
.top
: 0) + event
->y
;
465 DWORD event_time
= event
->time
- MSG_WineStartTicks
;
467 /* this allows support for dead keys */
468 if ((event
->keycode
>> 8) == 0x10)
469 event
->keycode
=(event
->keycode
& 0xff);
471 ascii_chars
= TSXLookupString(event
, Str
, 1, &keysym
, &cs
);
473 TRACE(key
, "EVENT_key : state = %X\n", event
->state
);
474 if (keysym
== XK_Mode_switch
)
476 TRACE(key
, "Alt Gr key event received\n");
477 event
->keycode
= kcControl
; /* Simulate Control */
478 KEYBOARD_HandleEvent( pWnd
, event
);
480 event
->keycode
= kcAlt
; /* Simulate Alt */
481 force_extended
= TRUE
;
482 KEYBOARD_HandleEvent( pWnd
, event
);
483 force_extended
= FALSE
;
487 Str
[ascii_chars
] = '\0';
491 ksname
= TSXKeysymToString(keysym
);
494 TRACE(key
, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
495 (event
->type
== KeyPress
) ? "KeyPress" : "KeyRelease",
496 keysym
, ksname
, ascii_chars
, Str
[0] & 0xff, Str
);
499 vkey
= EVENT_event_to_vkey(event
);
500 if (force_extended
) vkey
|= 0x100;
502 TRACE(key
, "keycode 0x%x converted to vkey 0x%x\n",
503 event
->keycode
, vkey
);
510 KEYBOARD_GenerateMsg( VK_NUMLOCK
, event
->type
, event_x
, event_y
,
514 TRACE(keyboard
,"Caps Lock event. (type %d). State before : %#.2x\n",event
->type
,pKeyStateTable
[vkey
]);
515 KEYBOARD_GenerateMsg( VK_CAPITAL
, event
->type
, event_x
, event_y
,
517 TRACE(keyboard
,"State after : %#.2x\n",pKeyStateTable
[vkey
]);
520 /* Adjust the NUMLOCK state if it has been changed outside wine */
521 if (!(pKeyStateTable
[VK_NUMLOCK
] & 0x01) != !(event
->state
& NumLockMask
))
523 TRACE(keyboard
,"Adjusting NumLock state. \n");
524 KEYBOARD_GenerateMsg( VK_NUMLOCK
, KeyPress
, event_x
, event_y
,
526 KEYBOARD_GenerateMsg( VK_NUMLOCK
, KeyRelease
, event_x
, event_y
,
529 /* Adjust the CAPSLOCK state if it has been changed outside wine */
530 if (!(pKeyStateTable
[VK_CAPITAL
] & 0x01) != !(event
->state
& LockMask
))
532 TRACE(keyboard
,"Adjusting Caps Lock state.\n");
533 KEYBOARD_GenerateMsg( VK_CAPITAL
, KeyPress
, event_x
, event_y
,
535 KEYBOARD_GenerateMsg( VK_CAPITAL
, KeyRelease
, event_x
, event_y
,
538 /* Not Num nor Caps : end of intermediary states for both. */
542 bScan
= event
->keycode
- min_keycode
; /* Windows starts from 0, X from
543 min_keycode (8 usually) */
545 if ( event
->type
== KeyRelease
) dwFlags
|= KEYEVENTF_KEYUP
;
546 if ( vkey
& 0x100 ) dwFlags
|= KEYEVENTF_EXTENDEDKEY
;
547 if ( force_extended
) dwFlags
|= KEYEVENTF_WINE_FORCEEXTENDED
;
549 KEYBOARD_SendEvent( vkey
& 0xff, bScan
, dwFlags
,
550 event_x
, event_y
, event_time
);
556 /**********************************************************************
557 * ScreenSwitchEnable (KEYBOARD.100)
559 VOID WINAPI
ScreenSwitchEnable(WORD unused
)
561 FIXME(keyboard
,"(%04x): stub\n",unused
);
564 /**********************************************************************
565 * OemKeyScan (KEYBOARD.128)(USER32.401)
567 DWORD WINAPI
OemKeyScan(WORD wOemChar
)
569 TRACE(keyboard
,"*OemKeyScan (%d)\n",wOemChar
);
574 /**********************************************************************
575 * VkKeyScan [KEYBOARD.129]
577 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
578 * for the current keyboard.
579 * high-order byte yields :
583 * 3-5 Shift-key combinations that are not used for characters
586 * I.e. : Shift = 1, Ctrl = 2, Alt = 4.
587 * FIXME : works ok except for dead chars :
588 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
589 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
592 WORD WINAPI
VkKeyScan16(CHAR cChar
)
599 /* char->keysym (same for ANSI chars) */
600 keysym
=(unsigned char) cChar
;/* (!) cChar is signed */
601 if (keysym
<=27) keysym
+=0xFF00;/*special chars : return, backspace...*/
603 keycode
= TSXKeysymToKeycode(display
, keysym
); /* keysym -> keycode */
605 { /* It didn't work ... let's try with deadchar code. */
606 keycode
= TSXKeysymToKeycode(display
, keysym
| 0xFE00);
609 TRACE(keyboard
,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
610 cChar
,keysym
,keysym
,keycode
);
614 for (index
=-1, i
=0; (i
<8) && (index
<0); i
++) /* find shift state */
615 if (TSXKeycodeToKeysym(display
,keycode
,i
)==keysym
) index
=i
;
618 WARN(keyboard
,"Keysym %lx not found while parsing the keycode table\n",keysym
); break;
620 case 1 : highbyte
= 0x0100; break;
621 case 2 : highbyte
= 0X0600; break;
622 default : ERR(keyboard
,"index %d found by XKeycodeToKeysym. please report! \n",index
);
625 index : 0 adds 0x0000
626 index : 1 adds 0x0100 (shift)
627 index : ? adds 0x0200 (ctrl)
628 index : 2 adds 0x0600 (ctrl+alt)
629 index : ? adds 0x0700 (ctrl+alt+shift (used?))
632 TRACE(keyboard
," ... returning %#.2x\n", keyc2vkey
[keycode
]+highbyte
);
633 return keyc2vkey
[keycode
]+highbyte
; /* keycode -> (keyc2vkey) vkey */
636 /******************************************************************************
637 * GetKeyboardType16 (KEYBOARD.130)
639 INT16 WINAPI
GetKeyboardType16(INT16 nTypeFlag
)
641 TRACE(keyboard
,"(%d)\n",nTypeFlag
);
644 case 0: /* Keyboard type */
645 return 4; /* AT-101 */
647 case 1: /* Keyboard Subtype */
648 return 0; /* There are no defined subtypes */
650 case 2: /* Number of F-keys */
651 return 12; /* We're doing an 101 for now, so return 12 F-keys */
654 WARN(keyboard
, "Unknown type\n");
655 return 0; /* The book says 0 here, so 0 */
659 /******************************************************************************
660 * MapVirtualKey16 (KEYBOARD.131)
662 * MapVirtualKey translates keycodes from one format to another
664 UINT16 WINAPI
MapVirtualKey16(UINT16 wCode
, UINT16 wMapType
)
666 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
668 TRACE(keyboard
,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
671 case 0: { /* vkey-code to scan-code */
672 /* let's do vkey -> keycode -> scan */
674 for (keyc
=min_keycode
; keyc
<=max_keycode
; keyc
++)
675 if ((keyc2vkey
[keyc
] & 0xFF) == wCode
)
676 returnMVK (keyc
- min_keycode
);
679 case 1: /* scan-code to vkey-code */
680 /* let's do scan -> keycode -> vkey */
682 returnMVK (keyc2vkey
[(wCode
& 0xFF) + min_keycode
]);
684 case 2: { /* vkey-code to unshifted ANSI code */
685 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
686 /* My Windows returns 'A'. */
687 /* let's do vkey -> keycode -> (XLookupString) ansi char */
692 e
.state
= 0; /* unshifted */
693 e
.keycode
= MapVirtualKey16( wCode
, 0);
694 if (!TSXLookupString(&e
, s
, 2 , &keysym
, NULL
))
699 default: /* reserved */
700 WARN(keyboard
, "Unknown wMapType %d !\n",
708 /****************************************************************************
709 * GetKBCodePage16 (KEYBOARD.132)
711 INT16 WINAPI
GetKBCodePage16(void)
713 TRACE(keyboard
,"(void)\n");
717 /****************************************************************************
718 * GetKeyboardLayoutName16 (USER.477)
720 INT16 WINAPI
GetKeyboardLayoutName16(LPSTR pwszKLID
)
722 FIXME(keyboard
,"always returns primary U.S. English layout\n");
723 strcpy(pwszKLID
,"00000409");
727 /****************************************************************************
728 * GetKeyNameText16 (KEYBOARD.133)
730 INT16 WINAPI
GetKeyNameText16(LONG lParam
, LPSTR lpBuffer
, INT16 nSize
)
734 FIXME(keyboard
,"(%ld,<ptr>,%d): stub\n",lParam
,nSize
);
740 for (i = 0 ; i != KeyTableSize ; i++)
741 if (KeyTable[i].scancode == lParam) {
742 lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
743 return strlen(lpBuffer);
751 /****************************************************************************
752 * ToAscii (KEYBOARD.4)
754 The ToAscii function translates the specified virtual-key code and keyboard
755 state to the corresponding Windows character or characters.
757 If the specified key is a dead key, the return value is negative. Otherwise,
758 it is one of the following values:
760 0 The specified virtual key has no translation for the current state of the keyboard.
761 1 One Windows character was copied to the buffer.
762 2 Two characters were copied to the buffer. This usually happens when a
763 dead-key character (accent or diacritic) stored in the keyboard layout cannot
764 be composed with the specified virtual key to form a single character.
766 FIXME : should do the above (return 2 for non matching deadchar+char combinations)
769 INT16 WINAPI
ToAscii16(UINT16 virtKey
,UINT16 scanCode
, LPBYTE lpKeyState
,
770 LPVOID lpChar
, UINT16 flags
)
774 static XComposeStatus cs
;
779 /* This happens when doing Alt+letter : a fake 'down arrow' key press
780 event is generated by windows. Just ignore it. */
781 TRACE(keyboard
,"scanCode=0, doing nothing\n");
787 if (lpKeyState
[VK_SHIFT
] & 0x80)
788 e
.state
|= ShiftMask
;
789 if (lpKeyState
[VK_CAPITAL
] & 0x01)
791 if (lpKeyState
[VK_CONTROL
] & 0x80)
793 if (lpKeyState
[VK_MENU
] & 0x80)
794 e
.state
|= AltGrMask
;
796 e
.state
|= ControlMask
;
798 if (lpKeyState
[VK_NUMLOCK
] & 0x01)
799 e
.state
|= NumLockMask
;
800 TRACE(key
, "(%04X, %04X) : faked state = %X\n",
801 virtKey
, scanCode
, e
.state
);
802 /* We exit on the first keycode found, to speed up the thing. */
803 for (keyc
=min_keycode
; (keyc
<=max_keycode
) && (!e
.keycode
) ; keyc
++)
804 { /* Find a keycode that could have generated this virtual key */
805 if ((keyc2vkey
[keyc
] & 0xFF) == virtKey
)
806 { /* We filter the extended bit, we don't know it */
807 e
.keycode
= keyc
; /* Store it temporarily */
808 if ((EVENT_event_to_vkey(&e
) & 0xFF) != virtKey
) {
809 e
.keycode
= 0; /* Wrong one (ex: because of the NumLock
810 state), so set it to 0, we'll find another one */
815 if ((virtKey
>=VK_NUMPAD0
) && (virtKey
<=VK_NUMPAD9
))
816 e
.keycode
= TSXKeysymToKeycode(e
.display
, virtKey
-VK_NUMPAD0
+XK_KP_0
);
818 if (virtKey
==VK_DECIMAL
)
819 e
.keycode
= TSXKeysymToKeycode(e
.display
, XK_KP_Decimal
);
823 WARN(keyboard
,"Unknown virtual key %X !!! \n",virtKey
);
824 return virtKey
; /* whatever */
826 else TRACE(keyboard
,"Found keycode %d (0x%2X)\n",e
.keycode
,e
.keycode
);
828 ret
= TSXLookupString(&e
, (LPVOID
)lpChar
, 2, &keysym
, &cs
);
833 ((char*)lpChar
)[1] = '\0';
836 /* symbolic ASCII is the same as defined in rfc1345 */
840 case 0x1000FE7E : /* Xfree's XK_Dtilde */
841 dead_char
= '~'; /* '? */
846 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
847 dead_char
= 0xb4; /* '' */
849 #ifdef XK_dead_circumflex
850 case XK_dead_circumflex
:
852 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
853 dead_char
= '^'; /* '> */
858 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
859 dead_char
= '`'; /* '! */
861 #ifdef XK_dead_diaeresis
862 case XK_dead_diaeresis
:
864 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
865 dead_char
= 0xa8; /* ': */
867 #ifdef XK_dead_cedilla
868 case XK_dead_cedilla
:
869 dead_char
= 0xb8; /* ', */
872 #ifdef XK_dead_macron
873 case XK_dead_macron
:
874 dead_char
= '-'; /* 'm isn't defined on iso-8859-x */
879 dead_char
= 0xa2; /* '( */
882 #ifdef XK_dead_abovedot
883 case XK_dead_abovedot
:
884 dead_char
= 0xff; /* '. */
887 #ifdef XK_dead_abovering
888 case XK_dead_abovering
:
889 dead_char
= '0'; /* '0 isn't defined on iso-8859-x */
892 #ifdef XK_dead_doubleacute
893 case XK_dead_doubleacute
:
894 dead_char
= 0xbd; /* '" */
899 dead_char
= 0xb7; /* '< */
902 #ifdef XK_dead_ogonek
903 case XK_dead_ogonek
:
904 dead_char
= 0xb2; /* '; */
907 /* FIXME: I don't know this three.
911 case XK_dead_voiced_sound :
914 case XK_dead_semivoiced_sound :
921 *(char*)lpChar
= dead_char
;
928 ksname
= TSXKeysymToString(keysym
);
931 if ((keysym
>> 8) != 0xff)
933 ERR(keyboard
, "Please report: no char for keysym %04lX (%s) :\n",
935 ERR(keyboard
, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
936 virtKey
, scanCode
, e
.keycode
, e
.state
);
941 /* We have a special case to handle : Shift + arrow, shift + home, ...
942 X returns a char for it, but Windows doesn't. Let's eat it. */
943 if (!(lpKeyState
[VK_NUMLOCK
] & 0x01) /* NumLock is off */
944 && (lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
945 && (keysym
>=XK_KP_0
) && (keysym
<=XK_KP_9
))
952 TRACE(key
, "ToAscii about to return %d with char %x\n",
953 ret
, *(char*)lpChar
);