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