Better comments, and added ANSI codepages in table.
[wine] / windows / x11drv / keyboard.c
1 /*
2  * X11 keyboard driver
3  *
4  * Copyright 1993 Bob Amstadt
5  * Copyright 1996 Albrecht Kleine 
6  * Copyright 1997 David Faure
7  * Copyright 1998 Morten Welinder
8  * Copyright 1998 Ulrich Weigand
9  * Copyright 1999 Ove Kåven
10  */
11
12 #include "config.h"
13
14 #ifndef X_DISPLAY_MISSING
15
16 #include <X11/Xatom.h>
17 #include <X11/keysym.h>
18 #include "ts_xlib.h"
19 #include "ts_xresource.h"
20 #include "ts_xutil.h"
21
22 #include "debug.h"
23 #include "keyboard.h"
24 #include "message.h"
25 #include "windef.h"
26 #include "x11drv.h"
27 #include "winnls.h"
28
29 extern LPBYTE pKeyStateTable;
30
31 int min_keycode, max_keycode, keysyms_per_keycode;
32 WORD keyc2vkey[256], keyc2scan[256];
33
34 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
35 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
36
37 /* Keyboard translation tables */
38 #define MAIN_LEN 48
39 static const int main_key_scan[MAIN_LEN] =
40 {
41 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
42    0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
43    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
44    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
45    0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
46    0x56 /* the 102nd key (actually to the right of l-shift) */
47 };
48
49 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
50
51 /* the VK mappings for the main keyboard will be auto-assigned as before,
52    so what we have here is just the character tables */
53 /* order: Normal, Shift, AltGr, Shift-AltGr */
54 /* We recommend you write just what is guaranteed to be correct (i.e. what's
55    written on the keycaps), not the bunch of special characters behind AltGr
56    and Shift-AltGr if it can vary among different X servers */
57 /* Remember that your 102nd key (to the right of l-shift) should be on a
58    separate line, see existing tables */
59 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
60 /* Remember to also add your new table to the layout index table far below! */
61
62 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
63 static const char main_key_US[MAIN_LEN][4] =
64 {
65  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
66  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
67  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
68  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
69 };
70
71 /*** French keyboard layout (contributed by Eric Pouech) */
72 static const char main_key_FR[MAIN_LEN][4] =
73 {
74  "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
75  "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","","$£¤",
76  "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
77  "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
78  "<>"
79 };
80
81 /*** German keyboard layout (contributed by Ulrich Weigand) */
82 static const char main_key_DE[MAIN_LEN][4] =
83 {
84  "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
85  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
86  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
87  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
88  "<>"
89 };
90
91 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
92 static const char main_key_NO[MAIN_LEN][4] =
93 {
94  "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
95  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
96  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
97  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
98  "<>"
99 };
100
101 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
102 static const char main_key_DA[MAIN_LEN][4] =
103 {
104  "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´|",
105  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
106  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
107  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
108  "<>\\"
109 };
110
111 /*** Layout table. Add your keyboard mappings to this list */
112 static struct {
113  WORD lang, ansi_codepage, oem_codepage;
114  const char (*key)[MAIN_LEN][4];
115 } main_key_tab[]={
116  {MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), 1252, 437, &main_key_US},
117  {MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT),     1252, 850, &main_key_FR},
118  {MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT),     1252, 850, &main_key_DE},
119  {MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT),  1252, 865, &main_key_NO},
120  {MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT),     1252, 865, &main_key_DA},
121
122  {0} /* sentinel */
123 };
124 static unsigned kbd_layout=0; /* index into above table of layouts */
125
126 /* maybe more of these scancodes should be extended? */
127                 /* extended must be set for ALT_R, CTRL_R,
128                    INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
129                    keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
130                 /* FIXME should we set extended bit for NumLock ? My
131                  * Windows does ... DF */
132 static const int special_key_vkey[] =
133 {
134     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
135     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
136     0, 0, 0, VK_ESCAPE                                          /* FF18 */
137 };
138 static const int special_key_scan[] =
139 {
140     0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0,                      /* FF08 */
141     0,    0,    0, 0x45, 0x46, 0   , 0, 0,                      /* FF10 */
142     0,    0,    0, 0x01                                         /* FF18 */
143 };
144
145 static const int cursor_key_vkey[] =
146 {
147     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
148                                        VK_NEXT, VK_END          /* FF50 */
149 };
150 static const int cursor_key_scan[] =
151 {
152     0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F      /* FF50 */
153 };
154
155 static const int misc_key_vkey[] =
156 {
157     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
158     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
159 };
160 static const int misc_key_scan[] =
161 {
162     /*?*/ 0, 0x37, /*?*/ 0, 0x152, 0, 0, 0, 0,                  /* FF60 */
163     /*?*/ 0, /*?*/ 0, 0x38                                      /* FF68 */
164 };
165
166 static const int keypad_key_vkey[] =
167 {
168     0, VK_NUMLOCK,                                              /* FF7E */
169     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
170     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
171     0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,                     /* FF90 */
172     VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
173                                  VK_INSERT, VK_DELETE,          /* FF98 */
174     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
175     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
176                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
177     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
178                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
179     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
180 };
181 static const int keypad_key_scan[] =
182 {
183     0x138, 0x45,                                                /* FF7E */
184     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
185     0, 0, 0, 0, 0, 0x11C, 0, 0,                                 /* FF88 */
186     0, 0, 0, 0, 0, 0x47, 0x4B, 0x48,                            /* FF90 */
187     0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53,             /* FF98 */
188     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
189     0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135,               /* FFA8 */
190     0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47,             /* FFB0 */
191     0x48, 0x49                                                  /* FFB8 */
192 };
193     
194 static const int function_key_vkey[] =
195 {
196     VK_F1, VK_F2,                                               /* FFBE */
197     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
198     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
199 };
200 static const int function_key_scan[] =
201 {
202     0x3B, 0x3C,                                                 /* FFBE */
203     0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,             /* FFC0 */
204     0x57, 0x58, 0, 0, 0, 0                                      /* FFC8 */
205 };
206
207 static const int modifier_key_vkey[] =
208 {
209     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
210     VK_MENU, VK_MENU, VK_MENU, VK_MENU                         /* FFE7 */
211 };
212 static const int modifier_key_scan[] =
213 {
214     0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0,                          /* FFE1 */
215     0x38, 0x138, 0x38, 0x138                                   /* FFE7 */
216 };
217
218 /* Returns the Windows virtual key code associated with the X event <e> */
219 static WORD EVENT_event_to_vkey( XKeyEvent *e)
220 {
221     KeySym keysym;
222
223     TSXLookupString(e, NULL, 0, &keysym, NULL);
224
225     if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (e->state & NumLockMask)) 
226         /* Only the Keypad keys 0-9 and . send different keysyms
227          * depending on the NumLock state */
228         return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
229
230     return keyc2vkey[e->keycode];
231 }
232
233 static BOOL NumState=FALSE, CapsState=FALSE;
234
235 /**********************************************************************
236  *              KEYBOARD_GenerateMsg
237  *
238  * Generate Down+Up messages when NumLock or CapsLock is pressed.
239  *
240  * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
241  *
242  */
243 void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
244                            DWORD event_time )
245 {
246   BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
247
248   if (*State) {
249     /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
250        don't treat it. It's from the same key press. Then the state goes to ON.
251        And from there, a 'release' event will switch off the toggle key. */
252     *State=FALSE;
253     TRACE(keyboard,"INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
254   } else
255     {
256         if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
257           {
258             if (Evtype!=KeyPress)
259               {
260                 TRACE(keyboard,"ON + KeyRelease => generating DOWN and UP messages.\n");
261                 KEYBOARD_SendEvent( vkey, scan, 0,
262                                     event_x, event_y, event_time );
263                 KEYBOARD_SendEvent( vkey, scan, KEYEVENTF_KEYUP, 
264                                     event_x, event_y, event_time );
265                 *State=FALSE;
266                 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */ 
267               } 
268           }
269         else /* it was OFF */
270           if (Evtype==KeyPress)
271             {
272               TRACE(keyboard,"OFF + Keypress => generating DOWN and UP messages.\n");
273               KEYBOARD_SendEvent( vkey, scan, 0,
274                                   event_x, event_y, event_time );
275               KEYBOARD_SendEvent( vkey, scan, KEYEVENTF_KEYUP, 
276                                   event_x, event_y, event_time );
277               *State=TRUE; /* Goes to intermediary state before going to ON */
278               pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
279             }
280     }
281 }
282
283 /***********************************************************************
284  *           KEYBOARD_UpdateOneState
285  *
286  * Updates internal state for <vkey>, depending on key <state> under X
287  *
288  */
289 void KEYBOARD_UpdateOneState ( int vkey, int state )
290 {
291     /* Do something if internal table state != X state for keycode */
292     if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
293     {
294         TRACE(keyboard,"Adjusting state for vkey %#.2x. State before %#.2x \n",
295               vkey, pKeyStateTable[vkey]);
296
297         /* Fake key being pressed inside wine */
298         KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP, 
299                             0, 0, GetTickCount() );
300
301         TRACE(keyboard,"State after %#.2x \n",pKeyStateTable[vkey]);
302     }
303 }
304
305 /***********************************************************************
306  *           X11DRV_KEYBOARD_UpdateState
307  *
308  * Update modifiers state (Ctrl, Alt, Shift)
309  * when window is activated (called by EVENT_FocusIn in event.c)
310  *
311  * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
312  * from wine to another application and back.
313  * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
314  *  about them)
315  */
316 void X11DRV_KEYBOARD_UpdateState ( void )
317 {
318 /* extract a bit from the char[32] bit suite */
319 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
320
321     char keys_return[32];
322
323     TRACE(keyboard,"called\n");
324     if (!TSXQueryKeymap(display, keys_return)) {
325         ERR(keyboard,"Error getting keymap !");
326         return;
327     }
328
329     /* Adjust the ALT and CONTROL state if any has been changed outside wine */
330     KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
331     KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
332     KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
333 #undef KeyState
334 }
335
336 /***********************************************************************
337  *           X11DRV_KEYBOARD_HandleEvent
338  *
339  * Handle a X key event
340  */
341 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
342 {
343     char Str[24]; 
344     XComposeStatus cs; 
345     KeySym keysym;
346     WORD vkey = 0, bScan;
347     DWORD dwFlags;
348     static BOOL force_extended = FALSE; /* hack for AltGr translation */
349     
350     int ascii_chars;
351
352     INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
353     INT event_y = (pWnd? pWnd->rectWindow.top  : 0) + event->y;
354     DWORD event_time = event->time - MSG_WineStartTicks;
355
356     /* this allows support for dead keys */
357     if ((event->keycode >> 8) == 0x10)
358         event->keycode=(event->keycode & 0xff);
359
360     ascii_chars = TSXLookupString(event, Str, 1, &keysym, &cs);
361
362     TRACE(key, "EVENT_key : state = %X\n", event->state);
363     if (keysym == XK_Mode_switch)
364         {
365         TRACE(key, "Alt Gr key event received\n");
366         event->keycode = kcControl; /* Simulate Control */
367         X11DRV_KEYBOARD_HandleEvent( pWnd, event );
368
369         event->keycode = kcAlt; /* Simulate Alt */
370         force_extended = TRUE;
371         X11DRV_KEYBOARD_HandleEvent( pWnd, event );
372         force_extended = FALSE;
373         return;
374         }
375
376     Str[ascii_chars] = '\0';
377     if (TRACE_ON(key)){
378         char    *ksname;
379
380         ksname = TSXKeysymToString(keysym);
381         if (!ksname)
382           ksname = "No Name";
383         TRACE(key, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n", 
384                      (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
385                      keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
386     }
387
388     vkey = EVENT_event_to_vkey(event);
389     if (force_extended) vkey |= 0x100;
390
391     TRACE(key, "keycode 0x%x converted to vkey 0x%x\n",
392                     event->keycode, vkey);
393
394    if (vkey)
395    {
396     switch (vkey & 0xff)
397     {
398     case VK_NUMLOCK:    
399       KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
400                             event_time );
401       break;
402     case VK_CAPITAL:
403       TRACE(keyboard,"Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
404       KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
405                             event_time ); 
406       TRACE(keyboard,"State after : %#.2x\n",pKeyStateTable[vkey]);
407       break;
408     default:
409         /* Adjust the NUMLOCK state if it has been changed outside wine */
410         if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
411           { 
412             TRACE(keyboard,"Adjusting NumLock state. \n");
413             KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
414                                   event_time );
415             KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
416                                   event_time );
417           }
418         /* Adjust the CAPSLOCK state if it has been changed outside wine */
419         if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
420           {
421               TRACE(keyboard,"Adjusting Caps Lock state.\n");
422             KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
423                                   event_time );
424             KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
425                                   event_time );
426           }
427         /* Not Num nor Caps : end of intermediary states for both. */
428         NumState = FALSE;
429         CapsState = FALSE;
430
431         bScan = keyc2scan[event->keycode] & 0xFF;
432         TRACE(key, "bScan = 0x%02x.\n", bScan);
433
434         dwFlags = 0;
435         if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
436         if ( vkey & 0x100 )              dwFlags |= KEYEVENTF_EXTENDEDKEY;
437         if ( force_extended )            dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
438
439         KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags, 
440                             event_x, event_y, event_time );
441     }
442    }
443 }
444
445 /**********************************************************************
446  *              X11DRV_KEYBOARD_DetectLayout
447  *
448  * Called from X11DRV_KEYBOARD_Init
449  *  This routine walks through the defined keyboard layouts and selects
450  *  whichever matches most closely.
451  */
452 void X11DRV_KEYBOARD_DetectLayout(void)
453 {
454     unsigned current, match, mismatch;
455     int max_score = 0, ismatch = 0;
456     int score, keyc, i, key, ok, syms = (keysyms_per_keycode>4) ? 4 : keysyms_per_keycode;
457     KeySym keysym;
458     char ckey[4]={0,0,0,0};
459     const char (*lkey)[MAIN_LEN][4];
460
461     for (current=0; main_key_tab[current].lang; current++) {
462       TRACE(keyboard,"Attempting to match against layout %04x\n",main_key_tab[current].lang);
463       match = 0; mismatch = 0;
464       lkey = main_key_tab[current].key;
465       for (keyc=min_keycode; keyc<=max_keycode; keyc++) {
466         /* get data for keycode from X server */
467         for (i=0; i<syms; i++) {
468           keysym = TSXKeycodeToKeysym(display, keyc, i);
469           if ((keysym<0x100)&&(keysym!=' ')) ckey[i] = keysym;
470           else ckey[i] = 0;
471         }
472         if (ckey[0]) {
473           /* search for a match in layout table */
474           /* right now, we just find an absolute match for defined positions */
475           /* (undefined positions are ignored, so if it's defined as "3#"
476              in the table, it's okay that the X server has "3#£", for example) */
477           for (key=0; key<MAIN_LEN; key++) {
478             for (ok=(*lkey)[key][i=0]; ok&&(i<4); i++)
479               if ((*lkey)[key][i] && (*lkey)[key][i]!=ckey[i]) ok=0;
480             if (ok) break;
481           }
482           /* count the matches and mismatches */
483           if (key<MAIN_LEN) match++; else {
484             TRACE(key,"mismatch for keycode %d, character %c\n",keyc,ckey[0]);
485             mismatch++;
486           }
487         }
488       }
489       /* estimate and check score */
490       score = match - mismatch;
491       TRACE(keyboard,"matches=%d, mismatches=%d, score=%d\n",match,mismatch,score);
492       if (score > max_score) {
493         /* best match so far */
494         kbd_layout = current;
495         max_score = score;
496         ismatch = !mismatch;
497       }
498     }
499     /* we're done, report results if necessary */
500     if (!ismatch) {
501       FIXME(keyboard,"Your keyboard layout was not found! Using closest match (%04x).\n",
502             main_key_tab[kbd_layout].lang);
503       FIXME(keyboard,"Please define your layout in windows/x11drv/keyboard.c, and submit them\n");
504       FIXME(keyboard,"to us for inclusion into future Wine releases.\n");
505       FIXME(keyboard,"See documentation/keyboard for more information.\n");
506     }
507     TRACE(keyboard,"detected layout is %04x\n",main_key_tab[kbd_layout].lang);
508 }
509
510 /**********************************************************************
511  *              X11DRV_KEYBOARD_Init
512  */
513 void X11DRV_KEYBOARD_Init(void)
514 {
515     KeySym *ksp;
516     XModifierKeymap *mmp;
517     KeySym keysym;
518     KeyCode *kcp;
519     XKeyEvent e2;
520     WORD scan, vkey, OEMvkey;
521     int keyc, i, keyn, syms;
522     char ckey[4]={0,0,0,0};
523     const char (*lkey)[MAIN_LEN][4];
524
525     TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
526     ksp = TSXGetKeyboardMapping(display, min_keycode,
527                               max_keycode + 1 - min_keycode, &keysyms_per_keycode);
528     /* We are only interested in keysyms_per_keycode.
529        There is no need to hold a local copy of the keysyms table */
530     TSXFree(ksp);
531     mmp = TSXGetModifierMapping(display);
532     kcp = mmp->modifiermap;
533     for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
534     {
535         int j;
536         
537         for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
538             if (*kcp)
539             {
540                 int k;
541                 
542                 for (k = 0; k < keysyms_per_keycode; k += 1)
543                     if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
544                     {
545                         AltGrMask = 1 << i;
546                         TRACE(key, "AltGrMask is %x\n", AltGrMask);
547                     }
548                     else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
549                     {
550                         NumLockMask = 1 << i;
551                         TRACE(key, "NumLockMask is %x\n", NumLockMask);
552                     }
553             }
554     }
555     TSXFreeModifiermap(mmp);
556
557     /* Detect the keyboard layout */
558     X11DRV_KEYBOARD_DetectLayout();
559     lkey = main_key_tab[kbd_layout].key;
560     syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
561
562     /* Now build two conversion arrays :
563      * keycode -> vkey + scancode + extended
564      * vkey + extended -> keycode */
565
566     e2.display = display;
567     e2.state = 0;
568
569     OEMvkey = VK_OEM_7; /* next is available.  */
570     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
571     {
572         e2.keycode = (KeyCode)keyc;
573         TSXLookupString(&e2, NULL, 0, &keysym, NULL);
574         vkey = 0; scan = 0;
575         if (keysym)  /* otherwise, keycode not used */
576         {
577             if ((keysym >> 8) == 0xFF)         /* non-character key */
578             {
579                 int key = keysym & 0xff;
580                 
581                 if (key >= 0x08 && key <= 0x1B) {        /* special key */
582                     vkey = special_key_vkey[key - 0x08];
583                     scan = special_key_scan[key - 0x08];
584                 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
585                     vkey = cursor_key_vkey[key - 0x50];
586                     scan = cursor_key_scan[key - 0x50];
587                 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
588                     vkey = misc_key_vkey[key - 0x60];
589                     scan = misc_key_scan[key - 0x60];
590                 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
591                     vkey = keypad_key_vkey[key - 0x7E];
592                     scan = keypad_key_scan[key - 0x7E];
593                 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
594                     vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
595                     scan = function_key_scan[key - 0xBE];
596                 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
597                     vkey = modifier_key_vkey[key - 0xE1];
598                     scan = modifier_key_scan[key - 0xE1];
599                 } else if (key == 0xFF) {                /* DEL key */
600                     vkey = VK_DELETE;
601                     scan = 0x153;
602                 }
603                 /* set extended bit when necessary */
604                 if (scan & 0x100) vkey |= 0x100;
605             } else if (keysym == 0x20) {                 /* Spacebar */
606                 vkey = VK_SPACE;
607                 scan = 0x39;
608             } else {
609               /* we seem to need to search the layout-dependent scancodes */
610               int maxlen=0,maxval=-1,ok;
611               for (i=0; i<syms; i++) {
612                 keysym = TSXKeycodeToKeysym(display, keyc, i);
613                 if ((keysym<0x100)&&(keysym!=' ')) ckey[i] = keysym;
614                 else ckey[i] = 0;
615               }
616               /* find key with longest match streak */
617               for (keyn=0; keyn<MAIN_LEN; keyn++) {
618                 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
619                   if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
620                 if (ok||(i>maxlen)) {
621                   maxlen=i; maxval=keyn;
622                 }
623                 if (ok) break;
624               }
625               if (maxval>=0) {
626                 /* got it */
627                 scan = main_key_scan[maxval];
628               }
629             }
630
631             /* find a suitable layout-dependent VK code */
632             /* (most Winelib apps ought to be able to work without layout tables!) */
633             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
634             {
635                 keysym = TSXLookupKeysym(&e2, i);
636                 if ((keysym >= VK_0 && keysym <= VK_9)
637                     || (keysym >= VK_A && keysym <= VK_Z)) {
638                     vkey = keysym;
639                 }
640             }
641
642             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
643             {
644                 keysym = TSXLookupKeysym(&e2, i);
645                 switch (keysym)
646                 {
647                 case ';':             vkey = VK_OEM_1; break;
648                 case '/':             vkey = VK_OEM_2; break;
649                 case '`':             vkey = VK_OEM_3; break;
650                 case '[':             vkey = VK_OEM_4; break;
651                 case '\\':            vkey = VK_OEM_5; break;
652                 case ']':             vkey = VK_OEM_6; break;
653                 case '\'':            vkey = VK_OEM_7; break;
654                 case ',':             vkey = VK_OEM_COMMA; break;
655                 case '.':             vkey = VK_OEM_PERIOD; break;
656                 case '-':             vkey = VK_OEM_MINUS; break;
657                 case '+':             vkey = VK_OEM_PLUS; break;
658                 }
659             }
660
661             if (!vkey)
662             {
663                 /* Others keys: let's assign OEM virtual key codes in the allowed range,
664                  * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
665                 switch (++OEMvkey)
666                 {
667                 case 0xc1 : OEMvkey=0xdb; break;
668                 case 0xe5 : OEMvkey=0xe9; break;
669                 case 0xf6 : OEMvkey=0xf5; WARN(keyboard,"No more OEM vkey available!\n");
670                 }
671
672                 vkey = OEMvkey;
673                   
674                 if (TRACE_ON(keyboard))
675                 {
676                     dbg_decl_str(keyboard, 1024);
677
678                     TRACE(keyboard, "OEM specific virtual key %X assigned "
679                                  "to keycode %X:\n", OEMvkey, e2.keycode);
680                     for (i = 0; i < keysyms_per_keycode; i += 1)
681                     {
682                         char    *ksname;
683                         
684                         keysym = TSXLookupKeysym(&e2, i);
685                         ksname = TSXKeysymToString(keysym);
686                         if (!ksname)
687                             ksname = "NoSymbol";
688                         dsprintf(keyboard, "%lX (%s) ", keysym, ksname);
689                     }
690                     TRACE(keyboard, "(%s)\n", dbg_str(keyboard));
691                 }
692             }
693         }
694         keyc2vkey[e2.keycode] = vkey;
695         keyc2scan[e2.keycode] = scan;
696     } /* for */
697
698     /* If some keys still lack scancodes, assign some arbitrary ones to them now */
699     for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
700       if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
701         char *ksname;
702         keysym = TSXKeycodeToKeysym(display, keyc, 0);
703         ksname = TSXKeysymToString(keysym);
704         if (!ksname) ksname = "NoSymbol";
705
706         /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
707
708         TRACE(key,"assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
709         keyc2scan[keyc]=scan++;
710       }
711
712     /* Now store one keycode for each modifier. Used to simulate keypresses. */
713     kcControl = TSXKeysymToKeycode(display, XK_Control_L);
714     kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
715     if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
716     kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
717     kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
718     kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
719 }
720
721 /***********************************************************************
722  *              X11DRV_KEYBOARD_VkKeyScan
723  */
724 WORD X11DRV_KEYBOARD_VkKeyScan(CHAR cChar)
725 {
726         KeyCode keycode;
727         KeySym keysym;          
728         int i,index;
729         int highbyte=0;
730
731         /* char->keysym (same for ANSI chars) */
732         keysym=(unsigned char) cChar;/* (!) cChar is signed */
733         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
734         
735         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
736         if (!keycode)
737         { /* It didn't work ... let's try with deadchar code. */
738           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
739         }
740
741         TRACE(keyboard,"VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
742                          cChar,keysym,keysym,keycode);
743         
744         if (keycode)
745           {
746             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
747               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
748             switch (index) {
749             case -1 :
750               WARN(keyboard,"Keysym %lx not found while parsing the keycode table\n",keysym); break;
751             case 0 : break;
752             case 1 : highbyte = 0x0100; break;
753             case 2 : highbyte = 0X0600; break;
754             default : ERR(keyboard,"index %d found by XKeycodeToKeysym. please report! \n",index);
755             }
756             /*
757               index : 0     adds 0x0000
758               index : 1     adds 0x0100 (shift)
759               index : ?     adds 0x0200 (ctrl)
760               index : 2     adds 0x0600 (ctrl+alt)
761               index : ?     adds 0x0700 (ctrl+alt+shift (used?))
762              */
763           }
764         TRACE(keyboard," ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
765         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
766 }
767
768 /***********************************************************************
769  *              X11DRV_KEYBOARD_MapVirtualKey
770  */
771 UINT16 X11DRV_KEYBOARD_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
772 {
773 #define returnMVK(value) { TRACE(keyboard,"returning 0x%x.\n",value); return value; }
774
775         TRACE(keyboard,"MapVirtualKey wCode=0x%x wMapType=%d ... \n",
776                          wCode,wMapType);
777         switch(wMapType) {
778                 case 0: { /* vkey-code to scan-code */
779                         /* let's do vkey -> keycode -> scan */
780                         int keyc;
781                         for (keyc=min_keycode; keyc<=max_keycode; keyc++)
782                                 if ((keyc2vkey[keyc] & 0xFF) == wCode)
783                                         returnMVK (keyc2scan[keyc] & 0xFF);
784                         return 0; }
785
786                 case 1: { /* scan-code to vkey-code */
787                         /* let's do scan -> keycode -> vkey */
788                         int keyc;
789                         for (keyc=min_keycode; keyc<=max_keycode; keyc++)
790                                 if ((keyc2scan[keyc] & 0xFF) == wCode)
791                                         returnMVK (keyc2vkey[keyc] & 0xFF);
792                         return 0; }
793
794                 case 2: { /* vkey-code to unshifted ANSI code */
795                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
796                         /* My Windows returns 'A'. */
797                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
798                         XKeyEvent e;
799                         KeySym keysym;
800                         char s[2];
801                         e.display = display;
802                         e.state = 0; /* unshifted */
803                         e.keycode = MapVirtualKey16( wCode, 0);
804                         if (!TSXLookupString(&e, s , 2 , &keysym, NULL))
805                           returnMVK (*s);
806                         
807                         return 0;
808                         }
809                 default: /* reserved */
810                         WARN(keyboard, "Unknown wMapType %d !\n",
811                                 wMapType);
812                         return 0;       
813         }
814         return 0;
815 }
816
817 /***********************************************************************
818  *              X11DRV_KEYBOARD_GetKeyNameText
819  */
820 INT16 X11DRV_KEYBOARD_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
821 {
822 #if 0
823   int i;
824 #endif
825         
826   FIXME(keyboard,"(%ld,<ptr>,%d): stub\n",lParam,nSize);
827
828 #if 0
829   lParam >>= 16;
830   lParam &= 0xff;
831   
832   for (i = 0 ; i != KeyTableSize ; i++) 
833     if (KeyTable[i].scancode == lParam)  {
834       lstrcpynA( lpBuffer, KeyTable[i].name, nSize );
835       return strlen(lpBuffer);
836     }
837 #endif
838
839   *lpBuffer = 0;
840   return 0;
841 }
842
843 /***********************************************************************
844  *              X11DRV_KEYBOARD_ToAscii
845  *
846  * The ToAscii function translates the specified virtual-key code and keyboard
847  * state to the corresponding Windows character or characters.
848  *
849  * If the specified key is a dead key, the return value is negative. Otherwise,
850  * it is one of the following values:
851  * Value        Meaning
852  * 0    The specified virtual key has no translation for the current state of the keyboard.
853  * 1    One Windows character was copied to the buffer.
854  * 2    Two characters were copied to the buffer. This usually happens when a
855  *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
856  *      be composed with the specified virtual key to form a single character.
857  *
858  * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
859  *
860  */
861 INT16 X11DRV_KEYBOARD_ToAscii(
862     UINT16 virtKey,UINT16 scanCode, LPBYTE lpKeyState, 
863     LPVOID lpChar, UINT16 flags)
864 {
865     XKeyEvent e;
866     KeySym keysym;
867     static XComposeStatus cs;
868     INT ret;
869     int keyc;
870
871     if (scanCode==0) {
872         /* This happens when doing Alt+letter : a fake 'down arrow' key press
873            event is generated by windows. Just ignore it. */
874         TRACE(keyboard,"scanCode=0, doing nothing\n");
875         return 0;
876     }
877     if (scanCode & 0x8000)
878     {
879         TRACE( keyboard, "Key UP, doing nothing\n" );
880         return 0;
881     }
882     e.display = display;
883     e.keycode = 0;
884     e.state = 0;
885     if (lpKeyState[VK_SHIFT] & 0x80)
886         e.state |= ShiftMask;
887     if (lpKeyState[VK_CAPITAL] & 0x01)
888         e.state |= LockMask;
889     if (lpKeyState[VK_CONTROL] & 0x80)
890     {
891         if (lpKeyState[VK_MENU] & 0x80)
892             e.state |= AltGrMask;
893         else
894             e.state |= ControlMask;
895     }
896     if (lpKeyState[VK_NUMLOCK] & 0x01)
897         e.state |= NumLockMask;
898     TRACE(key, "(%04X, %04X) : faked state = %X\n",
899                 virtKey, scanCode, e.state);
900     /* We exit on the first keycode found, to speed up the thing. */
901     for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
902       { /* Find a keycode that could have generated this virtual key */
903           if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
904           { /* We filter the extended bit, we don't know it */
905               e.keycode = keyc; /* Store it temporarily */
906               if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
907                   e.keycode = 0; /* Wrong one (ex: because of the NumLock
908                          state), so set it to 0, we'll find another one */
909               }
910           }
911       }
912
913     if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
914         e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
915           
916     if (virtKey==VK_DECIMAL)
917         e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
918
919     if (!e.keycode)
920       {
921         WARN(keyboard,"Unknown virtual key %X !!! \n",virtKey);
922         return virtKey; /* whatever */
923       }
924     else TRACE(keyboard,"Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
925
926     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, &cs);
927     if (ret == 0)
928         {
929         BYTE dead_char = 0;
930
931         ((char*)lpChar)[1] = '\0';
932         switch (keysym)
933             {
934         /* symbolic ASCII is the same as defined in rfc1345 */
935 #ifdef XK_dead_tilde
936             case XK_dead_tilde :
937 #endif
938             case 0x1000FE7E : /* Xfree's XK_Dtilde */
939                 dead_char = '~';        /* '? */
940                 break;
941 #ifdef XK_dead_acute
942             case XK_dead_acute :
943 #endif
944             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
945                 dead_char = 0xb4;       /* '' */
946                 break;
947 #ifdef XK_dead_circumflex
948             case XK_dead_circumflex :
949 #endif
950             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
951                 dead_char = '^';        /* '> */
952                 break;
953 #ifdef XK_dead_grave
954             case XK_dead_grave :
955 #endif
956             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
957                 dead_char = '`';        /* '! */
958                 break;
959 #ifdef XK_dead_diaeresis
960             case XK_dead_diaeresis :
961 #endif
962             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
963                 dead_char = 0xa8;       /* ': */
964                 break;
965 #ifdef XK_dead_cedilla
966             case XK_dead_cedilla :
967                 dead_char = 0xb8;       /* ', */
968                 break;
969 #endif
970 #ifdef XK_dead_macron
971             case XK_dead_macron :
972                 dead_char = '-';        /* 'm isn't defined on iso-8859-x */
973                 break;
974 #endif
975 #ifdef XK_dead_breve
976             case XK_dead_breve :
977                 dead_char = 0xa2;       /* '( */
978                 break;
979 #endif
980 #ifdef XK_dead_abovedot
981             case XK_dead_abovedot :
982                 dead_char = 0xff;       /* '. */
983                 break;
984 #endif
985 #ifdef XK_dead_abovering
986             case XK_dead_abovering :
987                 dead_char = '0';        /* '0 isn't defined on iso-8859-x */
988                 break;
989 #endif
990 #ifdef XK_dead_doubleacute
991             case XK_dead_doubleacute :
992                 dead_char = 0xbd;       /* '" */
993                 break;
994 #endif
995 #ifdef XK_dead_caron
996             case XK_dead_caron :
997                 dead_char = 0xb7;       /* '< */
998                 break;
999 #endif
1000 #ifdef XK_dead_ogonek
1001             case XK_dead_ogonek :
1002                 dead_char = 0xb2;       /* '; */
1003                 break;
1004 #endif
1005 /* FIXME: I don't know this three.
1006             case XK_dead_iota :
1007                 dead_char = 'i';         
1008                 break;
1009             case XK_dead_voiced_sound :
1010                 dead_char = 'v';
1011                 break;
1012             case XK_dead_semivoiced_sound :
1013                 dead_char = 's';
1014                 break;
1015 */
1016             }
1017         if (dead_char)
1018             {
1019             *(char*)lpChar = dead_char;
1020             ret = -1;
1021             }
1022         else
1023             {
1024             char        *ksname;
1025
1026             ksname = TSXKeysymToString(keysym);
1027             if (!ksname)
1028                 ksname = "No Name";
1029             if ((keysym >> 8) != 0xff)
1030                 {
1031                 ERR(keyboard, "Please report: no char for keysym %04lX (%s) :\n",
1032                         keysym, ksname);
1033                 ERR(keyboard, "(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1034                         virtKey, scanCode, e.keycode, e.state);
1035                 }
1036             }
1037         }
1038     else {  /* ret = 1 */
1039         /* We have a special case to handle : Shift + arrow, shift + home, ...
1040            X returns a char for it, but Windows doesn't. Let's eat it. */
1041         if (!(lpKeyState[VK_NUMLOCK] & 0x01)  /* NumLock is off */
1042             && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1043             && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1044         {
1045             *(char*)lpChar = 0;
1046             ret = 0;
1047         }
1048     }
1049
1050     TRACE(key, "ToAscii about to return %d with char %x\n",
1051                 ret, *(char*)lpChar);
1052     return ret;
1053 }
1054
1055 #endif /* !defined(X_DISPLAY_MISSING) */
1056
1057