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