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