Deleted the vkey->sancode array, because QWERTY specific.
[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 int min_keycode, max_keycode, keysyms_per_keycode;
38 WORD keyc2vkey[256];
39
40 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
41 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
42
43 typedef union
44 {
45     struct
46     {
47         unsigned long count : 16;
48         unsigned long code : 8;
49         unsigned long extended : 1;
50         unsigned long unused : 2;
51         unsigned long win_internal : 2;
52         unsigned long context : 1;
53         unsigned long previous : 1;
54         unsigned long transition : 1;
55     } lp1;
56     unsigned long lp2;
57 } KEYLP;
58
59 /* Keyboard translation tables */
60 static const int special_key[] =
61 {
62     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
63     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
64     0, 0, 0, VK_ESCAPE                                          /* FF18 */
65 };
66
67 static const int cursor_key[] =
68 {
69     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
70                                        VK_NEXT, VK_END          /* FF50 */
71 };
72
73 static const int misc_key[] =
74 {
75     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
76     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
77 };
78
79 static const int keypad_key[] =
80 {
81     0, VK_NUMLOCK,                                              /* FF7E */
82     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
83     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
84     0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,                     /* FF90 */
85     VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
86                                  VK_INSERT, VK_DELETE,          /* FF98 */
87     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
88     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
89                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
90     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
91                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
92     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
93 };
94     
95 static const int function_key[] =
96 {
97     VK_F1, VK_F2,                                               /* FFBE */
98     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
99     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
100 };
101
102 static const int modifier_key[] =
103 {
104     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
105     VK_MENU, VK_MENU, VK_MENU, VK_MENU                         /* FFE7 */
106 };
107
108 static WORD EVENT_event_to_vkey( XKeyEvent *e)
109 {
110     KeySym keysym;
111
112     TSXLookupString(e, NULL, 0, &keysym, NULL);
113
114     if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (e->state & NumLockMask)) 
115         /* Only the Keypad keys 0-9 and . send different keysyms
116          * depending on the NumLock state */
117         return keypad_key[(keysym & 0xFF) - 0x7E];
118
119     return keyc2vkey[e->keycode];
120 }
121
122 /**********************************************************************
123  *              KEYBOARD_Init
124  */
125 BOOL32 KEYBOARD_Init(void)
126 {
127     int i;
128     KeySym *ksp;
129     XModifierKeymap *mmp;
130     KeySym keysym;
131     KeyCode *kcp;
132     XKeyEvent e2;
133     WORD vkey, OEMvkey;
134     int keyc;
135
136     TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
137     ksp = TSXGetKeyboardMapping(display, min_keycode,
138                               max_keycode + 1 - min_keycode, &keysyms_per_keycode);
139     /* We are only interested in keysyms_per_keycode.
140        There is no need to hold a local copy of the keysyms table */
141     TSXFree(ksp);
142     mmp = TSXGetModifierMapping(display);
143     kcp = mmp->modifiermap;
144     for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
145     {
146         int j;
147         
148         for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
149             if (*kcp)
150             {
151                 int k;
152                 
153                 for (k = 0; k < keysyms_per_keycode; k += 1)
154                     if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
155                     {
156                         AltGrMask = 1 << i;
157                         TRACE(key, "AltGrMask is %x\n", AltGrMask);
158                     }
159                     else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
160                     {
161                         NumLockMask = 1 << i;
162                         TRACE(key, "NumLockMask is %x\n", NumLockMask);
163                     }
164             }
165     }
166     TSXFreeModifiermap(mmp);
167
168     /* Now build two conversion arrays :
169      * keycode -> vkey + extended
170      * vkey + extended -> keycode */
171
172     e2.display = display;
173     e2.state = 0;
174
175     OEMvkey = VK_OEM_7; /* next is available.  */
176     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
177     {
178         e2.keycode = (KeyCode)keyc;
179         TSXLookupString(&e2, NULL, 0, &keysym, NULL);
180         vkey = 0;
181         if (keysym)  /* otherwise, keycode not used */
182         {
183             if ((keysym >> 8) == 0xFF)         /* non-character key */
184             {
185                 int key = keysym & 0xff;
186                 
187                 if (key >= 0x08 && key <= 0x1B)         /* special key */
188                     vkey = special_key[key - 0x08];
189                 else if (key >= 0x50 && key <= 0x57)    /* cursor key */
190                     vkey = cursor_key[key - 0x50];
191                 else if (key >= 0x60 && key <= 0x6B)    /* miscellaneous key */
192                     vkey = misc_key[key - 0x60];
193                 else if (key >= 0x7E && key <= 0xB9)    /* keypad key */
194                     vkey = keypad_key[key - 0x7E];
195                 else if (key >= 0xBE && key <= 0xCD)    /* function key */
196                 {
197                     vkey = function_key[key - 0xBE];
198                     vkey |= 0x100; /* set extended bit */
199                 }
200                 else if (key >= 0xE1 && key <= 0xEA)    /* modifier key */
201                     vkey = modifier_key[key - 0xE1];
202                 else if (key == 0xFF)                   /* DEL key */
203                     vkey = VK_DELETE;
204                 /* extended must also be set for ALT_R, CTRL_R,
205                    INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
206                    keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
207                 /* FIXME should we set extended bit for NumLock ? My
208                  * Windows does ... DF */
209                 switch (keysym)
210                 {
211                 case XK_Control_R :
212                 case XK_Alt_R :
213                 case XK_Insert :
214                 case XK_Delete :
215                 case XK_Home :
216                 case XK_End :
217                 case XK_Prior :
218                 case XK_Next :
219                 case XK_Left :
220                 case XK_Up :
221                 case XK_Right :
222                 case XK_Down :
223                 case XK_KP_Divide :
224                 case XK_KP_Enter :
225                     vkey |= 0x100;
226                 }
227             }
228             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
229             {
230                 keysym = TSXLookupKeysym(&e2, i);
231                 if ((keysym >= VK_0 && keysym <= VK_9)
232                     || (keysym >= VK_A && keysym <= VK_Z)
233                     || keysym == VK_SPACE)
234                     vkey = keysym;
235             }
236
237             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
238             {
239                 keysym = TSXLookupKeysym(&e2, i);
240                 switch (keysym)
241                 {
242                 case ';':             vkey = VK_OEM_1; break;
243                 case '/':             vkey = VK_OEM_2; break;
244                 case '`':             vkey = VK_OEM_3; break;
245                 case '[':             vkey = VK_OEM_4; break;
246                 case '\\':            vkey = VK_OEM_5; break;
247                 case ']':             vkey = VK_OEM_6; break;
248                 case '\'':            vkey = VK_OEM_7; break;
249                 case ',':             vkey = VK_OEM_COMMA; break;
250                 case '.':             vkey = VK_OEM_PERIOD; break;
251                 case '-':             vkey = VK_OEM_MINUS; break;
252                 case '+':             vkey = VK_OEM_PLUS; break;
253                 }
254             }
255
256             if (!vkey)
257             {
258                 /* Others keys: let's assign OEM virtual key codes in the allowed range,
259                  * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
260                 switch (++OEMvkey)
261                 {
262                 case 0xc1 : OEMvkey=0xdb; break;
263                 case 0xe5 : OEMvkey=0xe9; break;
264                 case 0xf6 : OEMvkey=0xf5; WARN(keyboard,"No more OEM vkey available!\n");
265                 }
266
267                 vkey = OEMvkey;
268                   
269                 if (TRACE_ON(keyboard))
270                 {
271                     dbg_decl_str(keyboard, 1024);
272
273                     TRACE(keyboard, "OEM specific virtual key %X assigned "
274                                  "to keycode %X:\n", OEMvkey, e2.keycode);
275                     for (i = 0; i < keysyms_per_keycode; i += 1)
276                     {
277                         char    *ksname;
278                         
279                         keysym = TSXLookupKeysym(&e2, i);
280                         ksname = TSXKeysymToString(keysym);
281                         if (!ksname)
282                             ksname = "NoSymbol";
283                         dsprintf(keyboard, "%lX (%s) ", keysym, ksname);
284                     }
285                     TRACE(keyboard, "(%s)\n", dbg_str(keyboard));
286                 }
287             }
288         }
289         keyc2vkey[e2.keycode] = vkey;
290     } /* for */
291     /* Now store one keycode for each modifier. Used to simulate keypresses. */
292     kcControl = TSXKeysymToKeycode(display, XK_Control_L);
293     kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
294     kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
295     kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
296     kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
297
298     /* all states to false */
299     memset( InputKeyStateTable, 0, sizeof(InputKeyStateTable) );
300
301     return TRUE;
302 }
303
304 static BOOL32 NumState=FALSE, CapsState=FALSE;
305
306 /**********************************************************************
307  *              KEYBOARD_GenerateMsg
308  *
309  * Generate Down+Up messages when NumLock or CapsLock is pressed.
310  *
311  * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
312  *
313  */
314 void KEYBOARD_GenerateMsg( WORD vkey, int Evtype, INT32 event_x, INT32 event_y,
315                            DWORD event_time, KEYLP localkeylp )
316 {
317   BOOL32 * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
318
319   if (*State) {
320     /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
321        don't treat it. It's from the same key press. Then the state goes to ON.
322        And from there, a 'release' event will switch off the toggle key. */
323     *State=FALSE;
324     TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,InputKeyStateTable[vkey]);
325   } else
326     {
327         if ( InputKeyStateTable[vkey] & 0x1 ) /* it was ON */
328           {
329             if (Evtype!=KeyPress)
330               {
331                 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
332                 localkeylp.lp1.previous = 0; /* ? */
333                 localkeylp.lp1.transition = 0;
334                 hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
335                                 event_x, event_y, event_time, 0 );
336                 hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
337                                 event_x, event_y, event_time, 0 );
338                 *State=FALSE;
339                 InputKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */ 
340               } 
341           }
342         else /* it was OFF */
343           if (Evtype==KeyPress)
344             {
345               TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
346               hardware_event( WM_KEYDOWN, vkey, localkeylp.lp2,
347                               event_x, event_y, event_time, 0 );
348               localkeylp.lp1.previous = 1;
349               localkeylp.lp1.transition = 1;
350               hardware_event( WM_KEYUP, vkey, localkeylp.lp2,
351                               event_x, event_y, event_time, 0 );
352               *State=TRUE; /* Goes to intermediary state before going to ON */
353               InputKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
354             }
355     }
356 }
357
358 /***********************************************************************
359  *           KEYBOARD_UpdateOneState
360  *
361  * Updates internal state for <vkey>, depending on key <state> under X
362  *
363  */
364 void KEYBOARD_UpdateOneState ( int vkey, int state, KEYLP keylp)
365 {
366     WORD message;
367     /* Do something if internal table state != X state for keycode */
368     if (((InputKeyStateTable[vkey] & 0x80)!=0) != state)
369     {
370         TRACE(keyboard,"Adjusting state for vkey %#.2x. State before %#.2x \n",
371               vkey, InputKeyStateTable[vkey]);
372         keylp.lp1.previous = !state; /* 1 if state = 0, 0 if state = 1 */
373         keylp.lp1.transition = !state;
374         if (state) { /* Fake key being pressed inside wine */
375             InputKeyStateTable[vkey] ^= 0x01;
376             InputKeyStateTable[vkey] |= 0x80;
377             message = (InputKeyStateTable[VK_MENU] & 0x80)
378                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
379                 ? WM_SYSKEYDOWN : WM_KEYDOWN;
380         } else {
381             InputKeyStateTable[vkey] &= ~0x80; 
382             message = (InputKeyStateTable[VK_MENU] & 0x80)
383                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
384                 ? WM_SYSKEYUP : WM_KEYUP;
385         }
386         
387         hardware_event( message, vkey, keylp.lp2, 0, 0,
388                         GetTickCount() + MSG_WineStartTicks, 0 );
389
390         TRACE(keyboard,"State after %#.2x \n",InputKeyStateTable[vkey]);
391     }
392 }
393
394 /***********************************************************************
395  *           KEYBOARD_UpdateState
396  *
397  * Update modifiers state (Ctrl, Alt, Shift)
398  * when window is activated (called by EVENT_FocusIn in event.c)
399  *
400  * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
401  * from wine to another application and back.
402  * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
403  *  about them)
404  */
405 void KEYBOARD_UpdateState ( void )
406 {
407 /* extract a bit from the char[32] bit suite */
408 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
409
410     char keys_return[32];
411     KEYLP keylp;
412
413     TRACE(keyboard,"called\n");
414     if (!TSXQueryKeymap(display, keys_return)) {
415         ERR(keyboard,"Error getting keymap !");
416         return;
417     }
418
419     keylp.lp1.count = 1;
420     keylp.lp1.extended = 0; /* (vkey & 0x100 ? 1 : 0); */
421     keylp.lp1.win_internal = 0;
422     keylp.lp1.context = KeyState(kcAlt);/*(event->state & Mod1Mask)?1:0*/
423
424     /* Adjust the ALT and CONTROL state if any has been changed outside wine */
425     KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt), keylp);
426     KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl), keylp);
427     KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift), keylp);
428 #undef KeyState
429 }
430
431
432 /***********************************************************************
433  *           KEYBOARD_HandleEvent
434  *
435  * Handle a X key event
436  */
437 void KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
438 {
439     char Str[24]; 
440     XComposeStatus cs; 
441     KeySym keysym;
442     WORD vkey = 0;
443     KEYLP keylp;
444     static BOOL32 force_extended = FALSE; /* hack for AltGr translation */
445     
446     int ascii_chars;
447
448     INT32 event_x = pWnd->rectWindow.left + event->x;
449     INT32 event_y = pWnd->rectWindow.top + event->y;
450     DWORD event_time = event->time - MSG_WineStartTicks;
451
452     /* this allows support for dead keys */
453     if ((event->keycode >> 8) == 0x10)
454         event->keycode=(event->keycode & 0xff);
455
456     ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
457
458     TRACE(key, "EVENT_key : state = %X\n", event->state);
459     if (keysym == XK_Mode_switch)
460         {
461         TRACE(key, "Alt Gr key event received\n");
462         event->keycode = kcControl; /* Simulate Control */
463         KEYBOARD_HandleEvent( pWnd, event );
464
465         event->keycode = kcAlt; /* Simulate Alt */
466         force_extended = TRUE;
467         KEYBOARD_HandleEvent( pWnd, event );
468         force_extended = FALSE;
469         return;
470         }
471
472     Str[ascii_chars] = '\0';
473     if (TRACE_ON(key)){
474         char    *ksname;
475
476         ksname = TSXKeysymToString(keysym);
477         if (!ksname)
478           ksname = "No Name";
479         TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n", 
480                      (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
481                      keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
482     }
483
484     vkey = EVENT_event_to_vkey(event);
485     if (force_extended) vkey |= 0x100;
486
487     TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
488                     event->keycode, vkey);
489
490    if (vkey)
491    {
492     keylp.lp1.count = 1;
493     keylp.lp1.code = event->keycode - min_keycode; /* Windows starts from 0, X from
494                                                       min_keycode (8 usually) */
495     keylp.lp1.extended = (vkey & 0x100 ? 1 : 0);
496     keylp.lp1.win_internal = 0; /* this has something to do with dialogs, 
497                                 * don't remember where I read it - AK */
498                                 /* it's '1' under windows, when a dialog box appears
499                                  * and you press one of the underlined keys - DF*/
500     vkey &= 0xff;
501
502     switch(vkey)
503     {
504     case VK_NUMLOCK:    
505       KEYBOARD_GenerateMsg( VK_NUMLOCK, event->type, event_x, event_y,
506                             event_time, keylp);
507       break;
508     case VK_CAPITAL:
509       TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,InputKeyStateTable[vkey]);
510       KEYBOARD_GenerateMsg( VK_CAPITAL, event->type, event_x, event_y,
511                             event_time, keylp ); 
512       TRACE(keyboard,"State after : %#.2x\n",InputKeyStateTable[vkey]);
513       break;
514     default:
515       {
516         WORD message;
517
518         keylp.lp1.context = ( event->state & Mod1Mask ) ? 1 : 0; /* 1 if alt */
519         if (event->type == KeyPress)
520           {
521             keylp.lp1.previous = (InputKeyStateTable[vkey] & 0x80) != 0;
522             if (!(InputKeyStateTable[vkey] & 0x80))
523               InputKeyStateTable[vkey] ^= 0x01;
524             InputKeyStateTable[vkey] |= 0x80;
525             keylp.lp1.transition = 0;
526             message = (InputKeyStateTable[VK_MENU] & 0x80)
527               && !(InputKeyStateTable[VK_CONTROL] & 0x80)
528               ? WM_SYSKEYDOWN : WM_KEYDOWN;
529           }
530         else
531           {
532             BOOL32 sysKey = (InputKeyStateTable[VK_MENU] & 0x80)
533                 && !(InputKeyStateTable[VK_CONTROL] & 0x80)
534                 && (force_extended == FALSE); /* for Alt from AltGr */
535             
536             InputKeyStateTable[vkey] &= ~0x80; 
537             keylp.lp1.previous = 1;
538             keylp.lp1.transition = 1;
539             message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
540           }
541         /* Adjust the NUMLOCK state if it has been changed outside wine */
542         if (!(InputKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
543           { 
544             TRACE(keyboard,"Adjusting NumLock state. \n");
545             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyPress, event_x, event_y,
546                                   event_time, keylp );
547             KEYBOARD_GenerateMsg( VK_NUMLOCK, KeyRelease, event_x, event_y,
548                                   event_time, keylp );
549           }
550         /* Adjust the CAPSLOCK state if it has been changed outside wine */
551         if (!(InputKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
552           {
553               TRACE(keyboard,"Adjusting Caps Lock state.\n");
554             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyPress, event_x, event_y,
555                                   event_time, keylp );
556             KEYBOARD_GenerateMsg( VK_CAPITAL, KeyRelease, event_x, event_y,
557                                   event_time, keylp );
558           }
559         /* Not Num nor Caps : end of intermediary states for both. */
560         NumState = FALSE;
561         CapsState = FALSE;
562
563         TRACE(key,"            wParam=%04X, lParam=%08lX\n", 
564                     vkey, keylp.lp2 );
565         TRACE(key,"            InputKeyState=%X\n",
566                     InputKeyStateTable[vkey]);
567
568         hardware_event( message, vkey, keylp.lp2,
569                         event_x, event_y, event_time, 0 );
570       }
571     }
572    }
573 }
574
575
576 /**********************************************************************
577  *           GetKeyState      (USER.106)
578  */
579 WORD WINAPI GetKeyState16(INT16 vkey)
580 {
581     return GetKeyState32(vkey);
582 }
583
584 /**********************************************************************
585  *           GetKeyState      (USER32.249)
586  *
587  * An application calls the GetKeyState function in response to a
588  * keyboard-input message.  This function retrieves the state of the key
589  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 390)
590  */
591 WORD WINAPI GetKeyState32(INT32 vkey)
592 {
593     INT32 retval;
594
595     switch (vkey)
596         {
597         case VK_LBUTTON : /* VK_LBUTTON is 1 */
598             retval = MouseButtonsStates[0] ? 0x8000 : 0;
599             break;
600         case VK_MBUTTON : /* VK_MBUTTON is 4 */
601             retval = MouseButtonsStates[1] ? 0x8000 : 0;
602             break;
603         case VK_RBUTTON : /* VK_RBUTTON is 2 */
604             retval = MouseButtonsStates[2] ? 0x8000 : 0;
605             break;
606         default :
607             if (vkey >= 'a' && vkey <= 'z')
608                 vkey += 'A' - 'a';
609             retval = ( (WORD)(QueueKeyStateTable[vkey] & 0x80) << 8 ) |
610                        (WORD)(QueueKeyStateTable[vkey] & 0x01);
611         }
612     /* TRACE(key, "(0x%x) -> %x\n", vkey, retval); */
613     return retval;
614 }
615
616 /**********************************************************************
617  *           GetKeyboardState      (USER.222)(USER32.254)
618  *
619  * An application calls the GetKeyboardState function in response to a
620  * keyboard-input message.  This function retrieves the state of the keyboard
621  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 387)
622  */
623 VOID WINAPI GetKeyboardState(LPBYTE lpKeyState)
624 {
625     TRACE(key, "(%p)\n", lpKeyState);
626     if (lpKeyState != NULL) {
627         QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
628         QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
629         QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
630         memcpy(lpKeyState, QueueKeyStateTable, 256);
631     }
632 }
633
634 /**********************************************************************
635  *          SetKeyboardState      (USER.223)(USER32.484)
636  */
637 VOID WINAPI SetKeyboardState(LPBYTE lpKeyState)
638 {
639     TRACE(key, "(%p)\n", lpKeyState);
640     if (lpKeyState != NULL) {
641         memcpy(QueueKeyStateTable, lpKeyState, 256);
642         MouseButtonsStates[0] = (QueueKeyStateTable[VK_LBUTTON] != 0);
643         MouseButtonsStates[1] = (QueueKeyStateTable[VK_MBUTTON] != 0);
644         MouseButtonsStates[2] = (QueueKeyStateTable[VK_RBUTTON] != 0);
645     }
646 }
647
648 /**********************************************************************
649  *           GetAsyncKeyState32      (USER32.207)
650  *
651  *      Determine if a key is or was pressed.  retval has high-order 
652  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
653  * been pressed.
654  *
655  *      This uses the variable AsyncMouseButtonsStates and
656  * AsyncKeyStateTable (set in event.c) which have the mouse button
657  * number or key number (whichever is applicable) set to true if the
658  * mouse or key had been depressed since the last call to 
659  * GetAsyncKeyState.
660  */
661 WORD WINAPI GetAsyncKeyState32(INT32 nKey)
662 {
663     short retval;       
664
665     switch (nKey) {
666      case VK_LBUTTON:
667         retval = (AsyncMouseButtonsStates[0] ? 0x0001 : 0) | 
668                  (MouseButtonsStates[0] ? 0x8000 : 0);
669         break;
670      case VK_MBUTTON:
671         retval = (AsyncMouseButtonsStates[1] ? 0x0001 : 0) | 
672                  (MouseButtonsStates[1] ? 0x8000 : 0);
673         break;
674      case VK_RBUTTON:
675         retval = (AsyncMouseButtonsStates[2] ? 0x0001 : 0) | 
676                  (MouseButtonsStates[2] ? 0x8000 : 0);
677         break;
678      default:
679         retval = AsyncKeyStateTable[nKey] | 
680                 ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0); 
681         break;
682     }
683
684     /* all states to false */
685     memset( AsyncMouseButtonsStates, 0, sizeof(AsyncMouseButtonsStates) );
686     memset( AsyncKeyStateTable, 0, sizeof(AsyncKeyStateTable) );
687
688     TRACE(key, "(%x) -> %x\n", nKey, retval);
689     return retval;
690 }
691
692 /**********************************************************************
693  *            GetAsyncKeyState16        (USER.249)
694  */
695 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
696 {
697     return GetAsyncKeyState32(nKey);
698 }
699
700 /**********************************************************************
701  *           KBD_translate_accelerator
702  *
703  * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP  -messages
704  */
705 static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
706                                         BYTE fVirt,WORD key,WORD cmd)
707 {
708     BOOL32      sendmsg = FALSE;
709
710     if(msg->wParam == key) 
711     {
712         if (msg->message == WM_CHAR) {
713         if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
714         {
715           TRACE(accel,"found accel for WM_CHAR: ('%c')\n",
716                         msg->wParam&0xff);
717           sendmsg=TRUE;
718         }  
719       } else {
720        if(fVirt & FVIRTKEY) {
721         INT32 mask = 0;
722         TRACE(accel,"found accel for virt_key %04x (scan %04x)\n",
723                                msg->wParam,0xff & HIWORD(msg->lParam));                
724         if(GetKeyState32(VK_SHIFT) & 0x8000) mask |= FSHIFT;
725         if(GetKeyState32(VK_CONTROL) & 0x8000) mask |= FCONTROL;
726         if(GetKeyState32(VK_MENU) & 0x8000) mask |= FALT;
727         if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
728           sendmsg=TRUE;                     
729         else
730           TRACE(accel,", but incorrect SHIFT/CTRL/ALT-state\n");
731        }
732        else
733        {
734          if (!(msg->lParam & 0x01000000))  /* no special_key */
735          {
736            if ((fVirt & FALT) && (msg->lParam & 0x20000000))
737            {                                                   /* ^^ ALT pressed */
738             TRACE(accel,"found accel for Alt-%c\n", msg->wParam&0xff);
739             sendmsg=TRUE;           
740            } 
741          } 
742        }
743       } 
744
745       if (sendmsg)      /* found an accelerator, but send a message... ? */
746       {
747         INT16  iSysStat,iStat,mesg=0;
748         HMENU16 hMenu;
749         
750         if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
751           mesg=1;
752         else 
753          if (GetCapture32())
754            mesg=2;
755          else
756           if (!IsWindowEnabled32(hWnd))
757             mesg=3;
758           else
759           {
760             WND* wndPtr = WIN_FindWndPtr(hWnd);
761
762             hMenu = (wndPtr->dwStyle & WS_CHILD) ? 0 : (HMENU32)wndPtr->wIDmenu;
763             iSysStat = (wndPtr->hSysMenu) ? GetMenuState32(GetSubMenu16(wndPtr->hSysMenu, 0),
764                                             cmd, MF_BYCOMMAND) : -1 ;
765             iStat = (hMenu) ? GetMenuState32(hMenu,
766                                             cmd, MF_BYCOMMAND) : -1 ;
767
768             if (iSysStat!=-1)
769             {
770               if (iSysStat & (MF_DISABLED|MF_GRAYED))
771                 mesg=4;
772               else
773                 mesg=WM_SYSCOMMAND;
774             }
775             else
776             {
777               if (iStat!=-1)
778               {
779                 if (IsIconic32(hWnd))
780                   mesg=5;
781                 else
782                 {
783                  if (iStat & (MF_DISABLED|MF_GRAYED))
784                    mesg=6;
785                  else
786                    mesg=WM_COMMAND;  
787                 }   
788               }
789               else
790                mesg=WM_COMMAND;  
791             }
792           }
793           if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
794           {
795               TRACE(accel,", sending %s, wParam=%0x\n",
796                   mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
797                   cmd);
798               SendMessage32A(hWnd, mesg, cmd, 0x00010000L);
799           }
800           else
801           {
802            /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
803             *   #0: unknown (please report!)
804             *   #1: for WM_KEYUP,WM_SYSKEYUP
805             *   #2: mouse is captured
806             *   #3: window is disabled 
807             *   #4: it's a disabled system menu option
808             *   #5: it's a menu option, but window is iconic
809             *   #6: it's a menu option, but disabled
810             */
811             TRACE(accel,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
812             if(mesg==0)
813               ERR(accel, " unknown reason - please report!");
814           }          
815           return TRUE;         
816       }
817     }
818     return FALSE;
819 }
820
821 /**********************************************************************
822  *      TranslateAccelerator32      (USER32.551)(USER32.552)(USER32.553)
823  */
824 INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
825 {
826     LPACCEL32   lpAccelTbl = (LPACCEL32)LockResource32(hAccel);
827     int         i;
828
829     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);
830     
831     if (hAccel == 0 || msg == NULL ||
832         (msg->message != WM_KEYDOWN &&
833          msg->message != WM_KEYUP &&
834          msg->message != WM_SYSKEYDOWN &&
835          msg->message != WM_SYSKEYUP &&
836          msg->message != WM_CHAR)) {
837       WARN(accel, "erraneous input parameters\n");
838       SetLastError(ERROR_INVALID_PARAMETER);
839       return 0;
840     }
841
842     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,"
843           "msg->hwnd=%04x, msg->message=%04x\n",
844           hAccel,hWnd,msg->hwnd,msg->message);
845
846     i = 0;
847     do
848     {
849         if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
850                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
851                 return 1;
852     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
853     WARN(accel, "couldn't translate accelerator key\n");
854     return 0;
855 }
856
857 /**********************************************************************
858  *           TranslateAccelerator16      (USER.178)
859  */     
860 INT16 WINAPI TranslateAccelerator16(HWND16 hWnd, HACCEL16 hAccel, LPMSG16 msg)
861 {
862     LPACCEL16   lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
863     int         i;
864     MSG32       msg32;
865     
866     if (hAccel == 0 || msg == NULL ||
867         (msg->message != WM_KEYDOWN &&
868          msg->message != WM_KEYUP &&
869          msg->message != WM_SYSKEYDOWN &&
870          msg->message != WM_SYSKEYUP &&
871          msg->message != WM_CHAR)) {
872       WARN(accel, "erraneous input parameters\n");
873       SetLastError(ERROR_INVALID_PARAMETER);
874       return 0;
875     }
876
877     TRACE(accel, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
878 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
879     STRUCT32_MSG16to32(msg,&msg32);
880
881
882     i = 0;
883     do
884     {
885         if (KBD_translate_accelerator(hWnd,&msg32,lpAccelTbl[i].fVirt,
886                                       lpAccelTbl[i].key,lpAccelTbl[i].cmd))
887                 return 1;
888     } while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
889     WARN(accel, "couldn't translate accelerator key\n");
890     return 0;
891 }
892
893
894 /**********************************************************************
895  *           ScreenSwitchEnable      (KEYBOARD.100)
896  */
897 VOID WINAPI ScreenSwitchEnable(WORD unused)
898 {
899     FIXME(keyboard,"(%04x): stub\n",unused);
900 }
901
902 /**********************************************************************
903  *           OemKeyScan      (KEYBOARD.128)(USER32.401)
904  */
905 DWORD WINAPI OemKeyScan(WORD wOemChar)
906 {
907     TRACE(keyboard,"*OemKeyScan (%d)\n",wOemChar);
908
909     return wOemChar;
910 }
911
912 /**********************************************************************
913  *           VkKeyScanA      (USER32.573)
914  */
915 /* VkKeyScan translates an ANSI character to a virtual-key and shift code
916  * for the current keyboard.
917  * high-order byte yields :
918  *      0       Unshifted
919  *      1       Shift
920  *      2       Ctrl
921  *      3-5     Shift-key combinations that are not used for characters
922  *      6       Ctrl-Alt
923  *      7       Ctrl-Alt-Shift
924  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
925  * FIXME : works ok except for dead chars :
926  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
927  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
928  */
929
930 WORD WINAPI VkKeyScan32A(CHAR cChar)
931 {
932         KeyCode keycode;
933         KeySym keysym;          
934         int i,index;
935         int highbyte=0;
936
937         /* char->keysym (same for ANSI chars) */
938         keysym=(unsigned char) cChar;/* (!) cChar is signed */
939         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
940         
941         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
942         if (!keycode)
943         { /* It didn't work ... let's try with deadchar code. */
944           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
945         }
946
947         TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
948                          cChar,keysym,keysym,keycode);
949         
950         if (keycode)
951           {
952             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
953               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
954             switch (index) {
955             case -1 :
956               WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
957             case 0 : break;
958             case 1 : highbyte = 0x0100; break;
959             case 2 : highbyte = 0X0600; break;
960             default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
961             }
962             /*
963               index : 0     adds 0x0000
964               index : 1     adds 0x0100 (shift)
965               index : ?     adds 0x0200 (ctrl)
966               index : 2     adds 0x0600 (ctrl+alt)
967               index : ?     adds 0x0700 (ctrl+alt+shift (used?))
968              */
969           }
970         TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
971         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
972 }
973
974 /******************************************************************************
975  *      VkKeyScan                       [KEYBOARD.129]
976  */
977 WORD WINAPI VkKeyScan16(CHAR cChar)
978 {
979         return VkKeyScan32A(cChar);
980 }
981
982 /******************************************************************************
983  *      VkKeyScanW      (USER32.576)
984  */
985 WORD WINAPI VkKeyScan32W(WCHAR cChar)
986 {
987         return VkKeyScan32A((CHAR)cChar); /* FIXME: check unicode */
988 }
989
990 /******************************************************************************
991  *      GetKeyboardType16      (KEYBOARD.130)
992  */
993 INT16 WINAPI GetKeyboardType16(INT16 nTypeFlag)
994 {
995   return GetKeyboardType32(nTypeFlag);
996 }
997
998 /******************************************************************************
999  *      GetKeyboardType32      (USER32.255)
1000  */
1001 INT32 WINAPI GetKeyboardType32(INT32 nTypeFlag)
1002 {
1003   TRACE(keyboard,"(%d)\n",nTypeFlag);
1004   switch(nTypeFlag)
1005     {
1006     case 0:      /* Keyboard type */
1007       return 4;    /* AT-101 */
1008       break;
1009     case 1:      /* Keyboard Subtype */
1010       return 0;    /* There are no defined subtypes */
1011       break;
1012     case 2:      /* Number of F-keys */
1013       return 12;   /* We're doing an 101 for now, so return 12 F-keys */
1014       break;
1015     default:     
1016       WARN(keyboard, "Unknown type\n");
1017       return 0;    /* The book says 0 here, so 0 */
1018     }
1019 }
1020
1021
1022 /******************************************************************************
1023  *      MapVirtualKey32A      (USER32.383)
1024  */
1025 UINT32 WINAPI MapVirtualKey32A(UINT32 code, UINT32 maptype)
1026 {
1027     return MapVirtualKey16(code,maptype);
1028 }
1029
1030 /******************************************************************************
1031  *      MapVirtualKey32W      (USER32.385)
1032  */
1033 UINT32 WINAPI MapVirtualKey32W(UINT32 code, UINT32 maptype)
1034 {
1035     return MapVirtualKey16(code,maptype);
1036 }
1037
1038 /******************************************************************************
1039  *      MapVirtualKey16      (KEYBOARD.131)
1040  *
1041  * MapVirtualKey translates keycodes from one format to another
1042  */
1043 UINT16 WINAPI MapVirtualKey16(UINT16 wCode, UINT16 wMapType)
1044 {
1045 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
1046
1047         TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
1048                          wCode,wMapType);
1049         switch(wMapType) {
1050                 case 0: { /* vkey-code to scan-code */
1051                         /* let's do vkey -> keycode -> scan */
1052                         int keyc;
1053                         for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1054                                 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1055                                         returnMVK (keyc - min_keycode);
1056                         return 0; }
1057
1058                 case 1: /* scan-code to vkey-code */
1059                         /* let's do scan -> keycode -> vkey */
1060
1061                         returnMVK (keyc2vkey[(wCode & 0xFF) + min_keycode]);
1062
1063                 case 2: { /* vkey-code to unshifted ANSI code */
1064                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1065                         /* My Windows returns 'A'. */
1066                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
1067                         XKeyEvent e;
1068                         KeySym keysym;
1069                         char s[2];
1070                         e.display = display;
1071                         e.state = 0; /* unshifted */
1072                         e.keycode = MapVirtualKey16( wCode, 0);
1073                         if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
1074                           returnMVK (*s);
1075                         
1076                         return 0;
1077                         }
1078                 default: /* reserved */
1079                         WARN(keyboard, "Unknown wMapType %d !\n",
1080                                 wMapType);
1081                         return 0;       
1082         }
1083         return 0;
1084 }
1085
1086
1087 /****************************************************************************
1088  *      GetKBCodePage16   (KEYBOARD.132)
1089  */
1090 INT16 WINAPI GetKBCodePage16(void)
1091 {
1092     TRACE(keyboard,"(void)\n");
1093     return 850;
1094 }
1095
1096
1097 /****************************************************************************
1098  *      GetKBCodePage32   (USER32.246)
1099  */
1100 UINT32 WINAPI GetKBCodePage32(void)
1101 {
1102     TRACE(keyboard,"(void)\n");
1103     return 850;
1104 }
1105
1106 /****************************************************************************
1107  *      GetKeyboardLayoutName32A   (USER32.252)
1108  */
1109 INT32 WINAPI GetKeyboardLayoutName32A(LPSTR pwszKLID)
1110 {
1111         return GetKeyboardLayoutName16(pwszKLID);
1112 }
1113
1114 /****************************************************************************
1115  *      GetKeyboardLayoutName32W   (USER32.253)
1116  */
1117 INT32 WINAPI GetKeyboardLayoutName32W(LPWSTR pwszKLID)
1118 {
1119         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, strlen("00000409")+1);
1120         int res = GetKeyboardLayoutName32A(buf);
1121         lstrcpyAtoW(pwszKLID,buf);
1122         HeapFree( GetProcessHeap(), 0, buf );
1123         return res;
1124 }
1125
1126 /****************************************************************************
1127  *      GetKeyboardLayoutName16   (USER.477)
1128  */
1129 INT16 WINAPI GetKeyboardLayoutName16(LPSTR pwszKLID)
1130 {
1131         FIXME(keyboard,"always returns primary U.S. English layout\n");
1132         strcpy(pwszKLID,"00000409");
1133         return 1;
1134 }
1135
1136 /****************************************************************************
1137  *      GetKeyNameText32A   (USER32.247)
1138  */
1139 INT32 WINAPI GetKeyNameText32A(LONG lParam, LPSTR lpBuffer, INT32 nSize)
1140 {
1141         return GetKeyNameText16(lParam,lpBuffer,nSize);
1142 }
1143
1144 /****************************************************************************
1145  *      GetKeyNameText32W   (USER32.248)
1146  */
1147 INT32 WINAPI GetKeyNameText32W(LONG lParam, LPWSTR lpBuffer, INT32 nSize)
1148 {
1149         LPSTR buf = HEAP_xalloc( GetProcessHeap(), 0, nSize );
1150         int res = GetKeyNameText32A(lParam,buf,nSize);
1151
1152         lstrcpynAtoW(lpBuffer,buf,nSize);
1153         HeapFree( GetProcessHeap(), 0, buf );
1154         return res;
1155 }
1156
1157
1158 /****************************************************************************
1159  *      GetKeyNameText16   (KEYBOARD.133)
1160  */
1161 INT16 WINAPI GetKeyNameText16(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1162 {
1163   /*    int i; */
1164         
1165         FIXME(keyboard,"(%ld,<ptr>,%d): stub\n",lParam,nSize);
1166
1167         /*
1168         lParam >>= 16;
1169         lParam &= 0xff;
1170
1171                 for (i = 0 ; i != KeyTableSize ; i++) 
1172                 if (KeyTable[i].scancode == lParam)  {
1173                         lstrcpyn32A( lpBuffer, KeyTable[i].name, nSize );
1174                         return strlen(lpBuffer);
1175                 }
1176                 */
1177
1178         *lpBuffer = 0;
1179         return 0;
1180 }
1181
1182
1183 /****************************************************************************
1184  *      ToAscii   (KEYBOARD.4)
1185  */
1186 INT16 WINAPI ToAscii16(UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState, 
1187                        LPVOID lpChar, UINT16 flags) 
1188 {
1189     return ToAscii32(virtKey,scanCode,lpKeyState,lpChar,flags);
1190 }
1191
1192 /****************************************************************************
1193  *      ToAscii32      (USER32.546)
1194  */
1195 INT32 WINAPI ToAscii32( UINT32 virtKey,UINT32 scanCode,LPBYTE lpKeyState,
1196                         LPWORD lpChar,UINT32 flags )
1197 {
1198     XKeyEvent e;
1199     KeySym keysym;
1200     static XComposeStatus cs;
1201     INT32 ret;
1202     int keyc;
1203
1204     if (scanCode==0) {
1205         /* This happens when doing Alt+letter : a fake 'down arrow' key press
1206            event is generated by windows. Just ignore it. */
1207         TRACE(keyboard,"scanCode=0, doing nothing\n");
1208         return 0;
1209     }
1210     e.display = display;
1211     e.keycode = 0;
1212     e.state = 0;
1213     if (lpKeyState[VK_SHIFT] & 0x80)
1214         e.state |= ShiftMask;
1215     if (lpKeyState[VK_CAPITAL] & 0x01)
1216         e.state |= LockMask;
1217     if (lpKeyState[VK_CONTROL] & 0x80)
1218     {
1219         if (lpKeyState[VK_MENU] & 0x80)
1220             e.state |= AltGrMask;
1221         else
1222             e.state |= ControlMask;
1223     }
1224     if (lpKeyState[VK_NUMLOCK] & 0x01)
1225         e.state |= NumLockMask;
1226     TRACE(key, "(%04X, %04X) : faked state = %X\n",
1227                 virtKey, scanCode, e.state);
1228     /* We exit on the first keycode found, to speed up the thing. */
1229     for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1230       { /* Find a keycode that could have generated this virtual key */
1231           if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
1232           { /* we can filter the extended bit, VK* are different enough... */
1233               e.keycode = keyc; /* Store it temporarily */
1234               if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey)
1235                   e.keycode = 0; /* Wrong one (ex: because of the NumLock
1236                          state), so set it to 0, we'll find another one */
1237           }
1238       }
1239     if ((!e.keycode) && (lpKeyState[VK_NUMLOCK] & 0x01)) 
1240     {
1241         if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1242           e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1243         if (virtKey==VK_DECIMAL)
1244           e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1245       }
1246     if (!e.keycode)
1247       {
1248         WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
1249         return virtKey; /* whatever */
1250       }
1251     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
1252     if (ret == 0)
1253         {
1254         BYTE dead_char = 0;
1255
1256         ((char*)lpChar)[1] = '\0';
1257         switch (keysym)
1258             {
1259         /* symbolic ASCII is the same as defined in rfc1345 */
1260 #ifdef XK_dead_tilde
1261             case XK_dead_tilde :
1262 #endif
1263             case 0x1000FE7E : /* Xfree's XK_Dtilde */
1264                 dead_char = '~';        /* '? */
1265                 break;
1266 #ifdef XK_dead_acute
1267             case XK_dead_acute :
1268 #endif
1269             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1270                 dead_char = 0xb4;       /* '' */
1271                 break;
1272 #ifdef XK_dead_circumflex
1273             case XK_dead_circumflex :
1274 #endif
1275             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1276                 dead_char = '^';        /* '> */
1277                 break;
1278 #ifdef XK_dead_grave
1279             case XK_dead_grave :
1280 #endif
1281             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1282                 dead_char = '`';        /* '! */
1283                 break;
1284 #ifdef XK_dead_diaeresis
1285             case XK_dead_diaeresis :
1286 #endif
1287             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1288                 dead_char = 0xa8;       /* ': */
1289                 break;
1290 #ifdef XK_dead_cedilla
1291             case XK_dead_cedilla :
1292                 dead_char = 0xb8;       /* ', */
1293                 break;
1294 #endif
1295 #ifdef XK_dead_macron
1296             case XK_dead_macron :
1297                 dead_char = '-';        /* 'm isn't defined on iso-8859-x */
1298                 break;
1299 #endif
1300 #ifdef XK_dead_breve
1301             case XK_dead_breve :
1302                 dead_char = 0xa2;       /* '( */
1303                 break;
1304 #endif
1305 #ifdef XK_dead_abovedot
1306             case XK_dead_abovedot :
1307                 dead_char = 0xff;       /* '. */
1308                 break;
1309 #endif
1310 #ifdef XK_dead_abovering
1311             case XK_dead_abovering :
1312                 dead_char = '0';        /* '0 isn't defined on iso-8859-x */
1313                 break;
1314 #endif
1315 #ifdef XK_dead_doubleacute
1316             case XK_dead_doubleacute :
1317                 dead_char = 0xbd;       /* '" */
1318                 break;
1319 #endif
1320 #ifdef XK_dead_caron
1321             case XK_dead_caron :
1322                 dead_char = 0xb7;       /* '< */
1323                 break;
1324 #endif
1325 #ifdef XK_dead_ogonek
1326             case XK_dead_ogonek :
1327                 dead_char = 0xb2;       /* '; */
1328                 break;
1329 #endif
1330 /* FIXME: I don't know this three.
1331             case XK_dead_iota :
1332                 dead_char = 'i';         
1333                 break;
1334             case XK_dead_voiced_sound :
1335                 dead_char = 'v';
1336                 break;
1337             case XK_dead_semivoiced_sound :
1338                 dead_char = 's';
1339                 break;
1340 */
1341             }
1342         if (dead_char)
1343             {
1344             *(char*)lpChar = dead_char;
1345             ret = -1;
1346             }
1347         else
1348             {
1349             char        *ksname;
1350
1351             ksname = TSXKeysymToString(keysym);
1352             if (!ksname)
1353                 ksname = "No Name";
1354             if ((keysym >> 8) != 0xff)
1355                 {
1356                 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1357                         keysym, ksname);
1358                 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1359                         virtKey, scanCode, e.keycode, e.state);
1360                 }
1361             }
1362         }
1363     TRACE(key, "ToAscii about to return %d with char %x\n",
1364                 ret, *(char*)lpChar);
1365     return ret;
1366 }
1367
1368
1369 /***********************************************************************
1370  *           GetKeyboardLayout                  (USER32.250)
1371  */
1372 HKL32 WINAPI GetKeyboardLayout(DWORD dwLayout)
1373 {
1374         HKL32 layout;
1375         FIXME(keyboard,"(%ld): stub\n",dwLayout);
1376         layout = (0xcafe<<16)|GetSystemDefaultLCID(); /* FIXME */
1377         TRACE(keyboard,"returning %x\n",layout);
1378         return layout;
1379 }
1380
1381 /***********************************************************************
1382  *           GetKeyboardLayoutList              (USER32.251)
1383  * FIXME
1384  */
1385 INT32 WINAPI GetKeyboardLayoutList(INT32 nBuff,HKL32 *layouts)
1386 {
1387         FIXME(keyboard,"(%d,%p): stub\n",nBuff,layouts);
1388         if (layouts)
1389                 layouts[0] = GetKeyboardLayout(0);
1390         return 1;
1391 }
1392
1393
1394 /***********************************************************************
1395  *           RegisterHotKey                     (USER32.433)
1396  */
1397 BOOL32 WINAPI RegisterHotKey(HWND32 hwnd,INT32 id,UINT32 modifiers,UINT32 vk) {
1398         FIXME(keyboard,"(0x%08x,%d,0x%08x,%d): stub\n",hwnd,id,modifiers,vk);
1399         return TRUE;
1400 }
1401
1402 /***********************************************************************
1403  *           UnregisterHotKey                   (USER32.565)
1404  */
1405 BOOL32 WINAPI UnregisterHotKey(HWND32 hwnd,INT32 id) {
1406         FIXME(keyboard,"(0x%08x,%d): stub\n",hwnd,id);
1407         return TRUE;
1408 }
1409
1410 /***********************************************************************
1411  *           KeyboardInquire                    (KEYBOARD.1)
1412  */
1413
1414 #pragma pack(1)
1415 typedef struct _KBINFO
1416 {
1417     BYTE Begin_First_Range;
1418     BYTE End_First_Range;
1419     BYTE Begin_Second_Range;
1420     BYTE End_Second_Range;
1421     WORD StateSize;
1422 } KBINFO;
1423 #pragma pack(4)
1424
1425 WORD WINAPI KeyboardInquire(KBINFO *kbInfo) 
1426 {
1427     kbInfo->Begin_First_Range = 0;
1428     kbInfo->End_First_Range = 0;
1429     kbInfo->Begin_Second_Range = 0;
1430     kbInfo->End_Second_Range = 0;
1431     kbInfo->StateSize = 16; 
1432
1433     return sizeof(KBINFO);
1434 }
1435
1436 /***********************************************************************
1437  *           KeyboardEnable                     (KEYBOARD.2)
1438  */
1439 VOID WINAPI KeyboardEnable(FARPROC16 eventProc, LPBYTE lpKeyState)
1440 {
1441     FIXME(keyboard, "(%08lx,%08lx): stub\n", 
1442                     (DWORD)eventProc, (DWORD)lpKeyState);
1443 }
1444
1445 /***********************************************************************
1446  *           KeyboardDisable                    (KEYBOARD.3)
1447  */
1448 VOID WINAPI KeyboardDisable(VOID)
1449 {
1450     FIXME(keyboard, "(): stub\n");
1451 }
1452
1453
1454 /***********************************************************************
1455  *           DisplayInquire                     (DISPLAY.101)
1456  */
1457
1458 #pragma pack(1)
1459 typedef struct _CURSORINFO
1460 {
1461     WORD wXMickeys;
1462     WORD wYMickeys;
1463 } CURSORINFO;
1464 #pragma pack(4)
1465
1466 WORD WINAPI DisplayInquire(CURSORINFO *cursorInfo) 
1467 {
1468     cursorInfo->wXMickeys = 1;
1469     cursorInfo->wYMickeys = 1;
1470
1471     return sizeof(CURSORINFO);
1472 }
1473
1474 /***********************************************************************
1475  *           DisplaySetCursor                   (DISPLAY.102)
1476  */
1477 VOID WINAPI DisplaySetCursor( LPVOID cursorShape )
1478 {
1479     FIXME(keyboard, "(%p): stub\n", cursorShape );
1480 }
1481
1482 /***********************************************************************
1483  *           DisplayMoveCursor                  (DISPLAY.103)
1484  */
1485 VOID WINAPI DisplayMoveCursor( WORD wAbsX, WORD wAbsY )
1486 {
1487     FIXME(keyboard, "(%d,%d): stub\n", wAbsX, wAbsY );
1488 }
1489
1490 /***********************************************************************
1491  *           UserRepaintDisable                 (DISPLAY.103)
1492  */
1493 VOID WINAPI UserRepaintDisable( BOOL16 disable )
1494 {
1495     FIXME(keyboard, "(%d): stub\n", disable);
1496 }
1497