XQueryKeymap -> TSXQueryKeymap (fixes the XIO errors reported).
[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, AltGrMask; /* mask in the XKeyEvent state */
38 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
39 static int min_keycode, max_keycode, keysyms_per_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;
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     /* Now store one keycode for each modifier. Used to simulate keypresses. */
330     kcControl = TSXKeysymToKeycode(display, XK_Control_L);
331     kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
332     kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
333     kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
334     kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
335
336     /* all states to false */
337     memset( InputKeyStateTable, 0, sizeof(InputKeyStateTable) );
338
339     return TRUE;
340 }
341
342 static BOOL32 NumState=FALSE, CapsState=FALSE;
343
344 /**********************************************************************
345  *              KEYBOARD_GenerateMsg
346  *
347  * Generate Down+Up messages when NumLock or CapsLock is pressed.
348  *
349  * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
350  *
351  */
352 void KEYBOARD_GenerateMsg( WORD vkey, int Evtype, INT32 event_x, INT32 event_y,
353                            DWORD event_time, KEYLP localkeylp )
354 {
355   BOOL32 * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
356
357   if (*State) {
358     /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
359        don't treat it. It's from the same key press. Then the state goes to ON.
360        And from there, a 'release' event will switch off the toggle key. */
361     *State=FALSE;
362     TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,InputKeyStateTable[vkey]);
363   } else
364     {
365         if ( InputKeyStateTable[vkey] & 0x1 ) /* it was ON */
366           {
367             if (Evtype!=KeyPress)
368               {
369                 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
370                 localkeylp.lp1.previous = 0; /* ? */
371                 localkeylp.lp1.transition = 0;
372                 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
373                                 event_x, event_y, event_time, 0 );
374                 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
375                                 event_x, event_y, event_time, 0 );
376                 *State=FALSE;
377                 InputKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */ 
378               } 
379           }
380         else /* it was OFF */
381           if (Evtype==KeyPress)
382             {
383               TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
384               hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
385                               event_x, event_y, event_time, 0 );
386               localkeylp.lp1.previous = 1;
387               localkeylp.lp1.transition = 1;
388               hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
389                               event_x, event_y, event_time, 0 );
390               *State=TRUE; /* Goes to intermediary state before going to ON */
391               InputKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
392             }
393     }
394 }
395
396 /***********************************************************************
397  *           KEYBOARD_UpdateOneState
398  *
399  * Updates internal state for <vkey>, depending on key <state> under X
400  *
401  */
402 void KEYBOARD_UpdateOneState ( int vkey, int state, KEYLP keylp)
403 {
404     WORD message;
405     /* Do something if internal table state != X state for keycode */
406     if (((InputKeyStateTable[vkey] & 0x80)!=0) != state)
407     {
408         TRACE(keyboard,"Adjusting state for vkey %#.2x. State before %#.2x \n",
409               vkey, InputKeyStateTable[vkey]);
410         keylp.lp1.previous = !state; /* 1 if state = 0, 0 if state = 1 */
411         keylp.lp1.transition = !state;
412         if (state) { /* Fake key being pressed inside wine */
413             InputKeyStateTable[vkey] ^= 0x01;
414             InputKeyStateTable[vkey] |= 0x80;
415             message = (InputKeyStateTable[VK_MENU] & 0x80)
416                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
417                 ? WM_SYSKEYDOWN : WM_KEYDOWN;
418         } else {
419             InputKeyStateTable[vkey] &= ~0x80; 
420             message = (InputKeyStateTable[VK_MENU] & 0x80)
421                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
422                 ? WM_SYSKEYUP : WM_KEYUP;
423         }
424         
425         hardware_event( message, vkey, keylp.lp2, 0, 0,
426                         GetTickCount() + MSG_WineStartTicks, 0 );
427
428         TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[vkey]);
429     }
430 }
431
432 /***********************************************************************
433  *           KEYBOARD_UpdateState
434  *
435  * Update modifiers state (Ctrl, Alt, Shift)
436  * when window is activated (called by EVENT_FocusIn in event.c)
437  *
438  * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
439  * from wine to another application and back.
440  * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
441  *  about them)
442  */
443 void KEYBOARD_UpdateState ( void )
444 {
445 /* extract a bit from the char[32] bit suite */
446 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
447
448     char keys_return[32];
449     KEYLP keylp;
450
451     TRACE(keyboard,"called\n");
452     if (!TSXQueryKeymap(display, keys_return)) {
453         ERR(keyboard,"Error getting keymap !");
454         return;
455     }
456
457     keylp.lp1.count = 1;
458     keylp.lp1.extended = 0; /* (vkey & 0x100 ? 1 : 0); */
459     keylp.lp1.win_internal = 0;
460     keylp.lp1.context = KeyState(kcAlt);/*(event->state & Mod1Mask)?1:0*/
461
462     /* Adjust the ALT and CONTROL state if any has been changed outside wine */
463     KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt), keylp);
464     KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl), keylp);
465     KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift), keylp);
466 #undef KeyState
467 }
468
469
470 /***********************************************************************
471  *           KEYBOARD_HandleEvent
472  *
473  * Handle a X key event
474  */
475 void KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
476 {
477     char Str[24]; 
478     XComposeStatus cs; 
479     KeySym keysym;
480     WORD vkey = 0;
481     KEYLP keylp;
482     static BOOL32 force_extended = FALSE; /* hack for AltGr translation */
483     
484     int ascii_chars;
485
486     INT32 event_x = pWnd->rectWindow.left + event->x;
487     INT32 event_y = pWnd->rectWindow.top + event->y;
488     DWORD event_time = event->time - MSG_WineStartTicks;
489
490     /* this allows support for dead keys */
491     if ((event->keycode >> 8) == 0x10)
492         event->keycode=(event->keycode & 0xff);
493
494     ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
495
496     TRACE(key, "EVENT_key : state = %X\n", event->state);
497     if (keysym == XK_Mode_switch)
498         {
499         TRACE(key, "Alt Gr key event received\n");
500         event->keycode = kcControl; /* Simulate Control */
501         KEYBOARD_HandleEvent( pWnd, event );
502
503         event->keycode = kcAlt; /* Simulate Alt */
504         force_extended = TRUE;
505         KEYBOARD_HandleEvent( pWnd, event );
506         force_extended = FALSE;
507         return;
508         }
509
510     Str[ascii_chars] = '\0';
511     if (TRACE_ON(key)){
512         char    *ksname;
513
514         ksname = TSXKeysymToString(keysym);
515         if (!ksname)
516           ksname = "No Name";
517         TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n", 
518                      (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
519                      keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
520     }
521
522     vkey = EVENT_event_to_vkey(event);
523     if (force_extended) vkey |= 0x100;
524
525     TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
526                     event->keycode, vkey);
527
528    if (vkey)
529    {
530     keylp.lp1.count = 1;
531     keylp.lp1.code = vkey2scode[vkey]; /* 5/29/97 chrisf@america.com */
532     keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
533     keylp.lp1.win_internal = 0; /* this has something to do with dialogs, 
534                                 * don't remember where I read it - AK */
535                                 /* it's '1' under windows, when a dialog box appears
536                                  * and you press one of the underlined keys - DF*/
537     vkey &= 0xff;
538
539     switch(vkey)
540     {
541     case VK_NUMLOCK:    
542       KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
543                             event_time, keylp);
544       break;
545     case VK_CAPITAL:
546       TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
547       KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
548                             event_time, keylp ); 
549       TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
550       break;
551     default:
552       {
553         WORD message;
554
555         keylp.lp1.context = ( event->state & Mod1Mask ) ? 1 : 0; /* 1 if alt */
556         if (event->type == KeyPress)
557           {
558             keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
559             if (!(InputKeyStateTable[vkey] & 0x80))
560               InputKeyStateTable[vkey] ^= 0x01;
561             InputKeyStateTable[vkey] |= 0x80;
562             keylp.lp1.transition = 0;
563             message = (InputKeyStateTable[VK_MENU] & 0x80)
564               && !(InputKeyStateTable[VK_CONTROL] & 0x80)
565               ? WM_SYSKEYDOWN : WM_KEYDOWN;
566           }
567         else
568           {
569             BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
570                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
571                 && (force_extended == FALSE); /* for Alt from AltGr */
572             
573             InputKeyStateTable[vkey] &= ~0x80; 
574             keylp.lp1.previous = 1;
575             keylp.lp1.transition = 1;
576             message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
577           }
578         /* Adjust the NUMLOCK state if it has been changed outside wine */
579         if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
580           { 
581             TRACE(keyboard,"Adjusting NumLock state. \n");
582             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
583                                   event_time, keylp );
584             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
585                                   event_time, keylp );
586           }
587         /* Adjust the CAPSLOCK state if it has been changed outside wine */
588         if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
589           {
590               TRACE(keyboard,"Adjusting Caps Lock state.\n");
591             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
592                                   event_time, keylp );
593             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
594                                   event_time, keylp );
595           }
596         /* Not Num nor Caps : end of intermediary states for both. */
597         NumState = FALSE;
598         CapsState = FALSE;
599
600         TRACE(key,"            wParam=%04X, lParam=%08lX\n", 
601                     vkey, keylp.lp2 );
602         TRACE(key,"            InputKeyState=%X\n",
603                     InputKeyStateTable[vkey]);
604
605         hardware_event( message, vkey, keylp.lp2,
606                         event_x, event_y, event_time, 0 );
607       }
608     }
609    }
610 }
611
612
613 /**********************************************************************
614  *           GetKeyState      (USER.106)
615  */
616 WORD WINAPI GetKeyState16(INT16 vkey)
617 {
618     return GetKeyState32(vkey);
619 }
620
621 /**********************************************************************
622  *           GetKeyState      (USER32.249)
623  *
624  * An application calls the GetKeyState function in response to a
625  * keyboard-input message.  This function retrieves the state of the key
626  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 390)
627  */
628 WORD WINAPI GetKeyState32(INT32 vkey)
629 {
630     INT32 retval;
631
632     switch (vkey)
633         {
634         case VK_LBUTTON : /* VK_LBUTTON is 1 */
635             retval = MouseButtonsStates[0] ? 0x8000 : 0;
636             break;
637         case VK_MBUTTON : /* VK_MBUTTON is 4 */
638             retval = MouseButtonsStates[1] ? 0x8000 : 0;
639             break;
640         case VK_RBUTTON : /* VK_RBUTTON is 2 */
641             retval = MouseButtonsStates[2] ? 0x8000 : 0;
642             break;
643         default :
644             if (vkey >= 'a' && vkey <= 'z')
645                 vkey += 'A' - 'a';
646             retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
647                        (WORD)(QueueKeyStateTable[vkey] & 0x01);
648         }
649     TRACE(key, "(0x%x) -> %x\n", vkey, retval);
650     return retval;
651 }
652
653 /**********************************************************************
654  *           GetKeyboardState      (USER.222)(USER32.254)
655  *
656  * An application calls the GetKeyboardState function in response to a
657  * keyboard-input message.  This function retrieves the state of the keyboard
658  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 387)
659  */
660 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
661 {
662     TRACE(key, "(%p)\n", lpKeyState);
663     if (lpKeyState != NULL) {
664         QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
665         QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
666         QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
667         memcpy(lpKeyState, QueueKeyStateTable, 256);
668     }
669 }
670
671 /**********************************************************************
672  *          SetKeyboardState      (USER.223)(USER32.484)
673  */
674 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
675 {
676     TRACE(key, "(%p)\n", lpKeyState);
677     if (lpKeyState != NULL) {
678         memcpy(QueueKeyStateTable, lpKeyState, 256);
679         MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
680         MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
681         MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
682     }
683 }
684
685 /**********************************************************************
686  *           GetAsyncKeyState32      (USER32.207)
687  *
688  *      Determine if a key is or was pressed.  retval has high-order 
689  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
690  * been pressed.
691  *
692  *      This uses the variable AsyncMouseButtonsStates and
693  * AsyncKeyStateTable (set in event.c) which have the mouse button
694  * number or key number (whichever is applicable) set to true if the
695  * mouse or key had been depressed since the last call to 
696  * GetAsyncKeyState.
697  */
698 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
699 {
700     short retval;       
701
702     switch (nKey) {
703      case VK_LBUTTON:
704         retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) | 
705                  (MouseButtonsStates[0] ? 0x8000 : 0);
706         break;
707      case VK_MBUTTON:
708         retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) | 
709                  (MouseButtonsStates[1] ? 0x8000 : 0);
710         break;
711      case VK_RBUTTON:
712         retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) | 
713                  (MouseButtonsStates[2] ? 0x8000 : 0);
714         break;
715      default:
716         retval = AsyncKeyStateTable[nKey] | 
717                 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0); 
718         break;
719     }
720
721     /* all states to false */
722     memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
723     memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
724
725     TRACE(key, "(%x) -> %x\n", nKey, retval);
726     return retval;
727 }
728
729 /**********************************************************************
730  *            GetAsyncKeyState16        (USER.249)
731  */
732 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
733 {
734     return GetAsyncKeyState32(nKey);
735 }
736
737 /**********************************************************************
738  *           KBD_translate_accelerator
739  *
740  * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP  -messages
741  */
742 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
743                                         BYTE fVirt,WORD key,WORD cmd)
744 {
745     BOOL32      sendmsg = FALSE;
746
747     if(msg->wParam == key) 
748     {
749         if (msg->message == WM_CHAR) {
750         if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
751         {
752           TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
753                         msg->wParam&0xff);
754           sendmsg=TRUE;
755         }  
756       } else {
757        if(fVirt & FVIRTKEY) {
758         INT32 mask = 0;
759         TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
760                                msg->wParam,0xff & HIWORD(msg->lParam));                
761         if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
762         if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
763         if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
764         if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
765           sendmsg=TRUE;                     
766         else
767           TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
768        }
769        else
770        {
771          if (!(msg->lParam & 0x01000000))  /* no special_key */
772          {
773            if ((fVirt & FALT) && (msg->lParam & 0x20000000))
774            {                                                   /* ^^ ALT pressed */
775             TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
776             sendmsg=TRUE;           
777            } 
778          } 
779        }
780       } 
781
782       if (sendmsg)      /* found an accelerator, but send a message... ? */
783       {
784         INT16  iSysStat,iStat,mesg=0;
785         HMENU16 hMenu;
786         
787         if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
788           mesg=1;
789         else 
790          if (GetCapture32())
791            mesg=2;
792          else
793           if (!IsWindowEnabled32(hWnd))
794             mesg=3;
795           else
796           {
797             WND* wndPtr = WIN_FindWndPtr(hWnd);
798
799             hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
800             iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
801                                             cmd, MF_BYCOMMAND) : -1 ;
802             iStat = (hMenu) ? GetMenuState32(hMenu,
803                                             cmd, MF_BYCOMMAND) : -1 ;
804
805             if (iSysStat!=-1)
806             {
807               if (iSysStat & (MF_DISABLED|MF_GRAYED))
808                 mesg=4;
809               else
810                 mesg=WM_SYSCOMMAND;
811             }
812             else
813             {
814               if (iStat!=-1)
815               {
816                 if (IsIconic32(hWnd))
817                   mesg=5;
818                 else
819                 {
820                  if (iStat & (MF_DISABLED|MF_GRAYED))
821                    mesg=6;
822                  else
823                    mesg=WM_COMMAND;  
824                 }   
825               }
826               else
827                mesg=WM_COMMAND;  
828             }
829           }
830           if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
831           {
832               TRACE(accel,", sending %s, wParam=%0x\n",
833                   mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
834                   cmd);
835               SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
836           }
837           else
838           {
839            /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
840             *   #0: unknown (please report!)
841             *   #1: for WM_KEYUP,WM_SYSKEYUP
842             *   #2: mouse is captured
843             *   #3: window is disabled 
844             *   #4: it's a disabled system menu option
845             *   #5: it's a menu option, but window is iconic
846             *   #6: it's a menu option, but disabled
847             */
848             TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
849             if(mesg==0)
850               ERR(accel, " unknown reason - please report!");
851           }          
852           return TRUE;         
853       }
854     }
855     return FALSE;
856 }
857
858 /**********************************************************************
859  *      TranslateAccelerator32      (USER32.551)(USER32.552)(USER32.553)
860  */
861 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
862 {
863     LPACCEL32   lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
864     int         i;
865
866     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);
867     
868     if (hAccel == 0 || msg == NULL ||
869         (msg->message != WM_KEYDOWN &&
870          msg->message != WM_KEYUP &&
871          msg->message != WM_SYSKEYDOWN &&
872          msg->message != WM_SYSKEYUP &&
873          msg->message != WM_CHAR)) {
874       WARN(accel, "erraneous input parameters\n");
875       SetLastError(ERROR_INVALID_PARAMETER);
876       return 0;
877     }
878
879     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
880           "msg->hwnd=%04x, msg->message=%04x\n",
881           hAccel,hWnd,msg->hwnd,msg->message);
882
883     i = 0;
884     do
885     {
886         if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
887                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
888                 return 1;
889     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
890     WARN(accel, "couldn't translate accelerator key");
891     return 0;
892 }
893
894 /**********************************************************************
895  *           TranslateAccelerator16      (USER.178)
896  */     
897 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
898 {
899     LPACCEL16   lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
900     int         i;
901     MSG32       msg32;
902     
903     if (hAccel == 0 || msg == NULL ||
904         (msg->message != WM_KEYDOWN &&
905          msg->message != WM_KEYUP &&
906          msg->message != WM_SYSKEYDOWN &&
907          msg->message != WM_SYSKEYUP &&
908          msg->message != WM_CHAR)) {
909       WARN(accel, "erraneous input parameters\n");
910       SetLastError(ERROR_INVALID_PARAMETER);
911       return 0;
912     }
913
914     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
915 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
916     STRUCT32_MSG16to32(msg,&msg32);
917
918
919     i = 0;
920     do
921     {
922         if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
923                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
924                 return 1;
925     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
926     WARN(accel, "couldn't translate accelerator key");
927     return 0;
928 }
929
930
931 /**********************************************************************
932  *           ScreenSwitchEnable      (KEYBOARD.100)
933  */
934 VOID WINAPI ScreenSwitchEnable(WORD unused)
935 {
936     FIXME(keyboard,"(%04x): stub\n",unused);
937 }
938
939 /**********************************************************************
940  *           OemKeyScan      (KEYBOARD.128)(USER32.401)
941  */
942 DWORD WINAPI OemKeyScan(WORD wOemChar)
943 {
944     TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
945
946     return wOemChar;
947 }
948
949 /**********************************************************************
950  *           VkKeyScanA      (USER32.573)
951  */
952 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
953  * for the current keyboard.
954  * high-order byte yields :
955  *      0       Unshifted
956  *      1       Shift
957  *      2       Ctrl
958  *      3-5     Shift-key combinations that are not used for characters
959  *      6       Ctrl-Alt
960  *      7       Ctrl-Alt-Shift
961  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
962  * FIXME : works ok except for dead chars :
963  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
964  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
965  */
966
967 WORD WINAPI VkKeyScan32A(CHAR cChar)
968 {
969         KeyCode keycode;
970         KeySym keysym;          
971         int i,index;
972         int highbyte=0;
973
974         /* char->keysym (same for ANSI chars) */
975         keysym=(unsigned char) cChar;/* (!) cChar is signed */
976         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
977         
978         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
979         if (!keycode)
980         { /* It didn't work ... let's try with deadchar code. */
981           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
982         }
983
984         TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
985                          cChar,keysym,keysym,keycode);
986         
987         if (keycode)
988           {
989             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
990               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
991             switch (index) {
992             case -1 :
993               WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
994             case 0 : break;
995             case 1 : highbyte = 0x0100; break;
996             case 2 : highbyte = 0X0600; break;
997             default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
998             }
999             /*
1000               index : 0     adds 0x0000
1001               index : 1     adds 0x0100 (shift)
1002               index : ?     adds 0x0200 (ctrl)
1003               index : 2     adds 0x0600 (ctrl+alt)
1004               index : ?     adds 0x0700 (ctrl+alt+shift (used?))
1005              */
1006           }
1007         TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1008         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
1009 }
1010
1011 /******************************************************************************
1012  *      VkKeyScan                       [KEYBOARD.129]
1013  */
1014 WORD WINAPI VkKeyScan16(CHAR cChar)
1015 {
1016         return VkKeyScan32A(cChar);
1017 }
1018
1019 /******************************************************************************
1020  *      VkKeyScanW      (USER32.576)
1021  */
1022 WORD WINAPI VkKeyScan32W(WCHAR cChar)
1023 {
1024         return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
1025 }
1026
1027 /******************************************************************************
1028  *      GetKeyboardType16      (KEYBOARD.130)
1029  */
1030 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
1031 {
1032   return GetKeyboardType32(nTypeFlag);
1033 }
1034
1035 /******************************************************************************
1036  *      GetKeyboardType32      (USER32.255)
1037  */
1038 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
1039 {
1040   TRACE(keyboard,"(%d)\n",nTypeFlag);
1041   switch(nTypeFlag)
1042     {
1043     case 0:      /* Keyboard type */
1044       return 4;    /* AT-101 */
1045       break;
1046     case 1:      /* Keyboard Subtype */
1047       return 0;    /* There are no defined subtypes */
1048       break;
1049     case 2:      /* Number of F-keys */
1050       return 12;   /* We're doing an 101 for now, so return 12 F-keys */
1051       break;
1052     default:     
1053       WARN(keyboard, "Unknown type\n");
1054       return 0;    /* The book says 0 here, so 0 */
1055     }
1056 }
1057
1058
1059 /******************************************************************************
1060  *      MapVirtualKey32A      (USER32.383)
1061  */
1062 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
1063 {
1064     return MapVirtualKey16(code,maptype);
1065 }
1066
1067 /******************************************************************************
1068  *      MapVirtualKey32W      (USER32.385)
1069  */
1070 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
1071 {
1072     return MapVirtualKey16(code,maptype);
1073 }
1074
1075 /******************************************************************************
1076  *      MapVirtualKey16      (KEYBOARD.131)
1077  *
1078  * MapVirtualKey translates keycodes from one format to another
1079  */
1080 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
1081 {
1082 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
1083
1084         TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
1085                          wCode,wMapType);
1086         switch(wMapType) {
1087                 case 0: { /* vkey-code to scan-code */
1088                         /* let's do vkey -> keycode -> scan */
1089                         int keyc;
1090                         for (keyc=min_keycode; keyc<=max_keycode; keyc++) /* see event.c */
1091                                 if ((keyc2vkey[keyc] & 0xFF)== wCode)
1092                                         returnMVK (keyc - 8);
1093                         return 0; }
1094
1095                 case 1: /* scan-code to vkey-code */
1096                         /* let's do scan -> keycode -> vkey */
1097
1098                         returnMVK (keyc2vkey[(wCode & 0xFF) + 8]);
1099
1100                 case 2: { /* vkey-code to unshifted ANSI code */
1101                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1102                         /* My Windows returns 'A'. */
1103                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
1104                         XKeyEvent e;
1105                         KeySym keysym;
1106                         char s[2];
1107                         e.display = display;
1108                         e.state = 0; /* unshifted */
1109                         e.keycode = MapVirtualKey16( wCode, 0);
1110                         if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1111                           returnMVK (*s);
1112                         
1113                         return 0;
1114                         }
1115                 default: /* reserved */
1116                         WARN(keyboard, "Unknown wMapType %d !\n",
1117                                 wMapType);
1118                         return 0;       
1119         }
1120         return 0;
1121 }
1122
1123
1124 /****************************************************************************
1125  *      GetKBCodePage16   (KEYBOARD.132)
1126  */
1127 INT16 WINAPI GetKBCodePage16(void)
1128 {
1129     TRACE(keyboard,"(void)\n");
1130     return 850;
1131 }
1132
1133
1134 /****************************************************************************
1135  *      GetKBCodePage32   (USER32.246)
1136  */
1137 UINT32 WINAPI GetKBCodePage32(void)
1138 {
1139     TRACE(keyboard,"(void)\n");
1140     return 850;
1141 }
1142
1143 /****************************************************************************
1144  *      GetKeyboardLayoutName32A   (USER32.252)
1145  */
1146 INT32 WINAPI GetKeyboardLayoutName32A(LPSTR pwszKLID)
1147 {
1148         return GetKeyboardLayoutName16(pwszKLID);
1149 }
1150
1151 /****************************************************************************
1152  *      GetKeyboardLayoutName32W   (USER32.253)
1153  */
1154 INT32 WINAPI GetKeyboardLayoutName32W(LPWSTR pwszKLID)
1155 {
1156         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, strlen("00000409")+1);
1157         int res = GetKeyboardLayoutName32A(buf);
1158         lstrcpyAtoW(pwszKLID,buf);
1159         HeapFree( GetProcessHeap(), 0, buf );
1160         return res;
1161 }
1162
1163 /****************************************************************************
1164  *      GetKeyboardLayoutName16   (USER.477)
1165  */
1166 INT16 WINAPI GetKeyboardLayoutName16(LPSTR pwszKLID)
1167 {
1168         FIXME(keyboard,"always returns primary U.S. English layout\n");
1169         strcpy(pwszKLID,"00000409");
1170         return 1;
1171 }
1172
1173 /****************************************************************************
1174  *      GetKeyNameText32A   (USER32.247)
1175  */
1176 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1177 {
1178         return GetKeyNameText16(lParam,lpBuffer,nSize);
1179 }
1180
1181 /****************************************************************************
1182  *      GetKeyNameText32W   (USER32.248)
1183  */
1184 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1185 {
1186         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1187         int res = GetKeyNameText32A(lParam,buf,nSize);
1188
1189         lstrcpynAtoW(lpBuffer,buf,nSize);
1190         HeapFree( GetProcessHeap(), 0, buf );
1191         return res;
1192 }
1193
1194
1195 /****************************************************************************
1196  *      GetKeyNameText16   (KEYBOARD.133)
1197  */
1198 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1199 {
1200   /*    int i; */
1201         
1202         TRACE(keyboard,"(%ld,<ptr>,%d)\n",lParam,nSize);
1203
1204         lParam >>= 16;
1205         lParam &= 0xff;
1206
1207         /*      for (i = 0 ; i != KeyTableSize ; i++) 
1208                 if (KeyTable[i].scancode == lParam)  {
1209                         lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1210                         return strlen(lpBuffer);
1211                 }
1212                 */
1213         /* FIXME ! GetKeyNameText is still to do...
1214  */
1215         *lpBuffer = 0;
1216         return 0;
1217 }
1218
1219
1220 /****************************************************************************
1221  *      ToAscii   (KEYBOARD.4)
1222  */
1223 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState, 
1224                        LPVOID lpChar, UINT16 flags) 
1225 {
1226     return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1227 }
1228
1229 /****************************************************************************
1230  *      ToAscii32      (USER32.546)
1231  */
1232 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1233                         LPWORD lpChar,UINT32 flags )
1234 {
1235     XKeyEvent e;
1236     KeySym keysym;
1237     static XComposeStatus cs;
1238     INT32 ret;
1239     int keyc;
1240
1241     if (scanCode==0) {
1242         /* This happens when doing Alt+letter : a fake 'down arrow' key press
1243            event is generated by windows. Just ignore it. */
1244         TRACE(keyboard,"scanCode=0, doing nothing\n");
1245         return 0;
1246     }
1247     e.display = display;
1248     e.keycode = 0;
1249     e.state = 0;
1250     if (lpKeyState[VK_SHIFT] & 0x80)
1251         e.state |= ShiftMask;
1252     if (lpKeyState[VK_CAPITAL] & 0x01)
1253         e.state |= LockMask;
1254     if (lpKeyState[VK_CONTROL] & 0x80)
1255         if (lpKeyState[VK_MENU] & 0x80)
1256             e.state |= AltGrMask;
1257         else
1258             e.state |= ControlMask;
1259     if (lpKeyState[VK_NUMLOCK] & 0x01)
1260         e.state |= NumLockMask;
1261     TRACE(key, "(%04X, %04X) : faked state = %X\n",
1262                 virtKey, scanCode, e.state);
1263     /* We exit on the first keycode found, to speed up the thing. */
1264     for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1265       { /* Find a keycode that could have generated this virtual key */
1266           if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
1267           { /* we can filter the extended bit, VK* are different enough... */
1268               e.keycode = keyc; /* Store it temporarily */
1269               if (EVENT_event_to_vkey(&e) != virtKey)
1270                   e.keycode = 0; /* Wrong one (ex: because of the NumLock
1271                          state), so set it to 0, we'll find another one */
1272           }
1273       }
1274     if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01)) 
1275     {
1276         if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1277           e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1278         if (virtKey==VK_DECIMAL)
1279           e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1280       }
1281     if (!e.keycode)
1282       {
1283         WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1284         return virtKey; /* whatever */
1285       }
1286     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1287     if (ret == 0)
1288         {
1289         BYTE dead_char = 0;
1290
1291         ((char*)lpChar)[1] = '\0';
1292         switch (keysym)
1293             {
1294         /* symbolic ASCII is the same as defined in rfc1345 */
1295 #ifdef XK_dead_tilde
1296             case XK_dead_tilde :
1297 #endif
1298             case 0x1000FE7E : /* Xfree's XK_Dtilde */
1299                 dead_char = '~';        /* '? */
1300                 break;
1301 #ifdef XK_dead_acute
1302             case XK_dead_acute :
1303 #endif
1304             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1305                 dead_char = 0xb4;       /* '' */
1306                 break;
1307 #ifdef XK_dead_circumflex
1308             case XK_dead_circumflex :
1309 #endif
1310             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1311                 dead_char = '^';        /* '> */
1312                 break;
1313 #ifdef XK_dead_grave
1314             case XK_dead_grave :
1315 #endif
1316             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1317                 dead_char = '`';        /* '! */
1318                 break;
1319 #ifdef XK_dead_diaeresis
1320             case XK_dead_diaeresis :
1321 #endif
1322             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1323                 dead_char = 0xa8;       /* ': */
1324                 break;
1325 #ifdef XK_dead_cedilla
1326             case XK_dead_cedilla :
1327                 dead_char = 0xb8;       /* ', */
1328                 break;
1329 #endif
1330 #ifdef XK_dead_macron
1331             case XK_dead_macron :
1332                 dead_char = '-';        /* 'm isn't defined on iso-8859-x */
1333                 break;
1334 #endif
1335 #ifdef XK_dead_breve
1336             case XK_dead_breve :
1337                 dead_char = 0xa2;       /* '( */
1338                 break;
1339 #endif
1340 #ifdef XK_dead_abovedot
1341             case XK_dead_abovedot :
1342                 dead_char = 0xff;       /* '. */
1343                 break;
1344 #endif
1345 #ifdef XK_dead_abovering
1346             case XK_dead_abovering :
1347                 dead_char = '0';        /* '0 isn't defined on iso-8859-x */
1348                 break;
1349 #endif
1350 #ifdef XK_dead_doubleacute
1351             case XK_dead_doubleacute :
1352                 dead_char = 0xbd;       /* '" */
1353                 break;
1354 #endif
1355 #ifdef XK_dead_caron
1356             case XK_dead_caron :
1357                 dead_char = 0xb7;       /* '< */
1358                 break;
1359 #endif
1360 #ifdef XK_dead_ogonek
1361             case XK_dead_ogonek :
1362                 dead_char = 0xb2;       /* '; */
1363                 break;
1364 #endif
1365 /* FIXME: I don't know this three.
1366             case XK_dead_iota :
1367                 dead_char = 'i';         
1368                 break;
1369             case XK_dead_voiced_sound :
1370                 dead_char = 'v';
1371                 break;
1372             case XK_dead_semivoiced_sound :
1373                 dead_char = 's';
1374                 break;
1375 */
1376             }
1377         if (dead_char)
1378             {
1379             *(char*)lpChar = dead_char;
1380             ret = -1;
1381             }
1382         else
1383             {
1384             char        *ksname;
1385
1386             ksname = TSXKeysymToString(keysym);
1387             if (!ksname)
1388                 ksname = "No Name";
1389             if ((keysym >> 8) != 0xff)
1390                 {
1391                 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1392                         keysym, ksname);
1393                 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1394                         virtKey, scanCode, e.keycode, e.state);
1395                 }
1396             }
1397         }
1398     TRACE(key, "ToAscii about to return %d with char %x\n",
1399                 ret, *(char*)lpChar);
1400     return ret;
1401 }
1402
1403
1404 /***********************************************************************
1405  *           GetKeyboardLayout                  (USER32.250)
1406  */
1407 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1408 {
1409         FIXME(keyboard,"(%ld): stub\n",dwLayout);
1410         return (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1411 }
1412
1413 /***********************************************************************
1414  *           GetKeyboardLayoutList              (USER32.251)
1415  * FIXME
1416  */
1417 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1418 {
1419         FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1420         if (layouts)
1421                 layouts[0] = GetKeyboardLayout(0);
1422         return 1;
1423 }
1424
1425
1426 /***********************************************************************
1427  *           RegisterHotKey                     (USER32.433)
1428  */
1429 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1430         FIXME(keyboard,"(0x%08x,%d,0x%08x,%d): stub\n",hwnd,id,modifiers,vk);
1431         return TRUE;
1432 }
1433
1434 /***********************************************************************
1435  *           UnregisterHotKey                   (USER32.565)
1436  */
1437 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1438         FIXME(keyboard,"(0x%08x,%d): stub\n",hwnd,id);
1439         return TRUE;
1440 }
1441
1442 /***********************************************************************
1443  *           KeyboardInquire                    (KEYBOARD.1)
1444  */
1445
1446 #pragma pack(1)
1447 typedef struct _KBINFO
1448 {
1449     BYTE Begin_First_Range;
1450     BYTE End_First_Range;
1451     BYTE Begin_Second_Range;
1452     BYTE End_Second_Range;
1453     WORD StateSize;
1454 } KBINFO;
1455 #pragma pack(4)
1456
1457 WORD WINAPI KeyboardInquire(KBINFO *kbInfo) 
1458 {
1459     kbInfo->Begin_First_Range = 0;
1460     kbInfo->End_First_Range = 0;
1461     kbInfo->Begin_Second_Range = 0;
1462     kbInfo->End_Second_Range = 0;
1463     kbInfo->StateSize = 16; 
1464
1465     return sizeof(KBINFO);
1466 }
1467
1468 /***********************************************************************
1469  *           KeyboardEnable                     (KEYBOARD.2)
1470  */
1471 VOID WINAPI KeyboardEnable(FARPROC16 eventProc, LPBYTE lpKeyState)
1472 {
1473     FIXME(keyboard, "(%08lx,%08lx): stub\n", 
1474                     (DWORD)eventProc, (DWORD)lpKeyState);
1475 }
1476
1477 /***********************************************************************
1478  *           KeyboardDisable                    (KEYBOARD.3)
1479  */
1480 VOID WINAPI KeyboardDisable(VOID)
1481 {
1482     FIXME(keyboard, "(): stub\n");
1483 }
1484
1485
1486 /***********************************************************************
1487  *           DisplayInquire                     (DISPLAY.101)
1488  */
1489
1490 #pragma pack(1)
1491 typedef struct _CURSORINFO
1492 {
1493     WORD wXMickeys;
1494     WORD wYMickeys;
1495 } CURSORINFO;
1496 #pragma pack(4)
1497
1498 WORD WINAPI DisplayInquire(CURSORINFO *cursorInfo) 
1499 {
1500     cursorInfo->wXMickeys = 1;
1501     cursorInfo->wYMickeys = 1;
1502
1503     return sizeof(CURSORINFO);
1504 }
1505
1506 /***********************************************************************
1507  *           DisplaySetCursor                   (DISPLAY.102)
1508  */
1509 VOID WINAPI DisplaySetCursor( LPVOID cursorShape )
1510 {
1511     FIXME(keyboard, "(%p): stub\n", cursorShape );
1512 }
1513
1514 /***********************************************************************
1515  *           DisplayMoveCursor                  (DISPLAY.103)
1516  */
1517 VOID WINAPI DisplayMoveCursor( WORD wAbsX, WORD wAbsY )
1518 {
1519     FIXME(keyboard, "(%d,%d): stub\n", wAbsX, wAbsY );
1520 }
1521
1522 /***********************************************************************
1523  *           UserRepaintDisable                 (DISPLAY.103)
1524  */
1525 VOID WINAPI UserRepaintDisable( BOOL16 disable )
1526 {
1527     FIXME(keyboard, "(%d): stub\n", disable);
1528 }
1529