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"
21 #include <X11/XKBlib.h>
29 #include "wine/winuser16.h"
31 #include "debugtools.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 */
53 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
56 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
58 /* Keyboard translation tables */
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",",<",".>","/?",
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",",?",";.",":/","!§",
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",",;",".:","þÞ",
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
\80","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µ",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",'-",".","éÉ",
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", ",;", ".:", "-_",
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µ",",;",".:·","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",?",";.",":/","=+~",
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",",?;",".:·","-_*",
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",",<",".>","/?",
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",",<",".>","/?",
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§",",;",".:","-_/",
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",",<",".>","/?",
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",",<",".>","/?",
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",",?<",".:>","-_*",
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åÅ",",<",".>","/?",
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",",?<",".:>","-_*",
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",",;",".:","-_",
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 {
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 */
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)
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,
613 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
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. */
621 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
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 );
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
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];
694 if (!TSXQueryKeymap(thread_display(), keys_return)) {
695 ERR("Error getting keymap !\n");
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));
706 /***********************************************************************
707 * X11DRV_KEYBOARD_HandleEvent
709 * Handle a X key event
711 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
715 WORD vkey = 0, bScan;
717 static BOOL force_extended = FALSE; /* hack for AltGr translation */
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;
763 Str[ascii_chars] = '\0';
767 ksname = TSXKeysymToString(keysym);
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);
786 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
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,
793 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
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,
802 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
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,
811 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
814 /* Not Num nor Caps : end of intermediary states for both. */
818 bScan = keyc2scan[event->keycode] & 0xFF;
819 TRACE_(key)("bScan = 0x%02x.\n", bScan);
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.
840 X11DRV_KEYBOARD_DetectLayout (void)
842 Display *display = thread_display();
843 unsigned current, match, mismatch, seq;
844 int score, keyc, i, key, pkey, ok, syms;
846 const char (*lkey)[MAIN_LEN][4];
847 unsigned max_seq = 0;
848 int max_score = 0, ismatch = 0;
852 syms = keysyms_per_keycode;
854 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
857 for (current = 0; main_key_tab[current].comment; current++) {
858 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
863 lkey = main_key_tab[current].key;
865 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
866 /* get data for keycode from X server */
867 for (i = 0; i < syms; i++) {
868 keysym = TSXKeycodeToKeysym (display, keyc, i);
869 /* Allow both one-byte and two-byte national keysyms */
870 if ((keysym < 0x800) && (keysym != ' '))
871 ckey[i] = keysym & 0xFF;
873 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
877 /* search for a match in layout table */
878 /* right now, we just find an absolute match for defined positions */
879 /* (undefined positions are ignored, so if it's defined as "3#" in */
880 /* the table, it's okay that the X server has "3#£", for example) */
881 /* however, the score will be higher for longer matches */
882 for (key = 0; key < MAIN_LEN; key++) {
883 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
884 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
886 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
894 /* count the matches and mismatches */
897 /* and how much the keycode order matches */
898 if (key > pkey) seq++;
901 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
908 TRACE("matches=%d, mismatches=%d, score=%d\n",
909 match, mismatch, score);
910 if ((score > max_score) ||
911 ((score == max_score) && (seq > max_seq))) {
912 /* best match so far */
913 kbd_layout = current;
919 /* we're done, report results if necessary */
922 "Your keyboard layout was not found!\n"
923 "Using closest match instead (%s) for scancode mapping.\n"
924 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
925 "to us for inclusion into future Wine releases.\n"
926 "See documentation/keyboard for more information.\n",
927 main_key_tab[kbd_layout].comment);
930 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
933 /**********************************************************************
934 * InitKeyboard (X11DRV.@)
936 void X11DRV_InitKeyboard(void)
939 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
941 Display *display = thread_display();
943 XModifierKeymap *mmp;
947 WORD scan, vkey, OEMvkey;
948 int keyc, i, keyn, syms;
949 char ckey[4]={0,0,0,0};
950 const char (*lkey)[MAIN_LEN][4];
954 is_xkb = XkbQueryExtension(display,
955 &xkb_opcode, &xkb_event, &xkb_error,
956 &xkb_major, &xkb_minor);
958 /* we have XKB, approximate Windows behaviour */
959 XkbSetDetectableAutoRepeat(display, True, NULL);
963 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
964 ksp = TSXGetKeyboardMapping(display, min_keycode,
965 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
966 /* We are only interested in keysyms_per_keycode.
967 There is no need to hold a local copy of the keysyms table */
969 mmp = TSXGetModifierMapping(display);
970 kcp = mmp->modifiermap;
971 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
975 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
980 for (k = 0; k < keysyms_per_keycode; k += 1)
981 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
984 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
986 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
988 NumLockMask = 1 << i;
989 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
993 TSXFreeModifiermap(mmp);
995 /* Detect the keyboard layout */
996 X11DRV_KEYBOARD_DetectLayout();
997 lkey = main_key_tab[kbd_layout].key;
998 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1000 /* Now build two conversion arrays :
1001 * keycode -> vkey + scancode + extended
1002 * vkey + extended -> keycode */
1004 e2.display = display;
1007 OEMvkey = VK_OEM_7; /* next is available. */
1008 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1010 e2.keycode = (KeyCode)keyc;
1011 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1013 if (keysym) /* otherwise, keycode not used */
1015 if ((keysym >> 8) == 0xFF) /* non-character key */
1017 int key = keysym & 0xff;
1019 if (key >= 0x08 && key <= 0x1B) { /* special key */
1020 vkey = special_key_vkey[key - 0x08];
1021 scan = special_key_scan[key - 0x08];
1022 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
1023 vkey = cursor_key_vkey[key - 0x50];
1024 scan = cursor_key_scan[key - 0x50];
1025 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
1026 vkey = misc_key_vkey[key - 0x60];
1027 scan = misc_key_scan[key - 0x60];
1028 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
1029 vkey = keypad_key_vkey[key - 0x7E];
1030 scan = keypad_key_scan[key - 0x7E];
1031 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
1032 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
1033 scan = function_key_scan[key - 0xBE];
1034 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
1035 vkey = modifier_key_vkey[key - 0xE1];
1036 scan = modifier_key_scan[key - 0xE1];
1037 } else if (key == 0xFF) { /* DEL key */
1041 /* set extended bit when necessary */
1042 if (scan & 0x100) vkey |= 0x100;
1043 } else if (keysym == 0x20) { /* Spacebar */
1047 /* we seem to need to search the layout-dependent scancodes */
1048 int maxlen=0,maxval=-1,ok;
1049 for (i=0; i<syms; i++) {
1050 keysym = TSXKeycodeToKeysym(display, keyc, i);
1051 if ((keysym<0x800) && (keysym!=' ')) {
1052 ckey[i] = keysym & 0xFF;
1054 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1057 /* find key with longest match streak */
1058 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1059 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1060 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1061 if (ok||(i>maxlen)) {
1062 maxlen=i; maxval=keyn;
1068 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1069 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1070 scan = (*lscan)[maxval];
1071 vkey = (*lvkey)[maxval];
1075 /* find a suitable layout-dependent VK code */
1076 /* (most Winelib apps ought to be able to work without layout tables!) */
1077 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1079 keysym = TSXLookupKeysym(&e2, i);
1080 if ((keysym >= VK_0 && keysym <= VK_9)
1081 || (keysym >= VK_A && keysym <= VK_Z)) {
1086 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1088 keysym = TSXLookupKeysym(&e2, i);
1091 case ';': vkey = VK_OEM_1; break;
1092 case '/': vkey = VK_OEM_2; break;
1093 case '`': vkey = VK_OEM_3; break;
1094 case '[': vkey = VK_OEM_4; break;
1095 case '\\': vkey = VK_OEM_5; break;
1096 case ']': vkey = VK_OEM_6; break;
1097 case '\'': vkey = VK_OEM_7; break;
1098 case ',': vkey = VK_OEM_COMMA; break;
1099 case '.': vkey = VK_OEM_PERIOD; break;
1100 case '-': vkey = VK_OEM_MINUS; break;
1101 case '+': vkey = VK_OEM_PLUS; break;
1107 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1108 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1111 case 0xc1 : OEMvkey=0xdb; break;
1112 case 0xe5 : OEMvkey=0xe9; break;
1113 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1118 if (TRACE_ON(keyboard))
1120 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1121 OEMvkey, e2.keycode);
1123 for (i = 0; i < keysyms_per_keycode; i += 1)
1127 keysym = TSXLookupKeysym(&e2, i);
1128 ksname = TSXKeysymToString(keysym);
1130 ksname = "NoSymbol";
1131 DPRINTF( "%lX (%s) ", keysym, ksname);
1137 keyc2vkey[e2.keycode] = vkey;
1138 keyc2scan[e2.keycode] = scan;
1141 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1142 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1143 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1145 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1146 ksname = TSXKeysymToString(keysym);
1147 if (!ksname) ksname = "NoSymbol";
1149 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1151 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1152 keyc2scan[keyc]=scan++;
1155 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1156 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1157 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1158 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1159 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1160 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1161 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1164 /***********************************************************************
1165 * VkKeyScan (X11DRV.@)
1167 WORD X11DRV_VkKeyScan(CHAR cChar)
1169 Display *display = thread_display();
1175 /* char->keysym (same for ANSI chars) */
1176 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1177 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1179 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1181 { /* It didn't work ... let's try with deadchar code. */
1182 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1185 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1186 cChar,keysym,keysym,keycode);
1190 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1191 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1194 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1196 case 1 : highbyte = 0x0100; break;
1197 case 2 : highbyte = 0x0600; break;
1198 case 3 : highbyte = 0x0700; break;
1199 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1202 index : 0 adds 0x0000
1203 index : 1 adds 0x0100 (shift)
1204 index : ? adds 0x0200 (ctrl)
1205 index : 2 adds 0x0600 (ctrl+alt)
1206 index : 3 adds 0x0700 (ctrl+alt+shift)
1209 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1210 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1213 /***********************************************************************
1214 * MapVirtualKey (X11DRV.@)
1216 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1218 Display *display = thread_display();
1220 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1222 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1224 case 0: { /* vkey-code to scan-code */
1225 /* let's do vkey -> keycode -> scan */
1227 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1228 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1229 returnMVK (keyc2scan[keyc] & 0xFF);
1230 TRACE("returning no scan-code.\n");
1233 case 1: { /* scan-code to vkey-code */
1234 /* let's do scan -> keycode -> vkey */
1236 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1237 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1238 returnMVK (keyc2vkey[keyc] & 0xFF);
1239 TRACE("returning no vkey-code.\n");
1242 case 2: { /* vkey-code to unshifted ANSI code */
1243 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1244 /* My Windows returns 'A'. */
1245 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1250 e.display = display;
1251 e.state = 0; /* unshifted */
1254 /* We exit on the first keycode found, to speed up the thing. */
1255 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1256 { /* Find a keycode that could have generated this virtual key */
1257 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1258 { /* We filter the extended bit, we don't know it */
1259 e.keycode = keyc; /* Store it temporarily */
1260 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1261 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1262 state), so set it to 0, we'll find another one */
1267 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1268 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1270 if (wCode==VK_DECIMAL)
1271 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1275 WARN("Unknown virtual key %X !!! \n", wCode);
1276 return 0; /* whatever */
1278 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1280 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1283 TRACE("returning no ANSI.\n");
1287 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1288 /* left and right */
1289 FIXME(" stub for NT\n");
1292 default: /* reserved */
1293 WARN("Unknown wMapType %d !\n", wMapType);
1299 /***********************************************************************
1300 * GetKeyNameText (X11DRV.@)
1302 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1304 int vkey, ansi, scanCode;
1309 scanCode = lParam >> 16;
1310 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1312 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1313 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1315 /* handle "don't care" bit (0x02000000) */
1316 if (!(lParam & 0x02000000)) {
1335 ansi = X11DRV_MapVirtualKey(vkey, 2);
1336 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1338 /* first get the name of the "regular" keys which is the Upper case
1339 value of the keycap imprint. */
1340 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1341 (scanCode != 0x137) && /* PrtScn */
1342 (scanCode != 0x135) && /* numpad / */
1343 (scanCode != 0x37 ) && /* numpad * */
1344 (scanCode != 0x4a ) && /* numpad - */
1345 (scanCode != 0x4e ) ) /* numpad + */
1347 if ((nSize >= 2) && lpBuffer)
1349 *lpBuffer = toupper((char)ansi);
1357 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1358 without "extended-key" flag. However Wine generates scancode
1359 *with* "extended-key" flag. Seems to occur *only* for the
1360 function keys. Soooo.. We will leave the table alone and
1361 fudge the lookup here till the other part is found and fixed!!! */
1363 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1364 (scanCode == 0x157) || (scanCode == 0x158))
1365 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1367 /* let's do scancode -> keycode -> keysym -> String */
1369 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1370 if ((keyc2scan[keyc]) == scanCode)
1372 if (keyc <= max_keycode)
1374 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1375 name = TSXKeysymToString(keys);
1376 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1377 scanCode, keyc, (int)keys, name);
1378 if (lpBuffer && nSize && name)
1380 lstrcpynA(lpBuffer, name, nSize);
1385 /* Finally issue FIXME for unknown keys */
1387 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1388 if (lpBuffer && nSize)
1393 /***********************************************************************
1394 * X11DRV_KEYBOARD_MapDeadKeysym
1396 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1400 /* symbolic ASCII is the same as defined in rfc1345 */
1401 #ifdef XK_dead_tilde
1402 case XK_dead_tilde :
1404 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1405 return '~'; /* '? */
1406 #ifdef XK_dead_acute
1407 case XK_dead_acute :
1409 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1410 return 0xb4; /* '' */
1411 #ifdef XK_dead_circumflex
1412 case XK_dead_circumflex:
1414 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1415 return '^'; /* '> */
1416 #ifdef XK_dead_grave
1417 case XK_dead_grave :
1419 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1420 return '`'; /* '! */
1421 #ifdef XK_dead_diaeresis
1422 case XK_dead_diaeresis :
1424 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1425 return 0xa8; /* ': */
1426 #ifdef XK_dead_cedilla
1427 case XK_dead_cedilla :
1428 return 0xb8; /* ', */
1430 #ifdef XK_dead_macron
1431 case XK_dead_macron :
1432 return '-'; /* 'm isn't defined on iso-8859-x */
1434 #ifdef XK_dead_breve
1435 case XK_dead_breve :
1436 return 0xa2; /* '( */
1438 #ifdef XK_dead_abovedot
1439 case XK_dead_abovedot :
1440 return 0xff; /* '. */
1442 #ifdef XK_dead_abovering
1443 case XK_dead_abovering :
1444 return '0'; /* '0 isn't defined on iso-8859-x */
1446 #ifdef XK_dead_doubleacute
1447 case XK_dead_doubleacute :
1448 return 0xbd; /* '" */
1450 #ifdef XK_dead_caron
1451 case XK_dead_caron :
1452 return 0xb7; /* '< */
1454 #ifdef XK_dead_ogonek
1455 case XK_dead_ogonek :
1456 return 0xb2; /* '; */
1458 /* FIXME: I don't know this three.
1461 case XK_dead_voiced_sound :
1463 case XK_dead_semivoiced_sound :
1467 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1471 /***********************************************************************
1472 * ToUnicode (X11DRV.@)
1474 * The ToUnicode function translates the specified virtual-key code and keyboard
1475 * state to the corresponding Windows character or characters.
1477 * If the specified key is a dead key, the return value is negative. Otherwise,
1478 * it is one of the following values:
1480 * 0 The specified virtual key has no translation for the current state of the keyboard.
1481 * 1 One Windows character was copied to the buffer.
1482 * 2 Two characters were copied to the buffer. This usually happens when a
1483 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1484 * be composed with the specified virtual key to form a single character.
1486 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1489 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1490 LPWSTR bufW, int bufW_size, UINT flags)
1492 Display *display = thread_display();
1500 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1501 event is generated by windows. Just ignore it. */
1502 TRACE("scanCode=0, doing nothing\n");
1505 if (scanCode & 0x8000)
1507 TRACE("Key UP, doing nothing\n" );
1510 e.display = display;
1513 if (lpKeyState[VK_SHIFT] & 0x80)
1514 e.state |= ShiftMask;
1515 if (lpKeyState[VK_CAPITAL] & 0x01)
1516 e.state |= LockMask;
1517 if (lpKeyState[VK_CONTROL] & 0x80)
1519 if (lpKeyState[VK_MENU] & 0x80)
1520 e.state |= AltGrMask;
1522 e.state |= ControlMask;
1524 if (lpKeyState[VK_NUMLOCK] & 0x01)
1525 e.state |= NumLockMask;
1526 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1527 virtKey, scanCode, e.state);
1528 /* We exit on the first keycode found, to speed up the thing. */
1529 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1530 { /* Find a keycode that could have generated this virtual key */
1531 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1532 { /* We filter the extended bit, we don't know it */
1533 e.keycode = keyc; /* Store it temporarily */
1534 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1535 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1536 state), so set it to 0, we'll find another one */
1541 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1542 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1544 if (virtKey==VK_DECIMAL)
1545 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1549 WARN("Unknown virtual key %X !!! \n",virtKey);
1550 return virtKey; /* whatever */
1552 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1554 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1559 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1562 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1569 ksname = TSXKeysymToString(keysym);
1572 if ((keysym >> 8) != 0xff)
1574 ERR("Please report: no char for keysym %04lX (%s) :\n",
1576 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1577 virtKey, scanCode, e.keycode, e.state);
1581 else { /* ret != 0 */
1582 /* We have a special case to handle : Shift + arrow, shift + home, ...
1583 X returns a char for it, but Windows doesn't. Let's eat it. */
1584 if (!(e.state & NumLockMask) /* NumLock is off */
1585 && (e.state & ShiftMask) /* Shift is pressed */
1586 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1592 /* more areas where X returns characters but Windows does not
1593 CTRL + number or CTRL + symbol*/
1594 if (e.state & ControlMask)
1596 if (((keysym>=33) && (keysym < 'A')) ||
1597 ((keysym > 'Z') && (keysym < 'a')))
1604 /* We have another special case for delete key (XK_Delete) on an
1605 extended keyboard. X returns a char for it, but Windows doesn't */
1606 if (keysym == XK_Delete)
1611 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1612 && (keysym == XK_KP_Decimal))
1618 /* perform translation to unicode */
1621 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1622 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1623 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1627 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1628 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1632 /***********************************************************************
1635 void X11DRV_Beep(void)
1637 TSXBell(thread_display(), 0);
1640 /***********************************************************************
1641 * GetDIState (X11DRV.@)
1643 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1649 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1651 /* X keycode to virtual key */
1652 vkey = keyc2vkey[keyc] & 0xFF;
1653 /* The windows scancode is keyc-min_keycode */
1654 if (InputKeyStateTable[vkey]&0x80) {
1655 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1656 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1661 WARN("whoops, got len %ld?\n", len);
1665 /***********************************************************************
1666 * GetDIData (X11DRV.@)
1668 BOOL X11DRV_GetDIData(
1670 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1671 LPDWORD entries, DWORD flags)
1673 int keyc,n,vkey,xentries;
1678 xentries = *entries;
1684 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1686 /* X keycode to virtual key */
1687 vkey = keyc2vkey[keyc] & 0xFF;
1688 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1692 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1693 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1694 dod[n].dwTimeStamp = 0; /* umm */
1695 dod[n].dwSequence = 0; /* umm */
1698 if (!(flags & DIGDD_PEEK))
1699 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1703 if (n) TRACE_(dinput)("%d entries\n",n);