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