Release 980913
[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     TRACE(accel,"hwnd=0x%x hacc=0x%x msg=0x%x wp=0x%x lp=0x%lx\n", hWnd, hAccel, msg->message, msg->wParam, msg->lParam);
778     
779     if (hAccel == 0 || msg == NULL ||
780         (msg->message != WM_KEYDOWN &&
781          msg->message != WM_KEYUP &&
782          msg->message != WM_SYSKEYDOWN &&
783          msg->message != WM_SYSKEYUP &&
784          msg->message != WM_CHAR)) {
785       WARN(accel, "erraneous input parameters\n");
786       SetLastError(ERROR_INVALID_PARAMETER);
787       return 0;
788     }
789
790     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
791           "msg->hwnd=%04x, msg->message=%04x\n",
792           hAccel,hWnd,msg->hwnd,msg->message);
793
794     i = 0;
795     do
796     {
797         if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
798                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
799                 return 1;
800     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
801     WARN(accel, "couldn't translate accelerator key");
802     return 0;
803 }
804
805 /**********************************************************************
806  *           TranslateAccelerator16      (USER.178)
807  */     
808 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
809 {
810     LPACCEL16   lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
811     int         i;
812     MSG32       msg32;
813     
814     if (hAccel == 0 || msg == NULL ||
815         (msg->message != WM_KEYDOWN &&
816          msg->message != WM_KEYUP &&
817          msg->message != WM_SYSKEYDOWN &&
818          msg->message != WM_SYSKEYUP &&
819          msg->message != WM_CHAR)) {
820       WARN(accel, "erraneous input parameters\n");
821       SetLastError(ERROR_INVALID_PARAMETER);
822       return 0;
823     }
824
825     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
826 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
827     STRUCT32_MSG16to32(msg,&msg32);
828
829
830     i = 0;
831     do
832     {
833         if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
834                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
835                 return 1;
836     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
837     WARN(accel, "couldn't translate accelerator key");
838     return 0;
839 }
840
841
842 /**********************************************************************
843  *           ScreenSwitchEnable      (KEYBOARD.100)
844  */
845 VOID WINAPI ScreenSwitchEnable(WORD unused)
846 {
847     FIXME(keyboard,"(%04x): stub\n",unused);
848 }
849
850 /**********************************************************************
851  *           OemKeyScan      (KEYBOARD.128)(USER32.401)
852  */
853 DWORD WINAPI OemKeyScan(WORD wOemChar)
854 {
855     TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
856
857     return wOemChar;
858 }
859
860 /**********************************************************************
861  *           VkKeyScanA      (USER32.573)
862  */
863 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
864  * for the current keyboard.
865  * high-order byte yields :
866  *      0       Unshifted
867  *      1       Shift
868  *      2       Ctrl
869  *      3-5     Shift-key combinations that are not used for characters
870  *      6       Ctrl-Alt
871  *      7       Ctrl-Alt-Shift
872  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
873  * FIXME : works ok except for dead chars :
874  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
875  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
876  */
877
878 WORD WINAPI VkKeyScan32A(CHAR cChar)
879 {
880         KeyCode keycode;
881         KeySym keysym;          
882         int i,index;
883         int highbyte=0;
884
885         /* char->keysym (same for ANSI chars) */
886         keysym=(unsigned char) cChar;/* (!) cChar is signed */
887         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
888         
889         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
890         if (!keycode)
891         { /* It didn't work ... let's try with deadchar code. */
892           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
893         }
894
895         TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
896                          cChar,keysym,keysym,keycode);
897         
898         if (keycode)
899           {
900             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
901               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
902             switch (index) {
903             case -1 :
904               WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
905             case 0 : break;
906             case 1 : highbyte = 0x0100; break;
907             case 2 : highbyte = 0X0600; break;
908             default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
909             }
910             /*
911               index : 0     adds 0x0000
912               index : 1     adds 0x0100 (shift)
913               index : ?     adds 0x0200 (ctrl)
914               index : 2     adds 0x0600 (ctrl+alt)
915               index : ?     adds 0x0700 (ctrl+alt+shift (used?))
916              */
917           }
918         TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
919         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
920 }
921
922 /******************************************************************************
923  *      VkKeyScan                       [KEYBOARD.129]
924  */
925 WORD WINAPI VkKeyScan16(CHAR cChar)
926 {
927         return VkKeyScan32A(cChar);
928 }
929
930 /******************************************************************************
931  *      VkKeyScanW      (USER32.576)
932  */
933 WORD WINAPI VkKeyScan32W(WCHAR cChar)
934 {
935         return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
936 }
937
938 /******************************************************************************
939  *      GetKeyboardType16      (KEYBOARD.130)
940  */
941 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
942 {
943   return GetKeyboardType32(nTypeFlag);
944 }
945
946 /******************************************************************************
947  *      GetKeyboardType32      (USER32.255)
948  */
949 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
950 {
951   TRACE(keyboard,"(%d)\n",nTypeFlag);
952   switch(nTypeFlag)
953     {
954     case 0:      /* Keyboard type */
955       return 4;    /* AT-101 */
956       break;
957     case 1:      /* Keyboard Subtype */
958       return 0;    /* There are no defined subtypes */
959       break;
960     case 2:      /* Number of F-keys */
961       return 12;   /* We're doing an 101 for now, so return 12 F-keys */
962       break;
963     default:     
964       WARN(keyboard, "Unknown type\n");
965       return 0;    /* The book says 0 here, so 0 */
966     }
967 }
968
969
970 /******************************************************************************
971  *      MapVirtualKey32A      (USER32.383)
972  */
973 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
974 {
975     return MapVirtualKey16(code,maptype);
976 }
977
978 /******************************************************************************
979  *      MapVirtualKey32W      (USER32.385)
980  */
981 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
982 {
983     return MapVirtualKey16(code,maptype);
984 }
985
986 /******************************************************************************
987  *      MapVirtualKey16      (KEYBOARD.131)
988  *
989  * MapVirtualKey translates keycodes from one format to another
990  */
991 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
992 {
993 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
994
995         TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
996                          wCode,wMapType);
997         switch(wMapType) {
998                 case 0: { /* vkey-code to scan-code */
999                         /* let's do vkey -> keycode -> scan */
1000                         int keyc;
1001                         for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
1002                                 if ((keyc2vkey[keyc] & 0xFF)== wCode)
1003                                         returnMVK (keyc - 8);
1004                         return 0; }
1005
1006                 case 1: /* scan-code to vkey-code */
1007                         /* let's do scan -> keycode -> vkey */
1008
1009                         returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
1010
1011                 case 2: { /* vkey-code to unshifted ANSI code */
1012                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1013                         /* My Windows returns 'A'. */
1014                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
1015                         XKeyEvent e;
1016                         KeySym keysym;
1017                         char s[2];
1018                         e.display = display;
1019                         e.state = 0; /* unshifted */
1020                         e.keycode = MapVirtualKey16( wCode, 0);
1021                         if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1022                           returnMVK (*s);
1023                         
1024                         return 0;
1025                         }
1026                 default: /* reserved */
1027                         WARN(keyboard, "Unknown wMapType %d !\n",
1028                                 wMapType);
1029                         return 0;       
1030         }
1031         return 0;
1032 }
1033
1034
1035 /****************************************************************************
1036  *      GetKBCodePage16   (KEYBOARD.132)
1037  */
1038 INT16 WINAPI GetKBCodePage16(void)
1039 {
1040     TRACE(keyboard,"(void)\n");
1041     return 850;
1042 }
1043
1044
1045 /****************************************************************************
1046  *      GetKBCodePage32   (USER32.246)
1047  */
1048 UINT32 WINAPI GetKBCodePage32(void)
1049 {
1050     TRACE(keyboard,"(void)\n");
1051     return 850;
1052 }
1053
1054 /****************************************************************************
1055  *      GetKeyNameText32A   (USER32.247)
1056  */
1057 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1058 {
1059         return GetKeyNameText16(lParam,lpBuffer,nSize);
1060 }
1061
1062 /****************************************************************************
1063  *      GetKeyNameText32W   (USER32.248)
1064  */
1065 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1066 {
1067         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1068         int res = GetKeyNameText32A(lParam,buf,nSize);
1069
1070         lstrcpynAtoW(lpBuffer,buf,nSize);
1071         HeapFree( GetProcessHeap(), 0, buf );
1072         return res;
1073 }
1074
1075
1076 /****************************************************************************
1077  *      GetKeyNameText16   (KEYBOARD.133)
1078  */
1079 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1080 {
1081   /*    int i; */
1082         
1083         TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1084
1085         lParam >>= 16;
1086         lParam &= 0xff;
1087
1088         /*      for (i = 0 ; i != KeyTableSize ; i++) 
1089                 if (KeyTable[i].scancode == lParam)  {
1090                         lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1091                         return strlen(lpBuffer);
1092                 }
1093                 */
1094         /* FIXME ! GetKeyNameText is still to do...
1095  */
1096         *lpBuffer = 0;
1097         return 0;
1098 }
1099
1100
1101 /****************************************************************************
1102  *      ToAscii   (KEYBOARD.4)
1103  */
1104 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState, 
1105                        LPVOID lpChar, UINT16 flags) 
1106 {
1107     return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1108 }
1109
1110 /****************************************************************************
1111  *      ToAscii32      (USER32.546)
1112  */
1113 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1114                         LPWORD lpChar,UINT32 flags )
1115 {
1116     XKeyEvent e;
1117     KeySym keysym;
1118     static XComposeStatus cs;
1119     INT32 ret;
1120     int keyc;
1121
1122     e.display = display;
1123     e.keycode = 0;
1124     for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1125       { /* this could be speeded up by making another table, an array of struct vkey,keycode
1126          * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)!  DF */
1127         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... */
1128           {
1129             if ((e.keycode) && ((virtKey<0x10) || (virtKey>0x12))) 
1130                 /* it's normal to have 2 shift, control, and alt ! */
1131                 TRACE(keyboard,"ToAscii : The keycodes %d and %d are matching the same vkey %#X\n",
1132                                  e.keycode,keyc,virtKey);
1133             e.keycode = keyc;
1134           }
1135       }
1136     if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01)) 
1137       {
1138         if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1139           e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1140         if (virtKey==VK_DECIMAL)
1141           e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1142       }
1143     if (!e.keycode)
1144       {
1145         WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1146         return virtKey; /* whatever */
1147       }
1148     e.state = 0;
1149     if (lpKeyState[VK_SHIFT] & 0x80)
1150         e.state |= ShiftMask;
1151     TRACE(keyboard,"ToAscii : lpKeyState[0x14(VK_CAPITAL)]=%#x\n",lpKeyState[VK_CAPITAL]);
1152     if (lpKeyState[VK_CAPITAL] & 0x01)
1153         e.state |= LockMask;
1154     if (lpKeyState[VK_CONTROL] & 0x80)
1155         if (lpKeyState[VK_MENU] & 0x80)
1156             e.state |= AltGrMask;
1157         else
1158             e.state |= ControlMask;
1159     if (lpKeyState[VK_NUMLOCK] & 0x01)
1160         e.state |= NumLockMask;
1161     TRACE(key, "(%04X, %04X) : faked state = %X\n",
1162                 virtKey, scanCode, e.state);
1163     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1164     if (ret == 0)
1165         {
1166         BYTE dead_char = 0;
1167
1168         ((char*)lpChar)[1] = '\0';
1169         switch (keysym)
1170             {
1171         /* symbolic ASCII is the same as defined in rfc1345 */
1172 #ifdef XK_dead_tilde
1173             case XK_dead_tilde :
1174 #endif
1175             case 0x1000FE7E : /* Xfree's XK_Dtilde */
1176                 dead_char = '~';        /* '? */
1177                 break;
1178 #ifdef XK_dead_acute
1179             case XK_dead_acute :
1180 #endif
1181             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1182                 dead_char = 0xb4;       /* '' */
1183                 break;
1184 #ifdef XK_dead_circumflex
1185             case XK_dead_circumflex :
1186 #endif
1187             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1188                 dead_char = '^';        /* '> */
1189                 break;
1190 #ifdef XK_dead_grave
1191             case XK_dead_grave :
1192 #endif
1193             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1194                 dead_char = '`';        /* '! */
1195                 break;
1196 #ifdef XK_dead_diaeresis
1197             case XK_dead_diaeresis :
1198 #endif
1199             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1200                 dead_char = 0xa8;       /* ': */
1201                 break;
1202 #ifdef XK_dead_cedilla
1203             case XK_dead_cedilla :
1204                 dead_char = 0xb8;       /* ', */
1205                 break;
1206 #endif
1207 #ifdef XK_dead_macron
1208             case XK_dead_macron :
1209                 dead_char = '-';        /* 'm isn't defined on iso-8859-x */
1210                 break;
1211 #endif
1212 #ifdef XK_dead_breve
1213             case XK_dead_breve :
1214                 dead_char = 0xa2;       /* '( */
1215                 break;
1216 #endif
1217 #ifdef XK_dead_abovedot
1218             case XK_dead_abovedot :
1219                 dead_char = 0xff;       /* '. */
1220                 break;
1221 #endif
1222 #ifdef XK_dead_abovering
1223             case XK_dead_abovering :
1224                 dead_char = '0';        /* '0 isn't defined on iso-8859-x */
1225                 break;
1226 #endif
1227 #ifdef XK_dead_doubleacute
1228             case XK_dead_doubleacute :
1229                 dead_char = 0xbd;       /* '" */
1230                 break;
1231 #endif
1232 #ifdef XK_dead_caron
1233             case XK_dead_caron :
1234                 dead_char = 0xb7;       /* '< */
1235                 break;
1236 #endif
1237 #ifdef XK_dead_ogonek
1238             case XK_dead_ogonek :
1239                 dead_char = 0xb2;       /* '; */
1240                 break;
1241 #endif
1242 /* FIXME: I don't know this three.
1243             case XK_dead_iota :
1244                 dead_char = 'i';         
1245                 break;
1246             case XK_dead_voiced_sound :
1247                 dead_char = 'v';
1248                 break;
1249             case XK_dead_semivoiced_sound :
1250                 dead_char = 's';
1251                 break;
1252 */
1253             }
1254         if (dead_char)
1255             {
1256             *(char*)lpChar = dead_char;
1257             ret = -1;
1258             }
1259         else
1260             {
1261             char        *ksname;
1262
1263             ksname = TSXKeysymToString(keysym);
1264             if (!ksname)
1265                 ksname = "No Name";
1266             if ((keysym >> 8) != 0xff)
1267                 {
1268                 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1269                         keysym, ksname);
1270                 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1271                         virtKey, scanCode, e.keycode, e.state);
1272                 }
1273             }
1274         }
1275     TRACE(key, "ToAscii about to return %d with char %x\n",
1276                 ret, *(char*)lpChar);
1277     return ret;
1278 }
1279
1280
1281 /***********************************************************************
1282  *           GetKeyboardLayout                  (USER32.250)
1283  */
1284 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1285 {
1286         FIXME(keyboard,"(%ld): stub\n",dwLayout);
1287         return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1288 }
1289
1290 /***********************************************************************
1291  *           GetKeyboardLayoutList              (USER32.251)
1292  * FIXME
1293  */
1294 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1295 {
1296         FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1297         if (layouts)
1298                 layouts[0] = GetKeyboardLayout(0);
1299         return 1;
1300 }
1301
1302
1303 /***********************************************************************
1304  *           RegisterHotKey                     (USER32.433)
1305  */
1306 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1307         FIXME(keyboard,"(%08x,%d,%08x,%d): stub\n",
1308                 hwnd,id,modifiers,vk
1309         );
1310         return TRUE;
1311 }
1312
1313 /***********************************************************************
1314  *           UnregisterHotKey                   (USER32.565)
1315  */
1316 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1317         FIXME(keyboard,"(%08x,%d): stub\n",hwnd,id);
1318         return TRUE;
1319 }