Release 980601
[wine] / windows / keyboard.c
1 /*
2  * Keyboard related functions
3  *
4  * Copyright 1993 Bob Amstadt
5  * Copyright 1996 Albrecht Kleine 
6  * Copyright 1997 David Faure
7  * Copyright 1998 Morten Welinder
8  *
9  */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <X11/keysym.h>
15 #include "ts_xlib.h"
16 #include "ts_xresource.h"
17 #include "ts_xutil.h"
18 #include <X11/Xatom.h>
19
20 #include "windows.h"
21 #include "win.h"
22 #include "gdi.h"
23 #include "heap.h"
24 #include "keyboard.h"
25 #include "message.h"
26 #include "debug.h"
27 #include "debugtools.h"
28 #include "struct32.h"
29 #include "winerror.h"
30
31 BOOL32 MouseButtonsStates[3];
32 BOOL32 AsyncMouseButtonsStates[3];
33 BYTE InputKeyStateTable[256];
34 BYTE QueueKeyStateTable[256];
35 BYTE AsyncKeyStateTable[256];
36
37 static int NumLockMask;
38 static int AltGrMask;
39 static int min_keycode, max_keycode;
40 static int keyc2vkey[256];
41
42 typedef union
43 {
44     struct
45     {
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;
54     } lp1;
55     unsigned long lp2;
56 } KEYLP;
57
58 /* Keyboard translation tables */
59 static const int special_key[] =
60 {
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 */
64 };
65
66 static const int cursor_key[] =
67 {
68     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
69                                        VK_NEXT, VK_END          /* FF50 */
70 };
71
72 static const int misc_key[] =
73 {
74     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
75     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
76 };
77
78 static const int keypad_key[] =
79 {
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 */
92 };
93     
94 static const int function_key[] =
95 {
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 */
99 };
100
101 static const int modifier_key[] =
102 {
103     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
104     VK_MENU, VK_MENU, VK_MENU, VK_MENU                         /* FFE7 */
105 };
106
107 /*
108  * Table for vkey to scancode translation - 5/29/97 chrisf@america.com 
109  */
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,
127 /* 256 */
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,
144 };
145
146 static WORD EVENT_event_to_vkey( XKeyEvent *e)
147 {
148     KeySym keysym;
149
150     TSXLookupString(e, NULL, 0, &keysym, NULL);
151
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];
156
157     return keyc2vkey[e->keycode];
158 }
159
160 /**********************************************************************
161  *              KEYBOARD_Init
162  */
163 BOOL32 KEYBOARD_Init(void)
164 {
165     int i, keysyms_per_keycode;
166     KeySym *ksp;
167     XModifierKeymap *mmp;
168     KeySym keysym;
169     KeyCode *kcp;
170     XKeyEvent e2;
171     WORD vkey, OEMvkey;
172
173     TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
174     ksp = TSXGetKeyboardMapping(display, min_keycode,
175                               max_keycode + 1 - min_keycode, &keysyms_per_keycode);
176     /* We are only interested in keysyms_per_keycode.
177        There is no need to hold a local copy of the keysyms table */
178     TSXFree(ksp);
179     mmp = TSXGetModifierMapping(display);
180     kcp = mmp->modifiermap;
181     for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
182     {
183         int j;
184         
185         for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
186             if (*kcp)
187             {
188                 int k;
189                 
190                 for (k = 0; k < keysyms_per_keycode; k += 1)
191                     if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
192                     {
193                         AltGrMask = 1 << i;
194                         TRACE(key, "AltGrMask is %x\n", AltGrMask);
195                     }
196                     else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
197                     {
198                         NumLockMask = 1 << i;
199                         TRACE(key, "NumLockMask is %x\n", NumLockMask);
200                     }
201             }
202     }
203     TSXFreeModifiermap(mmp);
204
205     /* Now build two conversion arrays :
206      * keycode -> vkey + extended
207      * vkey + extended -> keycode */
208
209     e2.display = display;
210     e2.state = 0;
211
212     OEMvkey = VK_OEM_7; /* next is available.  */
213     for (e2.keycode=min_keycode; e2.keycode<=max_keycode; e2.keycode++)
214     {
215         TSXLookupString(&e2, NULL, 0, &keysym, NULL);
216         vkey = 0;
217         if (keysym)  /* otherwise, keycode not used */
218         {
219             if ((keysym >> 8) == 0xFF)         /* non-character key */
220             {
221                 int key = keysym & 0xff;
222                 
223                 if (key >= 0x08 && key <= 0x1B)         /* special key */
224                     vkey = special_key[key - 0x08];
225                 else if (key >= 0x50 && key <= 0x57)    /* cursor key */
226                     vkey = cursor_key[key - 0x50];
227                 else if (key >= 0x60 && key <= 0x6B)    /* miscellaneous key */
228                     vkey = misc_key[key - 0x60];
229                 else if (key >= 0x7E && key <= 0xB9)    /* keypad key */
230                     vkey = keypad_key[key - 0x7E];
231                 else if (key >= 0xBE && key <= 0xCD)    /* function key */
232                 {
233                     vkey = function_key[key - 0xBE];
234                     vkey |= 0x100; /* set extended bit */
235                 }
236                 else if (key >= 0xE1 && key <= 0xEA)    /* modifier key */
237                     vkey = modifier_key[key - 0xE1];
238                 else if (key == 0xFF)                   /* DEL key */
239                     vkey = VK_DELETE;
240                 /* extended must also be set for ALT_R, CTRL_R,
241                    INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
242                    keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
243                 /* FIXME should we set extended bit for NumLock ? My
244                  * Windows does ... DF */
245                 switch (keysym)
246                 {
247                 case XK_Control_R :
248                 case XK_Alt_R :
249                 case XK_Insert :
250                 case XK_Delete :
251                 case XK_Home :
252                 case XK_End :
253                 case XK_Prior :
254                 case XK_Next :
255                 case XK_Left :
256                 case XK_Up :
257                 case XK_Right :
258                 case XK_Down :
259                 case XK_KP_Divide :
260                 case XK_KP_Enter :
261                     vkey |= 0x100;
262                 }
263             }
264             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
265             {
266                 keysym = TSXLookupKeysym(&e2, i);
267                 if ((keysym >= VK_0 && keysym <= VK_9)
268                     || (keysym >= VK_A && keysym <= VK_Z)
269                     || keysym == VK_SPACE)
270                     vkey = keysym;
271             }
272
273             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
274             {
275                 keysym = TSXLookupKeysym(&e2, i);
276                 switch (keysym)
277                 {
278                 case ';': case ':':   vkey = VK_OEM_1; break;
279                 case '/': case '?':   vkey = VK_OEM_2; break;
280                 case '`': case '~':   vkey = VK_OEM_3; break;
281                 case '[':             vkey = VK_OEM_4; break;
282                 case '\\':            vkey = VK_OEM_5; break;
283                 case ']':             vkey = VK_OEM_6; break;
284                 case '\'': case '\"': vkey = VK_OEM_7; break;
285                 case ',':             vkey = VK_OEM_COMMA; break;
286                 case '.':             vkey = VK_OEM_PERIOD; break;
287                 case '-':             vkey = VK_OEM_MINUS; break;
288                 case '+':             vkey = VK_OEM_PLUS; break;
289                 }
290             }
291
292             if (!vkey)
293             {
294                 /* Others keys: let's assign OEM virtual key codes in the allowed range,
295                  * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
296                 switch (++OEMvkey)
297                 {
298                 case 0xc1 : OEMvkey=0xdb; break;
299                 case 0xe5 : OEMvkey=0xe9; break;
300                 case 0xf6 : OEMvkey=0xf5; WARN(keyboard,"No more OEM vkey available!\n");
301                 }
302
303                 vkey = OEMvkey;
304                   
305                 if (TRACE_ON(keyboard))
306                 {
307                     dbg_decl_str(keyboard, 1024);
308
309                     TRACE(keyboard, "OEM specific virtual key %X assigned "
310                                  "to keycode %X:\n", OEMvkey, e2.keycode);
311                     for (i = 0; i < keysyms_per_keycode; i += 1)
312                     {
313                         char    *ksname;
314                         
315                         keysym = TSXLookupKeysym(&e2, i);
316                         ksname = TSXKeysymToString(keysym);
317                         if (!ksname)
318                             ksname = "NoSymbol";
319                         dsprintf(keyboard, "%lX (%s) ", keysym, ksname);
320                     }
321                     TRACE(keyboard, "(%s)\n", dbg_str(keyboard));
322                 }
323             }
324         }
325         keyc2vkey[e2.keycode] = vkey;
326     } /* for */
327     return TRUE;
328 }
329
330 static BOOL32 NumState=FALSE, CapsState=FALSE;
331
332 /**********************************************************************
333  *              KEYBOARD_GenerateMsg
334  */
335 void KEYBOARD_GenerateMsg( WORD vkey, int Evtype, INT32 event_x, INT32 event_y,
336                            DWORD event_time, KEYLP localkeylp )
337 {
338   BOOL32 * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
339
340   if (*State) {
341     /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
342        don't treat it. It's from the same key press. Then the state goes to ON.
343        And from there, a 'release' event will switch off the toggle key. */
344     *State=FALSE;
345     TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,InputKeyStateTable[vkey]);
346   } else
347     {
348         if ( InputKeyStateTable[vkey] & 0x1 ) /* it was ON */
349           {
350             if (Evtype!=KeyPress)
351               {
352                 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
353                 localkeylp.lp1.previous = 0; /* ? */
354                 localkeylp.lp1.transition = 0;
355                 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
356                                 event_x, event_y, event_time, 0 );
357                 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
358                                 event_x, event_y, event_time, 0 );
359                 *State=FALSE;
360                 InputKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */ 
361               } 
362           }
363         else /* it was OFF */
364           if (Evtype==KeyPress)
365             {
366               TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
367               hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
368                               event_x, event_y, event_time, 0 );
369               localkeylp.lp1.previous = 1;
370               localkeylp.lp1.transition = 1;
371               hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
372                               event_x, event_y, event_time, 0 );
373               *State=TRUE; /* Goes to intermediary state before going to ON */
374               InputKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
375             }
376     }
377 }
378
379 /***********************************************************************
380  *           KEYBOARD_HandleEvent
381  *
382  * Handle a X key event
383  */
384 void KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
385 {
386     char Str[24]; 
387     XComposeStatus cs; 
388     KeySym keysym;
389     WORD vkey = 0;
390     KEYLP keylp;
391     static BOOL32 force_extended = FALSE; /* hack for AltGr translation */
392
393     int ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
394
395     INT32 event_x = pWnd->rectWindow.left + event->x;
396     INT32 event_y = pWnd->rectWindow.top + event->y;
397     DWORD event_time = event->time - MSG_WineStartTicks;
398
399     TRACE(key, "EVENT_key : state = %X\n", event->state);
400     if (keysym == XK_Mode_switch)
401         {
402         TRACE(key, "Alt Gr key event received\n");
403         event->keycode = TSXKeysymToKeycode(event->display, XK_Control_L);
404         TRACE(key, "Control_L is keycode 0x%x\n", event->keycode);
405         KEYBOARD_HandleEvent( pWnd, event );
406         event->keycode = TSXKeysymToKeycode(event->display, XK_Alt_L);
407         TRACE(key, "Alt_L is keycode 0x%x\n", event->keycode);
408         force_extended = TRUE;
409         KEYBOARD_HandleEvent( pWnd, event );
410         force_extended = FALSE;
411         return;
412         }
413
414     Str[ascii_chars] = '\0';
415     if (TRACE_ON(key)){
416         char    *ksname;
417
418         ksname = TSXKeysymToString(keysym);
419         if (!ksname)
420           ksname = "No Name";
421         TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n", 
422                      (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
423                      keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
424     }
425
426     vkey = EVENT_event_to_vkey(event);
427     if (force_extended) vkey |= 0x100;
428
429     TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
430                     event->keycode, vkey);
431
432    if (vkey)
433    {
434     keylp.lp1.count = 1;
435     keylp.lp1.code = vkey2scode[vkey]; /* 5/29/97 chrisf@america.com */
436     keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
437     keylp.lp1.win_internal = 0; /* this has something to do with dialogs, 
438                                 * don't remember where I read it - AK */
439                                 /* it's '1' under windows, when a dialog box appears
440                                  * and you press one of the underlined keys - DF*/
441     vkey &= 0xff;
442
443     switch(vkey)
444     {
445     case VK_NUMLOCK:    
446       KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
447                             event_time, keylp);
448       break;
449     case VK_CAPITAL:
450       TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
451       KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
452                             event_time, keylp ); 
453       TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
454       break;
455     default:
456       {
457         WORD message;
458         if (event->type == KeyPress)
459           {
460             keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
461             if (!(InputKeyStateTable[vkey] & 0x80))
462               InputKeyStateTable[vkey] ^= 0x01;
463             InputKeyStateTable[vkey] |= 0x80;
464             keylp.lp1.transition = 0;
465             message = (InputKeyStateTable[VK_MENU] & 0x80)
466               && !(InputKeyStateTable[VK_CONTROL] & 0x80)
467               ? WM_SYSKEYDOWN : WM_KEYDOWN;
468           }
469         else
470           {
471             BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
472                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
473                 && (force_extended == FALSE); /* for Alt from AltGr */
474             
475             InputKeyStateTable[vkey] &= ~0x80; 
476             keylp.lp1.previous = 1;
477             keylp.lp1.transition = 1;
478             message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
479           }
480         keylp.lp1.context = ( (event->state & Mod1Mask)  || 
481                               (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
482         if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
483           { 
484             TRACE(keyboard,"Adjusting NumLock state. \n");
485             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
486                                   event_time, keylp );
487             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
488                                   event_time, keylp );
489           }
490         if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
491           {
492             TRACE(keyboard,"Adjusting Caps Lock state. State before %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
493             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
494                                   event_time, keylp );
495             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
496                                   event_time, keylp );
497             TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[VK_CAPITAL]);
498           }
499         /* End of intermediary states. */
500         NumState = FALSE;
501         CapsState = FALSE;
502
503         TRACE(key,"            wParam=%04X, lParam=%08lX\n", 
504                     vkey, keylp.lp2 );
505         TRACE(key,"            InputKeyState=%X\n",
506                     InputKeyStateTable[vkey]);
507
508         hardware_event( message, vkey, keylp.lp2,
509                         event_x, event_y, event_time, 0 );
510       }
511     }
512    }
513 }
514
515
516 /**********************************************************************
517  *           GetKeyState      (USER.106)
518  */
519 WORD WINAPI GetKeyState16(INT16 vkey)
520 {
521     return GetKeyState32(vkey);
522 }
523
524 /**********************************************************************
525  *           GetKeyState      (USER32.249)
526  *
527  * An application calls the GetKeyState function in response to a
528  * keyboard-input message.  This function retrieves the state of the key
529  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 390)
530  */
531 WORD WINAPI GetKeyState32(INT32 vkey)
532 {
533     INT32 retval;
534
535     switch (vkey)
536         {
537         case VK_LBUTTON : /* VK_LBUTTON is 1 */
538             retval = MouseButtonsStates[0] ? 0x8000 : 0;
539             break;
540         case VK_MBUTTON : /* VK_MBUTTON is 4 */
541             retval = MouseButtonsStates[1] ? 0x8000 : 0;
542             break;
543         case VK_RBUTTON : /* VK_RBUTTON is 2 */
544             retval = MouseButtonsStates[2] ? 0x8000 : 0;
545             break;
546         default :
547             if (vkey >= 'a' && vkey <= 'z')
548                 vkey += 'A' - 'a';
549             retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
550                        (WORD)(QueueKeyStateTable[vkey] & 0x01);
551         }
552     TRACE(key, "(0x%x) -> %x\n", vkey, retval);
553     return retval;
554 }
555
556 /**********************************************************************
557  *           GetKeyboardState      (USER.222)(USER32.254)
558  *
559  * An application calls the GetKeyboardState function in response to a
560  * keyboard-input message.  This function retrieves the state of the keyboard
561  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 387)
562  */
563 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
564 {
565     TRACE(key, "(%p)\n", lpKeyState);
566     if (lpKeyState != NULL) {
567         QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
568         QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
569         QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
570         memcpy(lpKeyState, QueueKeyStateTable, 256);
571     }
572 }
573
574 /**********************************************************************
575  *          SetKeyboardState      (USER.223)(USER32.484)
576  */
577 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
578 {
579     TRACE(key, "(%p)\n", lpKeyState);
580     if (lpKeyState != NULL) {
581         memcpy(QueueKeyStateTable, lpKeyState, 256);
582         MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
583         MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
584         MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
585     }
586 }
587
588 /**********************************************************************
589  *           GetAsyncKeyState32      (USER32.207)
590  *
591  *      Determine if a key is or was pressed.  retval has high-order 
592  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
593  * been pressed.
594  *
595  *      This uses the variable AsyncMouseButtonsStates and
596  * AsyncKeyStateTable (set in event.c) which have the mouse button
597  * number or key number (whichever is applicable) set to true if the
598  * mouse or key had been depressed since the last call to 
599  * GetAsyncKeyState.
600  */
601 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
602 {
603     short retval;       
604
605     switch (nKey) {
606      case VK_LBUTTON:
607         retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) | 
608                  (MouseButtonsStates[0] ? 0x8000 : 0);
609         break;
610      case VK_MBUTTON:
611         retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) | 
612                  (MouseButtonsStates[1] ? 0x8000 : 0);
613         break;
614      case VK_RBUTTON:
615         retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) | 
616                  (MouseButtonsStates[2] ? 0x8000 : 0);
617         break;
618      default:
619         retval = AsyncKeyStateTable[nKey] | 
620                 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0); 
621         break;
622     }
623
624     /* all states to false */
625     memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
626     memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
627
628     TRACE(key, "(%x) -> %x\n", nKey, retval);
629     return retval;
630 }
631
632 /**********************************************************************
633  *            GetAsyncKeyState16        (USER.249)
634  */
635 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
636 {
637     return GetAsyncKeyState32(nKey);
638 }
639
640 /**********************************************************************
641  *           KBD_translate_accelerator
642  *
643  * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP  -messages
644  */
645 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
646                                         BYTE fVirt,WORD key,WORD cmd)
647 {
648     BOOL32      sendmsg = FALSE;
649
650     if(msg->wParam == key) 
651     {
652         if (msg->message == WM_CHAR) {
653         if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
654         {
655           TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
656                         msg->wParam&0xff);
657           sendmsg=TRUE;
658         }  
659       } else {
660        if(fVirt & FVIRTKEY) {
661         INT32 mask = 0;
662         TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
663                                msg->wParam,0xff & HIWORD(msg->lParam));                
664         if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
665         if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
666         if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
667         if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
668           sendmsg=TRUE;                     
669         else
670           TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
671        }
672        else
673        {
674          if (!(msg->lParam & 0x01000000))  /* no special_key */
675          {
676            if ((fVirt & FALT) && (msg->lParam & 0x20000000))
677            {                                                   /* ^^ ALT pressed */
678             TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
679             sendmsg=TRUE;           
680            } 
681          } 
682        }
683       } 
684
685       if (sendmsg)      /* found an accelerator, but send a message... ? */
686       {
687         INT16  iSysStat,iStat,mesg=0;
688         HMENU16 hMenu;
689         
690         if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
691           mesg=1;
692         else 
693          if (GetCapture32())
694            mesg=2;
695          else
696           if (!IsWindowEnabled32(hWnd))
697             mesg=3;
698           else
699           {
700             WND* wndPtr = WIN_FindWndPtr(hWnd);
701
702             hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
703             iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
704                                             cmd, MF_BYCOMMAND) : -1 ;
705             iStat = (hMenu) ? GetMenuState32(hMenu,
706                                             cmd, MF_BYCOMMAND) : -1 ;
707
708             if (iSysStat!=-1)
709             {
710               if (iSysStat & (MF_DISABLED|MF_GRAYED))
711                 mesg=4;
712               else
713                 mesg=WM_SYSCOMMAND;
714             }
715             else
716             {
717               if (iStat!=-1)
718               {
719                 if (IsIconic32(hWnd))
720                   mesg=5;
721                 else
722                 {
723                  if (iStat & (MF_DISABLED|MF_GRAYED))
724                    mesg=6;
725                  else
726                    mesg=WM_COMMAND;  
727                 }   
728               }
729               else
730                mesg=WM_COMMAND;  
731             }
732           }
733           if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
734           {
735               TRACE(accel,", sending %s, wParam=%0x\n",
736                   mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
737                   cmd);
738               SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
739           }
740           else
741           {
742            /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
743             *   #0: unknown (please report!)
744             *   #1: for WM_KEYUP,WM_SYSKEYUP
745             *   #2: mouse is captured
746             *   #3: window is disabled 
747             *   #4: it's a disabled system menu option
748             *   #5: it's a menu option, but window is iconic
749             *   #6: it's a menu option, but disabled
750             */
751             TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
752             if(mesg==0)
753               ERR(accel, " unknown reason - please report!");
754           }          
755           return TRUE;         
756       }
757     }
758     return FALSE;
759 }
760
761 /**********************************************************************
762  *      TranslateAccelerator32      (USER32.551)(USER32.552)(USER32.553)
763  */
764 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
765 {
766     LPACCEL32   lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
767     int         i;
768     
769     if (hAccel == 0 || msg == NULL ||
770         (msg->message != WM_KEYDOWN &&
771          msg->message != WM_KEYUP &&
772          msg->message != WM_SYSKEYDOWN &&
773          msg->message != WM_SYSKEYUP &&
774          msg->message != WM_CHAR)) {
775       WARN(accel, "erraneous input parameters\n");
776       SetLastError(ERROR_INVALID_PARAMETER);
777       return 0;
778     }
779
780     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
781           "msg->hwnd=%04x, msg->message=%04x\n",
782           hAccel,hWnd,msg->hwnd,msg->message);
783
784     i = 0;
785     do
786     {
787         if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
788                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
789                 return 1;
790     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
791     WARN(accel, "couldn't translate accelerator key");
792     return 0;
793 }
794
795 /**********************************************************************
796  *           TranslateAccelerator16      (USER.178)
797  */     
798 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
799 {
800     LPACCEL16   lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
801     int         i;
802     MSG32       msg32;
803     
804     if (hAccel == 0 || msg == NULL ||
805         (msg->message != WM_KEYDOWN &&
806          msg->message != WM_KEYUP &&
807          msg->message != WM_SYSKEYDOWN &&
808          msg->message != WM_SYSKEYUP &&
809          msg->message != WM_CHAR)) {
810       WARN(accel, "erraneous input parameters\n");
811       SetLastError(ERROR_INVALID_PARAMETER);
812       return 0;
813     }
814
815     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
816 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
817     STRUCT32_MSG16to32(msg,&msg32);
818
819
820     i = 0;
821     do
822     {
823         if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
824                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
825                 return 1;
826     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
827     WARN(accel, "couldn't translate accelerator key");
828     return 0;
829 }
830
831
832 /**********************************************************************
833  *           OemKeyScan      (KEYBOARD.128)(USER32.401)
834  */
835 DWORD WINAPI OemKeyScan(WORD wOemChar)
836 {
837     TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
838
839     return wOemChar;
840 }
841
842 /**********************************************************************
843  *           VkKeyScanA      (USER32.573)
844  */
845 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
846  * for the current keyboard.
847  * high-order byte yields :
848  *      0       Unshifted
849  *      1       Shift
850  *      2       Ctrl
851  *      3-5     Shift-key combinations that are not used for characters
852  *      6       Ctrl-Alt
853  *      7       Ctrl-Alt-Shift
854  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
855  * FIXME : works ok except for dead chars :
856  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
857  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
858  */
859
860 WORD WINAPI VkKeyScan32A(CHAR cChar)
861 {
862         KeyCode keycode;
863         KeySym keysym;          
864         int i,index;
865         int highbyte=0;
866
867         /* char->keysym (same for ANSI chars) */
868         keysym=(unsigned char) cChar;/* (!) cChar is signed */
869         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
870         
871         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
872         if (!keycode)
873         { /* It didn't work ... let's try with deadchar code. */
874           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
875         }
876
877         TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
878                          cChar,keysym,keysym,keycode);
879         
880         if (keycode)
881           {
882             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
883               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
884             switch (index) {
885             case -1 :
886               WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
887             case 0 : break;
888             case 1 : highbyte = 0x0100; break;
889             case 2 : highbyte = 0X0600; break;
890             default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
891             }
892             /*
893               index : 0     adds 0x0000
894               index : 1     adds 0x0100 (shift)
895               index : ?     adds 0x0200 (ctrl)
896               index : 2     adds 0x0600 (ctrl+alt)
897               index : ?     adds 0x0700 (ctrl+alt+shift (used?))
898              */
899           }
900         TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
901         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
902 }
903
904 /******************************************************************************
905  *      VkKeyScan                       [KEYBOARD.129]
906  */
907 WORD WINAPI VkKeyScan16(CHAR cChar)
908 {
909         return VkKeyScan32A(cChar);
910 }
911
912 /******************************************************************************
913  *      VkKeyScanW      (USER32.576)
914  */
915 WORD WINAPI VkKeyScan32W(WCHAR cChar)
916 {
917         return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
918 }
919
920 /******************************************************************************
921  *      GetKeyboardType16      (KEYBOARD.130)
922  */
923 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
924 {
925   return GetKeyboardType32(nTypeFlag);
926 }
927
928 /******************************************************************************
929  *      GetKeyboardType32      (USER32.255)
930  */
931 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
932 {
933   TRACE(keyboard,"(%d)\n",nTypeFlag);
934   switch(nTypeFlag)
935     {
936     case 0:      /* Keyboard type */
937       return 4;    /* AT-101 */
938       break;
939     case 1:      /* Keyboard Subtype */
940       return 0;    /* There are no defined subtypes */
941       break;
942     case 2:      /* Number of F-keys */
943       return 12;   /* We're doing an 101 for now, so return 12 F-keys */
944       break;
945     default:     
946       WARN(keyboard, "Unknown type\n");
947       return 0;    /* The book says 0 here, so 0 */
948     }
949 }
950
951
952 /******************************************************************************
953  *      MapVirtualKey32A      (USER32.383)
954  */
955 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
956 {
957     return MapVirtualKey16(code,maptype);
958 }
959
960 /******************************************************************************
961  *      MapVirtualKey32W      (USER32.385)
962  */
963 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
964 {
965     return MapVirtualKey16(code,maptype);
966 }
967
968 /******************************************************************************
969  *      MapVirtualKey16      (KEYBOARD.131)
970  *
971  * MapVirtualKey translates keycodes from one format to another
972  */
973 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
974 {
975 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
976
977         TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
978                          wCode,wMapType);
979         switch(wMapType) {
980                 case 0: { /* vkey-code to scan-code */
981                         /* let's do vkey -> keycode -> scan */
982                         KeyCode keyc;
983                         for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
984                                 if ((keyc2vkey[keyc] & 0xFF)== wCode)
985                                         returnMVK (keyc - 8);
986                         return 0; }
987
988                 case 1: /* scan-code to vkey-code */
989                         /* let's do scan -> keycode -> vkey */
990
991                         returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
992
993                 case 2: { /* vkey-code to unshifted ANSI code */
994                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
995                         /* My Windows returns 'A'. */
996                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
997                         XKeyEvent e;
998                         KeySym keysym;
999                         char s[2];
1000                         e.display = display;
1001                         e.state = 0; /* unshifted */
1002                         e.keycode = MapVirtualKey16( wCode, 0);
1003                         if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1004                           returnMVK (*s);
1005                         
1006                         return 0;
1007                         }
1008                 default: /* reserved */
1009                         WARN(keyboard, "Unknown wMapType %d !\n",
1010                                 wMapType);
1011                         return 0;       
1012         }
1013         return 0;
1014 }
1015
1016
1017 /****************************************************************************
1018  *      GetKBCodePage16   (KEYBOARD.132)
1019  */
1020 INT16 WINAPI GetKBCodePage16(void)
1021 {
1022     TRACE(keyboard,"(void)\n");
1023     return 850;
1024 }
1025
1026
1027 /****************************************************************************
1028  *      GetKBCodePage32   (USER32.246)
1029  */
1030 UINT32 WINAPI GetKBCodePage32(void)
1031 {
1032     TRACE(keyboard,"(void)\n");
1033     return 850;
1034 }
1035
1036 /****************************************************************************
1037  *      GetKeyNameText32A   (USER32.247)
1038  */
1039 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1040 {
1041         return GetKeyNameText16(lParam,lpBuffer,nSize);
1042 }
1043
1044 /****************************************************************************
1045  *      GetKeyNameText32W   (USER32.248)
1046  */
1047 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1048 {
1049         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1050         int res = GetKeyNameText32A(lParam,buf,nSize);
1051
1052         lstrcpynAtoW(lpBuffer,buf,nSize);
1053         HeapFree( GetProcessHeap(), 0, buf );
1054         return res;
1055 }
1056
1057
1058 /****************************************************************************
1059  *      GetKeyNameText16   (KEYBOARD.133)
1060  */
1061 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1062 {
1063   /*    int i; */
1064         
1065         TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1066
1067         lParam >>= 16;
1068         lParam &= 0xff;
1069
1070         /*      for (i = 0 ; i != KeyTableSize ; i++) 
1071                 if (KeyTable[i].scancode == lParam)  {
1072                         lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1073                         return strlen(lpBuffer);
1074                 }
1075                 */
1076         /* FIXME ! GetKeyNameText is still to do...
1077  */
1078         *lpBuffer = 0;
1079         return 0;
1080 }
1081
1082
1083 /****************************************************************************
1084  *      ToAscii   (KEYBOARD.4)
1085  */
1086 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState, 
1087                        LPVOID lpChar, UINT16 flags) 
1088 {
1089     return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1090 }
1091
1092 /****************************************************************************
1093  *      ToAscii32      (USER32.546)
1094  */
1095 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1096                         LPWORD lpChar,UINT32 flags )
1097 {
1098     XKeyEvent e;
1099     KeySym keysym;
1100     static XComposeStatus cs;
1101     INT32 ret;
1102     WORD keyc;
1103
1104     e.display = display;
1105     e.keycode = 0;
1106     for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1107       { /* this could be speeded up by making another table, an array of struct vkey,keycode
1108          * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)!  DF */
1109         if ((keyc2vkey[keyc] & 0xFF)== virtKey) /* no need to make a more precise test (with the extended bit correctly set above virtKey ... VK* are different enough... */
1110           {
1111             if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12))) 
1112                 /* it's normal to have 2 shift, control, and alt ! */
1113                 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1114                                  e.keycode,keyc,virtKey);
1115             e.keycode = keyc;
1116           }
1117       }
1118     if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01)) 
1119       {
1120         if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1121           e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1122         if (virtKey==VK_DECIMAL)
1123           e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1124       }
1125     if (!e.keycode)
1126       {
1127         WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1128         return virtKey; /* whatever */
1129       }
1130     e.state = 0;
1131     if (lpKeyState[VK_SHIFT] & 0x80)
1132         e.state |= ShiftMask;
1133     TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1134     if (lpKeyState[VK_CAPITAL] & 0x01)
1135         e.state |= LockMask;
1136     if (lpKeyState[VK_CONTROL] & 0x80)
1137         if (lpKeyState[VK_MENU] & 0x80)
1138             e.state |= AltGrMask;
1139         else
1140             e.state |= ControlMask;
1141     if (lpKeyState[VK_NUMLOCK] & 0x01)
1142         e.state |= NumLockMask;
1143     TRACE(key, "(%04X, %04X) : faked state = %X\n",
1144                 virtKey, scanCode, e.state);
1145     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1146     if (ret == 0)
1147         {
1148         BYTE dead_char = 0;
1149
1150         ((char*)lpChar)[1] = '\0';
1151         switch (keysym)
1152             {
1153         /* symbolic ASCII is the same as defined in rfc1345 */
1154 #ifdef XK_dead_tilde
1155             case XK_dead_tilde :
1156 #endif
1157             case 0x1000FE7E : /* Xfree's XK_Dtilde */
1158                 dead_char = '~';        /* '? */
1159                 break;
1160 #ifdef XK_dead_acute
1161             case XK_dead_acute :
1162 #endif
1163             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1164                 dead_char = 0xb4;       /* '' */
1165                 break;
1166 #ifdef XK_dead_circumflex
1167             case XK_dead_circumflex :
1168 #endif
1169             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1170                 dead_char = '^';        /* '> */
1171                 break;
1172 #ifdef XK_dead_grave
1173             case XK_dead_grave :
1174 #endif
1175             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1176                 dead_char = '`';        /* '! */
1177                 break;
1178 #ifdef XK_dead_diaeresis
1179             case XK_dead_diaeresis :
1180 #endif
1181             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1182                 dead_char = 0xa8;       /* ': */
1183                 break;
1184 #ifdef XK_dead_cedilla
1185             case XK_dead_cedilla :
1186                 dead_char = 0xb8;       /* ', */
1187                 break;
1188 #endif
1189 #ifdef XK_dead_macron
1190             case XK_dead_macron :
1191                 dead_char = '-';        /* 'm isn't defined on iso-8859-x */
1192                 break;
1193 #endif
1194 #ifdef XK_dead_breve
1195             case XK_dead_breve :
1196                 dead_char = 0xa2;       /* '( */
1197                 break;
1198 #endif
1199 #ifdef XK_dead_abovedot
1200             case XK_dead_abovedot :
1201                 dead_char = 0xff;       /* '. */
1202                 break;
1203 #endif
1204 #ifdef XK_dead_abovering
1205             case XK_dead_abovering :
1206                 dead_char = '0';        /* '0 isn't defined on iso-8859-x */
1207                 break;
1208 #endif
1209 #ifdef XK_dead_doubleacute
1210             case XK_dead_doubleacute :
1211                 dead_char = 0xbd;       /* '" */
1212                 break;
1213 #endif
1214 #ifdef XK_dead_caron
1215             case XK_dead_caron :
1216                 dead_char = 0xb7;       /* '< */
1217                 break;
1218 #endif
1219 #ifdef XK_dead_ogonek
1220             case XK_dead_ogonek :
1221                 dead_char = 0xb2;       /* '; */
1222                 break;
1223 #endif
1224 /* FIXME: I don't know this three.
1225             case XK_dead_iota :
1226                 dead_char = 'i';         
1227                 break;
1228             case XK_dead_voiced_sound :
1229                 dead_char = 'v';
1230                 break;
1231             case XK_dead_semivoiced_sound :
1232                 dead_char = 's';
1233                 break;
1234 */
1235             }
1236         if (dead_char)
1237             {
1238             *(char*)lpChar = dead_char;
1239             ret = -1;
1240             }
1241         else
1242             {
1243             char        *ksname;
1244
1245             ksname = TSXKeysymToString(keysym);
1246             if (!ksname)
1247                 ksname = "No Name";
1248             if ((keysym >> 8) != 0xff)
1249                 {
1250                 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1251                         keysym, ksname);
1252                 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1253                         virtKey, scanCode, e.keycode, e.state);
1254                 }
1255             }
1256         }
1257     TRACE(key, "ToAscii about to return %d with char %x\n",
1258                 ret, *(char*)lpChar);
1259     return ret;
1260 }
1261
1262
1263 /***********************************************************************
1264  *           GetKeyboardLayout                  (USER32.250)
1265  */
1266 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1267 {
1268         FIXME(keyboard,"(%ld): stub\n",dwLayout);
1269         return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1270 }
1271
1272 /***********************************************************************
1273  *           GetKeyboardLayoutList              (USER32.251)
1274  * FIXME
1275  */
1276 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1277 {
1278         FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1279         if (layouts)
1280                 layouts[0] = GetKeyboardLayout(0);
1281         return 1;
1282 }
1283
1284
1285 /***********************************************************************
1286  *           RegisterHotKey                     (USER32.433)
1287  */
1288 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1289         FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1290                 hwnd,id,modifiers,vk
1291         );
1292         return TRUE;
1293 }
1294
1295 /***********************************************************************
1296  *           UnregisterHotKey                   (USER32.565)
1297  */
1298 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1299         FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);
1300         return TRUE;
1301 }