Use the X state instead of the VK key state to check for eatable
[wine/dcerpc.git] / windows / x11drv / keyboard.c
blob6e73f22134055cdfe1f9c5e5d7312618f4057553
1 /*
2 * X11 keyboard driver
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
12 #include "config.h"
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
21 #include <ctype.h>
22 #include <string.h>
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"
36 DEFAULT_DEBUG_CHANNEL(keyboard);
37 DECLARE_DEBUG_CHANNEL(key);
38 DECLARE_DEBUG_CHANNEL(dinput);
40 extern BYTE InputKeyStateTable[256];
42 extern LPBYTE pKeyStateTable;
44 int min_keycode, max_keycode, keysyms_per_keycode;
45 WORD keyc2vkey[256], keyc2scan[256];
47 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
48 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
50 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
52 /* Keyboard translation tables */
53 #define MAIN_LEN 48
54 static const WORD main_key_scan_qwerty[MAIN_LEN] =
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) */
64 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
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) */
74 static const WORD main_key_vkey_azerty[MAIN_LEN] =
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) */
84 /* FIXME: add other layouts, such as DVORAK and German QWERTZ */
86 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
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! */
99 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
100 static const char main_key_US[MAIN_LEN][4] =
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",",<",".>","/?"
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] =
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 */
119 /*** British keyboard layout */
120 static const char main_key_UK[MAIN_LEN][4] =
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 "\\|"
129 /*** French keyboard layout (contributed by Eric Pouech) */
130 static const char main_key_FR[MAIN_LEN][4] =
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 "<>"
139 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
140 static const char main_key_IS[MAIN_LEN][4] =
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 "<>|"
149 /*** German keyboard layout (contributed by Ulrich Weigand) */
150 static const char main_key_DE[MAIN_LEN][4] =
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 "<>"
159 /*** German keyboard layout without dead keys */
160 static const char main_key_DE_nodead[MAIN_LEN][4] =
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 "<>"
169 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
170 static const char main_key_SG[MAIN_LEN][4] =
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 "<>\\"
179 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
180 static const char main_key_SF[MAIN_LEN][4] =
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 "<>\\"
189 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
190 static const char main_key_NO[MAIN_LEN][4] =
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 "<>"
199 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
200 static const char main_key_DA[MAIN_LEN][4] =
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 "<>\\"
209 /*** Swedish keyboard layout (contributed by Peter Bortas) */
210 static const char main_key_SE[MAIN_LEN][4] =
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 "<>|"
219 /*** Canadian French keyboard layout */
220 static const char main_key_CF[MAIN_LEN][4] =
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 "«»°"
229 /*** Portuguese keyboard layout */
230 static const char main_key_PT[MAIN_LEN][4] =
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 "<>"
239 /*** Italian keyboard layout */
240 static const char main_key_IT[MAIN_LEN][4] =
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 "<>|"
249 /*** Finnish keyboard layout */
250 static const char main_key_FI[MAIN_LEN][4] =
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 "<>|"
259 /*** Russian keyboard layout (contributed by Pavel Roskin) */
260 static const char main_key_RU[MAIN_LEN][4] =
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Øø",",<Ââ",".>Àà","/?"
268 /*** Russian keyboard layout KOI8-R */
269 static const char main_key_RU_koi8r[MAIN_LEN][4] =
271 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
272 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
273 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
274 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
275 "<>" /* the phantom key */
278 /*** Spanish keyboard layout (contributed by José Marcos López) */
279 static const char main_key_ES[MAIN_LEN][4] =
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 "<>"
288 /*** Belgian keyboard layout ***/
289 static const char main_key_BE[MAIN_LEN][4] =
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 "<>\\"
298 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
299 static const char main_key_HU[MAIN_LEN][4] =
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 "íÍ<"
308 /*** Polish (programmer's) keyboard layout ***/
309 static const char main_key_PL[MAIN_LEN][4] =
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 "<>|"
318 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
319 static const char main_key_HR_jelly[MAIN_LEN][4] =
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 "<>|"
328 /*** Croatian keyboard layout ***/
329 static const char main_key_HR[MAIN_LEN][4] =
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 "<>"
338 /*** Japanese 106 keyboard layout ***/
339 static const char main_key_JA_jp106[MAIN_LEN][4] =
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 "\\_",
348 /*** Japanese pc98x1 keyboard layout ***/
349 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
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 "\\_",
358 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
359 static const char main_key_PT_br[MAIN_LEN][4] =
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",",<",".>","/?"
367 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
368 - dead_abovering replaced with degree - no symbol in iso8859-2
369 - brokenbar replaced with bar */
370 static const char main_key_SK[MAIN_LEN][4] =
372 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0)","=%","",
373 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/÷","ä(×",
374 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","ò)¤",
375 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
376 "<>\\|"
379 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
380 static const char main_key_SK_prog[MAIN_LEN][4] =
382 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
383 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
384 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
385 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
386 "<>"
389 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
390 static const char main_key_CS[MAIN_LEN][4] =
392 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
393 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
394 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
395 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
396 "<>\\|"
399 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
400 static const char main_key_LA[MAIN_LEN][4] =
402 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
403 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
404 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
405 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
406 "<>"
409 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
410 static const char main_key_LT_B[MAIN_LEN][4] =
412 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
413 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
414 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
415 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
418 /*** Layout table. Add your keyboard mappings to this list */
419 static const struct {
420 const char *comment;
421 const UINT layout_cp; /* Code page for this layout */
422 const char (*key)[MAIN_LEN][4];
423 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
424 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
425 } main_key_tab[]={
426 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
427 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
428 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
429 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
430 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
431 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
432 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
433 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
434 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
435 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
436 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
437 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
438 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
439 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
440 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
441 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
442 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
443 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
444 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
445 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
446 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
447 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
448 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
449 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
450 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
451 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
452 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
453 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
454 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
455 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
456 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
457 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
459 {NULL, 0, NULL, NULL, NULL} /* sentinel */
461 static unsigned kbd_layout=0; /* index into above table of layouts */
463 /* maybe more of these scancodes should be extended? */
464 /* extended must be set for ALT_R, CTRL_R,
465 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
466 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
467 /* FIXME should we set extended bit for NumLock ? My
468 * Windows does ... DF */
469 /* Yes, to distinguish based on scan codes, also
470 for PrtScn key ... GA */
472 static const WORD special_key_vkey[] =
474 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
475 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
476 0, 0, 0, VK_ESCAPE /* FF18 */
478 static const WORD special_key_scan[] =
480 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
481 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
482 0, 0, 0, 0x01 /* FF18 */
485 static const WORD cursor_key_vkey[] =
487 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
488 VK_NEXT, VK_END /* FF50 */
490 static const WORD cursor_key_scan[] =
492 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
495 static const WORD misc_key_vkey[] =
497 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
498 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
500 static const WORD misc_key_scan[] =
502 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
503 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
506 static const WORD keypad_key_vkey[] =
508 0, VK_NUMLOCK, /* FF7E */
509 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
510 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
511 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
512 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
513 VK_INSERT, VK_DELETE, /* FF98 */
514 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
515 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
516 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
517 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
518 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
519 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
521 static const WORD keypad_key_scan[] =
523 0x138, 0x145, /* FF7E */
524 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
525 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
526 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
527 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
528 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
529 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
530 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
531 0x48, 0x49 /* FFB8 */
534 static const WORD function_key_vkey[] =
536 VK_F1, VK_F2, /* FFBE */
537 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
538 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
540 static const WORD function_key_scan[] =
542 0x3B, 0x3C, /* FFBE */
543 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
544 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
547 static const WORD modifier_key_vkey[] =
549 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
550 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
552 static const WORD modifier_key_scan[] =
554 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
555 0x38, 0x138, 0x38, 0x138 /* FFE7 */
558 /* Returns the Windows virtual key code associated with the X event <e> */
559 static WORD EVENT_event_to_vkey( XKeyEvent *e)
561 KeySym keysym;
563 TSXLookupString(e, NULL, 0, &keysym, NULL);
565 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
566 && (e->state & NumLockMask))
567 /* Only the Keypad keys 0-9 and . send different keysyms
568 * depending on the NumLock state */
569 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
571 return keyc2vkey[e->keycode];
574 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
576 /**********************************************************************
577 * KEYBOARD_GenerateMsg
579 * Generate Down+Up messages when NumLock or CapsLock is pressed.
581 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
584 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
585 DWORD event_time )
587 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
588 DWORD up, down;
590 if (*State) {
591 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
592 don't treat it. It's from the same key press. Then the state goes to ON.
593 And from there, a 'release' event will switch off the toggle key. */
594 *State=FALSE;
595 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
596 } else
598 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
599 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
600 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
602 if (Evtype!=KeyPress)
604 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
605 KEYBOARD_SendEvent( vkey, scan, down,
606 event_x, event_y, event_time );
607 KEYBOARD_SendEvent( vkey, scan, up,
608 event_x, event_y, event_time );
609 *State=FALSE;
610 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
613 else /* it was OFF */
614 if (Evtype==KeyPress)
616 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
617 KEYBOARD_SendEvent( vkey, scan, down,
618 event_x, event_y, event_time );
619 KEYBOARD_SendEvent( vkey, scan, up,
620 event_x, event_y, event_time );
621 *State=TRUE; /* Goes to intermediary state before going to ON */
622 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
627 /***********************************************************************
628 * KEYBOARD_UpdateOneState
630 * Updates internal state for <vkey>, depending on key <state> under X
633 static void KEYBOARD_UpdateOneState ( int vkey, int state )
635 /* Do something if internal table state != X state for keycode */
636 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
638 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
639 vkey, pKeyStateTable[vkey]);
641 /* Fake key being pressed inside wine */
642 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
643 0, 0, GetTickCount() );
645 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
649 /***********************************************************************
650 * X11DRV_KEYBOARD_UpdateState
652 * Update modifiers state (Ctrl, Alt, Shift)
653 * when window is activated (called by EVENT_FocusIn in event.c)
655 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
656 * from wine to another application and back.
657 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
658 * about them)
660 void X11DRV_KEYBOARD_UpdateState ( void )
662 /* extract a bit from the char[32] bit suite */
663 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
665 char keys_return[32];
667 TRACE("called\n");
668 if (!TSXQueryKeymap(display, keys_return)) {
669 ERR("Error getting keymap !");
670 return;
673 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
674 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
675 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
676 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
677 #undef KeyState
680 /***********************************************************************
681 * X11DRV_KEYBOARD_HandleEvent
683 * Handle a X key event
685 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
687 char Str[24];
688 KeySym keysym;
689 WORD vkey = 0, bScan;
690 DWORD dwFlags;
691 static BOOL force_extended = FALSE; /* hack for AltGr translation */
692 int ascii_chars;
694 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
695 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
696 DWORD event_time = event->time - X11DRV_server_startticks;
698 /* this allows support for dead keys */
699 if ((event->keycode >> 8) == 0x10)
700 event->keycode=(event->keycode & 0xff);
702 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
704 TRACE_(key)("state = %X\n", event->state);
706 /* If XKB extensions is used, the state mask for AltGr will used the group
707 index instead of the modifier mask. The group index is set in bits
708 13-14 of the state field in the XKeyEvent structure. So if AltGr is
709 pressed, look if the group index is diferent than 0. From XKB
710 extension documentation, the group index should for AltGr should
711 be 2 (event->state = 0x2000). It's probably better to not assume a
712 predefined group index and find it dynamically
714 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
715 if ( AltGrState && (event->state & 0x6000) )
716 AltGrMask = event->state & 0x6000;
718 if (keysym == XK_Mode_switch)
720 TRACE_(key)("Alt Gr key event received\n");
721 event->keycode = kcControl; /* Simulate Control */
722 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
724 event->keycode = kcAlt; /* Simulate Alt */
725 force_extended = TRUE;
726 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
727 force_extended = FALSE;
729 /* Here we save the pressed/released state of the AltGr key, to be able to
730 identify the group index associated with AltGr on the next key pressed *
731 see comment above. */
732 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
734 return;
737 Str[ascii_chars] = '\0';
738 if (TRACE_ON(key)){
739 char *ksname;
741 ksname = TSXKeysymToString(keysym);
742 if (!ksname)
743 ksname = "No Name";
744 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
745 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
746 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
749 vkey = EVENT_event_to_vkey(event);
750 if (force_extended) vkey |= 0x100;
752 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
753 event->keycode, vkey);
755 if (vkey)
757 switch (vkey & 0xff)
759 case VK_NUMLOCK:
760 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
761 event_time );
762 break;
763 case VK_CAPITAL:
764 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
765 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
766 event_time );
767 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
768 break;
769 default:
770 /* Adjust the NUMLOCK state if it has been changed outside wine */
771 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
773 TRACE("Adjusting NumLock state. \n");
774 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
775 event_time );
776 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
777 event_time );
779 /* Adjust the CAPSLOCK state if it has been changed outside wine */
780 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
782 TRACE("Adjusting Caps Lock state.\n");
783 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
784 event_time );
785 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
786 event_time );
788 /* Not Num nor Caps : end of intermediary states for both. */
789 NumState = FALSE;
790 CapsState = FALSE;
792 bScan = keyc2scan[event->keycode] & 0xFF;
793 TRACE_(key)("bScan = 0x%02x.\n", bScan);
795 dwFlags = 0;
796 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
797 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
798 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
800 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
801 event_x, event_y, event_time );
806 /**********************************************************************
807 * X11DRV_KEYBOARD_DetectLayout
809 * Called from X11DRV_InitKeyboard
810 * This routine walks through the defined keyboard layouts and selects
811 * whichever matches most closely.
813 static void
814 X11DRV_KEYBOARD_DetectLayout (void)
816 unsigned current, match, mismatch, seq;
817 int score, keyc, i, key, pkey, ok, syms;
818 KeySym keysym;
819 const char (*lkey)[MAIN_LEN][4];
820 unsigned max_seq = 0;
821 int max_score = 0, ismatch = 0;
822 char ckey[4] =
823 {0, 0, 0, 0};
825 syms = keysyms_per_keycode;
826 if (syms > 4) {
827 WARN("%d keysyms per keycode not supported, set to 4", syms);
828 syms = 4;
830 for (current = 0; main_key_tab[current].comment; current++) {
831 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
832 match = 0;
833 mismatch = 0;
834 score = 0;
835 seq = 0;
836 lkey = main_key_tab[current].key;
837 pkey = -1;
838 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
839 /* get data for keycode from X server */
840 for (i = 0; i < syms; i++) {
841 keysym = TSXKeycodeToKeysym (display, keyc, i);
842 /* Allow both one-byte and two-byte national keysyms */
843 if ((keysym < 0x800) && (keysym != ' '))
844 ckey[i] = keysym & 0xFF;
845 else {
846 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
849 if (ckey[0]) {
850 /* search for a match in layout table */
851 /* right now, we just find an absolute match for defined positions */
852 /* (undefined positions are ignored, so if it's defined as "3#" in */
853 /* the table, it's okay that the X server has "3#£", for example) */
854 /* however, the score will be higher for longer matches */
855 for (key = 0; key < MAIN_LEN; key++) {
856 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
857 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
858 ok++;
859 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
860 ok = -1;
862 if (ok > 0) {
863 score += ok;
864 break;
867 /* count the matches and mismatches */
868 if (ok > 0) {
869 match++;
870 /* and how much the keycode order matches */
871 if (key > pkey) seq++;
872 pkey = key;
873 } else {
874 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
875 ckey[0]);
876 mismatch++;
877 score -= syms;
881 TRACE("matches=%d, mismatches=%d, score=%d\n",
882 match, mismatch, score);
883 if ((score > max_score) ||
884 ((score == max_score) && (seq > max_seq))) {
885 /* best match so far */
886 kbd_layout = current;
887 max_score = score;
888 max_seq = seq;
889 ismatch = !mismatch;
892 /* we're done, report results if necessary */
893 if (!ismatch) {
894 FIXME(
895 "Your keyboard layout was not found!\n"
896 "Instead of using closest match (%s) for scancode mapping.\n"
897 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
898 "to us for inclusion into future Wine releases.\n"
899 "See documentation/keyboard for more information.\n",
900 main_key_tab[kbd_layout].comment);
903 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
906 /**********************************************************************
907 * X11DRV_InitKeyboard (X11DRV.@)
909 void X11DRV_InitKeyboard(void)
911 KeySym *ksp;
912 XModifierKeymap *mmp;
913 KeySym keysym;
914 KeyCode *kcp;
915 XKeyEvent e2;
916 WORD scan, vkey, OEMvkey;
917 int keyc, i, keyn, syms;
918 char ckey[4]={0,0,0,0};
919 const char (*lkey)[MAIN_LEN][4];
921 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
922 ksp = TSXGetKeyboardMapping(display, min_keycode,
923 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
924 /* We are only interested in keysyms_per_keycode.
925 There is no need to hold a local copy of the keysyms table */
926 TSXFree(ksp);
927 mmp = TSXGetModifierMapping(display);
928 kcp = mmp->modifiermap;
929 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
931 int j;
933 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
934 if (*kcp)
936 int k;
938 for (k = 0; k < keysyms_per_keycode; k += 1)
939 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
941 AltGrMask = 1 << i;
942 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
944 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
946 NumLockMask = 1 << i;
947 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
951 TSXFreeModifiermap(mmp);
953 /* Detect the keyboard layout */
954 X11DRV_KEYBOARD_DetectLayout();
955 lkey = main_key_tab[kbd_layout].key;
956 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
958 /* Now build two conversion arrays :
959 * keycode -> vkey + scancode + extended
960 * vkey + extended -> keycode */
962 e2.display = display;
963 e2.state = 0;
965 OEMvkey = VK_OEM_7; /* next is available. */
966 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
968 e2.keycode = (KeyCode)keyc;
969 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
970 vkey = 0; scan = 0;
971 if (keysym) /* otherwise, keycode not used */
973 if ((keysym >> 8) == 0xFF) /* non-character key */
975 int key = keysym & 0xff;
977 if (key >= 0x08 && key <= 0x1B) { /* special key */
978 vkey = special_key_vkey[key - 0x08];
979 scan = special_key_scan[key - 0x08];
980 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
981 vkey = cursor_key_vkey[key - 0x50];
982 scan = cursor_key_scan[key - 0x50];
983 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
984 vkey = misc_key_vkey[key - 0x60];
985 scan = misc_key_scan[key - 0x60];
986 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
987 vkey = keypad_key_vkey[key - 0x7E];
988 scan = keypad_key_scan[key - 0x7E];
989 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
990 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
991 scan = function_key_scan[key - 0xBE];
992 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
993 vkey = modifier_key_vkey[key - 0xE1];
994 scan = modifier_key_scan[key - 0xE1];
995 } else if (key == 0xFF) { /* DEL key */
996 vkey = VK_DELETE;
997 scan = 0x153;
999 /* set extended bit when necessary */
1000 if (scan & 0x100) vkey |= 0x100;
1001 } else if (keysym == 0x20) { /* Spacebar */
1002 vkey = VK_SPACE;
1003 scan = 0x39;
1004 } else {
1005 /* we seem to need to search the layout-dependent scancodes */
1006 int maxlen=0,maxval=-1,ok;
1007 for (i=0; i<syms; i++) {
1008 keysym = TSXKeycodeToKeysym(display, keyc, i);
1009 if ((keysym<0x800) && (keysym!=' ')) {
1010 ckey[i] = keysym & 0xFF;
1011 } else {
1012 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1015 /* find key with longest match streak */
1016 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1017 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1018 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1019 if (ok||(i>maxlen)) {
1020 maxlen=i; maxval=keyn;
1022 if (ok) break;
1024 if (maxval>=0) {
1025 /* got it */
1026 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1027 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1028 scan = (*lscan)[maxval];
1029 vkey = (*lvkey)[maxval];
1033 /* find a suitable layout-dependent VK code */
1034 /* (most Winelib apps ought to be able to work without layout tables!) */
1035 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1037 keysym = TSXLookupKeysym(&e2, i);
1038 if ((keysym >= VK_0 && keysym <= VK_9)
1039 || (keysym >= VK_A && keysym <= VK_Z)) {
1040 vkey = keysym;
1044 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1046 keysym = TSXLookupKeysym(&e2, i);
1047 switch (keysym)
1049 case ';': vkey = VK_OEM_1; break;
1050 case '/': vkey = VK_OEM_2; break;
1051 case '`': vkey = VK_OEM_3; break;
1052 case '[': vkey = VK_OEM_4; break;
1053 case '\\': vkey = VK_OEM_5; break;
1054 case ']': vkey = VK_OEM_6; break;
1055 case '\'': vkey = VK_OEM_7; break;
1056 case ',': vkey = VK_OEM_COMMA; break;
1057 case '.': vkey = VK_OEM_PERIOD; break;
1058 case '-': vkey = VK_OEM_MINUS; break;
1059 case '+': vkey = VK_OEM_PLUS; break;
1063 if (!vkey)
1065 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1066 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1067 switch (++OEMvkey)
1069 case 0xc1 : OEMvkey=0xdb; break;
1070 case 0xe5 : OEMvkey=0xe9; break;
1071 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1074 vkey = OEMvkey;
1076 if (TRACE_ON(keyboard))
1078 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1079 OEMvkey, e2.keycode);
1080 TRACE("(");
1081 for (i = 0; i < keysyms_per_keycode; i += 1)
1083 char *ksname;
1085 keysym = TSXLookupKeysym(&e2, i);
1086 ksname = TSXKeysymToString(keysym);
1087 if (!ksname)
1088 ksname = "NoSymbol";
1089 DPRINTF( "%lX (%s) ", keysym, ksname);
1091 DPRINTF(")\n");
1095 keyc2vkey[e2.keycode] = vkey;
1096 keyc2scan[e2.keycode] = scan;
1097 } /* for */
1099 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1100 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1101 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1102 char *ksname;
1103 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1104 ksname = TSXKeysymToString(keysym);
1105 if (!ksname) ksname = "NoSymbol";
1107 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1109 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1110 keyc2scan[keyc]=scan++;
1113 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1114 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1115 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1116 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1117 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1118 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1119 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1122 /***********************************************************************
1123 * X11DRV_VkKeyScan (X11DRV.@)
1125 WORD X11DRV_VkKeyScan(CHAR cChar)
1127 KeyCode keycode;
1128 KeySym keysym;
1129 int i,index;
1130 int highbyte=0;
1132 /* char->keysym (same for ANSI chars) */
1133 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1134 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1136 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1137 if (!keycode)
1138 { /* It didn't work ... let's try with deadchar code. */
1139 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1142 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1143 cChar,keysym,keysym,keycode);
1145 if (keycode)
1147 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1148 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1149 switch (index) {
1150 case -1 :
1151 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1152 case 0 : break;
1153 case 1 : highbyte = 0x0100; break;
1154 case 2 : highbyte = 0x0600; break;
1155 case 3 : highbyte = 0x0700; break;
1156 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1159 index : 0 adds 0x0000
1160 index : 1 adds 0x0100 (shift)
1161 index : ? adds 0x0200 (ctrl)
1162 index : 2 adds 0x0600 (ctrl+alt)
1163 index : 3 adds 0x0700 (ctrl+alt+shift)
1166 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1167 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1170 /***********************************************************************
1171 * X11DRV_MapVirtualKey (X11DRV.@)
1173 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1175 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1177 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1178 switch(wMapType) {
1179 case 0: { /* vkey-code to scan-code */
1180 /* let's do vkey -> keycode -> scan */
1181 int keyc;
1182 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1183 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1184 returnMVK (keyc2scan[keyc] & 0xFF);
1185 TRACE("returning no scan-code.\n");
1186 return 0; }
1188 case 1: { /* scan-code to vkey-code */
1189 /* let's do scan -> keycode -> vkey */
1190 int keyc;
1191 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1192 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1193 returnMVK (keyc2vkey[keyc] & 0xFF);
1194 TRACE("returning no vkey-code.\n");
1195 return 0; }
1197 case 2: { /* vkey-code to unshifted ANSI code */
1198 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1199 /* My Windows returns 'A'. */
1200 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1201 XKeyEvent e;
1202 KeySym keysym;
1203 int keyc;
1204 char s[2];
1205 e.display = display;
1206 e.state = 0; /* unshifted */
1208 e.keycode = 0;
1209 /* We exit on the first keycode found, to speed up the thing. */
1210 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1211 { /* Find a keycode that could have generated this virtual key */
1212 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1213 { /* We filter the extended bit, we don't know it */
1214 e.keycode = keyc; /* Store it temporarily */
1215 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1216 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1217 state), so set it to 0, we'll find another one */
1222 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1223 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1225 if (wCode==VK_DECIMAL)
1226 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1228 if (!e.keycode)
1230 WARN("Unknown virtual key %X !!! \n", wCode);
1231 return 0; /* whatever */
1233 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1235 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1236 returnMVK (*s);
1238 TRACE("returning no ANSI.\n");
1239 return 0;
1242 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1243 /* left and right */
1244 FIXME(" stub for NT\n");
1245 return 0;
1247 default: /* reserved */
1248 WARN("Unknown wMapType %d !\n", wMapType);
1249 return 0;
1251 return 0;
1254 /***********************************************************************
1255 * X11DRV_GetKeyNameText (X11DRV.@)
1257 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1259 int vkey, ansi, scanCode;
1260 KeyCode keyc;
1261 KeySym keys;
1262 char *name;
1264 scanCode = lParam >> 16;
1265 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1267 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1268 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1270 /* handle "don't care" bit (0x02000000) */
1271 if (!(lParam & 0x02000000)) {
1272 switch (vkey) {
1273 case VK_LSHIFT:
1274 case VK_RSHIFT:
1275 vkey = VK_SHIFT;
1276 break;
1277 case VK_LCONTROL:
1278 case VK_RCONTROL:
1279 vkey = VK_CONTROL;
1280 break;
1281 case VK_LMENU:
1282 case VK_RMENU:
1283 vkey = VK_MENU;
1284 break;
1285 default:
1286 break;
1290 ansi = X11DRV_MapVirtualKey(vkey, 2);
1291 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1293 /* first get the name of the "regular" keys which is the Upper case
1294 value of the keycap imprint. */
1295 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1296 (scanCode != 0x137) && /* PrtScn */
1297 (scanCode != 0x135) && /* numpad / */
1298 (scanCode != 0x37 ) && /* numpad * */
1299 (scanCode != 0x4a ) && /* numpad - */
1300 (scanCode != 0x4e ) ) /* numpad + */
1302 if ((nSize >= 2) && lpBuffer)
1304 *lpBuffer = toupper((char)ansi);
1305 *(lpBuffer+1) = 0;
1306 return 1;
1308 else
1309 return 0;
1312 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1313 without "extended-key" flag. However Wine generates scancode
1314 *with* "extended-key" flag. Seems to occur *only* for the
1315 function keys. Soooo.. We will leave the table alone and
1316 fudge the lookup here till the other part is found and fixed!!! */
1318 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1319 (scanCode == 0x157) || (scanCode == 0x158))
1320 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1322 /* let's do scancode -> keycode -> keysym -> String */
1324 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1325 if ((keyc2scan[keyc]) == scanCode)
1326 break;
1327 if (keyc <= max_keycode)
1329 keys = TSXKeycodeToKeysym(display, keyc, 0);
1330 name = TSXKeysymToString(keys);
1331 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1332 scanCode, keyc, (int)keys, name);
1333 if (lpBuffer && nSize && name)
1335 lstrcpynA(lpBuffer, name, nSize);
1336 return 1;
1340 /* Finally issue FIXME for unknown keys */
1342 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1343 if (lpBuffer && nSize)
1344 *lpBuffer = 0;
1345 return 0;
1348 /***********************************************************************
1349 * X11DRV_KEYBOARD_MapDeadKeysym
1351 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1353 switch (keysym)
1355 /* symbolic ASCII is the same as defined in rfc1345 */
1356 #ifdef XK_dead_tilde
1357 case XK_dead_tilde :
1358 #endif
1359 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1360 return '~'; /* '? */
1361 #ifdef XK_dead_acute
1362 case XK_dead_acute :
1363 #endif
1364 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1365 return 0xb4; /* '' */
1366 #ifdef XK_dead_circumflex
1367 case XK_dead_circumflex:
1368 #endif
1369 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1370 return '^'; /* '> */
1371 #ifdef XK_dead_grave
1372 case XK_dead_grave :
1373 #endif
1374 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1375 return '`'; /* '! */
1376 #ifdef XK_dead_diaeresis
1377 case XK_dead_diaeresis :
1378 #endif
1379 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1380 return 0xa8; /* ': */
1381 #ifdef XK_dead_cedilla
1382 case XK_dead_cedilla :
1383 return 0xb8; /* ', */
1384 #endif
1385 #ifdef XK_dead_macron
1386 case XK_dead_macron :
1387 return '-'; /* 'm isn't defined on iso-8859-x */
1388 #endif
1389 #ifdef XK_dead_breve
1390 case XK_dead_breve :
1391 return 0xa2; /* '( */
1392 #endif
1393 #ifdef XK_dead_abovedot
1394 case XK_dead_abovedot :
1395 return 0xff; /* '. */
1396 #endif
1397 #ifdef XK_dead_abovering
1398 case XK_dead_abovering :
1399 return '0'; /* '0 isn't defined on iso-8859-x */
1400 #endif
1401 #ifdef XK_dead_doubleacute
1402 case XK_dead_doubleacute :
1403 return 0xbd; /* '" */
1404 #endif
1405 #ifdef XK_dead_caron
1406 case XK_dead_caron :
1407 return 0xb7; /* '< */
1408 #endif
1409 #ifdef XK_dead_ogonek
1410 case XK_dead_ogonek :
1411 return 0xb2; /* '; */
1412 #endif
1413 /* FIXME: I don't know this three.
1414 case XK_dead_iota :
1415 return 'i';
1416 case XK_dead_voiced_sound :
1417 return 'v';
1418 case XK_dead_semivoiced_sound :
1419 return 's';
1422 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1423 return 0;
1426 /***********************************************************************
1427 * X11DRV_ToUnicode (X11DRV.@)
1429 * The ToUnicode function translates the specified virtual-key code and keyboard
1430 * state to the corresponding Windows character or characters.
1432 * If the specified key is a dead key, the return value is negative. Otherwise,
1433 * it is one of the following values:
1434 * Value Meaning
1435 * 0 The specified virtual key has no translation for the current state of the keyboard.
1436 * 1 One Windows character was copied to the buffer.
1437 * 2 Two characters were copied to the buffer. This usually happens when a
1438 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1439 * be composed with the specified virtual key to form a single character.
1441 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1444 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1445 LPWSTR bufW, int bufW_size, UINT flags)
1447 XKeyEvent e;
1448 KeySym keysym;
1449 INT ret;
1450 int keyc;
1451 BYTE lpChar[2];
1453 if (scanCode==0) {
1454 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1455 event is generated by windows. Just ignore it. */
1456 TRACE("scanCode=0, doing nothing\n");
1457 return 0;
1459 if (scanCode & 0x8000)
1461 TRACE("Key UP, doing nothing\n" );
1462 return 0;
1464 e.display = display;
1465 e.keycode = 0;
1466 e.state = 0;
1467 if (lpKeyState[VK_SHIFT] & 0x80)
1468 e.state |= ShiftMask;
1469 if (lpKeyState[VK_CAPITAL] & 0x01)
1470 e.state |= LockMask;
1471 if (lpKeyState[VK_CONTROL] & 0x80)
1473 if (lpKeyState[VK_MENU] & 0x80)
1474 e.state |= AltGrMask;
1475 else
1476 e.state |= ControlMask;
1478 if (lpKeyState[VK_NUMLOCK] & 0x01)
1479 e.state |= NumLockMask;
1480 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1481 virtKey, scanCode, e.state);
1482 /* We exit on the first keycode found, to speed up the thing. */
1483 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1484 { /* Find a keycode that could have generated this virtual key */
1485 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1486 { /* We filter the extended bit, we don't know it */
1487 e.keycode = keyc; /* Store it temporarily */
1488 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1489 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1490 state), so set it to 0, we'll find another one */
1495 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1496 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1498 if (virtKey==VK_DECIMAL)
1499 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1501 if (!e.keycode)
1503 WARN("Unknown virtual key %X !!! \n",virtKey);
1504 return virtKey; /* whatever */
1506 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1508 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1509 if (ret == 0)
1511 BYTE dead_char;
1513 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1514 if (dead_char)
1516 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1517 ret = -1;
1519 else
1521 char *ksname;
1523 ksname = TSXKeysymToString(keysym);
1524 if (!ksname)
1525 ksname = "No Name";
1526 if ((keysym >> 8) != 0xff)
1528 ERR("Please report: no char for keysym %04lX (%s) :\n",
1529 keysym, ksname);
1530 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1531 virtKey, scanCode, e.keycode, e.state);
1535 else { /* ret != 0 */
1536 /* We have a special case to handle : Shift + arrow, shift + home, ...
1537 X returns a char for it, but Windows doesn't. Let's eat it. */
1538 if (!(e.state & NumLockMask) /* NumLock is off */
1539 && (e.state & ShiftMask) /* Shift is pressed */
1540 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1542 *(char*)lpChar = 0;
1543 ret = 0;
1546 /* more areas where X returns characters but Windows does not
1547 CTRL + number or CTRL + symbol*/
1548 if (e.state & ControlMask)
1550 if (((keysym>=33) && (keysym < 'A')) ||
1551 ((keysym > 'Z') && (keysym < 'a')))
1553 *(char*)lpChar = 0;
1554 ret = 0;
1558 /* We have another special case for delete key (XK_Delete) on an
1559 extended keyboard. X returns a char for it, but Windows doesn't */
1560 if (keysym == XK_Delete)
1562 *(char*)lpChar = 0;
1563 ret = 0;
1565 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1566 && (keysym == XK_KP_Decimal))
1568 *(char*)lpChar = 0;
1569 ret = 0;
1572 /* perform translation to unicode */
1573 if(ret)
1575 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1576 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1577 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1581 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1582 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1583 return ret;
1586 /***********************************************************************
1587 * X11DRV_GetBeepActive (X11DRV.@)
1589 BOOL X11DRV_GetBeepActive(void)
1591 XKeyboardState keyboard_state;
1593 TSXGetKeyboardControl(display, &keyboard_state);
1595 return keyboard_state.bell_percent != 0;
1598 /***********************************************************************
1599 * X11DRV_SetBeepActive (X11DRV.@)
1601 void X11DRV_SetBeepActive(BOOL bActivate)
1603 XKeyboardControl keyboard_value;
1605 if(bActivate)
1606 keyboard_value.bell_percent = -1;
1607 else
1608 keyboard_value.bell_percent = 0;
1610 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1613 /***********************************************************************
1614 * X11DRV_Beep (X11DRV.@)
1616 void X11DRV_Beep(void)
1618 TSXBell(display, 0);
1621 /***********************************************************************
1622 * X11DRV_GetDIState (X11DRV.@)
1624 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1626 if (len==256) {
1627 int keyc,vkey;
1629 memset(ptr,0,256);
1630 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1632 /* X keycode to virtual key */
1633 vkey = keyc2vkey[keyc] & 0xFF;
1634 /* The windows scancode is keyc-min_keycode */
1635 if (InputKeyStateTable[vkey]&0x80) {
1636 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1637 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1640 return TRUE;
1642 WARN("whoops, got len %ld?\n", len);
1643 return TRUE;
1646 /***********************************************************************
1647 * X11DRV_GetDIData (X11DRV.@)
1649 BOOL X11DRV_GetDIData(
1650 BYTE *keystate,
1651 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1652 LPDWORD entries, DWORD flags)
1654 int keyc,n,vkey,xentries;
1656 /* FIXME !!! */
1658 if (entries)
1659 xentries = *entries;
1660 else
1661 xentries = 1;
1663 n = 0;
1665 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1667 /* X keycode to virtual key */
1668 vkey = keyc2vkey[keyc] & 0xFF;
1669 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1670 continue;
1671 if (dod) {
1672 /* add an entry */
1673 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1674 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1675 dod[n].dwTimeStamp = 0; /* umm */
1676 dod[n].dwSequence = 0; /* umm */
1677 n++;
1679 if (!(flags & DIGDD_PEEK))
1680 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1684 if (n) TRACE_(dinput)("%d entries\n",n);
1685 *entries = n;
1687 return TRUE;
1690 /***********************************************************************
1691 * X11DRV_GetKeyboardConfig (X11DRV.@)
1693 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1694 XKeyboardState xks;
1696 /* For the moment, only get the auto-repeat mode */
1697 TSXGetKeyboardControl(display, &xks);
1698 cfg->auto_repeat = xks.global_auto_repeat;
1701 /***********************************************************************
1702 * X11DRV_SetKeyboardConfig (X11DRV.@)
1704 void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1705 XKeyboardControl xkc;
1706 unsigned long X_mask = 0;
1708 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1709 X_mask |= KBAutoRepeatMode;
1710 xkc.auto_repeat_mode = cfg->auto_repeat;
1712 if (X_mask)
1713 TSXChangeKeyboardControl(display, X_mask, &xkc);