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