Use the standard CreateThread routine to create 16-bit tasks instead
[wine.git] / windows / x11drv / keyboard.c
blob44d140be901448f63c9d404b6ef7bd23415f48de
1 /*
2 * X11 keyboard driver
4 * Copyright 1993 Bob Amstadt
5 * Copyright 1996 Albrecht Kleine
6 * Copyright 1997 David Faure
7 * Copyright 1998 Morten Welinder
8 * Copyright 1998 Ulrich Weigand
9 * Copyright 1999 Ove Kåven
12 #include "config.h"
14 #include <X11/Xatom.h>
15 #include <X11/keysym.h>
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
20 #ifdef HAVE_XKB
21 #include <X11/XKBlib.h>
22 #endif
24 #include <ctype.h>
25 #include <string.h>
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "wine/winuser16.h"
30 #include "dinput.h"
31 #include "debugtools.h"
32 #include "user.h"
33 #include "keyboard.h"
34 #include "message.h"
35 #include "winnls.h"
36 #include "win.h"
37 #include "x11drv.h"
39 DEFAULT_DEBUG_CHANNEL(keyboard);
40 DECLARE_DEBUG_CHANNEL(key);
41 DECLARE_DEBUG_CHANNEL(dinput);
43 extern BYTE InputKeyStateTable[256];
45 extern LPBYTE pKeyStateTable;
47 int min_keycode, max_keycode, keysyms_per_keycode;
48 WORD keyc2vkey[256], keyc2scan[256];
50 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
51 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
52 #ifdef HAVE_XKB
53 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
54 #endif
56 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
58 /* Keyboard translation tables */
59 #define MAIN_LEN 48
60 static const WORD main_key_scan_qwerty[MAIN_LEN] =
62 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
63 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
64 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
65 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
66 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
67 0x56 /* the 102nd key (actually to the right of l-shift) */
70 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
72 /* NOTE: this layout must concur with the scan codes layout above */
73 VK_OEM_3,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_MINUS,VK_OEM_PLUS,
74 VK_Q,VK_W,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_4,VK_OEM_6,
75 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_7,VK_OEM_5,
76 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
77 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
80 static const WORD main_key_vkey_azerty[MAIN_LEN] =
82 /* NOTE: this layout must concur with the scan codes layout above */
83 VK_OEM_7,VK_1,VK_2,VK_3,VK_4,VK_5,VK_6,VK_7,VK_8,VK_9,VK_0,VK_OEM_4,VK_OEM_PLUS,
84 VK_A,VK_Z,VK_E,VK_R,VK_T,VK_Y,VK_U,VK_I,VK_O,VK_P,VK_OEM_6,VK_OEM_1,
85 VK_Q,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_M,VK_OEM_3,VK_OEM_5,
86 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
87 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
90 /* FIXME: add other layouts, such as DVORAK and German QWERTZ */
92 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
94 /* the VK mappings for the main keyboard will be auto-assigned as before,
95 so what we have here is just the character tables */
96 /* order: Normal, Shift, AltGr, Shift-AltGr */
97 /* We recommend you write just what is guaranteed to be correct (i.e. what's
98 written on the keycaps), not the bunch of special characters behind AltGr
99 and Shift-AltGr if it can vary among different X servers */
100 /* Remember that your 102nd key (to the right of l-shift) should be on a
101 separate line, see existing tables */
102 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
103 /* Remember to also add your new table to the layout index table far below! */
105 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
106 static const char main_key_US[MAIN_LEN][4] =
108 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
109 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
110 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
111 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
114 /*** United States keyboard layout (phantom key version) */
115 /* (XFree86 reports the <> key even if it's not physically there) */
116 static const char main_key_US_phantom[MAIN_LEN][4] =
118 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
119 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
120 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
121 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
122 "<>" /* the phantom key */
125 /*** British keyboard layout */
126 static const char main_key_UK[MAIN_LEN][4] =
128 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
129 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
130 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
131 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
132 "\\|"
135 /*** French keyboard layout (contributed by Eric Pouech) */
136 static const char main_key_FR[MAIN_LEN][4] =
138 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
139 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
140 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
141 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
142 "<>"
145 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
146 static const char main_key_IS[MAIN_LEN][4] =
148 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
149 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
150 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
151 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
152 "<>|"
155 /*** German keyboard layout (contributed by Ulrich Weigand) */
156 static const char main_key_DE[MAIN_LEN][4] =
158 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'",
159 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
160 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
161 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
162 "<>"
165 /*** German keyboard layout without dead keys */
166 static const char main_key_DE_nodead[MAIN_LEN][4] =
168 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
169 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
170 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
171 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
172 "<>"
175 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
176 static const char main_key_SG[MAIN_LEN][4] =
178 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
179 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
180 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
181 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
182 "<>\\"
185 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
186 static const char main_key_SF[MAIN_LEN][4] =
188 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
189 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
190 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
191 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
192 "<>\\"
195 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
196 static const char main_key_NO[MAIN_LEN][4] =
198 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
199 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
200 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
201 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
202 "<>"
205 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
206 static const char main_key_DA[MAIN_LEN][4] =
208 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
209 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
210 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
211 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
212 "<>\\"
215 /*** Swedish keyboard layout (contributed by Peter Bortas) */
216 static const char main_key_SE[MAIN_LEN][4] =
218 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
219 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
220 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
221 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
222 "<>|"
225 /*** Canadian French keyboard layout */
226 static const char main_key_CF[MAIN_LEN][4] =
228 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
229 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
230 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
231 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
232 "«»°"
235 /*** Portuguese keyboard layout */
236 static const char main_key_PT[MAIN_LEN][4] =
238 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
239 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
240 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
241 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
242 "<>"
245 /*** Italian keyboard layout */
246 static const char main_key_IT[MAIN_LEN][4] =
248 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
249 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
250 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
251 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
252 "<>|"
255 /*** Finnish keyboard layout */
256 static const char main_key_FI[MAIN_LEN][4] =
258 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
259 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
260 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
261 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
262 "<>|"
265 /*** Russian keyboard layout (contributed by Pavel Roskin) */
266 static const char main_key_RU[MAIN_LEN][4] =
268 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
269 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
270 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
271 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
274 /*** Russian keyboard layout KOI8-R */
275 static const char main_key_RU_koi8r[MAIN_LEN][4] =
277 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
278 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
279 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
280 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
281 "<>" /* the phantom key */
284 /*** Spanish keyboard layout (contributed by José Marcos López) */
285 static const char main_key_ES[MAIN_LEN][4] =
287 "ºª\\","1!|","2\"@","3·#","4$","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
288 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
289 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","'¨{","çÇ}",
290 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
291 "<>"
294 /*** Belgian keyboard layout ***/
295 static const char main_key_BE[MAIN_LEN][4] =
297 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
298 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
299 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
300 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
301 "<>\\"
304 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
305 static const char main_key_HU[MAIN_LEN][4] =
307 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
308 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
309 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
310 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
311 "íÍ<"
314 /*** Polish (programmer's) keyboard layout ***/
315 static const char main_key_PL[MAIN_LEN][4] =
317 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
318 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
319 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
320 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
321 "<>|"
324 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
325 static const char main_key_HR_jelly[MAIN_LEN][4] =
327 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
328 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
329 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
330 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
331 "<>|"
334 /*** Croatian keyboard layout ***/
335 static const char main_key_HR[MAIN_LEN][4] =
337 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
338 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
339 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
340 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
341 "<>"
344 /*** Japanese 106 keyboard layout ***/
345 static const char main_key_JA_jp106[MAIN_LEN][4] =
347 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
348 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
349 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
350 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
351 "\\_",
354 /*** Japanese pc98x1 keyboard layout ***/
355 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
357 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
358 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
359 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
360 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
361 "\\_",
364 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
365 static const char main_key_PT_br[MAIN_LEN][4] =
367 "'\"","1!","2@","3#","4$","5%","6\"","7&","8*","9(","0)","-_","=+",
368 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","'`","[{",
369 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
370 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
373 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
374 - dead_abovering replaced with degree - no symbol in iso8859-2
375 - brokenbar replaced with bar */
376 static const char main_key_SK[MAIN_LEN][4] =
378 ";°`'","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0)","=%","",
379 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/÷","ä(×",
380 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","ò)¤",
381 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
382 "<>\\|"
385 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
386 static const char main_key_SK_prog[MAIN_LEN][4] =
388 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
389 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
390 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
391 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
392 "<>"
395 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
396 static const char main_key_CS[MAIN_LEN][4] =
398 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
399 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
400 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
401 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
402 "<>\\|"
405 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
406 static const char main_key_LA[MAIN_LEN][4] =
408 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
409 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
410 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
411 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
412 "<>"
415 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
416 static const char main_key_LT_B[MAIN_LEN][4] =
418 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","((","))","-_","þÞ",
419 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
420 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
421 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
424 /*** Turkish keyboard Layout */
425 static const char main_key_TK[MAIN_LEN][4] =
427 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
428 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
429 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
430 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
433 /*** Layout table. Add your keyboard mappings to this list */
434 static const struct {
435 const char *comment;
436 const UINT layout_cp; /* Code page for this layout */
437 const char (*key)[MAIN_LEN][4];
438 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
439 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
440 } main_key_tab[]={
441 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
442 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
443 {"British keyboard layout", 28591, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
444 {"German keyboard layout", 28591, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
445 {"German keyboard layout without dead keys", 28591, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
446 {"Swiss German keyboard layout", 28591, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
447 {"Swedish keyboard layout", 28591, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
448 {"Norwegian keyboard layout", 28591, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
449 {"Danish keyboard layout", 28591, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
450 {"French keyboard layout", 28591, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
451 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
452 {"Belgian keyboard layout", 28591, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
453 {"Swiss French keyboard layout", 28591, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
454 {"Portuguese keyboard layout", 28591, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
455 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_qwerty, &main_key_vkey_qwerty},
456 {"Finnish keyboard layout", 28591, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
457 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
458 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
459 {"Spanish keyboard layout", 28591, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
460 {"Italian keyboard layout", 28591, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
461 {"Icelandic keyboard layout", 28591, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
462 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
463 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
464 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
465 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
466 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
467 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
468 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
469 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
470 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
471 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
472 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
473 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
475 {NULL, 0, NULL, NULL, NULL} /* sentinel */
477 static unsigned kbd_layout=0; /* index into above table of layouts */
479 /* maybe more of these scancodes should be extended? */
480 /* extended must be set for ALT_R, CTRL_R,
481 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
482 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
483 /* FIXME should we set extended bit for NumLock ? My
484 * Windows does ... DF */
485 /* Yes, to distinguish based on scan codes, also
486 for PrtScn key ... GA */
488 static const WORD special_key_vkey[] =
490 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
491 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
492 0, 0, 0, VK_ESCAPE /* FF18 */
494 static const WORD special_key_scan[] =
496 0x0E, 0x0F, 0, /*?*/ 0, 0, 0x1C, 0, 0, /* FF08 */
497 0, 0, 0, 0x45, 0x46, 0 , 0, 0, /* FF10 */
498 0, 0, 0, 0x01 /* FF18 */
501 static const WORD cursor_key_vkey[] =
503 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
504 VK_NEXT, VK_END /* FF50 */
506 static const WORD cursor_key_scan[] =
508 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F /* FF50 */
511 static const WORD misc_key_vkey[] =
513 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
514 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL /* FF68 */
516 static const WORD misc_key_scan[] =
518 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0, 0, 0, 0, /* FF60 */
519 /*?*/ 0, /*?*/ 0, 0x38, 0x146 /* FF68 */
522 static const WORD keypad_key_vkey[] =
524 0, VK_NUMLOCK, /* FF7E */
525 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
526 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
527 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
528 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, VK_END, 0,
529 VK_INSERT, VK_DELETE, /* FF98 */
530 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
531 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
532 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
533 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
534 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
535 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
537 static const WORD keypad_key_scan[] =
539 0x138, 0x145, /* FF7E */
540 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
541 0, 0, 0, 0, 0, 0x11C, 0, 0, /* FF88 */
542 0, 0, 0, 0, 0, 0x47, 0x4B, 0x48, /* FF90 */
543 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
544 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
545 0, 0, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
546 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
547 0x48, 0x49 /* FFB8 */
550 static const WORD function_key_vkey[] =
552 VK_F1, VK_F2, /* FFBE */
553 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
554 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
556 static const WORD function_key_scan[] =
558 0x3B, 0x3C, /* FFBE */
559 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
560 0x57, 0x58, 0, 0, 0, 0 /* FFC8 */
563 static const WORD modifier_key_vkey[] =
565 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, 0, /* FFE1 */
566 VK_MENU, VK_MENU, VK_MENU, VK_MENU /* FFE7 */
568 static const WORD modifier_key_scan[] =
570 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0, /* FFE1 */
571 0x38, 0x138, 0x38, 0x138 /* FFE7 */
574 /* Returns the Windows virtual key code associated with the X event <e> */
575 static WORD EVENT_event_to_vkey( XKeyEvent *e)
577 KeySym keysym;
579 TSXLookupString(e, NULL, 0, &keysym, NULL);
581 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
582 && (e->state & NumLockMask))
583 /* Only the Keypad keys 0-9 and . send different keysyms
584 * depending on the NumLock state */
585 return keypad_key_vkey[(keysym & 0xFF) - 0x7E];
587 return keyc2vkey[e->keycode];
590 static BOOL NumState=FALSE, CapsState=FALSE, AltGrState=FALSE;
592 /**********************************************************************
593 * KEYBOARD_GenerateMsg
595 * Generate Down+Up messages when NumLock or CapsLock is pressed.
597 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
600 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, INT event_x, INT event_y,
601 DWORD event_time )
603 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
604 DWORD up, down;
606 if (*State) {
607 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
608 don't treat it. It's from the same key press. Then the state goes to ON.
609 And from there, a 'release' event will switch off the toggle key. */
610 *State=FALSE;
611 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
612 } else
614 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
615 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
616 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
618 if (Evtype!=KeyPress)
620 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
621 KEYBOARD_SendEvent( vkey, scan, down,
622 event_x, event_y, event_time );
623 KEYBOARD_SendEvent( vkey, scan, up,
624 event_x, event_y, event_time );
625 *State=FALSE;
626 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
629 else /* it was OFF */
630 if (Evtype==KeyPress)
632 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
633 KEYBOARD_SendEvent( vkey, scan, down,
634 event_x, event_y, event_time );
635 KEYBOARD_SendEvent( vkey, scan, up,
636 event_x, event_y, event_time );
637 *State=TRUE; /* Goes to intermediary state before going to ON */
638 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
643 /***********************************************************************
644 * KEYBOARD_UpdateOneState
646 * Updates internal state for <vkey>, depending on key <state> under X
649 static void KEYBOARD_UpdateOneState ( int vkey, int state )
651 /* Do something if internal table state != X state for keycode */
652 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
654 TRACE("Adjusting state for vkey %#.2x. State before %#.2x \n",
655 vkey, pKeyStateTable[vkey]);
657 /* Fake key being pressed inside wine */
658 KEYBOARD_SendEvent( vkey, 0, state? 0 : KEYEVENTF_KEYUP,
659 0, 0, GetTickCount() );
661 TRACE("State after %#.2x \n",pKeyStateTable[vkey]);
665 /***********************************************************************
666 * X11DRV_KEYBOARD_UpdateState
668 * Update modifiers state (Ctrl, Alt, Shift)
669 * when window is activated (called by EVENT_FocusIn in event.c)
671 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
672 * from wine to another application and back.
673 * Toggle keys are handled in HandleEvent. (because XQueryKeymap says nothing
674 * about them)
676 void X11DRV_KEYBOARD_UpdateState ( void )
678 /* extract a bit from the char[32] bit suite */
679 #define KeyState(keycode) ((keys_return[keycode/8] & (1<<(keycode%8)))!=0)
681 char keys_return[32];
683 TRACE("called\n");
684 if (!TSXQueryKeymap(display, keys_return)) {
685 ERR("Error getting keymap !");
686 return;
689 /* Adjust the ALT and CONTROL state if any has been changed outside wine */
690 KEYBOARD_UpdateOneState(VK_MENU, KeyState(kcAlt));
691 KEYBOARD_UpdateOneState(VK_CONTROL, KeyState(kcControl));
692 KEYBOARD_UpdateOneState(VK_SHIFT, KeyState(kcShift));
693 #undef KeyState
696 /***********************************************************************
697 * X11DRV_KEYBOARD_HandleEvent
699 * Handle a X key event
701 void X11DRV_KEYBOARD_HandleEvent( WND *pWnd, XKeyEvent *event )
703 char Str[24];
704 KeySym keysym;
705 WORD vkey = 0, bScan;
706 DWORD dwFlags;
707 static BOOL force_extended = FALSE; /* hack for AltGr translation */
708 int ascii_chars;
710 INT event_x = (pWnd? pWnd->rectWindow.left : 0) + event->x;
711 INT event_y = (pWnd? pWnd->rectWindow.top : 0) + event->y;
712 DWORD event_time = event->time - X11DRV_server_startticks;
714 /* this allows support for dead keys */
715 if ((event->keycode >> 8) == 0x10)
716 event->keycode=(event->keycode & 0xff);
718 ascii_chars = TSXLookupString(event, Str, sizeof(Str), &keysym, NULL);
720 TRACE_(key)("state = %X\n", event->state);
722 /* If XKB extensions is used, the state mask for AltGr will used the group
723 index instead of the modifier mask. The group index is set in bits
724 13-14 of the state field in the XKeyEvent structure. So if AltGr is
725 pressed, look if the group index is diferent than 0. From XKB
726 extension documentation, the group index should for AltGr should
727 be 2 (event->state = 0x2000). It's probably better to not assume a
728 predefined group index and find it dynamically
730 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
731 if ( AltGrState && (event->state & 0x6000) )
732 AltGrMask = event->state & 0x6000;
734 if (keysym == XK_Mode_switch)
736 TRACE_(key)("Alt Gr key event received\n");
737 event->keycode = kcControl; /* Simulate Control */
738 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
740 event->keycode = kcAlt; /* Simulate Alt */
741 force_extended = TRUE;
742 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
743 force_extended = FALSE;
745 /* Here we save the pressed/released state of the AltGr key, to be able to
746 identify the group index associated with AltGr on the next key pressed *
747 see comment above. */
748 AltGrState = (event->type == KeyPress) ? TRUE : FALSE;
750 return;
753 Str[ascii_chars] = '\0';
754 if (TRACE_ON(key)){
755 char *ksname;
757 ksname = TSXKeysymToString(keysym);
758 if (!ksname)
759 ksname = "No Name";
760 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
761 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
762 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
765 vkey = EVENT_event_to_vkey(event);
766 if (force_extended) vkey |= 0x100;
768 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
769 event->keycode, vkey);
771 if (vkey)
773 switch (vkey & 0xff)
775 case VK_NUMLOCK:
776 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_x, event_y,
777 event_time );
778 break;
779 case VK_CAPITAL:
780 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
781 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_x, event_y,
782 event_time );
783 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
784 break;
785 default:
786 /* Adjust the NUMLOCK state if it has been changed outside wine */
787 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
789 TRACE("Adjusting NumLock state. \n");
790 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_x, event_y,
791 event_time );
792 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_x, event_y,
793 event_time );
795 /* Adjust the CAPSLOCK state if it has been changed outside wine */
796 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
798 TRACE("Adjusting Caps Lock state.\n");
799 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_x, event_y,
800 event_time );
801 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_x, event_y,
802 event_time );
804 /* Not Num nor Caps : end of intermediary states for both. */
805 NumState = FALSE;
806 CapsState = FALSE;
808 bScan = keyc2scan[event->keycode] & 0xFF;
809 TRACE_(key)("bScan = 0x%02x.\n", bScan);
811 dwFlags = 0;
812 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
813 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
814 if ( force_extended ) dwFlags |= KEYEVENTF_WINE_FORCEEXTENDED;
816 KEYBOARD_SendEvent( vkey & 0xff, bScan, dwFlags,
817 event_x, event_y, event_time );
822 /**********************************************************************
823 * X11DRV_KEYBOARD_DetectLayout
825 * Called from X11DRV_InitKeyboard
826 * This routine walks through the defined keyboard layouts and selects
827 * whichever matches most closely.
829 static void
830 X11DRV_KEYBOARD_DetectLayout (void)
832 unsigned current, match, mismatch, seq;
833 int score, keyc, i, key, pkey, ok, syms;
834 KeySym keysym;
835 const char (*lkey)[MAIN_LEN][4];
836 unsigned max_seq = 0;
837 int max_score = 0, ismatch = 0;
838 char ckey[4] =
839 {0, 0, 0, 0};
841 syms = keysyms_per_keycode;
842 if (syms > 4) {
843 WARN("%d keysyms per keycode not supported, set to 4", syms);
844 syms = 4;
846 for (current = 0; main_key_tab[current].comment; current++) {
847 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
848 match = 0;
849 mismatch = 0;
850 score = 0;
851 seq = 0;
852 lkey = main_key_tab[current].key;
853 pkey = -1;
854 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
855 /* get data for keycode from X server */
856 for (i = 0; i < syms; i++) {
857 keysym = TSXKeycodeToKeysym (display, keyc, i);
858 /* Allow both one-byte and two-byte national keysyms */
859 if ((keysym < 0x800) && (keysym != ' '))
860 ckey[i] = keysym & 0xFF;
861 else {
862 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
865 if (ckey[0]) {
866 /* search for a match in layout table */
867 /* right now, we just find an absolute match for defined positions */
868 /* (undefined positions are ignored, so if it's defined as "3#" in */
869 /* the table, it's okay that the X server has "3#£", for example) */
870 /* however, the score will be higher for longer matches */
871 for (key = 0; key < MAIN_LEN; key++) {
872 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
873 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
874 ok++;
875 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
876 ok = -1;
878 if (ok > 0) {
879 score += ok;
880 break;
883 /* count the matches and mismatches */
884 if (ok > 0) {
885 match++;
886 /* and how much the keycode order matches */
887 if (key > pkey) seq++;
888 pkey = key;
889 } else {
890 TRACE_(key)("mismatch for keycode %d, character %c\n", keyc,
891 ckey[0]);
892 mismatch++;
893 score -= syms;
897 TRACE("matches=%d, mismatches=%d, score=%d\n",
898 match, mismatch, score);
899 if ((score > max_score) ||
900 ((score == max_score) && (seq > max_seq))) {
901 /* best match so far */
902 kbd_layout = current;
903 max_score = score;
904 max_seq = seq;
905 ismatch = !mismatch;
908 /* we're done, report results if necessary */
909 if (!ismatch) {
910 FIXME(
911 "Your keyboard layout was not found!\n"
912 "Instead of using closest match (%s) for scancode mapping.\n"
913 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
914 "to us for inclusion into future Wine releases.\n"
915 "See documentation/keyboard for more information.\n",
916 main_key_tab[kbd_layout].comment);
919 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
922 /**********************************************************************
923 * InitKeyboard (X11DRV.@)
925 void X11DRV_InitKeyboard(void)
927 #ifdef HAVE_XKB
928 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
929 #endif
930 KeySym *ksp;
931 XModifierKeymap *mmp;
932 KeySym keysym;
933 KeyCode *kcp;
934 XKeyEvent e2;
935 WORD scan, vkey, OEMvkey;
936 int keyc, i, keyn, syms;
937 char ckey[4]={0,0,0,0};
938 const char (*lkey)[MAIN_LEN][4];
940 #ifdef HAVE_XKB
941 wine_tsx11_lock();
942 is_xkb = XkbQueryExtension(display,
943 &xkb_opcode, &xkb_event, &xkb_error,
944 &xkb_major, &xkb_minor);
945 if (is_xkb) {
946 /* we have XKB, approximate Windows behaviour */
947 XkbSetDetectableAutoRepeat(display, True, NULL);
949 wine_tsx11_unlock();
950 #endif
951 TSXDisplayKeycodes(display, &min_keycode, &max_keycode);
952 ksp = TSXGetKeyboardMapping(display, min_keycode,
953 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
954 /* We are only interested in keysyms_per_keycode.
955 There is no need to hold a local copy of the keysyms table */
956 TSXFree(ksp);
957 mmp = TSXGetModifierMapping(display);
958 kcp = mmp->modifiermap;
959 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
961 int j;
963 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
964 if (*kcp)
966 int k;
968 for (k = 0; k < keysyms_per_keycode; k += 1)
969 if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Mode_switch)
971 AltGrMask = 1 << i;
972 TRACE_(key)("AltGrMask is %x\n", AltGrMask);
974 else if (TSXKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
976 NumLockMask = 1 << i;
977 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
981 TSXFreeModifiermap(mmp);
983 /* Detect the keyboard layout */
984 X11DRV_KEYBOARD_DetectLayout();
985 lkey = main_key_tab[kbd_layout].key;
986 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
988 /* Now build two conversion arrays :
989 * keycode -> vkey + scancode + extended
990 * vkey + extended -> keycode */
992 e2.display = display;
993 e2.state = 0;
995 OEMvkey = VK_OEM_7; /* next is available. */
996 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
998 e2.keycode = (KeyCode)keyc;
999 TSXLookupString(&e2, NULL, 0, &keysym, NULL);
1000 vkey = 0; scan = 0;
1001 if (keysym) /* otherwise, keycode not used */
1003 if ((keysym >> 8) == 0xFF) /* non-character key */
1005 int key = keysym & 0xff;
1007 if (key >= 0x08 && key <= 0x1B) { /* special key */
1008 vkey = special_key_vkey[key - 0x08];
1009 scan = special_key_scan[key - 0x08];
1010 } else if (key >= 0x50 && key <= 0x57) { /* cursor key */
1011 vkey = cursor_key_vkey[key - 0x50];
1012 scan = cursor_key_scan[key - 0x50];
1013 } else if (key >= 0x60 && key <= 0x6B) { /* miscellaneous key */
1014 vkey = misc_key_vkey[key - 0x60];
1015 scan = misc_key_scan[key - 0x60];
1016 } else if (key >= 0x7E && key <= 0xB9) { /* keypad key */
1017 vkey = keypad_key_vkey[key - 0x7E];
1018 scan = keypad_key_scan[key - 0x7E];
1019 } else if (key >= 0xBE && key <= 0xCD) { /* function key */
1020 vkey = function_key_vkey[key - 0xBE] | 0x100; /* set extended bit */
1021 scan = function_key_scan[key - 0xBE];
1022 } else if (key >= 0xE1 && key <= 0xEA) { /* modifier key */
1023 vkey = modifier_key_vkey[key - 0xE1];
1024 scan = modifier_key_scan[key - 0xE1];
1025 } else if (key == 0xFF) { /* DEL key */
1026 vkey = VK_DELETE;
1027 scan = 0x153;
1029 /* set extended bit when necessary */
1030 if (scan & 0x100) vkey |= 0x100;
1031 } else if (keysym == 0x20) { /* Spacebar */
1032 vkey = VK_SPACE;
1033 scan = 0x39;
1034 } else {
1035 /* we seem to need to search the layout-dependent scancodes */
1036 int maxlen=0,maxval=-1,ok;
1037 for (i=0; i<syms; i++) {
1038 keysym = TSXKeycodeToKeysym(display, keyc, i);
1039 if ((keysym<0x800) && (keysym!=' ')) {
1040 ckey[i] = keysym & 0xFF;
1041 } else {
1042 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1045 /* find key with longest match streak */
1046 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1047 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1048 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1049 if (ok||(i>maxlen)) {
1050 maxlen=i; maxval=keyn;
1052 if (ok) break;
1054 if (maxval>=0) {
1055 /* got it */
1056 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1057 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1058 scan = (*lscan)[maxval];
1059 vkey = (*lvkey)[maxval];
1063 /* find a suitable layout-dependent VK code */
1064 /* (most Winelib apps ought to be able to work without layout tables!) */
1065 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1067 keysym = TSXLookupKeysym(&e2, i);
1068 if ((keysym >= VK_0 && keysym <= VK_9)
1069 || (keysym >= VK_A && keysym <= VK_Z)) {
1070 vkey = keysym;
1074 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1076 keysym = TSXLookupKeysym(&e2, i);
1077 switch (keysym)
1079 case ';': vkey = VK_OEM_1; break;
1080 case '/': vkey = VK_OEM_2; break;
1081 case '`': vkey = VK_OEM_3; break;
1082 case '[': vkey = VK_OEM_4; break;
1083 case '\\': vkey = VK_OEM_5; break;
1084 case ']': vkey = VK_OEM_6; break;
1085 case '\'': vkey = VK_OEM_7; break;
1086 case ',': vkey = VK_OEM_COMMA; break;
1087 case '.': vkey = VK_OEM_PERIOD; break;
1088 case '-': vkey = VK_OEM_MINUS; break;
1089 case '+': vkey = VK_OEM_PLUS; break;
1093 if (!vkey)
1095 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1096 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1097 switch (++OEMvkey)
1099 case 0xc1 : OEMvkey=0xdb; break;
1100 case 0xe5 : OEMvkey=0xe9; break;
1101 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1104 vkey = OEMvkey;
1106 if (TRACE_ON(keyboard))
1108 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1109 OEMvkey, e2.keycode);
1110 TRACE("(");
1111 for (i = 0; i < keysyms_per_keycode; i += 1)
1113 char *ksname;
1115 keysym = TSXLookupKeysym(&e2, i);
1116 ksname = TSXKeysymToString(keysym);
1117 if (!ksname)
1118 ksname = "NoSymbol";
1119 DPRINTF( "%lX (%s) ", keysym, ksname);
1121 DPRINTF(")\n");
1125 keyc2vkey[e2.keycode] = vkey;
1126 keyc2scan[e2.keycode] = scan;
1127 } /* for */
1129 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1130 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1131 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1132 char *ksname;
1133 keysym = TSXKeycodeToKeysym(display, keyc, 0);
1134 ksname = TSXKeysymToString(keysym);
1135 if (!ksname) ksname = "NoSymbol";
1137 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1139 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1140 keyc2scan[keyc]=scan++;
1143 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1144 kcControl = TSXKeysymToKeycode(display, XK_Control_L);
1145 kcAlt = TSXKeysymToKeycode(display, XK_Alt_L);
1146 if (!kcAlt) kcAlt = TSXKeysymToKeycode(display, XK_Meta_L);
1147 kcShift = TSXKeysymToKeycode(display, XK_Shift_L);
1148 kcNumLock = TSXKeysymToKeycode(display, XK_Num_Lock);
1149 kcCapsLock = TSXKeysymToKeycode(display, XK_Caps_Lock);
1152 /***********************************************************************
1153 * VkKeyScan (X11DRV.@)
1155 WORD X11DRV_VkKeyScan(CHAR cChar)
1157 KeyCode keycode;
1158 KeySym keysym;
1159 int i,index;
1160 int highbyte=0;
1162 /* char->keysym (same for ANSI chars) */
1163 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1164 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1166 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1167 if (!keycode)
1168 { /* It didn't work ... let's try with deadchar code. */
1169 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1172 TRACE("VkKeyScan '%c'(%#lx, %lu): got keycode %#.2x\n",
1173 cChar,keysym,keysym,keycode);
1175 if (keycode)
1177 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1178 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1179 switch (index) {
1180 case -1 :
1181 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1182 case 0 : break;
1183 case 1 : highbyte = 0x0100; break;
1184 case 2 : highbyte = 0x0600; break;
1185 case 3 : highbyte = 0x0700; break;
1186 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1189 index : 0 adds 0x0000
1190 index : 1 adds 0x0100 (shift)
1191 index : ? adds 0x0200 (ctrl)
1192 index : 2 adds 0x0600 (ctrl+alt)
1193 index : 3 adds 0x0700 (ctrl+alt+shift)
1196 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1197 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1200 /***********************************************************************
1201 * MapVirtualKey (X11DRV.@)
1203 UINT16 X11DRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
1205 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1207 TRACE("MapVirtualKey wCode=0x%x wMapType=%d ... \n", wCode,wMapType);
1208 switch(wMapType) {
1209 case 0: { /* vkey-code to scan-code */
1210 /* let's do vkey -> keycode -> scan */
1211 int keyc;
1212 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1213 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1214 returnMVK (keyc2scan[keyc] & 0xFF);
1215 TRACE("returning no scan-code.\n");
1216 return 0; }
1218 case 1: { /* scan-code to vkey-code */
1219 /* let's do scan -> keycode -> vkey */
1220 int keyc;
1221 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1222 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1223 returnMVK (keyc2vkey[keyc] & 0xFF);
1224 TRACE("returning no vkey-code.\n");
1225 return 0; }
1227 case 2: { /* vkey-code to unshifted ANSI code */
1228 /* (was FIXME) : what does unshifted mean ? 'a' or 'A' ? */
1229 /* My Windows returns 'A'. */
1230 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1231 XKeyEvent e;
1232 KeySym keysym;
1233 int keyc;
1234 char s[2];
1235 e.display = display;
1236 e.state = 0; /* unshifted */
1238 e.keycode = 0;
1239 /* We exit on the first keycode found, to speed up the thing. */
1240 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1241 { /* Find a keycode that could have generated this virtual key */
1242 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1243 { /* We filter the extended bit, we don't know it */
1244 e.keycode = keyc; /* Store it temporarily */
1245 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1246 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1247 state), so set it to 0, we'll find another one */
1252 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1253 e.keycode = TSXKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1255 if (wCode==VK_DECIMAL)
1256 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1258 if (!e.keycode)
1260 WARN("Unknown virtual key %X !!! \n", wCode);
1261 return 0; /* whatever */
1263 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1265 if (TSXLookupString(&e, s, 2, &keysym, NULL))
1266 returnMVK (*s);
1268 TRACE("returning no ANSI.\n");
1269 return 0;
1272 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1273 /* left and right */
1274 FIXME(" stub for NT\n");
1275 return 0;
1277 default: /* reserved */
1278 WARN("Unknown wMapType %d !\n", wMapType);
1279 return 0;
1281 return 0;
1284 /***********************************************************************
1285 * GetKeyNameText (X11DRV.@)
1287 INT16 X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT16 nSize)
1289 int vkey, ansi, scanCode;
1290 KeyCode keyc;
1291 KeySym keys;
1292 char *name;
1294 scanCode = lParam >> 16;
1295 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1297 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1298 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1300 /* handle "don't care" bit (0x02000000) */
1301 if (!(lParam & 0x02000000)) {
1302 switch (vkey) {
1303 case VK_LSHIFT:
1304 case VK_RSHIFT:
1305 vkey = VK_SHIFT;
1306 break;
1307 case VK_LCONTROL:
1308 case VK_RCONTROL:
1309 vkey = VK_CONTROL;
1310 break;
1311 case VK_LMENU:
1312 case VK_RMENU:
1313 vkey = VK_MENU;
1314 break;
1315 default:
1316 break;
1320 ansi = X11DRV_MapVirtualKey(vkey, 2);
1321 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1323 /* first get the name of the "regular" keys which is the Upper case
1324 value of the keycap imprint. */
1325 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1326 (scanCode != 0x137) && /* PrtScn */
1327 (scanCode != 0x135) && /* numpad / */
1328 (scanCode != 0x37 ) && /* numpad * */
1329 (scanCode != 0x4a ) && /* numpad - */
1330 (scanCode != 0x4e ) ) /* numpad + */
1332 if ((nSize >= 2) && lpBuffer)
1334 *lpBuffer = toupper((char)ansi);
1335 *(lpBuffer+1) = 0;
1336 return 1;
1338 else
1339 return 0;
1342 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1343 without "extended-key" flag. However Wine generates scancode
1344 *with* "extended-key" flag. Seems to occur *only* for the
1345 function keys. Soooo.. We will leave the table alone and
1346 fudge the lookup here till the other part is found and fixed!!! */
1348 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1349 (scanCode == 0x157) || (scanCode == 0x158))
1350 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1352 /* let's do scancode -> keycode -> keysym -> String */
1354 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1355 if ((keyc2scan[keyc]) == scanCode)
1356 break;
1357 if (keyc <= max_keycode)
1359 keys = TSXKeycodeToKeysym(display, keyc, 0);
1360 name = TSXKeysymToString(keys);
1361 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1362 scanCode, keyc, (int)keys, name);
1363 if (lpBuffer && nSize && name)
1365 lstrcpynA(lpBuffer, name, nSize);
1366 return 1;
1370 /* Finally issue FIXME for unknown keys */
1372 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1373 if (lpBuffer && nSize)
1374 *lpBuffer = 0;
1375 return 0;
1378 /***********************************************************************
1379 * X11DRV_KEYBOARD_MapDeadKeysym
1381 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1383 switch (keysym)
1385 /* symbolic ASCII is the same as defined in rfc1345 */
1386 #ifdef XK_dead_tilde
1387 case XK_dead_tilde :
1388 #endif
1389 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1390 return '~'; /* '? */
1391 #ifdef XK_dead_acute
1392 case XK_dead_acute :
1393 #endif
1394 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1395 return 0xb4; /* '' */
1396 #ifdef XK_dead_circumflex
1397 case XK_dead_circumflex:
1398 #endif
1399 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1400 return '^'; /* '> */
1401 #ifdef XK_dead_grave
1402 case XK_dead_grave :
1403 #endif
1404 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1405 return '`'; /* '! */
1406 #ifdef XK_dead_diaeresis
1407 case XK_dead_diaeresis :
1408 #endif
1409 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1410 return 0xa8; /* ': */
1411 #ifdef XK_dead_cedilla
1412 case XK_dead_cedilla :
1413 return 0xb8; /* ', */
1414 #endif
1415 #ifdef XK_dead_macron
1416 case XK_dead_macron :
1417 return '-'; /* 'm isn't defined on iso-8859-x */
1418 #endif
1419 #ifdef XK_dead_breve
1420 case XK_dead_breve :
1421 return 0xa2; /* '( */
1422 #endif
1423 #ifdef XK_dead_abovedot
1424 case XK_dead_abovedot :
1425 return 0xff; /* '. */
1426 #endif
1427 #ifdef XK_dead_abovering
1428 case XK_dead_abovering :
1429 return '0'; /* '0 isn't defined on iso-8859-x */
1430 #endif
1431 #ifdef XK_dead_doubleacute
1432 case XK_dead_doubleacute :
1433 return 0xbd; /* '" */
1434 #endif
1435 #ifdef XK_dead_caron
1436 case XK_dead_caron :
1437 return 0xb7; /* '< */
1438 #endif
1439 #ifdef XK_dead_ogonek
1440 case XK_dead_ogonek :
1441 return 0xb2; /* '; */
1442 #endif
1443 /* FIXME: I don't know this three.
1444 case XK_dead_iota :
1445 return 'i';
1446 case XK_dead_voiced_sound :
1447 return 'v';
1448 case XK_dead_semivoiced_sound :
1449 return 's';
1452 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1453 return 0;
1456 /***********************************************************************
1457 * ToUnicode (X11DRV.@)
1459 * The ToUnicode function translates the specified virtual-key code and keyboard
1460 * state to the corresponding Windows character or characters.
1462 * If the specified key is a dead key, the return value is negative. Otherwise,
1463 * it is one of the following values:
1464 * Value Meaning
1465 * 0 The specified virtual key has no translation for the current state of the keyboard.
1466 * 1 One Windows character was copied to the buffer.
1467 * 2 Two characters were copied to the buffer. This usually happens when a
1468 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1469 * be composed with the specified virtual key to form a single character.
1471 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1474 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1475 LPWSTR bufW, int bufW_size, UINT flags)
1477 XKeyEvent e;
1478 KeySym keysym;
1479 INT ret;
1480 int keyc;
1481 BYTE lpChar[2];
1483 if (scanCode==0) {
1484 /* This happens when doing Alt+letter : a fake 'down arrow' key press
1485 event is generated by windows. Just ignore it. */
1486 TRACE("scanCode=0, doing nothing\n");
1487 return 0;
1489 if (scanCode & 0x8000)
1491 TRACE("Key UP, doing nothing\n" );
1492 return 0;
1494 e.display = display;
1495 e.keycode = 0;
1496 e.state = 0;
1497 if (lpKeyState[VK_SHIFT] & 0x80)
1498 e.state |= ShiftMask;
1499 if (lpKeyState[VK_CAPITAL] & 0x01)
1500 e.state |= LockMask;
1501 if (lpKeyState[VK_CONTROL] & 0x80)
1503 if (lpKeyState[VK_MENU] & 0x80)
1504 e.state |= AltGrMask;
1505 else
1506 e.state |= ControlMask;
1508 if (lpKeyState[VK_NUMLOCK] & 0x01)
1509 e.state |= NumLockMask;
1510 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1511 virtKey, scanCode, e.state);
1512 /* We exit on the first keycode found, to speed up the thing. */
1513 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1514 { /* Find a keycode that could have generated this virtual key */
1515 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1516 { /* We filter the extended bit, we don't know it */
1517 e.keycode = keyc; /* Store it temporarily */
1518 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1519 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1520 state), so set it to 0, we'll find another one */
1525 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1526 e.keycode = TSXKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1528 if (virtKey==VK_DECIMAL)
1529 e.keycode = TSXKeysymToKeycode(e.display, XK_KP_Decimal);
1531 if (!e.keycode)
1533 WARN("Unknown virtual key %X !!! \n",virtKey);
1534 return virtKey; /* whatever */
1536 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1538 ret = TSXLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1539 if (ret == 0)
1541 BYTE dead_char;
1543 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1544 if (dead_char)
1546 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1547 ret = -1;
1549 else
1551 char *ksname;
1553 ksname = TSXKeysymToString(keysym);
1554 if (!ksname)
1555 ksname = "No Name";
1556 if ((keysym >> 8) != 0xff)
1558 ERR("Please report: no char for keysym %04lX (%s) :\n",
1559 keysym, ksname);
1560 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1561 virtKey, scanCode, e.keycode, e.state);
1565 else { /* ret != 0 */
1566 /* We have a special case to handle : Shift + arrow, shift + home, ...
1567 X returns a char for it, but Windows doesn't. Let's eat it. */
1568 if (!(e.state & NumLockMask) /* NumLock is off */
1569 && (e.state & ShiftMask) /* Shift is pressed */
1570 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1572 *(char*)lpChar = 0;
1573 ret = 0;
1576 /* more areas where X returns characters but Windows does not
1577 CTRL + number or CTRL + symbol*/
1578 if (e.state & ControlMask)
1580 if (((keysym>=33) && (keysym < 'A')) ||
1581 ((keysym > 'Z') && (keysym < 'a')))
1583 *(char*)lpChar = 0;
1584 ret = 0;
1588 /* We have another special case for delete key (XK_Delete) on an
1589 extended keyboard. X returns a char for it, but Windows doesn't */
1590 if (keysym == XK_Delete)
1592 *(char*)lpChar = 0;
1593 ret = 0;
1595 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1596 && (keysym == XK_KP_Decimal))
1598 *(char*)lpChar = 0;
1599 ret = 0;
1602 /* perform translation to unicode */
1603 if(ret)
1605 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1606 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1607 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1611 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1612 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1613 return ret;
1616 /***********************************************************************
1617 * GetBeepActive (X11DRV.@)
1619 BOOL X11DRV_GetBeepActive(void)
1621 XKeyboardState keyboard_state;
1623 TSXGetKeyboardControl(display, &keyboard_state);
1625 return keyboard_state.bell_percent != 0;
1628 /***********************************************************************
1629 * SetBeepActive (X11DRV.@)
1631 void X11DRV_SetBeepActive(BOOL bActivate)
1633 XKeyboardControl keyboard_value;
1635 if(bActivate)
1636 keyboard_value.bell_percent = -1;
1637 else
1638 keyboard_value.bell_percent = 0;
1640 TSXChangeKeyboardControl(display, KBBellPercent, &keyboard_value);
1643 /***********************************************************************
1644 * Beep (X11DRV.@)
1646 void X11DRV_Beep(void)
1648 TSXBell(display, 0);
1651 /***********************************************************************
1652 * GetDIState (X11DRV.@)
1654 BOOL X11DRV_GetDIState(DWORD len, LPVOID ptr)
1656 if (len==256) {
1657 int keyc,vkey;
1659 memset(ptr,0,256);
1660 for (keyc=min_keycode;keyc<max_keycode;keyc++)
1662 /* X keycode to virtual key */
1663 vkey = keyc2vkey[keyc] & 0xFF;
1664 /* The windows scancode is keyc-min_keycode */
1665 if (InputKeyStateTable[vkey]&0x80) {
1666 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
1667 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
1670 return TRUE;
1672 WARN("whoops, got len %ld?\n", len);
1673 return TRUE;
1676 /***********************************************************************
1677 * GetDIData (X11DRV.@)
1679 BOOL X11DRV_GetDIData(
1680 BYTE *keystate,
1681 DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
1682 LPDWORD entries, DWORD flags)
1684 int keyc,n,vkey,xentries;
1686 /* FIXME !!! */
1688 if (entries)
1689 xentries = *entries;
1690 else
1691 xentries = 1;
1693 n = 0;
1695 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
1697 /* X keycode to virtual key */
1698 vkey = keyc2vkey[keyc] & 0xFF;
1699 if (keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
1700 continue;
1701 if (dod) {
1702 /* add an entry */
1703 dod[n].dwOfs = keyc-min_keycode; /* scancode */
1704 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
1705 dod[n].dwTimeStamp = 0; /* umm */
1706 dod[n].dwSequence = 0; /* umm */
1707 n++;
1709 if (!(flags & DIGDD_PEEK))
1710 keystate[vkey] = InputKeyStateTable[vkey]&0x80;
1714 if (n) TRACE_(dinput)("%d entries\n",n);
1715 *entries = n;
1717 return TRUE;
1720 /***********************************************************************
1721 * GetKeyboardConfig (X11DRV.@)
1723 void X11DRV_GetKeyboardConfig(KEYBOARD_CONFIG *cfg) {
1724 XKeyboardState xks;
1726 /* For the moment, only get the auto-repeat mode */
1727 TSXGetKeyboardControl(display, &xks);
1728 cfg->auto_repeat = xks.global_auto_repeat;
1731 /***********************************************************************
1732 * SetKeyboardConfig (X11DRV.@)
1734 void X11DRV_SetKeyboardConfig(KEYBOARD_CONFIG *cfg, DWORD mask) {
1735 XKeyboardControl xkc;
1736 unsigned long X_mask = 0;
1738 if (mask & WINE_KEYBOARD_CONFIG_AUTO_REPEAT) {
1739 X_mask |= KBAutoRepeatMode;
1740 xkc.auto_repeat_mode = cfg->auto_repeat;
1742 if (X_mask)
1743 TSXChangeKeyboardControl(display, X_mask, &xkc);