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"
38 DEFAULT_DEBUG_CHANNEL(keyboard);
39 DECLARE_DEBUG_CHANNEL(key);
40 DECLARE_DEBUG_CHANNEL(dinput);
42 extern BYTE InputKeyStateTable[256];
44 extern LPBYTE pKeyStateTable;
46 int min_keycode, max_keycode, keysyms_per_keycode;
47 WORD keyc2vkey[256], keyc2scan[256];
49 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
50 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
52 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
55 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
57 /* Keyboard translation tables */
59 static const WORD main_key_scan_qwerty[MAIN_LEN] =
61 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
62 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
63 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
64 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
65 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
66 0x56 /* the 102nd key (actually to the right of l-shift) */
69 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
71 /* NOTE: this layout must concur with the scan codes layout above */
72 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,
73 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,
74 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,
75 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
76 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
79 static const WORD main_key_vkey_azerty[MAIN_LEN] =
81 /* NOTE: this layout must concur with the scan codes layout above */
82 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,
83 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,
84 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,
85 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
86 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
89 /* FIXME: add other layouts, such as DVORAK and German QWERTZ */
91 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
93 /* the VK mappings for the main keyboard will be auto-assigned as before,
94 so what we have here is just the character tables */
95 /* order: Normal, Shift, AltGr, Shift-AltGr */
96 /* We recommend you write just what is guaranteed to be correct (i.e. what's
97 written on the keycaps), not the bunch of special characters behind AltGr
98 and Shift-AltGr if it can vary among different X servers */
99 /* Remember that your 102nd key (to the right of l-shift) should be on a
100 separate line, see existing tables */
101 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
102 /* Remember to also add your new table to the layout index table far below! */
104 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
105 static const char main_key_US[MAIN_LEN][4] =
107 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
108 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
109 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
110 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
113 /*** United States keyboard layout (phantom key version) */
114 /* (XFree86 reports the <> key even if it's not physically there) */
115 static const char main_key_US_phantom[MAIN_LEN][4] =
117 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
118 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
119 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
120 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
121 "<>" /* the phantom key */
124 /*** British keyboard layout */
125 static const char main_key_UK[MAIN_LEN][4] =
127 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
128 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
129 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
130 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
134 /*** French keyboard layout (contributed by Eric Pouech) */
135 static const char main_key_FR[MAIN_LEN][4] =
137 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
138 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
139 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
140 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
144 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
145 static const char main_key_IS[MAIN_LEN][4] =
147 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
148 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
149 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
150 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
154 /*** German keyboard layout (contributed by Ulrich Weigand) */
155 static const char main_key_DE[MAIN_LEN][4] =
157 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
158 "qQ@","wW","eE
\80","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
159 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
160 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
164 /*** German keyboard layout without dead keys */
165 static const char main_key_DE_nodead[MAIN_LEN][4] =
167 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
168 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
169 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
170 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
174 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
175 static const char main_key_SG[MAIN_LEN][4] =
177 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
178 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
179 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
180 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
184 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
185 static const char main_key_SF[MAIN_LEN][4] =
187 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
188 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
189 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
190 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
194 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
195 static const char main_key_NO[MAIN_LEN][4] =
197 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
198 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
199 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
200 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
204 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
205 static const char main_key_DA[MAIN_LEN][4] =
207 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
208 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
209 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
210 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
214 /*** Swedish keyboard layout (contributed by Peter Bortas) */
215 static const char main_key_SE[MAIN_LEN][4] =
217 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
218 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
219 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
220 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
224 /*** Canadian French keyboard layout */
225 static const char main_key_CF[MAIN_LEN][4] =
227 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
228 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
229 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
230 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
234 /*** Portuguese keyboard layout */
235 static const char main_key_PT[MAIN_LEN][4] =
237 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
238 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
239 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
240 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
244 /*** Italian keyboard layout */
245 static const char main_key_IT[MAIN_LEN][4] =
247 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
248 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
249 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
250 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
254 /*** Finnish keyboard layout */
255 static const char main_key_FI[MAIN_LEN][4] =
257 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
258 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
259 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
260 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
264 /*** Russian keyboard layout (contributed by Pavel Roskin) */
265 static const char main_key_RU[MAIN_LEN][4] =
267 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
268 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
269 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
270 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
273 /*** Russian keyboard layout (phantom key version) */
274 static const char main_key_RU_phantom[MAIN_LEN][4] =
276 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
277 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
278 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
279 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
280 "<>" /* the phantom key */
283 /*** Russian keyboard layout KOI8-R */
284 static const char main_key_RU_koi8r[MAIN_LEN][4] =
286 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
287 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
288 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
289 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
290 "<>" /* the phantom key */
293 /*** Ukrainian keyboard layout KOI8-U */
294 static const char main_key_UA[MAIN_LEN][4] =
296 "`~½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
297 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
298 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
299 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
300 "<>" /* the phantom key */
303 /*** Spanish keyboard layout (contributed by José Marcos López) */
304 static const char main_key_ES[MAIN_LEN][4] =
306 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
307 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
308 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
309 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
313 /*** Belgian keyboard layout ***/
314 static const char main_key_BE[MAIN_LEN][4] =
316 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
317 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
318 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
319 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
323 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
324 static const char main_key_HU[MAIN_LEN][4] =
326 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
327 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
328 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
329 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
333 /*** Polish (programmer's) keyboard layout ***/
334 static const char main_key_PL[MAIN_LEN][4] =
336 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
337 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
338 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
339 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
343 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
344 static const char main_key_HR_jelly[MAIN_LEN][4] =
346 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
347 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
348 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
349 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
353 /*** Croatian keyboard layout ***/
354 static const char main_key_HR[MAIN_LEN][4] =
356 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
357 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
358 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
359 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
363 /*** Japanese 106 keyboard layout ***/
364 static const char main_key_JA_jp106[MAIN_LEN][4] =
366 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
367 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
368 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
369 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
373 /*** Japanese pc98x1 keyboard layout ***/
374 static const char main_key_JA_pc98x1[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",",<",".>","/?",
383 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
384 static const char main_key_PT_br[MAIN_LEN][4] =
386 "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
387 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
388 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
389 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
392 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
393 static const char main_key_US_intl[MAIN_LEN][4] =
395 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
396 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
397 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
398 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
401 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
402 - dead_abovering replaced with degree - no symbol in iso8859-2
403 - brokenbar replaced with bar */
404 static const char main_key_SK[MAIN_LEN][4] =
406 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0)","=%","",
407 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/÷","ä(×",
408 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ô\"$","§!ß","ò)¤",
409 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
413 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
414 static const char main_key_SK_prog[MAIN_LEN][4] =
416 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
417 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
418 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
419 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
423 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
424 static const char main_key_CS[MAIN_LEN][4] =
426 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
427 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
428 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£","ù\"$","§!ß","¨'",
429 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
433 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
434 static const char main_key_LA[MAIN_LEN][4] =
436 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
437 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
438 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
439 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
443 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
444 static const char main_key_LT_B[MAIN_LEN][4] =
446 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
447 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
448 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
449 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
452 /*** Turkish keyboard Layout */
453 static const char main_key_TK[MAIN_LEN][4] =
455 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
456 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
457 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
458 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
461 /*** Layout table. Add your keyboard mappings to this list */
462 static const struct {
464 const UINT layout_cp; /* Code page for this layout */
465 const char (*key)[MAIN_LEN][4];
466 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
467 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
469 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
470 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
471 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
472 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
473 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
474 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
475 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
476 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
477 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
478 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
479 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
480 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
481 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
482 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
483 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
484 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
485 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
486 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
487 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
488 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
489 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
490 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
491 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
492 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
493 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
494 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
495 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
496 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
497 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
498 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
499 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
500 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
501 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
502 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
503 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
504 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
506 {NULL, 0, NULL, NULL, NULL} /* sentinel */
508 static unsigned kbd_layout=0; /* index into above table of layouts */
510 /* maybe more of these scancodes should be extended? */
511 /* extended must be set for ALT_R, CTRL_R,
512 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
513 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
514 /* FIXME should we set extended bit for NumLock ? My
515 * Windows does ... DF */
516 /* Yes, to distinguish based on scan codes, also
517 for PrtScn key ... GA */
519 static const WORD special_key_vkey[] =
521 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
522 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
523 0, 0, 0, VK_ESCAPE /* FF18 */
525 static const WORD special_key_scan[] =
527 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
528 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
529 0, 0, 0, 0x01 /* FF18 */
532 static const WORD cursor_key_vkey[] =
534 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
535 VK_NEXT, VK_END /* FF50 */
537 static const WORD cursor_key_scan[] =
539 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
542 static const WORD misc_key_vkey[] =
544 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
545 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
547 static const WORD misc_key_scan[] =
549 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
550 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
553 static const WORD keypad_key_vkey[] =
555 0, VK_NUMLOCK, /* FF7E */
556 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
557 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
558 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
559 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
560 VK_INSERT, VK_DELETE, /* FF98 */
561 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
562 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
563 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
564 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
565 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
566 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
568 static const WORD keypad_key_scan[] =
570 0x138, 0x145, /* FF7E */
571 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
572 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
573 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
574 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
575 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
576 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
577 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
578 0x48, 0x49 /* FFB8 */
581 static const WORD function_key_vkey[] =
583 VK_F1, VK_F2, /* FFBE */
584 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
585 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
587 static const WORD function_key_scan[] =
589 0x3B, 0x3C, /* FFBE */
590 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
591 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
594 static const WORD modifier_key_vkey[] =
596 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
597 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
599 static const WORD modifier_key_scan[] =
601 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
602 0x38, 0x138, 0x38, 0x138 /* FFE7 */
605 /* Returns the Windows virtual key code associated with the X event <e> */
606 static WORD EVENT_event_to_vkey( XKeyEvent *e)
610 TSXLookupString(e, NULL, 0, &keysym, NULL);
612 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
613 && (e->state & NumLockMask))
614 /* Only the Keypad keys 0-9 and . send different keysyms
615 * depending on the NumLock state */
616 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
618 return keyc2vkey[e->keycode];
621 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
623 /**********************************************************************
624 * KEYBOARD_GenerateMsg
626 * Generate Down+Up messages when NumLock or CapsLock is pressed.
628 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
631 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
634 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
638 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
639 don't treat it. It's from the same key press. Then the state goes to ON.
640 And from there, a 'release' event will switch off the toggle key. */
642 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
645 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
646 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
647 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
649 if (Evtype!=KeyPress)
651 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
652 KEYBOARD_SendEvent( vkey, scan, down,
653 event_x, event_y, event_time );
654 KEYBOARD_SendEvent( vkey, scan, up,
655 event_x, event_y, event_time );
657 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
660 else /* it was OFF */
661 if (Evtype==KeyPress)
663 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
664 KEYBOARD_SendEvent( vkey, scan, down,
665 event_x, event_y, event_time );
666 KEYBOARD_SendEvent( vkey, scan, up,
667 event_x, event_y, event_time );
668 *State=TRUE; /* Goes to intermediary state before going to ON */
669 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
674 /***********************************************************************
675 * KEYBOARD_UpdateOneState
677 * Updates internal state for <vkey>, depending on key <state> under X
680 static void KEYBOARD_UpdateOneState ( int vkey, int state )
682 /* Do something if internal table state != X state for keycode */
683 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
685 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
686 vkey, pKeyStateTable[vkey]);
688 /* Fake key being pressed inside wine */
689 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
690 0, 0, GetTickCount() );
692 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
696 /***********************************************************************
697 * X11DRV_KEYBOARD_UpdateState
699 * Update modifiers state (Ctrl, Alt, Shift)
700 * when window is activated (called by EVENT_FocusIn in event.c)
702 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
703 * from wine to another application and back.
704 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
707 void X11DRV_KEYBOARD_UpdateState ( void )
709 /* extract a bit from the char[32] bit suite */
710 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
712 char keys_return[32];
715 if (!TSXQueryKeymap(thread_display(), keys_return)) {
716 ERR("Error getting keymap !\n");
720 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
721 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
722 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
723 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
727 /***********************************************************************
728 * X11DRV_KEYBOARD_HandleEvent
730 * Handle a X key event
732 void X11DRV_KEYBOARD_HandleEvent( XKeyEvent *event, int x, int y )
736 WORD vkey = 0, bScan;
738 static BOOL force_extended = FALSE; /* hack for AltGr translation */
741 DWORD event_time = event->time - X11DRV_server_startticks;
743 /* this allows support for dead keys */
744 if ((event->keycode >> 8) == 0x10)
745 event->keycode=(event->keycode & 0xff);
747 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
749 TRACE_(key)("state = %X\n", event->state);
751 /* If XKB extensions is used, the state mask for AltGr will used the group
752 index instead of the modifier mask. The group index is set in bits
753 13-14 of the state field in the XKeyEvent structure. So if AltGr is
754 pressed, look if the group index is diferent than 0. From XKB
755 extension documentation, the group index should for AltGr should
756 be 2 (event->state = 0x2000). It's probably better to not assume a
757 predefined group index and find it dynamically
759 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
760 if ( AltGrState && (event->state & 0x6000) )
761 AltGrMask = event->state & 0x6000;
763 if (keysym == XK_Mode_switch)
765 TRACE_(key)("Alt Gr key event received\n");
766 event->keycode = kcControl; /* Simulate Control */
767 X11DRV_KEYBOARD_HandleEvent( event, x, y );
769 event->keycode = kcAlt; /* Simulate Alt */
770 force_extended = TRUE;
771 X11DRV_KEYBOARD_HandleEvent( event, x, y );
772 force_extended = FALSE;
774 /* Here we save the pressed/released state of the AltGr key, to be able to
775 identify the group index associated with AltGr on the next key pressed *
776 see comment above. */
777 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
782 Str[ascii_chars] = '\0';
786 ksname = TSXKeysymToString(keysym);
789 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
790 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
791 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
794 vkey = EVENT_event_to_vkey(event);
795 if (force_extended) vkey |= 0x100;
797 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
798 event->keycode, vkey);
805 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, x, y, event_time );
808 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
809 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, x, y, event_time );
810 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
813 /* Adjust the NUMLOCK state if it has been changed outside wine */
814 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
816 TRACE("Adjusting NumLock state. \n");
817 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, x, y, event_time );
818 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, x, y, event_time );
820 /* Adjust the CAPSLOCK state if it has been changed outside wine */
821 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
823 TRACE("Adjusting Caps Lock state.\n");
824 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, x, y, event_time );
825 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, x, y, event_time );
827 /* Not Num nor Caps : end of intermediary states for both. */
831 bScan = keyc2scan[event->keycode] & 0xFF;
832 TRACE_(key)("bScan = 0x%02x.\n", bScan);
835 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
836 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
837 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
839 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags, x, y, event_time );
844 /**********************************************************************
845 * X11DRV_KEYBOARD_DetectLayout
847 * Called from X11DRV_InitKeyboard
848 * This routine walks through the defined keyboard layouts and selects
849 * whichever matches most closely.
852 X11DRV_KEYBOARD_DetectLayout (void)
854 Display *display = thread_display();
855 unsigned current, match, mismatch, seq;
856 int score, keyc, i, key, pkey, ok, syms;
858 const char (*lkey)[MAIN_LEN][4];
859 unsigned max_seq = 0;
860 int max_score = 0, ismatch = 0;
864 syms = keysyms_per_keycode;
866 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
869 for (current = 0; main_key_tab[current].comment; current++) {
870 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
875 lkey = main_key_tab[current].key;
877 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
878 /* get data for keycode from X server */
879 for (i = 0; i < syms; i++) {
880 keysym = TSXKeycodeToKeysym (display, keyc, i);
881 /* Allow both one-byte and two-byte national keysyms */
882 if ((keysym < 0x800) && (keysym != ' '))
883 ckey[i] = keysym & 0xFF;
885 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
889 /* search for a match in layout table */
890 /* right now, we just find an absolute match for defined positions */
891 /* (undefined positions are ignored, so if it's defined as "3#" in */
892 /* the table, it's okay that the X server has "3#£", for example) */
893 /* however, the score will be higher for longer matches */
894 for (key = 0; key < MAIN_LEN; key++) {
895 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
896 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
898 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
906 /* count the matches and mismatches */
909 /* and how much the keycode order matches */
910 if (key > pkey) seq++;
913 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
920 TRACE("matches=%d, mismatches=%d, score=%d\n",
921 match, mismatch, score);
922 if ((score > max_score) ||
923 ((score == max_score) && (seq > max_seq))) {
924 /* best match so far */
925 kbd_layout = current;
931 /* we're done, report results if necessary */
934 "Your keyboard layout was not found!\n"
935 "Using closest match instead (%s) for scancode mapping.\n"
936 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
937 "to us for inclusion into future Wine releases.\n"
938 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
939 main_key_tab[kbd_layout].comment);
942 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
945 /**********************************************************************
946 * InitKeyboard (X11DRV.@)
948 void X11DRV_InitKeyboard(void)
951 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
953 Display *display = thread_display();
955 XModifierKeymap *mmp;
959 WORD scan, vkey, OEMvkey;
960 int keyc, i, keyn, syms;
961 char ckey[4]={0,0,0,0};
962 const char (*lkey)[MAIN_LEN][4];
966 is_xkb = XkbQueryExtension(display,
967 &xkb_opcode, &xkb_event, &xkb_error,
968 &xkb_major, &xkb_minor);
970 /* we have XKB, approximate Windows behaviour */
971 XkbSetDetectableAutoRepeat(display, True, NULL);
975 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
976 ksp = TSXGetKeyboardMapping(display, min_keycode,
977 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
978 /* We are only interested in keysyms_per_keycode.
979 There is no need to hold a local copy of the keysyms table */
981 mmp = TSXGetModifierMapping(display);
982 kcp = mmp->modifiermap;
983 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
987 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
992 for (k = 0; k < keysyms_per_keycode; k += 1)
993 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
996 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
998 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1000 NumLockMask = 1 << i;
1001 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1005 TSXFreeModifiermap(mmp);
1007 /* Detect the keyboard layout */
1008 X11DRV_KEYBOARD_DetectLayout();
1009 lkey = main_key_tab[kbd_layout].key;
1010 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1012 /* Now build two conversion arrays :
1013 * keycode -> vkey + scancode + extended
1014 * vkey + extended -> keycode */
1016 e2.display = display;
1019 OEMvkey = VK_OEM_7; /* next is available. */
1020 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1022 e2.keycode = (KeyCode)keyc;
1023 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1025 if (keysym) /* otherwise, keycode not used */
1027 if ((keysym >> 8) == 0xFF) /* non-character key */
1029 int key = keysym & 0xff;
1031 if (key >= 0x08 && key <= 0x1B) { /* special key */
1032 vkey = special_key_vkey[key - 0x08];
1033 scan = special_key_scan[key - 0x08];
1034 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
1035 vkey = cursor_key_vkey[key - 0x50];
1036 scan = cursor_key_scan[key - 0x50];
1037 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
1038 vkey = misc_key_vkey[key - 0x60];
1039 scan = misc_key_scan[key - 0x60];
1040 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
1041 vkey = keypad_key_vkey[key - 0x7E];
1042 scan = keypad_key_scan[key - 0x7E];
1043 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
1044 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
1045 scan = function_key_scan[key - 0xBE];
1046 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
1047 vkey = modifier_key_vkey[key - 0xE1];
1048 scan = modifier_key_scan[key - 0xE1];
1049 } else if (key == 0xFF) { /* DEL key */
1053 /* set extended bit when necessary */
1054 if (scan & 0x100) vkey |= 0x100;
1055 } else if (keysym == 0x20) { /* Spacebar */
1059 /* we seem to need to search the layout-dependent scancodes */
1060 int maxlen=0,maxval=-1,ok;
1061 for (i=0; i<syms; i++) {
1062 keysym = TSXKeycodeToKeysym(display, keyc, i);
1063 if ((keysym<0x800) && (keysym!=' ')) {
1064 ckey[i] = keysym & 0xFF;
1066 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1069 /* find key with longest match streak */
1070 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1071 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1072 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1073 if (ok||(i>maxlen)) {
1074 maxlen=i; maxval=keyn;
1080 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1081 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1082 scan = (*lscan)[maxval];
1083 vkey = (*lvkey)[maxval];
1087 /* find a suitable layout-dependent VK code */
1088 /* (most Winelib apps ought to be able to work without layout tables!) */
1089 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1091 keysym = TSXLookupKeysym(&e2, i);
1092 if ((keysym >= VK_0 && keysym <= VK_9)
1093 || (keysym >= VK_A && keysym <= VK_Z)) {
1098 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1100 keysym = TSXLookupKeysym(&e2, i);
1103 case ';': vkey = VK_OEM_1; break;
1104 case '/': vkey = VK_OEM_2; break;
1105 case '`': vkey = VK_OEM_3; break;
1106 case '[': vkey = VK_OEM_4; break;
1107 case '\\': vkey = VK_OEM_5; break;
1108 case ']': vkey = VK_OEM_6; break;
1109 case '\'': vkey = VK_OEM_7; break;
1110 case ',': vkey = VK_OEM_COMMA; break;
1111 case '.': vkey = VK_OEM_PERIOD; break;
1112 case '-': vkey = VK_OEM_MINUS; break;
1113 case '+': vkey = VK_OEM_PLUS; break;
1119 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1120 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1123 case 0xc1 : OEMvkey=0xdb; break;
1124 case 0xe5 : OEMvkey=0xe9; break;
1125 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1130 if (TRACE_ON(keyboard))
1132 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1133 OEMvkey, e2.keycode);
1135 for (i = 0; i < keysyms_per_keycode; i += 1)
1139 keysym = TSXLookupKeysym(&e2, i);
1140 ksname = TSXKeysymToString(keysym);
1142 ksname = "NoSymbol";
1143 DPRINTF( "%lX (%s) ", keysym, ksname);
1149 keyc2vkey[e2.keycode] = vkey;
1150 keyc2scan[e2.keycode] = scan;
1153 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1154 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1155 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1157 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1158 ksname = TSXKeysymToString(keysym);
1159 if (!ksname) ksname = "NoSymbol";
1161 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1163 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1164 keyc2scan[keyc]=scan++;
1167 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1168 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1169 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1170 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1171 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1172 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1173 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1176 /***********************************************************************
1177 * VkKeyScan (X11DRV.@)
1179 WORD X11DRV_VkKeyScan(CHAR cChar)
1181 Display *display = thread_display();
1187 /* char->keysym (same for ANSI chars) */
1188 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1189 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1191 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1193 { /* It didn't work ... let's try with deadchar code. */
1194 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1197 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1198 cChar,keysym,keysym,keycode);
1202 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1203 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1206 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1208 case 1 : highbyte = 0x0100; break;
1209 case 2 : highbyte = 0x0600; break;
1210 case 3 : highbyte = 0x0700; break;
1211 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1214 index : 0 adds 0x0000
1215 index : 1 adds 0x0100 (shift)
1216 index : ? adds 0x0200 (ctrl)
1217 index : 2 adds 0x0600 (ctrl+alt)
1218 index : 3 adds 0x0700 (ctrl+alt+shift)
1221 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1222 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1225 /***********************************************************************
1226 * MapVirtualKey (X11DRV.@)
1228 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1230 Display *display = thread_display();
1232 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1234 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1236 case 0: { /* vkey-code to scan-code */
1237 /* let's do vkey -> keycode -> scan */
1239 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1240 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1241 returnMVK (keyc2scan[keyc] & 0xFF);
1242 TRACE("returning no scan-code.\n");
1245 case 1: { /* scan-code to vkey-code */
1246 /* let's do scan -> keycode -> vkey */
1248 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1249 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1250 returnMVK (keyc2vkey[keyc] & 0xFF);
1251 TRACE("returning no vkey-code.\n");
1254 case 2: { /* vkey-code to unshifted ANSI code */
1255 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1256 /* My Windows returns 'A'. */
1257 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1262 e.display = display;
1263 e.state = 0; /* unshifted */
1266 /* We exit on the first keycode found, to speed up the thing. */
1267 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1268 { /* Find a keycode that could have generated this virtual key */
1269 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1270 { /* We filter the extended bit, we don't know it */
1271 e.keycode = keyc; /* Store it temporarily */
1272 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1273 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1274 state), so set it to 0, we'll find another one */
1279 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1280 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1282 if (wCode==VK_DECIMAL)
1283 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1287 WARN("Unknown virtual key %X !!! \n", wCode);
1288 return 0; /* whatever */
1290 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1292 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1295 TRACE("returning no ANSI.\n");
1299 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1300 /* left and right */
1301 FIXME(" stub for NT\n");
1304 default: /* reserved */
1305 WARN("Unknown wMapType %d !\n", wMapType);
1311 /***********************************************************************
1312 * GetKeyNameText (X11DRV.@)
1314 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1316 int vkey, ansi, scanCode;
1321 scanCode = lParam >> 16;
1322 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1324 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1325 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1327 /* handle "don't care" bit (0x02000000) */
1328 if (!(lParam & 0x02000000)) {
1347 ansi = X11DRV_MapVirtualKey(vkey, 2);
1348 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1350 /* first get the name of the "regular" keys which is the Upper case
1351 value of the keycap imprint. */
1352 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1353 (scanCode != 0x137) && /* PrtScn */
1354 (scanCode != 0x135) && /* numpad / */
1355 (scanCode != 0x37 ) && /* numpad * */
1356 (scanCode != 0x4a ) && /* numpad - */
1357 (scanCode != 0x4e ) ) /* numpad + */
1359 if ((nSize >= 2) && lpBuffer)
1361 *lpBuffer = toupper((char)ansi);
1369 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1370 without "extended-key" flag. However Wine generates scancode
1371 *with* "extended-key" flag. Seems to occur *only* for the
1372 function keys. Soooo.. We will leave the table alone and
1373 fudge the lookup here till the other part is found and fixed!!! */
1375 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1376 (scanCode == 0x157) || (scanCode == 0x158))
1377 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1379 /* let's do scancode -> keycode -> keysym -> String */
1381 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1382 if ((keyc2scan[keyc]) == scanCode)
1384 if (keyc <= max_keycode)
1386 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1387 name = TSXKeysymToString(keys);
1388 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1389 scanCode, keyc, (int)keys, name);
1390 if (lpBuffer && nSize && name)
1392 lstrcpynA(lpBuffer, name, nSize);
1397 /* Finally issue FIXME for unknown keys */
1399 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1400 if (lpBuffer && nSize)
1405 /***********************************************************************
1406 * X11DRV_KEYBOARD_MapDeadKeysym
1408 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1412 /* symbolic ASCII is the same as defined in rfc1345 */
1413 #ifdef XK_dead_tilde
1414 case XK_dead_tilde :
1416 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1417 return '~'; /* '? */
1418 #ifdef XK_dead_acute
1419 case XK_dead_acute :
1421 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1422 return 0xb4; /* '' */
1423 #ifdef XK_dead_circumflex
1424 case XK_dead_circumflex:
1426 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1427 return '^'; /* '> */
1428 #ifdef XK_dead_grave
1429 case XK_dead_grave :
1431 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1432 return '`'; /* '! */
1433 #ifdef XK_dead_diaeresis
1434 case XK_dead_diaeresis :
1436 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1437 return 0xa8; /* ': */
1438 #ifdef XK_dead_cedilla
1439 case XK_dead_cedilla :
1440 return 0xb8; /* ', */
1442 #ifdef XK_dead_macron
1443 case XK_dead_macron :
1444 return '-'; /* 'm isn't defined on iso-8859-x */
1446 #ifdef XK_dead_breve
1447 case XK_dead_breve :
1448 return 0xa2; /* '( */
1450 #ifdef XK_dead_abovedot
1451 case XK_dead_abovedot :
1452 return 0xff; /* '. */
1454 #ifdef XK_dead_abovering
1455 case XK_dead_abovering :
1456 return '0'; /* '0 isn't defined on iso-8859-x */
1458 #ifdef XK_dead_doubleacute
1459 case XK_dead_doubleacute :
1460 return 0xbd; /* '" */
1462 #ifdef XK_dead_caron
1463 case XK_dead_caron :
1464 return 0xb7; /* '< */
1466 #ifdef XK_dead_ogonek
1467 case XK_dead_ogonek :
1468 return 0xb2; /* '; */
1470 /* FIXME: I don't know this three.
1473 case XK_dead_voiced_sound :
1475 case XK_dead_semivoiced_sound :
1479 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1483 /***********************************************************************
1484 * ToUnicode (X11DRV.@)
1486 * The ToUnicode function translates the specified virtual-key code and keyboard
1487 * state to the corresponding Windows character or characters.
1489 * If the specified key is a dead key, the return value is negative. Otherwise,
1490 * it is one of the following values:
1492 * 0 The specified virtual key has no translation for the current state of the keyboard.
1493 * 1 One Windows character was copied to the buffer.
1494 * 2 Two characters were copied to the buffer. This usually happens when a
1495 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1496 * be composed with the specified virtual key to form a single character.
1498 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1501 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1502 LPWSTR bufW, int bufW_size, UINT flags)
1504 Display *display = thread_display();
1512 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1513 event is generated by windows. Just ignore it. */
1514 TRACE("scanCode=0, doing nothing\n");
1517 if (scanCode & 0x8000)
1519 TRACE("Key UP, doing nothing\n" );
1522 e.display = display;
1525 if (lpKeyState[VK_SHIFT] & 0x80)
1526 e.state |= ShiftMask;
1527 if (lpKeyState[VK_CAPITAL] & 0x01)
1528 e.state |= LockMask;
1529 if (lpKeyState[VK_CONTROL] & 0x80)
1531 if (lpKeyState[VK_MENU] & 0x80)
1532 e.state |= AltGrMask;
1534 e.state |= ControlMask;
1536 if (lpKeyState[VK_NUMLOCK] & 0x01)
1537 e.state |= NumLockMask;
1538 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1539 virtKey, scanCode, e.state);
1540 /* We exit on the first keycode found, to speed up the thing. */
1541 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1542 { /* Find a keycode that could have generated this virtual key */
1543 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1544 { /* We filter the extended bit, we don't know it */
1545 e.keycode = keyc; /* Store it temporarily */
1546 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1547 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1548 state), so set it to 0, we'll find another one */
1553 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1554 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1556 if (virtKey==VK_DECIMAL)
1557 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1561 WARN("Unknown virtual key %X !!! \n",virtKey);
1562 return virtKey; /* whatever */
1564 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1566 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1571 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1574 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1581 ksname = TSXKeysymToString(keysym);
1584 if ((keysym >> 8) != 0xff)
1586 ERR("Please report: no char for keysym %04lX (%s) :\n",
1588 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1589 virtKey, scanCode, e.keycode, e.state);
1593 else { /* ret != 0 */
1594 /* We have a special case to handle : Shift + arrow, shift + home, ...
1595 X returns a char for it, but Windows doesn't. Let's eat it. */
1596 if (!(e.state & NumLockMask) /* NumLock is off */
1597 && (e.state & ShiftMask) /* Shift is pressed */
1598 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1604 /* more areas where X returns characters but Windows does not
1605 CTRL + number or CTRL + symbol*/
1606 if (e.state & ControlMask)
1608 if (((keysym>=33) && (keysym < 'A')) ||
1609 ((keysym > 'Z') && (keysym < 'a')))
1616 /* We have another special case for delete key (XK_Delete) on an
1617 extended keyboard. X returns a char for it, but Windows doesn't */
1618 if (keysym == XK_Delete)
1623 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1624 && (keysym == XK_KP_Decimal))
1630 /* perform translation to unicode */
1633 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1634 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1635 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1639 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1640 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1644 /***********************************************************************
1647 void X11DRV_Beep(void)
1649 TSXBell(thread_display(), 0);
1652 /***********************************************************************
1653 * GetDIState (X11DRV.@)
1655 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1661 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1663 /* X keycode to virtual key */
1664 vkey = keyc2vkey[keyc] & 0xFF;
1665 /* The windows scancode is keyc-min_keycode */
1666 if (InputKeyStateTable[vkey]&0x80) {
1667 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1668 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1673 WARN("whoops, got len %ld?\n", len);
1677 /***********************************************************************
1678 * GetDIData (X11DRV.@)
1680 BOOL X11DRV_GetDIData(
1682 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1683 LPDWORD entries, DWORD flags)
1685 int keyc,n,vkey,xentries;
1690 xentries = *entries;
1696 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1698 /* X keycode to virtual key */
1699 vkey = keyc2vkey[keyc] & 0xFF;
1700 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1704 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1705 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1706 dod[n].dwTimeStamp = 0; /* umm */
1707 dod[n].dwSequence = 0; /* umm */
1710 if (!(flags & DIGDD_PEEK))
1711 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1715 if (n) TRACE_(dinput)("%d entries\n",n);