Replaced ToAscii by ToUnicode in the User driver interface.
[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 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
16
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
20
21 #include <ctype.h>
22 #include <string.h>
23
24 #include "windef.h"
25 #include "wingdi.h"
26 #include "wine/winuser16.h"
27 #include "dinput.h"
28 #include "debugtools.h"
29 #include "user.h"
30 #include "keyboard.h"
31 #include "message.h"
32 #include "winnls.h"
33 #include "win.h"
34 #include "x11drv.h"
35
36 DEFAULT_DEBUG_CHANNEL(keyboard)
37 DECLARE_DEBUG_CHANNEL(key)
38 DECLARE_DEBUG_CHANNEL(dinput)
39
40 extern BYTE InputKeyStateTable[256];
41
42 extern LPBYTE pKeyStateTable;
43
44 int min_keycode, max_keycode, keysyms_per_keycode;
45 WORD keyc2vkey[256], keyc2scan[256];
46
47 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
48 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
49
50 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
51
52 /* Keyboard translation tables */
53 #define MAIN_LEN 48
54 static const WORD main_key_scan_qwerty[MAIN_LEN] =
55 {
56 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
57    0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
58    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
59    0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
60    0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
61    0x56 /* the 102nd key (actually to the right of l-shift) */
62 };
63
64 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
65 {
66 /* NOTE: this layout must concur with the scan codes layout above */
67    VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
68    VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
69    VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_7,VK_OEM_5,
70    VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
71    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
72 };
73
74 static const WORD main_key_vkey_azerty[MAIN_LEN] =
75 {
76 /* NOTE: this layout must concur with the scan codes layout above */
77    VK_OEM_7,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_PLUS,
78    VK_A,VK_Z,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_6,VK_OEM_1,
79    VK_Q,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_M,VK_OEM_3,VK_OEM_5,
80    VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
81    VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
82 };
83
84 /* FIXME: add other layouts, such as DVORAK and German QWERTZ */
85
86 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
87
88 /* the VK mappings for the main keyboard will be auto-assigned as before,
89    so what we have here is just the character tables */
90 /* order: Normal, Shift, AltGr, Shift-AltGr */
91 /* We recommend you write just what is guaranteed to be correct (i.e. what's
92    written on the keycaps), not the bunch of special characters behind AltGr
93    and Shift-AltGr if it can vary among different X servers */
94 /* Remember that your 102nd key (to the right of l-shift) should be on a
95    separate line, see existing tables */
96 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
97 /* Remember to also add your new table to the layout index table far below! */
98
99 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
100 static const char main_key_US[MAIN_LEN][4] =
101 {
102  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
103  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
104  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
105  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
106 };
107
108 /*** United States keyboard layout (phantom key version) */
109 /* (XFree86 reports the <> key even if it's not physically there) */
110 static const char main_key_US_phantom[MAIN_LEN][4] =
111 {
112  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
113  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
114  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
115  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
116  "<>" /* the phantom key */
117 };
118
119 /*** British keyboard layout */
120 static const char main_key_UK[MAIN_LEN][4] =
121 {
122  "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
123  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
124  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
125  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
126  "\\|"
127 };
128
129 /*** French keyboard layout (contributed by Eric Pouech) */
130 static const char main_key_FR[MAIN_LEN][4] =
131 {
132  "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
133  "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
134  "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
135  "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
136  "<>"
137 };
138
139 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
140 static const char main_key_IS[MAIN_LEN][4] =
141 {
142  "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
143  "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
144  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
145  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
146  "<>|"
147 };
148
149 /*** German keyboard layout (contributed by Ulrich Weigand) */
150 static const char main_key_DE[MAIN_LEN][4] =
151 {
152  "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
153  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
154  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
155  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
156  "<>"
157 };
158
159 /*** German keyboard layout without dead keys */
160 static const char main_key_DE_nodead[MAIN_LEN][4] =
161 {
162  "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
163  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
164  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
165  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
166  "<>"
167 };
168
169 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
170 static const char main_key_SG[MAIN_LEN][4] =
171 {
172  "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
173  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
174  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
175  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
176  "<>\\"
177 };
178
179 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
180 static const char main_key_SF[MAIN_LEN][4] =
181 {
182  "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
183  "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
184  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
185  "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
186  "<>\\"
187 };
188
189 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
190 static const char main_key_NO[MAIN_LEN][4] =
191 {
192  "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
193  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
194  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
195  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
196  "<>"
197 };
198
199 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
200 static const char main_key_DA[MAIN_LEN][4] =
201 {
202  "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
203  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
204  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
205  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
206  "<>\\"
207 };
208
209 /*** Swedish keyboard layout (contributed by Peter Bortas) */
210 static const char main_key_SE[MAIN_LEN][4] =
211 {
212  "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
213  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
214  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
215  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
216  "<>|"
217 };
218
219 /*** Canadian French keyboard layout */
220 static const char main_key_CF[MAIN_LEN][4] =
221 {
222  "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
223  "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
224  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
225  "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
226  "«»°"
227 };
228
229 /*** Portuguese keyboard layout */
230 static const char main_key_PT[MAIN_LEN][4] =
231 {
232  "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
233  "qQ",  "wW","eE",  "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
234  "aA",  "sS","dD",  "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
235  "zZ",  "xX","cC",  "vV", "bB", "nN", "mM", ",;", ".:", "-_",
236  "<>"
237 };
238
239 /*** Italian keyboard layout */
240 static const char main_key_IT[MAIN_LEN][4] =
241 {
242  "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
243  "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
244  "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
245  "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
246  "<>|"
247 };
248
249 /*** Finnish keyboard layout */
250 static const char main_key_FI[MAIN_LEN][4] =
251 {
252  "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
253  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
254  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
255  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
256  "<>|"
257 };
258
259 /*** Russian keyboard layout (contributed by Pavel Roskin) */
260 static const char main_key_RU[MAIN_LEN][4] =
261 {
262  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
263  "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
264  "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
265  "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
266 };
267
268 /*** Russian keyboard layout KOI8-R */
269 static const char main_key_RU_koi8r[MAIN_LEN][4] =
270 {
271  "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
272  "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
273  "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
274  "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
275  "<>" /* the phantom key */
276 };
277
278 /*** Spanish keyboard layout (contributed by José Marcos López) */
279 static const char main_key_ES[MAIN_LEN][4] =
280 {
281  "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
282  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
283  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
284  "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
285  "<>"
286 };
287
288 /*** Belgian keyboard layout ***/
289 static const char main_key_BE[MAIN_LEN][4] =
290 {
291  "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
292  "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
293  "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
294  "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
295  "<>\\"
296 };
297
298 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
299 static const char main_key_HU[MAIN_LEN][4] =
300 {
301  "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
302  "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
303  "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
304  "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
305  "íÍ<"
306 };
307
308 /*** Polish (programmer's) keyboard layout ***/
309 static const char main_key_PL[MAIN_LEN][4] =
310 {
311  "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
312  "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
313  "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
314  "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
315  "<>|"
316 };
317
318 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
319 static const char main_key_HR_jelly[MAIN_LEN][4] =
320 {
321  "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
322  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
323  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
324  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
325  "<>|"
326 };
327
328 /*** Croatian keyboard layout ***/
329 static const char main_key_HR[MAIN_LEN][4] =
330 {
331  "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
332  "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
333  "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
334  "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
335  "<>"
336 };
337
338 /*** Japanese 106 keyboard layout ***/
339 static const char main_key_JA_jp106[MAIN_LEN][4] =
340 {
341  "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
342  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
343  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
344  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
345  "\\_",
346 };
347
348 /*** Japanese pc98x1 keyboard layout ***/
349 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
350 {
351  "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
352  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
353  "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
354  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
355  "\\_",
356 };
357
358 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
359 static const char main_key_PT_br[MAIN_LEN][4] =
360 {
361  "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
362  "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
363  "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
364  "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
365 };
366
367
368 /*** Layout table. Add your keyboard mappings to this list */
369 static const struct {
370     const char *comment;
371     const UINT layout_cp; /* Code page for this layout */
372     const char (*key)[MAIN_LEN][4];
373     const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
374     const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
375 } main_key_tab[]={
376  {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
377  {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
378  {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
379  {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
380  {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
381  {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
382  {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
383  {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
384  {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
385  {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
386  {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
387  {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
388  {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
389  {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
390  {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
391  {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
392  {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
393  {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
394  {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
395  {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
396  {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
397  {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
398  {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
399  {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
400  {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
401  {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
402  {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
403
404  {NULL, 0, NULL, NULL, NULL} /* sentinel */
405 };
406 static unsigned kbd_layout=0; /* index into above table of layouts */
407
408 /* maybe more of these scancodes should be extended? */
409                 /* extended must be set for ALT_R, CTRL_R,
410                    INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
411                    keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
412                 /* FIXME should we set extended bit for NumLock ? My
413                  * Windows does ... DF */
414                 /* Yes, to distinguish based on scan codes, also
415                    for PrtScn key ... GA */
416
417 static const WORD special_key_vkey[] =
418 {
419     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
420     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
421     0, 0, 0, VK_ESCAPE                                          /* FF18 */
422 };
423 static const WORD special_key_scan[] =
424 {
425     0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0,                      /* FF08 */
426     0,    0,    0, 0x45, 0x46, 0   , 0, 0,                      /* FF10 */
427     0,    0,    0, 0x01                                         /* FF18 */
428 };
429
430 static const WORD cursor_key_vkey[] =
431 {
432     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
433                                        VK_NEXT, VK_END          /* FF50 */
434 };
435 static const WORD cursor_key_scan[] =
436 {
437     0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F      /* FF50 */
438 };
439
440 static const WORD misc_key_vkey[] =
441 {
442     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
443     VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL                    /* FF68 */
444 };
445 static const WORD misc_key_scan[] =
446 {
447     /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0,                 /* FF60 */
448     /*?*/ 0, /*?*/ 0, 0x38, 0x146                               /* FF68 */
449 };
450
451 static const WORD keypad_key_vkey[] =
452 {
453     0, VK_NUMLOCK,                                              /* FF7E */
454     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
455     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
456     0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,                     /* FF90 */
457     VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
458                                  VK_INSERT, VK_DELETE,          /* FF98 */
459     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
460     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
461                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
462     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
463                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
464     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
465 };
466 static const WORD keypad_key_scan[] =
467 {
468     0x138, 0x145,                                               /* FF7E */
469     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
470     0, 0, 0, 0, 0, 0x11C, 0, 0,                                 /* FF88 */
471     0, 0, 0, 0, 0, 0x47, 0x4B, 0x48,                            /* FF90 */
472     0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53,             /* FF98 */
473     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
474     0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135,               /* FFA8 */
475     0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47,             /* FFB0 */
476     0x48, 0x49                                                  /* FFB8 */
477 };
478     
479 static const WORD function_key_vkey[] =
480 {
481     VK_F1, VK_F2,                                               /* FFBE */
482     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
483     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
484 };
485 static const WORD function_key_scan[] =
486 {
487     0x3B, 0x3C,                                                 /* FFBE */
488     0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,             /* FFC0 */
489     0x57, 0x58, 0, 0, 0, 0                                      /* FFC8 */
490 };
491
492 static const WORD modifier_key_vkey[] =
493 {
494     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
495     VK_MENU, VK_MENU, VK_MENU, VK_MENU                         /* FFE7 */
496 };
497 static const WORD modifier_key_scan[] =
498 {
499     0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0,                          /* FFE1 */
500     0x38, 0x138, 0x38, 0x138                                   /* FFE7 */
501 };
502
503 /* Returns the Windows virtual key code associated with the X event <e> */
504 static WORD EVENT_event_to_vkey( XKeyEvent *e)
505 {
506     KeySym keysym;
507
508     TSXLookupString(e, NULL, 0, &keysym, NULL);
509
510     if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF) 
511         && (e->state & NumLockMask)) 
512         /* Only the Keypad keys 0-9 and . send different keysyms
513          * depending on the NumLock state */
514         return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
515
516     return keyc2vkey[e->keycode];
517 }
518
519 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
520
521 /**********************************************************************
522  *              KEYBOARD_GenerateMsg
523  *
524  * Generate Down+Up messages when NumLock or CapsLock is pressed.
525  *
526  * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
527  *
528  */
529 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
530                            DWORD event_time )
531 {
532   BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
533   DWORD up, down;
534
535   if (*State) {
536     /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
537        don't treat it. It's from the same key press. Then the state goes to ON.
538        And from there, a 'release' event will switch off the toggle key. */
539     *State=FALSE;
540     TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
541   } else
542     {
543         down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
544         up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
545         if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
546           {
547             if (Evtype!=KeyPress)
548               {
549                 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
550                 KEYBOARD_SendEvent( vkey, scan, down,
551                                     event_x, event_y, event_time );
552                 KEYBOARD_SendEvent( vkey, scan, up, 
553                                     event_x, event_y, event_time );
554                 *State=FALSE;
555                 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */ 
556               } 
557           }
558         else /* it was OFF */
559           if (Evtype==KeyPress)
560             {
561               TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
562               KEYBOARD_SendEvent( vkey, scan, down,
563                                   event_x, event_y, event_time );
564               KEYBOARD_SendEvent( vkey, scan, up, 
565                                   event_x, event_y, event_time );
566               *State=TRUE; /* Goes to intermediary state before going to ON */
567               pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
568             }
569     }
570 }
571
572 /***********************************************************************
573  *           KEYBOARD_UpdateOneState
574  *
575  * Updates internal state for <vkey>, depending on key <state> under X
576  *
577  */
578 static void KEYBOARD_UpdateOneState ( int vkey, int state )
579 {
580     /* Do something if internal table state != X state for keycode */
581     if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
582     {
583         TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
584               vkey, pKeyStateTable[vkey]);
585
586         /* Fake key being pressed inside wine */
587         KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP, 
588                             0, 0, GetTickCount() );
589
590         TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
591     }
592 }
593
594 /***********************************************************************
595  *           X11DRV_KEYBOARD_UpdateState
596  *
597  * Update modifiers state (Ctrl, Alt, Shift)
598  * when window is activated (called by EVENT_FocusIn in event.c)
599  *
600  * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
601  * from wine to another application and back.
602  * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
603  *  about them)
604  */
605 void X11DRV_KEYBOARD_UpdateState ( void )
606 {
607 /* extract a bit from the char[32] bit suite */
608 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
609
610     char keys_return[32];
611
612     TRACE("called\n");
613     if (!TSXQueryKeymap(display, keys_return)) {
614         ERR("Error getting keymap !");
615         return;
616     }
617
618     /* Adjust the ALT and CONTROL state if any has been changed outside wine */
619     KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
620     KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
621     KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
622 #undef KeyState
623 }
624
625 /***********************************************************************
626  *           X11DRV_KEYBOARD_HandleEvent
627  *
628  * Handle a X key event
629  */
630 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
631 {
632     char Str[24]; 
633     KeySym keysym;
634     WORD vkey = 0, bScan;
635     DWORD dwFlags;
636     static BOOL force_extended = FALSE; /* hack for AltGr translation */
637     int ascii_chars;
638
639     INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
640     INT event_y = (pWnd? pWnd->rectWindow.top  : 0) + event->y;
641     DWORD event_time = event->time - X11DRV_server_startticks;
642
643     /* this allows support for dead keys */
644     if ((event->keycode >> 8) == 0x10)
645         event->keycode=(event->keycode & 0xff);
646
647     ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
648
649     TRACE_(key)("state = %X\n", event->state);
650
651     /* If XKB extensions is used, the state mask for AltGr will used the group
652        index instead of the modifier mask. The group index is set in bits
653        13-14 of the state field in the XKeyEvent structure. So if AltGr is
654        pressed, look if the group index is diferent than 0. From XKB
655        extension documentation, the group index should for AltGr should 
656        be 2 (event->state = 0x2000). It's probably better to not assume a
657        predefined group index and find it dynamically
658
659        Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
660     if ( AltGrState && (event->state & 0x6000) )
661         AltGrMask = event->state & 0x6000;
662
663     if (keysym == XK_Mode_switch)
664         {
665         TRACE_(key)("Alt Gr key event received\n");
666         event->keycode = kcControl; /* Simulate Control */
667         X11DRV_KEYBOARD_HandleEvent( pWnd, event );
668
669         event->keycode = kcAlt; /* Simulate Alt */
670         force_extended = TRUE;
671         X11DRV_KEYBOARD_HandleEvent( pWnd, event );
672         force_extended = FALSE;
673     
674     /* Here we save the pressed/released state of the AltGr key, to be able to 
675        identify the group index associated with AltGr on the next key pressed *
676        see comment above. */
677     AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
678     
679         return;
680         }
681
682     Str[ascii_chars] = '\0';
683     if (TRACE_ON(key)){
684         char    *ksname;
685
686         ksname = TSXKeysymToString(keysym);
687         if (!ksname)
688           ksname = "No Name";
689         TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n", 
690                     (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
691                     keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
692     }
693
694     vkey = EVENT_event_to_vkey(event);
695     if (force_extended) vkey |= 0x100;
696
697     TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
698                 event->keycode, vkey);
699
700    if (vkey)
701    {
702     switch (vkey & 0xff)
703     {
704     case VK_NUMLOCK:    
705       KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
706                             event_time );
707       break;
708     case VK_CAPITAL:
709       TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
710       KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
711                             event_time ); 
712       TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
713       break;
714     default:
715         /* Adjust the NUMLOCK state if it has been changed outside wine */
716         if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
717           { 
718             TRACE("Adjusting NumLock state. \n");
719             KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
720                                   event_time );
721             KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
722                                   event_time );
723           }
724         /* Adjust the CAPSLOCK state if it has been changed outside wine */
725         if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
726           {
727               TRACE("Adjusting Caps Lock state.\n");
728             KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
729                                   event_time );
730             KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
731                                   event_time );
732           }
733         /* Not Num nor Caps : end of intermediary states for both. */
734         NumState = FALSE;
735         CapsState = FALSE;
736
737         bScan = keyc2scan[event->keycode] & 0xFF;
738         TRACE_(key)("bScan = 0x%02x.\n", bScan);
739
740         dwFlags = 0;
741         if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
742         if ( vkey & 0x100 )              dwFlags |= KEYEVENTF_EXTENDEDKEY;
743         if ( force_extended )            dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
744
745         KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags, 
746                             event_x, event_y, event_time );
747     }
748    }
749 }
750
751 /**********************************************************************
752  *              X11DRV_KEYBOARD_DetectLayout
753  *
754  * Called from X11DRV_InitKeyboard
755  *  This routine walks through the defined keyboard layouts and selects
756  *  whichever matches most closely.
757  */
758 static void
759 X11DRV_KEYBOARD_DetectLayout (void)
760 {
761   unsigned current, match, mismatch, seq;
762   int score, keyc, i, key, pkey, ok, syms;
763   KeySym keysym;
764   const char (*lkey)[MAIN_LEN][4];
765   unsigned max_seq = 0;
766   int max_score = 0, ismatch = 0;
767   char ckey[4] =
768   {0, 0, 0, 0};
769
770   syms = keysyms_per_keycode;
771   if (syms > 4) {
772     WARN("%d keysyms per keycode not supported, set to 4", syms);
773     syms = 4;
774   }
775   for (current = 0; main_key_tab[current].comment; current++) {
776     TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
777     match = 0;
778     mismatch = 0;
779     score = 0;
780     seq = 0;
781     lkey = main_key_tab[current].key;
782     pkey = -1;
783     for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
784       /* get data for keycode from X server */
785       for (i = 0; i < syms; i++) {
786         keysym = TSXKeycodeToKeysym (display, keyc, i);
787         /* Allow both one-byte and two-byte national keysyms */
788         if ((keysym < 0x800) && (keysym != ' '))
789           ckey[i] = keysym & 0xFF;
790         else {
791           ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
792         }
793       }
794       if (ckey[0]) {
795         /* search for a match in layout table */
796         /* right now, we just find an absolute match for defined positions */
797         /* (undefined positions are ignored, so if it's defined as "3#" in */
798         /* the table, it's okay that the X server has "3#£", for example) */
799         /* however, the score will be higher for longer matches */
800         for (key = 0; key < MAIN_LEN; key++) {
801           for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
802             if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
803               ok++;
804             if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
805               ok = -1;
806           }
807           if (ok > 0) {
808             score += ok;
809             break;
810           }
811         }
812         /* count the matches and mismatches */
813         if (ok > 0) {
814           match++;
815           /* and how much the keycode order matches */
816           if (key > pkey) seq++;
817           pkey = key;
818         } else {
819           TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
820                  ckey[0]);
821           mismatch++;
822           score -= syms;
823         }
824       }
825     }
826     TRACE("matches=%d, mismatches=%d, score=%d\n",
827            match, mismatch, score);
828     if ((score > max_score) ||
829         ((score == max_score) && (seq > max_seq))) {
830       /* best match so far */
831       kbd_layout = current;
832       max_score = score;
833       max_seq = seq;
834       ismatch = !mismatch;
835     }
836   }
837   /* we're done, report results if necessary */
838   if (!ismatch) {
839     FIXME(
840            "Your keyboard layout was not found!\n"
841            "Instead of using closest match (%s) for scancode mapping.\n"
842            "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
843            "to us for inclusion into future Wine releases.\n"
844            "See documentation/keyboard for more information.\n",
845            main_key_tab[kbd_layout].comment);
846   }
847
848   TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
849 }
850
851 /**********************************************************************
852  *              X11DRV_InitKeyboard
853  */
854 void X11DRV_InitKeyboard(void)
855 {
856     KeySym *ksp;
857     XModifierKeymap *mmp;
858     KeySym keysym;
859     KeyCode *kcp;
860     XKeyEvent e2;
861     WORD scan, vkey, OEMvkey;
862     int keyc, i, keyn, syms;
863     char ckey[4]={0,0,0,0};
864     const char (*lkey)[MAIN_LEN][4];
865
866     TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
867     ksp = TSXGetKeyboardMapping(display, min_keycode,
868                               max_keycode + 1 - min_keycode, &keysyms_per_keycode);
869     /* We are only interested in keysyms_per_keycode.
870        There is no need to hold a local copy of the keysyms table */
871     TSXFree(ksp);
872     mmp = TSXGetModifierMapping(display);
873     kcp = mmp->modifiermap;
874     for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
875     {
876         int j;
877         
878         for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
879             if (*kcp)
880             {
881                 int k;
882                 
883                 for (k = 0; k < keysyms_per_keycode; k += 1)
884                     if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
885                     {
886                         AltGrMask = 1 << i;
887                         TRACE_(key)("AltGrMask is %x\n", AltGrMask);
888                     }
889                     else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
890                     {
891                         NumLockMask = 1 << i;
892                         TRACE_(key)("NumLockMask is %x\n", NumLockMask);
893                     }
894             }
895     }
896     TSXFreeModifiermap(mmp);
897
898     /* Detect the keyboard layout */
899     X11DRV_KEYBOARD_DetectLayout();
900     lkey = main_key_tab[kbd_layout].key;
901     syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
902
903     /* Now build two conversion arrays :
904      * keycode -> vkey + scancode + extended
905      * vkey + extended -> keycode */
906
907     e2.display = display;
908     e2.state = 0;
909
910     OEMvkey = VK_OEM_7; /* next is available.  */
911     for (keyc = min_keycode; keyc <= max_keycode; keyc++)
912     {
913         e2.keycode = (KeyCode)keyc;
914         TSXLookupString(&e2, NULL, 0, &keysym, NULL);
915         vkey = 0; scan = 0;
916         if (keysym)  /* otherwise, keycode not used */
917         {
918             if ((keysym >> 8) == 0xFF)         /* non-character key */
919             {
920                 int key = keysym & 0xff;
921                 
922                 if (key >= 0x08 && key <= 0x1B) {        /* special key */
923                     vkey = special_key_vkey[key - 0x08];
924                     scan = special_key_scan[key - 0x08];
925                 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
926                     vkey = cursor_key_vkey[key - 0x50];
927                     scan = cursor_key_scan[key - 0x50];
928                 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
929                     vkey = misc_key_vkey[key - 0x60];
930                     scan = misc_key_scan[key - 0x60];
931                 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
932                     vkey = keypad_key_vkey[key - 0x7E];
933                     scan = keypad_key_scan[key - 0x7E];
934                 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
935                     vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
936                     scan = function_key_scan[key - 0xBE];
937                 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
938                     vkey = modifier_key_vkey[key - 0xE1];
939                     scan = modifier_key_scan[key - 0xE1];
940                 } else if (key == 0xFF) {                /* DEL key */
941                     vkey = VK_DELETE;
942                     scan = 0x153;
943                 }
944                 /* set extended bit when necessary */
945                 if (scan & 0x100) vkey |= 0x100;
946             } else if (keysym == 0x20) {                 /* Spacebar */
947                 vkey = VK_SPACE;
948                 scan = 0x39;
949             } else {
950               /* we seem to need to search the layout-dependent scancodes */
951               int maxlen=0,maxval=-1,ok;
952               for (i=0; i<syms; i++) {
953                 keysym = TSXKeycodeToKeysym(display, keyc, i);
954                 if ((keysym<0x800) && (keysym!=' ')) {
955                   ckey[i] = keysym & 0xFF;
956                 } else {
957                   ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
958                 }
959               }
960               /* find key with longest match streak */
961               for (keyn=0; keyn<MAIN_LEN; keyn++) {
962                 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
963                   if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
964                 if (ok||(i>maxlen)) {
965                   maxlen=i; maxval=keyn;
966                 }
967                 if (ok) break;
968               }
969               if (maxval>=0) {
970                 /* got it */
971                 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
972                 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
973                 scan = (*lscan)[maxval];
974                 vkey = (*lvkey)[maxval];
975               }
976             }
977
978             /* find a suitable layout-dependent VK code */
979             /* (most Winelib apps ought to be able to work without layout tables!) */
980             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
981             {
982                 keysym = TSXLookupKeysym(&e2, i);
983                 if ((keysym >= VK_0 && keysym <= VK_9)
984                     || (keysym >= VK_A && keysym <= VK_Z)) {
985                     vkey = keysym;
986                 }
987             }
988
989             for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
990             {
991                 keysym = TSXLookupKeysym(&e2, i);
992                 switch (keysym)
993                 {
994                 case ';':             vkey = VK_OEM_1; break;
995                 case '/':             vkey = VK_OEM_2; break;
996                 case '`':             vkey = VK_OEM_3; break;
997                 case '[':             vkey = VK_OEM_4; break;
998                 case '\\':            vkey = VK_OEM_5; break;
999                 case ']':             vkey = VK_OEM_6; break;
1000                 case '\'':            vkey = VK_OEM_7; break;
1001                 case ',':             vkey = VK_OEM_COMMA; break;
1002                 case '.':             vkey = VK_OEM_PERIOD; break;
1003                 case '-':             vkey = VK_OEM_MINUS; break;
1004                 case '+':             vkey = VK_OEM_PLUS; break;
1005                 }
1006             }
1007
1008             if (!vkey)
1009             {
1010                 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1011                  * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1012                 switch (++OEMvkey)
1013                 {
1014                 case 0xc1 : OEMvkey=0xdb; break;
1015                 case 0xe5 : OEMvkey=0xe9; break;
1016                 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1017                 }
1018
1019                 vkey = OEMvkey;
1020                   
1021                 if (TRACE_ON(keyboard))
1022                 {
1023                     TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1024                                      OEMvkey, e2.keycode);
1025                     TRACE("(");
1026                     for (i = 0; i < keysyms_per_keycode; i += 1)
1027                     {
1028                         char    *ksname;
1029                         
1030                         keysym = TSXLookupKeysym(&e2, i);
1031                         ksname = TSXKeysymToString(keysym);
1032                         if (!ksname)
1033                             ksname = "NoSymbol";
1034                         DPRINTF( "%lX (%s) ", keysym, ksname);
1035                     }
1036                     DPRINTF(")\n");
1037                 }
1038             }
1039         }
1040         keyc2vkey[e2.keycode] = vkey;
1041         keyc2scan[e2.keycode] = scan;
1042     } /* for */
1043
1044     /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1045     for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1046       if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1047         char *ksname;
1048         keysym = TSXKeycodeToKeysym(display, keyc, 0);
1049         ksname = TSXKeysymToString(keysym);
1050         if (!ksname) ksname = "NoSymbol";
1051
1052         /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1053
1054         TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1055         keyc2scan[keyc]=scan++;
1056       }
1057
1058     /* Now store one keycode for each modifier. Used to simulate keypresses. */
1059     kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1060     kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1061     if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1062     kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1063     kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1064     kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1065 }
1066
1067 /***********************************************************************
1068  *              X11DRV_VkKeyScan
1069  */
1070 WORD X11DRV_VkKeyScan(CHAR cChar)
1071 {
1072         KeyCode keycode;
1073         KeySym keysym;          
1074         int i,index;
1075         int highbyte=0;
1076
1077         /* char->keysym (same for ANSI chars) */
1078         keysym=(unsigned char) cChar;/* (!) cChar is signed */
1079         if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1080         
1081         keycode = TSXKeysymToKeycode(display, keysym);  /* keysym -> keycode */
1082         if (!keycode)
1083         { /* It didn't work ... let's try with deadchar code. */
1084           keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1085         }
1086
1087         TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1088               cChar,keysym,keysym,keycode);
1089         
1090         if (keycode)
1091           {
1092             for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1093               if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1094             switch (index) {
1095             case -1 :
1096               WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1097             case 0 : break;
1098             case 1 : highbyte = 0x0100; break;
1099             case 2 : highbyte = 0x0600; break;
1100             case 3 : highbyte = 0x0700; break;
1101             default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1102             }
1103             /*
1104               index : 0     adds 0x0000
1105               index : 1     adds 0x0100 (shift)
1106               index : ?     adds 0x0200 (ctrl)
1107               index : 2     adds 0x0600 (ctrl+alt)
1108               index : 3     adds 0x0700 (ctrl+alt+shift)
1109              */
1110           }
1111         TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1112         return keyc2vkey[keycode]+highbyte;   /* keycode -> (keyc2vkey) vkey */
1113 }
1114
1115 /***********************************************************************
1116  *              X11DRV_MapVirtualKey
1117  */
1118 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1119 {
1120 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1121
1122         TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1123         switch(wMapType) {
1124                 case 0: { /* vkey-code to scan-code */
1125                         /* let's do vkey -> keycode -> scan */
1126                         int keyc;
1127                         for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1128                                 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1129                                         returnMVK (keyc2scan[keyc] & 0xFF);
1130                         TRACE("returning no scan-code.\n");
1131                         return 0; }
1132
1133                 case 1: { /* scan-code to vkey-code */
1134                         /* let's do scan -> keycode -> vkey */
1135                         int keyc;
1136                         for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1137                                 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1138                                         returnMVK (keyc2vkey[keyc] & 0xFF);
1139                         TRACE("returning no vkey-code.\n");
1140                         return 0; }
1141
1142                 case 2: { /* vkey-code to unshifted ANSI code */
1143                         /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1144                         /* My Windows returns 'A'. */
1145                         /* let's do vkey -> keycode -> (XLookupString) ansi char */
1146                         XKeyEvent e;
1147                         KeySym keysym;
1148                         int keyc;
1149                         char s[2];
1150                         e.display = display;
1151                         e.state = 0; /* unshifted */
1152
1153                         e.keycode = 0;
1154                         /* We exit on the first keycode found, to speed up the thing. */
1155                         for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1156                         { /* Find a keycode that could have generated this virtual key */
1157                             if  ((keyc2vkey[keyc] & 0xFF) == wCode)
1158                             { /* We filter the extended bit, we don't know it */
1159                                 e.keycode = keyc; /* Store it temporarily */
1160                                 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1161                                     e.keycode = 0; /* Wrong one (ex: because of the NumLock
1162                                          state), so set it to 0, we'll find another one */
1163                                 }
1164                             }
1165                         }
1166
1167                         if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1168                           e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1169           
1170                         if (wCode==VK_DECIMAL)
1171                           e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1172
1173                         if (!e.keycode)
1174                         {
1175                           WARN("Unknown virtual key %X !!! \n", wCode);
1176                           return 0; /* whatever */
1177                         }
1178                         TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1179
1180                         if (TSXLookupString(&e, s, 2, &keysym, NULL))
1181                           returnMVK (*s);
1182                         
1183                         TRACE("returning no ANSI.\n");
1184                         return 0;
1185                         }
1186
1187                 case 3:   /* **NT only** scan-code to vkey-code but distinguish between  */
1188                           /*             left and right  */
1189                           FIXME(" stub for NT\n");
1190                           return 0;
1191
1192                 default: /* reserved */
1193                         WARN("Unknown wMapType %d !\n", wMapType);
1194                         return 0;       
1195         }
1196         return 0;
1197 }
1198
1199 /***********************************************************************
1200  *              X11DRV_GetKeyNameText
1201  */
1202 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1203 {
1204   int vkey, ansi, scanCode;
1205   KeyCode keyc;
1206   KeySym keys;
1207   char *name;
1208         
1209   scanCode = lParam >> 16;
1210   scanCode &= 0x1ff;  /* keep "extended-key" flag with code */
1211
1212   /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1213   vkey = X11DRV_MapVirtualKey(scanCode, 1);
1214
1215   /*  handle "don't care" bit (0x02000000) */
1216   if (!(lParam & 0x02000000)) {
1217     switch (vkey) {
1218          case VK_LSHIFT:
1219          case VK_RSHIFT:
1220                           vkey = VK_SHIFT;
1221                           break;
1222        case VK_LCONTROL:
1223        case VK_RCONTROL:
1224                           vkey = VK_CONTROL;
1225                           break;
1226           case VK_LMENU:
1227           case VK_RMENU:
1228                           vkey = VK_MENU;
1229                           break;
1230                default:
1231                           break;
1232     }
1233   }
1234
1235   ansi = X11DRV_MapVirtualKey(vkey, 2);
1236   TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1237
1238   /* first get the name of the "regular" keys which is the Upper case
1239      value of the keycap imprint.                                     */
1240   if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1241        (scanCode != 0x137) &&   /* PrtScn   */
1242        (scanCode != 0x135) &&   /* numpad / */
1243        (scanCode != 0x37 ) &&   /* numpad * */
1244        (scanCode != 0x4a ) &&   /* numpad - */
1245        (scanCode != 0x4e ) )    /* numpad + */
1246       {
1247         if ((nSize >= 2) && lpBuffer)
1248         {
1249         *lpBuffer = toupper((char)ansi);
1250           *(lpBuffer+1) = 0;
1251           return 1;
1252         } 
1253      else
1254         return 0;
1255   }
1256
1257   /* FIXME: horrible hack to fix function keys. Windows reports scancode
1258             without "extended-key" flag. However Wine generates scancode
1259             *with* "extended-key" flag. Seems to occur *only* for the
1260             function keys. Soooo.. We will leave the table alone and
1261             fudge the lookup here till the other part is found and fixed!!! */
1262
1263   if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1264        (scanCode == 0x157) || (scanCode == 0x158))
1265     scanCode &= 0xff;   /* remove "extended-key" flag for Fx keys */
1266
1267   /* let's do scancode -> keycode -> keysym -> String */
1268
1269   for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1270       if ((keyc2scan[keyc]) == scanCode)
1271          break;
1272   if (keyc <= max_keycode)
1273   {
1274       keys = TSXKeycodeToKeysym(display, keyc, 0);
1275       name = TSXKeysymToString(keys);
1276       TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1277             scanCode, keyc, (int)keys, name);
1278       if (lpBuffer && nSize && name)
1279       {
1280           lstrcpynA(lpBuffer, name, nSize);
1281           return 1;
1282       }
1283   }
1284
1285   /* Finally issue FIXME for unknown keys   */
1286
1287   FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1288   if (lpBuffer && nSize)
1289     *lpBuffer = 0;
1290   return 0;
1291 }
1292
1293 /***********************************************************************
1294  *              X11DRV_KEYBOARD_MapDeadKeysym
1295  */
1296 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1297 {
1298         switch (keysym)
1299             {
1300         /* symbolic ASCII is the same as defined in rfc1345 */
1301 #ifdef XK_dead_tilde
1302             case XK_dead_tilde :
1303 #endif
1304             case 0x1000FE7E : /* Xfree's XK_Dtilde */
1305                 return '~';     /* '? */
1306 #ifdef XK_dead_acute
1307             case XK_dead_acute :
1308 #endif
1309             case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1310                 return 0xb4;    /* '' */
1311 #ifdef XK_dead_circumflex
1312             case XK_dead_circumflex:
1313 #endif
1314             case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1315                 return '^';     /* '> */
1316 #ifdef XK_dead_grave
1317             case XK_dead_grave :
1318 #endif
1319             case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1320                 return '`';     /* '! */
1321 #ifdef XK_dead_diaeresis
1322             case XK_dead_diaeresis :
1323 #endif
1324             case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1325                 return 0xa8;    /* ': */
1326 #ifdef XK_dead_cedilla
1327             case XK_dead_cedilla :
1328                 return 0xb8;    /* ', */
1329 #endif
1330 #ifdef XK_dead_macron
1331             case XK_dead_macron :
1332                 return '-';     /* 'm isn't defined on iso-8859-x */
1333 #endif
1334 #ifdef XK_dead_breve
1335             case XK_dead_breve :
1336                 return 0xa2;    /* '( */
1337 #endif
1338 #ifdef XK_dead_abovedot
1339             case XK_dead_abovedot :
1340                 return 0xff;    /* '. */
1341 #endif
1342 #ifdef XK_dead_abovering
1343             case XK_dead_abovering :
1344                 return '0';     /* '0 isn't defined on iso-8859-x */
1345 #endif
1346 #ifdef XK_dead_doubleacute
1347             case XK_dead_doubleacute :
1348                 return 0xbd;    /* '" */
1349 #endif
1350 #ifdef XK_dead_caron
1351             case XK_dead_caron :
1352                 return 0xb7;    /* '< */
1353 #endif
1354 #ifdef XK_dead_ogonek
1355             case XK_dead_ogonek :
1356                 return 0xb2;    /* '; */
1357 #endif
1358 /* FIXME: I don't know this three.
1359             case XK_dead_iota :
1360                 return 'i';      
1361             case XK_dead_voiced_sound :
1362                 return 'v';
1363             case XK_dead_semivoiced_sound :
1364                 return 's';
1365 */
1366             }
1367         TRACE("no character for dead keysym 0x%08lx\n",keysym);
1368         return 0;
1369 }
1370
1371 /***********************************************************************
1372  *              X11DRV_ToUnicode
1373  *
1374  * The ToUnicode function translates the specified virtual-key code and keyboard
1375  * state to the corresponding Windows character or characters.
1376  *
1377  * If the specified key is a dead key, the return value is negative. Otherwise,
1378  * it is one of the following values:
1379  * Value        Meaning
1380  * 0    The specified virtual key has no translation for the current state of the keyboard.
1381  * 1    One Windows character was copied to the buffer.
1382  * 2    Two characters were copied to the buffer. This usually happens when a
1383  *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
1384  *      be composed with the specified virtual key to form a single character.
1385  *
1386  * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1387  *
1388  */
1389 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1390                      LPWSTR bufW, int bufW_size, UINT flags)
1391 {
1392     XKeyEvent e;
1393     KeySym keysym;
1394     INT ret;
1395     int keyc;
1396     BYTE lpChar[2];
1397
1398     if (scanCode==0) {
1399         /* This happens when doing Alt+letter : a fake 'down arrow' key press
1400            event is generated by windows. Just ignore it. */
1401         TRACE("scanCode=0, doing nothing\n");
1402         return 0;
1403     }
1404     if (scanCode & 0x8000)
1405     {
1406         TRACE("Key UP, doing nothing\n" );
1407         return 0;
1408     }
1409     e.display = display;
1410     e.keycode = 0;
1411     e.state = 0;
1412     if (lpKeyState[VK_SHIFT] & 0x80)
1413         e.state |= ShiftMask;
1414     if (lpKeyState[VK_CAPITAL] & 0x01)
1415         e.state |= LockMask;
1416     if (lpKeyState[VK_CONTROL] & 0x80)
1417     {
1418         if (lpKeyState[VK_MENU] & 0x80)
1419             e.state |= AltGrMask;
1420         else
1421             e.state |= ControlMask;
1422     }
1423     if (lpKeyState[VK_NUMLOCK] & 0x01)
1424         e.state |= NumLockMask;
1425     TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1426                 virtKey, scanCode, e.state);
1427     /* We exit on the first keycode found, to speed up the thing. */
1428     for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1429       { /* Find a keycode that could have generated this virtual key */
1430           if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
1431           { /* We filter the extended bit, we don't know it */
1432               e.keycode = keyc; /* Store it temporarily */
1433               if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1434                   e.keycode = 0; /* Wrong one (ex: because of the NumLock
1435                          state), so set it to 0, we'll find another one */
1436               }
1437           }
1438       }
1439
1440     if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1441         e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1442           
1443     if (virtKey==VK_DECIMAL)
1444         e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1445
1446     if (!e.keycode)
1447       {
1448         WARN("Unknown virtual key %X !!! \n",virtKey);
1449         return virtKey; /* whatever */
1450       }
1451     else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1452
1453     ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1454     if (ret == 0)
1455         {
1456         BYTE dead_char;
1457
1458         dead_char = KEYBOARD_MapDeadKeysym(keysym);
1459         if (dead_char)
1460             {
1461             MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1462             ret = -1;
1463             }
1464         else
1465             {
1466             char        *ksname;
1467
1468             ksname = TSXKeysymToString(keysym);
1469             if (!ksname)
1470                 ksname = "No Name";
1471             if ((keysym >> 8) != 0xff)
1472                 {
1473                 ERR("Please report: no char for keysym %04lX (%s) :\n",
1474                     keysym, ksname);
1475                 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1476                     virtKey, scanCode, e.keycode, e.state);
1477                 }
1478             }
1479         }
1480     else {  /* ret != 0 */
1481         /* We have a special case to handle : Shift + arrow, shift + home, ...
1482            X returns a char for it, but Windows doesn't. Let's eat it. */
1483         if (!(lpKeyState[VK_NUMLOCK] & 0x01)  /* NumLock is off */
1484             && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1485             && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1486         {
1487             *(char*)lpChar = 0;
1488             ret = 0;
1489         }
1490         
1491         /* We have another special case for delete key (XK_Delete) on an
1492          extended keyboard. X returns a char for it, but Windows doesn't */
1493         if (keysym == XK_Delete)
1494         {
1495             *(char*)lpChar = 0;
1496             ret = 0;
1497         }
1498
1499         /* perform translation to unicode */
1500         if(ret)
1501         {
1502             TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1503                 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1504             ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1505         }
1506     }
1507
1508     TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1509                 ret, bufW ? bufW[1] : 0, bufW ? "" : "(no buffer)");
1510     return ret;
1511 }
1512
1513 /***********************************************************************
1514  *              X11DRV_GetBeepActive
1515  */
1516 BOOL X11DRV_GetBeepActive(void)
1517 {
1518   XKeyboardState  keyboard_state;
1519
1520   TSXGetKeyboardControl(display, &keyboard_state);
1521
1522   return keyboard_state.bell_percent != 0;
1523 }
1524
1525 /***********************************************************************
1526  *              X11DRV_SetBeepActive
1527  */
1528 void X11DRV_SetBeepActive(BOOL bActivate)
1529 {
1530   XKeyboardControl keyboard_value;
1531   
1532   if(bActivate)
1533     keyboard_value.bell_percent = -1;
1534   else
1535     keyboard_value.bell_percent = 0;
1536   
1537   TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1538 }
1539
1540 /***********************************************************************
1541  *              X11DRV_Beep
1542  */
1543 void X11DRV_Beep(void)
1544 {
1545   TSXBell(display, 0);
1546 }
1547
1548 /***********************************************************************
1549  *              X11DRV_GetDIState
1550  */
1551 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1552 {
1553   if (len==256) {
1554     int keyc,vkey;
1555     
1556     memset(ptr,0,256);
1557     for (keyc=min_keycode;keyc<max_keycode;keyc++)
1558       {
1559         /* X keycode to virtual key */
1560         vkey = keyc2vkey[keyc] & 0xFF;
1561         /* The windows scancode is keyc-min_keycode */
1562         if (InputKeyStateTable[vkey]&0x80) {
1563           ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1564           ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1565         }
1566       }
1567     return TRUE;
1568   }
1569   WARN("whoops, got len %ld?\n", len);
1570   return TRUE;
1571 }
1572
1573 /***********************************************************************
1574  *              X11DRV_GetDIData
1575  */
1576 BOOL X11DRV_GetDIData(
1577   BYTE *keystate,
1578   DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1579   LPDWORD entries, DWORD flags)
1580 {
1581   int keyc,n,vkey,xentries;
1582     
1583   /* FIXME !!! */
1584   
1585   if (entries)
1586     xentries = *entries; 
1587   else
1588     xentries = 1;
1589   
1590   n = 0;
1591   
1592   for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1593     {
1594       /* X keycode to virtual key */
1595       vkey = keyc2vkey[keyc] & 0xFF;
1596       if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1597         continue;
1598       if (dod) {
1599         /* add an entry */
1600         dod[n].dwOfs            = keyc-min_keycode; /* scancode */
1601         dod[n].dwData           = InputKeyStateTable[vkey]&0x80;
1602         dod[n].dwTimeStamp      = 0; /* umm */
1603         dod[n].dwSequence       = 0; /* umm */
1604         n++;
1605       }
1606       if (!(flags & DIGDD_PEEK))
1607         keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1608       
1609     }
1610   
1611   if (n) TRACE_(dinput)("%d entries\n",n);
1612   *entries = n;
1613
1614   return TRUE;
1615 }
1616
1617 /***********************************************************************
1618  *              X11DRV_GetKeyboardConfig
1619  */
1620 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1621   XKeyboardState   xks;
1622
1623   /* For the moment, only get the auto-repeat mode */
1624   TSXGetKeyboardControl(display, &xks);
1625   cfg->auto_repeat = xks.global_auto_repeat;
1626 }
1627
1628 /***********************************************************************
1629  *              X11DRV_SetKeyboardConfig
1630  */
1631 extern void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1632   XKeyboardControl xkc;
1633   unsigned long X_mask = 0;
1634   
1635   if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1636     X_mask |= KBAutoRepeatMode;
1637     xkc.auto_repeat_mode = cfg->auto_repeat;
1638   }
1639   if (X_mask)
1640     TSXChangeKeyboardControl(display, X_mask, &xkc);
1641 }
1642