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