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