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
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
18 #include "ts_xresource.h"
26 #include "wine/winuser16.h"
28 #include "debugtools.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 */
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",",<",".>","/?",
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",",?",";.",":/","!§",
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",",;",".:","þÞ",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",'-",".","éÉ",
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", ",;", ".:", "-_",
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µ",",;",".:·","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",?",";.",":/","=+~",
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",",?;",".:·","-_*",
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",",<",".>","/?",
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",",<",".>","/?",
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§",",;",".:","-_/",
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",",<",".>","/?",
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",",<",".>","/?",
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",",?<",".:>","-_*",
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åÅ",",<",".>","/?",
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",",?<",".:>","-_*",
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",",;",".:","-_",
409 /*** Layout table. Add your keyboard mappings to this list */
410 static const struct {
412 const UINT layout_cp; /* Code page for this layout */
413 const char (*key)[MAIN_LEN][4];
414 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
415 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
417 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
418 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
419 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
420 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
421 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
422 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
423 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
424 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
425 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
426 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
427 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
428 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
429 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
430 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
431 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
432 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
433 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
434 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
435 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
436 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
437 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
438 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
439 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
440 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
441 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
442 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
443 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
444 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
445 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
446 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
447 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
449 {NULL, 0, NULL, NULL, NULL} /* sentinel */
451 static unsigned kbd_layout=0; /* index into above table of layouts */
453 /* maybe more of these scancodes should be extended? */
454 /* extended must be set for ALT_R, CTRL_R,
455 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
456 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
457 /* FIXME should we set extended bit for NumLock ? My
458 * Windows does ... DF */
459 /* Yes, to distinguish based on scan codes, also
460 for PrtScn key ... GA */
462 static const WORD special_key_vkey[] =
464 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
465 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
466 0, 0, 0, VK_ESCAPE /* FF18 */
468 static const WORD special_key_scan[] =
470 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
471 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
472 0, 0, 0, 0x01 /* FF18 */
475 static const WORD cursor_key_vkey[] =
477 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
478 VK_NEXT, VK_END /* FF50 */
480 static const WORD cursor_key_scan[] =
482 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
485 static const WORD misc_key_vkey[] =
487 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
488 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
490 static const WORD misc_key_scan[] =
492 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
493 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
496 static const WORD keypad_key_vkey[] =
498 0, VK_NUMLOCK, /* FF7E */
499 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
500 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
501 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
502 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
503 VK_INSERT, VK_DELETE, /* FF98 */
504 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
505 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
506 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
507 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
508 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
509 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
511 static const WORD keypad_key_scan[] =
513 0x138, 0x145, /* FF7E */
514 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
515 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
516 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
517 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
518 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
519 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
520 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
521 0x48, 0x49 /* FFB8 */
524 static const WORD function_key_vkey[] =
526 VK_F1, VK_F2, /* FFBE */
527 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
528 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
530 static const WORD function_key_scan[] =
532 0x3B, 0x3C, /* FFBE */
533 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
534 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
537 static const WORD modifier_key_vkey[] =
539 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
540 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
542 static const WORD modifier_key_scan[] =
544 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
545 0x38, 0x138, 0x38, 0x138 /* FFE7 */
548 /* Returns the Windows virtual key code associated with the X event <e> */
549 static WORD EVENT_event_to_vkey( XKeyEvent *e)
553 TSXLookupString(e, NULL, 0, &keysym, NULL);
555 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
556 && (e->state & NumLockMask))
557 /* Only the Keypad keys 0-9 and . send different keysyms
558 * depending on the NumLock state */
559 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
561 return keyc2vkey[e->keycode];
564 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
566 /**********************************************************************
567 * KEYBOARD_GenerateMsg
569 * Generate Down+Up messages when NumLock or CapsLock is pressed.
571 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
574 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
577 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
581 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
582 don't treat it. It's from the same key press. Then the state goes to ON.
583 And from there, a 'release' event will switch off the toggle key. */
585 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
588 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
589 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
590 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
592 if (Evtype!=KeyPress)
594 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
595 KEYBOARD_SendEvent( vkey, scan, down,
596 event_x, event_y, event_time );
597 KEYBOARD_SendEvent( vkey, scan, up,
598 event_x, event_y, event_time );
600 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
603 else /* it was OFF */
604 if (Evtype==KeyPress)
606 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
607 KEYBOARD_SendEvent( vkey, scan, down,
608 event_x, event_y, event_time );
609 KEYBOARD_SendEvent( vkey, scan, up,
610 event_x, event_y, event_time );
611 *State=TRUE; /* Goes to intermediary state before going to ON */
612 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
617 /***********************************************************************
618 * KEYBOARD_UpdateOneState
620 * Updates internal state for <vkey>, depending on key <state> under X
623 static void KEYBOARD_UpdateOneState ( int vkey, int state )
625 /* Do something if internal table state != X state for keycode */
626 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
628 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
629 vkey, pKeyStateTable[vkey]);
631 /* Fake key being pressed inside wine */
632 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
633 0, 0, GetTickCount() );
635 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
639 /***********************************************************************
640 * X11DRV_KEYBOARD_UpdateState
642 * Update modifiers state (Ctrl, Alt, Shift)
643 * when window is activated (called by EVENT_FocusIn in event.c)
645 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
646 * from wine to another application and back.
647 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
650 void X11DRV_KEYBOARD_UpdateState ( void )
652 /* extract a bit from the char[32] bit suite */
653 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
655 char keys_return[32];
658 if (!TSXQueryKeymap(display, keys_return)) {
659 ERR("Error getting keymap !");
663 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
664 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
665 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
666 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
670 /***********************************************************************
671 * X11DRV_KEYBOARD_HandleEvent
673 * Handle a X key event
675 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
679 WORD vkey = 0, bScan;
681 static BOOL force_extended = FALSE; /* hack for AltGr translation */
684 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
685 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
686 DWORD event_time = event->time - X11DRV_server_startticks;
688 /* this allows support for dead keys */
689 if ((event->keycode >> 8) == 0x10)
690 event->keycode=(event->keycode & 0xff);
692 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
694 TRACE_(key)("state = %X\n", event->state);
696 /* If XKB extensions is used, the state mask for AltGr will used the group
697 index instead of the modifier mask. The group index is set in bits
698 13-14 of the state field in the XKeyEvent structure. So if AltGr is
699 pressed, look if the group index is diferent than 0. From XKB
700 extension documentation, the group index should for AltGr should
701 be 2 (event->state = 0x2000). It's probably better to not assume a
702 predefined group index and find it dynamically
704 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
705 if ( AltGrState && (event->state & 0x6000) )
706 AltGrMask = event->state & 0x6000;
708 if (keysym == XK_Mode_switch)
710 TRACE_(key)("Alt Gr key event received\n");
711 event->keycode = kcControl; /* Simulate Control */
712 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
714 event->keycode = kcAlt; /* Simulate Alt */
715 force_extended = TRUE;
716 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
717 force_extended = FALSE;
719 /* Here we save the pressed/released state of the AltGr key, to be able to
720 identify the group index associated with AltGr on the next key pressed *
721 see comment above. */
722 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
727 Str[ascii_chars] = '\0';
731 ksname = TSXKeysymToString(keysym);
734 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
735 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
736 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
739 vkey = EVENT_event_to_vkey(event);
740 if (force_extended) vkey |= 0x100;
742 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
743 event->keycode, vkey);
750 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
754 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
755 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
757 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
760 /* Adjust the NUMLOCK state if it has been changed outside wine */
761 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
763 TRACE("Adjusting NumLock state. \n");
764 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
766 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
769 /* Adjust the CAPSLOCK state if it has been changed outside wine */
770 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
772 TRACE("Adjusting Caps Lock state.\n");
773 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
775 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
778 /* Not Num nor Caps : end of intermediary states for both. */
782 bScan = keyc2scan[event->keycode] & 0xFF;
783 TRACE_(key)("bScan = 0x%02x.\n", bScan);
786 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
787 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
788 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
790 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
791 event_x, event_y, event_time );
796 /**********************************************************************
797 * X11DRV_KEYBOARD_DetectLayout
799 * Called from X11DRV_InitKeyboard
800 * This routine walks through the defined keyboard layouts and selects
801 * whichever matches most closely.
804 X11DRV_KEYBOARD_DetectLayout (void)
806 unsigned current, match, mismatch, seq;
807 int score, keyc, i, key, pkey, ok, syms;
809 const char (*lkey)[MAIN_LEN][4];
810 unsigned max_seq = 0;
811 int max_score = 0, ismatch = 0;
815 syms = keysyms_per_keycode;
817 WARN("%d keysyms per keycode not supported, set to 4", syms);
820 for (current = 0; main_key_tab[current].comment; current++) {
821 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
826 lkey = main_key_tab[current].key;
828 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
829 /* get data for keycode from X server */
830 for (i = 0; i < syms; i++) {
831 keysym = TSXKeycodeToKeysym (display, keyc, i);
832 /* Allow both one-byte and two-byte national keysyms */
833 if ((keysym < 0x800) && (keysym != ' '))
834 ckey[i] = keysym & 0xFF;
836 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
840 /* search for a match in layout table */
841 /* right now, we just find an absolute match for defined positions */
842 /* (undefined positions are ignored, so if it's defined as "3#" in */
843 /* the table, it's okay that the X server has "3#£", for example) */
844 /* however, the score will be higher for longer matches */
845 for (key = 0; key < MAIN_LEN; key++) {
846 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
847 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
849 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
857 /* count the matches and mismatches */
860 /* and how much the keycode order matches */
861 if (key > pkey) seq++;
864 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
871 TRACE("matches=%d, mismatches=%d, score=%d\n",
872 match, mismatch, score);
873 if ((score > max_score) ||
874 ((score == max_score) && (seq > max_seq))) {
875 /* best match so far */
876 kbd_layout = current;
882 /* we're done, report results if necessary */
885 "Your keyboard layout was not found!\n"
886 "Instead of using closest match (%s) for scancode mapping.\n"
887 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
888 "to us for inclusion into future Wine releases.\n"
889 "See documentation/keyboard for more information.\n",
890 main_key_tab[kbd_layout].comment);
893 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
896 /**********************************************************************
897 * X11DRV_InitKeyboard
899 void X11DRV_InitKeyboard(void)
902 XModifierKeymap *mmp;
906 WORD scan, vkey, OEMvkey;
907 int keyc, i, keyn, syms;
908 char ckey[4]={0,0,0,0};
909 const char (*lkey)[MAIN_LEN][4];
911 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
912 ksp = TSXGetKeyboardMapping(display, min_keycode,
913 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
914 /* We are only interested in keysyms_per_keycode.
915 There is no need to hold a local copy of the keysyms table */
917 mmp = TSXGetModifierMapping(display);
918 kcp = mmp->modifiermap;
919 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
923 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
928 for (k = 0; k < keysyms_per_keycode; k += 1)
929 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
932 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
934 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
936 NumLockMask = 1 << i;
937 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
941 TSXFreeModifiermap(mmp);
943 /* Detect the keyboard layout */
944 X11DRV_KEYBOARD_DetectLayout();
945 lkey = main_key_tab[kbd_layout].key;
946 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
948 /* Now build two conversion arrays :
949 * keycode -> vkey + scancode + extended
950 * vkey + extended -> keycode */
952 e2.display = display;
955 OEMvkey = VK_OEM_7; /* next is available. */
956 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
958 e2.keycode = (KeyCode)keyc;
959 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
961 if (keysym) /* otherwise, keycode not used */
963 if ((keysym >> 8) == 0xFF) /* non-character key */
965 int key = keysym & 0xff;
967 if (key >= 0x08 && key <= 0x1B) { /* special key */
968 vkey = special_key_vkey[key - 0x08];
969 scan = special_key_scan[key - 0x08];
970 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
971 vkey = cursor_key_vkey[key - 0x50];
972 scan = cursor_key_scan[key - 0x50];
973 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
974 vkey = misc_key_vkey[key - 0x60];
975 scan = misc_key_scan[key - 0x60];
976 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
977 vkey = keypad_key_vkey[key - 0x7E];
978 scan = keypad_key_scan[key - 0x7E];
979 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
980 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
981 scan = function_key_scan[key - 0xBE];
982 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
983 vkey = modifier_key_vkey[key - 0xE1];
984 scan = modifier_key_scan[key - 0xE1];
985 } else if (key == 0xFF) { /* DEL key */
989 /* set extended bit when necessary */
990 if (scan & 0x100) vkey |= 0x100;
991 } else if (keysym == 0x20) { /* Spacebar */
995 /* we seem to need to search the layout-dependent scancodes */
996 int maxlen=0,maxval=-1,ok;
997 for (i=0; i<syms; i++) {
998 keysym = TSXKeycodeToKeysym(display, keyc, i);
999 if ((keysym<0x800) && (keysym!=' ')) {
1000 ckey[i] = keysym & 0xFF;
1002 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1005 /* find key with longest match streak */
1006 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1007 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1008 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1009 if (ok||(i>maxlen)) {
1010 maxlen=i; maxval=keyn;
1016 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1017 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1018 scan = (*lscan)[maxval];
1019 vkey = (*lvkey)[maxval];
1023 /* find a suitable layout-dependent VK code */
1024 /* (most Winelib apps ought to be able to work without layout tables!) */
1025 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1027 keysym = TSXLookupKeysym(&e2, i);
1028 if ((keysym >= VK_0 && keysym <= VK_9)
1029 || (keysym >= VK_A && keysym <= VK_Z)) {
1034 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1036 keysym = TSXLookupKeysym(&e2, i);
1039 case ';': vkey = VK_OEM_1; break;
1040 case '/': vkey = VK_OEM_2; break;
1041 case '`': vkey = VK_OEM_3; break;
1042 case '[': vkey = VK_OEM_4; break;
1043 case '\\': vkey = VK_OEM_5; break;
1044 case ']': vkey = VK_OEM_6; break;
1045 case '\'': vkey = VK_OEM_7; break;
1046 case ',': vkey = VK_OEM_COMMA; break;
1047 case '.': vkey = VK_OEM_PERIOD; break;
1048 case '-': vkey = VK_OEM_MINUS; break;
1049 case '+': vkey = VK_OEM_PLUS; break;
1055 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1056 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1059 case 0xc1 : OEMvkey=0xdb; break;
1060 case 0xe5 : OEMvkey=0xe9; break;
1061 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1066 if (TRACE_ON(keyboard))
1068 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1069 OEMvkey, e2.keycode);
1071 for (i = 0; i < keysyms_per_keycode; i += 1)
1075 keysym = TSXLookupKeysym(&e2, i);
1076 ksname = TSXKeysymToString(keysym);
1078 ksname = "NoSymbol";
1079 DPRINTF( "%lX (%s) ", keysym, ksname);
1085 keyc2vkey[e2.keycode] = vkey;
1086 keyc2scan[e2.keycode] = scan;
1089 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1090 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1091 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1093 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1094 ksname = TSXKeysymToString(keysym);
1095 if (!ksname) ksname = "NoSymbol";
1097 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1099 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1100 keyc2scan[keyc]=scan++;
1103 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1104 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1105 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1106 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1107 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1108 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1109 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1112 /***********************************************************************
1115 WORD X11DRV_VkKeyScan(CHAR cChar)
1122 /* char->keysym (same for ANSI chars) */
1123 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1124 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1126 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1128 { /* It didn't work ... let's try with deadchar code. */
1129 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1132 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1133 cChar,keysym,keysym,keycode);
1137 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1138 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1141 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1143 case 1 : highbyte = 0x0100; break;
1144 case 2 : highbyte = 0x0600; break;
1145 case 3 : highbyte = 0x0700; break;
1146 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1149 index : 0 adds 0x0000
1150 index : 1 adds 0x0100 (shift)
1151 index : ? adds 0x0200 (ctrl)
1152 index : 2 adds 0x0600 (ctrl+alt)
1153 index : 3 adds 0x0700 (ctrl+alt+shift)
1156 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1157 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1160 /***********************************************************************
1161 * X11DRV_MapVirtualKey
1163 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1165 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1167 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1169 case 0: { /* vkey-code to scan-code */
1170 /* let's do vkey -> keycode -> scan */
1172 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1173 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1174 returnMVK (keyc2scan[keyc] & 0xFF);
1175 TRACE("returning no scan-code.\n");
1178 case 1: { /* scan-code to vkey-code */
1179 /* let's do scan -> keycode -> vkey */
1181 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1182 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1183 returnMVK (keyc2vkey[keyc] & 0xFF);
1184 TRACE("returning no vkey-code.\n");
1187 case 2: { /* vkey-code to unshifted ANSI code */
1188 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1189 /* My Windows returns 'A'. */
1190 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1195 e.display = display;
1196 e.state = 0; /* unshifted */
1199 /* We exit on the first keycode found, to speed up the thing. */
1200 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1201 { /* Find a keycode that could have generated this virtual key */
1202 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1203 { /* We filter the extended bit, we don't know it */
1204 e.keycode = keyc; /* Store it temporarily */
1205 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1206 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1207 state), so set it to 0, we'll find another one */
1212 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1213 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1215 if (wCode==VK_DECIMAL)
1216 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1220 WARN("Unknown virtual key %X !!! \n", wCode);
1221 return 0; /* whatever */
1223 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1225 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1228 TRACE("returning no ANSI.\n");
1232 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1233 /* left and right */
1234 FIXME(" stub for NT\n");
1237 default: /* reserved */
1238 WARN("Unknown wMapType %d !\n", wMapType);
1244 /***********************************************************************
1245 * X11DRV_GetKeyNameText
1247 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1249 int vkey, ansi, scanCode;
1254 scanCode = lParam >> 16;
1255 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1257 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1258 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1260 /* handle "don't care" bit (0x02000000) */
1261 if (!(lParam & 0x02000000)) {
1280 ansi = X11DRV_MapVirtualKey(vkey, 2);
1281 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1283 /* first get the name of the "regular" keys which is the Upper case
1284 value of the keycap imprint. */
1285 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1286 (scanCode != 0x137) && /* PrtScn */
1287 (scanCode != 0x135) && /* numpad / */
1288 (scanCode != 0x37 ) && /* numpad * */
1289 (scanCode != 0x4a ) && /* numpad - */
1290 (scanCode != 0x4e ) ) /* numpad + */
1292 if ((nSize >= 2) && lpBuffer)
1294 *lpBuffer = toupper((char)ansi);
1302 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1303 without "extended-key" flag. However Wine generates scancode
1304 *with* "extended-key" flag. Seems to occur *only* for the
1305 function keys. Soooo.. We will leave the table alone and
1306 fudge the lookup here till the other part is found and fixed!!! */
1308 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1309 (scanCode == 0x157) || (scanCode == 0x158))
1310 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1312 /* let's do scancode -> keycode -> keysym -> String */
1314 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1315 if ((keyc2scan[keyc]) == scanCode)
1317 if (keyc <= max_keycode)
1319 keys = TSXKeycodeToKeysym(display, keyc, 0);
1320 name = TSXKeysymToString(keys);
1321 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1322 scanCode, keyc, (int)keys, name);
1323 if (lpBuffer && nSize && name)
1325 lstrcpynA(lpBuffer, name, nSize);
1330 /* Finally issue FIXME for unknown keys */
1332 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1333 if (lpBuffer && nSize)
1338 /***********************************************************************
1339 * X11DRV_KEYBOARD_MapDeadKeysym
1341 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1345 /* symbolic ASCII is the same as defined in rfc1345 */
1346 #ifdef XK_dead_tilde
1347 case XK_dead_tilde :
1349 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1350 return '~'; /* '? */
1351 #ifdef XK_dead_acute
1352 case XK_dead_acute :
1354 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1355 return 0xb4; /* '' */
1356 #ifdef XK_dead_circumflex
1357 case XK_dead_circumflex:
1359 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1360 return '^'; /* '> */
1361 #ifdef XK_dead_grave
1362 case XK_dead_grave :
1364 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1365 return '`'; /* '! */
1366 #ifdef XK_dead_diaeresis
1367 case XK_dead_diaeresis :
1369 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1370 return 0xa8; /* ': */
1371 #ifdef XK_dead_cedilla
1372 case XK_dead_cedilla :
1373 return 0xb8; /* ', */
1375 #ifdef XK_dead_macron
1376 case XK_dead_macron :
1377 return '-'; /* 'm isn't defined on iso-8859-x */
1379 #ifdef XK_dead_breve
1380 case XK_dead_breve :
1381 return 0xa2; /* '( */
1383 #ifdef XK_dead_abovedot
1384 case XK_dead_abovedot :
1385 return 0xff; /* '. */
1387 #ifdef XK_dead_abovering
1388 case XK_dead_abovering :
1389 return '0'; /* '0 isn't defined on iso-8859-x */
1391 #ifdef XK_dead_doubleacute
1392 case XK_dead_doubleacute :
1393 return 0xbd; /* '" */
1395 #ifdef XK_dead_caron
1396 case XK_dead_caron :
1397 return 0xb7; /* '< */
1399 #ifdef XK_dead_ogonek
1400 case XK_dead_ogonek :
1401 return 0xb2; /* '; */
1403 /* FIXME: I don't know this three.
1406 case XK_dead_voiced_sound :
1408 case XK_dead_semivoiced_sound :
1412 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1416 /***********************************************************************
1419 * The ToUnicode function translates the specified virtual-key code and keyboard
1420 * state to the corresponding Windows character or characters.
1422 * If the specified key is a dead key, the return value is negative. Otherwise,
1423 * it is one of the following values:
1425 * 0 The specified virtual key has no translation for the current state of the keyboard.
1426 * 1 One Windows character was copied to the buffer.
1427 * 2 Two characters were copied to the buffer. This usually happens when a
1428 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1429 * be composed with the specified virtual key to form a single character.
1431 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1434 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1435 LPWSTR bufW, int bufW_size, UINT flags)
1444 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1445 event is generated by windows. Just ignore it. */
1446 TRACE("scanCode=0, doing nothing\n");
1449 if (scanCode & 0x8000)
1451 TRACE("Key UP, doing nothing\n" );
1454 e.display = display;
1457 if (lpKeyState[VK_SHIFT] & 0x80)
1458 e.state |= ShiftMask;
1459 if (lpKeyState[VK_CAPITAL] & 0x01)
1460 e.state |= LockMask;
1461 if (lpKeyState[VK_CONTROL] & 0x80)
1463 if (lpKeyState[VK_MENU] & 0x80)
1464 e.state |= AltGrMask;
1466 e.state |= ControlMask;
1468 if (lpKeyState[VK_NUMLOCK] & 0x01)
1469 e.state |= NumLockMask;
1470 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1471 virtKey, scanCode, e.state);
1472 /* We exit on the first keycode found, to speed up the thing. */
1473 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1474 { /* Find a keycode that could have generated this virtual key */
1475 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1476 { /* We filter the extended bit, we don't know it */
1477 e.keycode = keyc; /* Store it temporarily */
1478 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1479 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1480 state), so set it to 0, we'll find another one */
1485 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1486 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1488 if (virtKey==VK_DECIMAL)
1489 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1493 WARN("Unknown virtual key %X !!! \n",virtKey);
1494 return virtKey; /* whatever */
1496 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1498 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1503 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1506 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1513 ksname = TSXKeysymToString(keysym);
1516 if ((keysym >> 8) != 0xff)
1518 ERR("Please report: no char for keysym %04lX (%s) :\n",
1520 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1521 virtKey, scanCode, e.keycode, e.state);
1525 else { /* ret != 0 */
1526 /* We have a special case to handle : Shift + arrow, shift + home, ...
1527 X returns a char for it, but Windows doesn't. Let's eat it. */
1528 if (!(lpKeyState[VK_NUMLOCK] & 0x01) /* NumLock is off */
1529 && (lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1530 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1536 /* more areas where X returns characters but Windows does not
1538 if ((lpKeyState[VK_CONTROL] & 0x80)&&(keysym>=48)&&
1545 /* We have another special case for delete key (XK_Delete) on an
1546 extended keyboard. X returns a char for it, but Windows doesn't */
1547 if (keysym == XK_Delete)
1552 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1553 && (keysym == XK_KP_Decimal))
1559 /* perform translation to unicode */
1562 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1563 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1564 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1568 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1569 ret, bufW ? bufW[1] : 0, bufW ? "" : "(no buffer)");
1573 /***********************************************************************
1574 * X11DRV_GetBeepActive
1576 BOOL X11DRV_GetBeepActive(void)
1578 XKeyboardState keyboard_state;
1580 TSXGetKeyboardControl(display, &keyboard_state);
1582 return keyboard_state.bell_percent != 0;
1585 /***********************************************************************
1586 * X11DRV_SetBeepActive
1588 void X11DRV_SetBeepActive(BOOL bActivate)
1590 XKeyboardControl keyboard_value;
1593 keyboard_value.bell_percent = -1;
1595 keyboard_value.bell_percent = 0;
1597 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1600 /***********************************************************************
1603 void X11DRV_Beep(void)
1605 TSXBell(display, 0);
1608 /***********************************************************************
1611 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1617 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1619 /* X keycode to virtual key */
1620 vkey = keyc2vkey[keyc] & 0xFF;
1621 /* The windows scancode is keyc-min_keycode */
1622 if (InputKeyStateTable[vkey]&0x80) {
1623 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1624 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1629 WARN("whoops, got len %ld?\n", len);
1633 /***********************************************************************
1636 BOOL X11DRV_GetDIData(
1638 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1639 LPDWORD entries, DWORD flags)
1641 int keyc,n,vkey,xentries;
1646 xentries = *entries;
1652 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1654 /* X keycode to virtual key */
1655 vkey = keyc2vkey[keyc] & 0xFF;
1656 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1660 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1661 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1662 dod[n].dwTimeStamp = 0; /* umm */
1663 dod[n].dwSequence = 0; /* umm */
1666 if (!(flags & DIGDD_PEEK))
1667 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1671 if (n) TRACE_(dinput)("%d entries\n",n);
1677 /***********************************************************************
1678 * X11DRV_GetKeyboardConfig
1680 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1683 /* For the moment, only get the auto-repeat mode */
1684 TSXGetKeyboardControl(display, &xks);
1685 cfg->auto_repeat = xks.global_auto_repeat;
1688 /***********************************************************************
1689 * X11DRV_SetKeyboardConfig
1691 extern void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1692 XKeyboardControl xkc;
1693 unsigned long X_mask = 0;
1695 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1696 X_mask |= KBAutoRepeatMode;
1697 xkc.auto_repeat_mode = cfg->auto_repeat;
1700 TSXChangeKeyboardControl(display, X_mask, &xkc);