Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / x11drv / keyboard.c
blobeb61dbe13ec5bfc1616e2100630012168a3122f1
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
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config.h"
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
31 #include "ts_xlib.h"
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
34 #ifdef HAVE_XKB
35 #include <X11/XKBlib.h>
36 #endif
38 #include <ctype.h>
39 #include <stdarg.h>
40 #include <string.h>
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wingdi.h"
47 #include "wine/winuser16.h"
48 #include "winnls.h"
49 #include "win.h"
50 #include "x11drv.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
54 WINE_DECLARE_DEBUG_CHANNEL(key);
55 WINE_DECLARE_DEBUG_CHANNEL(dinput);
57 int min_keycode, max_keycode, keysyms_per_keycode;
58 WORD keyc2vkey[256], keyc2scan[256];
60 static LPBYTE pKeyStateTable;
61 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
62 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
64 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
66 /* Keyboard translation tables */
67 #define MAIN_LEN 49
68 static const WORD main_key_scan_qwerty[MAIN_LEN] =
70 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
71 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
72 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
73 /* q w e r t y u i o p [ ] */
74 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
75 /* a s d f g h j k l ; ' \ */
76 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
77 /* z x c v b n m , . / */
78 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
79 0x56 /* the 102nd key (actually to the right of l-shift) */
82 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
84 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
85 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
86 /* q w e r t y u i o p [ ] */
87 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
88 /* a s d f g h j k l ; ' \ */
89 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
90 /* \ z x c v b n m , . / */
91 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
92 0x56, /* the 102nd key (actually to the right of l-shift) */
95 static const WORD main_key_scan_dvorak[MAIN_LEN] =
97 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
98 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
99 /* ' , . p y f g c r l / = */
100 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
101 /* a o e u i d h t n s - \ */
102 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
103 /* ; q j k x b m w v z */
104 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
105 0x56 /* the 102nd key (actually to the right of l-shift) */
108 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
110 /* NOTE: this layout must concur with the scan codes layout above */
111 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,
112 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,
113 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,
114 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
115 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
118 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
120 /* NOTE: this layout must concur with the scan codes layout above */
121 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,
122 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,
123 VK_A,VK_S,VK_D,VK_F,VK_G,VK_H,VK_J,VK_K,VK_L,VK_OEM_1,VK_OEM_8,VK_OEM_5,
124 VK_OEM_7,VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
125 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
128 static const WORD main_key_vkey_azerty[MAIN_LEN] =
130 /* NOTE: this layout must concur with the scan codes layout above */
131 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,
132 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,
133 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,
134 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
135 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
138 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
140 /* NOTE: this layout must concur with the scan codes layout above */
141 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_4,VK_OEM_6,
142 VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,VK_P,VK_Y,VK_F,VK_G,VK_C,VK_R,VK_L,VK_OEM_2,VK_OEM_PLUS,
143 VK_A,VK_O,VK_E,VK_U,VK_I,VK_D,VK_H,VK_T,VK_N,VK_S,VK_OEM_MINUS,VK_OEM_5,
144 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
145 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
148 /* FIXME: add other layouts, such as German QWERTZ */
150 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
152 /* the VK mappings for the main keyboard will be auto-assigned as before,
153 so what we have here is just the character tables */
154 /* order: Normal, Shift, AltGr, Shift-AltGr */
155 /* We recommend you write just what is guaranteed to be correct (i.e. what's
156 written on the keycaps), not the bunch of special characters behind AltGr
157 and Shift-AltGr if it can vary among different X servers */
158 /* Remember that your 102nd key (to the right of l-shift) should be on a
159 separate line, see existing tables */
160 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
161 /* Remember to also add your new table to the layout index table far below! */
163 /*** German Logitech Desktop Pro keyboard layout */
164 static const char main_key_DE_logitech[MAIN_LEN][4] =
166 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
167 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
168 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
169 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
170 "<>|"
173 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
174 static const char main_key_US[MAIN_LEN][4] =
176 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
177 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
178 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
179 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
182 /*** United States keyboard layout (phantom key version) */
183 /* (XFree86 reports the <> key even if it's not physically there) */
184 static const char main_key_US_phantom[MAIN_LEN][4] =
186 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
187 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
188 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
189 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
190 "<>" /* the phantom key */
193 /*** United States keyboard layout (dvorak version) */
194 static const char main_key_US_dvorak[MAIN_LEN][4] =
196 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
197 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
198 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
199 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
202 /*** British keyboard layout */
203 static const char main_key_UK[MAIN_LEN][4] =
205 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
206 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
207 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
208 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
209 "\\|"
212 /*** French keyboard layout (contributed by Eric Pouech) */
213 static const char main_key_FR[MAIN_LEN][4] =
215 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
216 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
217 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
218 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
219 "<>"
222 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
223 static const char main_key_IS[MAIN_LEN][4] =
225 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
226 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
227 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
228 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
229 "<>|"
232 /*** German keyboard layout (contributed by Ulrich Weigand) */
233 static const char main_key_DE[MAIN_LEN][4] =
235 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
236 "qQ@","wW","eE€","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
237 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
238 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
239 "<>|"
242 /*** German keyboard layout without dead keys */
243 static const char main_key_DE_nodead[MAIN_LEN][4] =
245 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
246 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
247 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
248 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
249 "<>"
252 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
253 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
255 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
256 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
257 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
258 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
261 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
262 static const char main_key_SG[MAIN_LEN][4] =
264 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
265 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
266 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
267 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
268 "<>\\"
271 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
272 static const char main_key_SF[MAIN_LEN][4] =
274 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
275 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
276 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
277 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
278 "<>\\"
281 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
282 static const char main_key_NO[MAIN_LEN][4] =
284 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
285 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
286 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
287 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
288 "<>"
291 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
292 static const char main_key_DA[MAIN_LEN][4] =
294 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
295 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
296 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
297 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
298 "<>\\"
301 /*** Swedish keyboard layout (contributed by Peter Bortas) */
302 static const char main_key_SE[MAIN_LEN][4] =
304 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
305 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
306 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
307 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
308 "<>|"
311 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
312 static const char main_key_ET[MAIN_LEN][4] =
314 "·~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
315 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
316 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
317 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
318 "<>|"
321 /*** Canadian French keyboard layout */
322 static const char main_key_CF[MAIN_LEN][4] =
324 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
325 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
326 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
327 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
328 "«»°"
331 /*** Portuguese keyboard layout */
332 static const char main_key_PT[MAIN_LEN][4] =
334 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
335 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
336 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
337 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
338 "<>"
341 /*** Italian keyboard layout */
342 static const char main_key_IT[MAIN_LEN][4] =
344 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
345 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
346 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
347 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
348 "<>|"
351 /*** Finnish keyboard layout */
352 static const char main_key_FI[MAIN_LEN][4] =
354 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
355 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
356 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
357 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
358 "<>|"
361 /*** Bulgarian bds keyboard layout */
362 static const char main_key_BG_bds[MAIN_LEN][4] =
364 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
365 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
366 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
367 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
368 "<>" /* the phantom key */
371 /*** Bulgarian phonetic keyboard layout */
372 static const char main_key_BG_phonetic[MAIN_LEN][4] =
374 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
375 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
376 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
377 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
378 "<>" /* the phantom key */
381 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
382 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
383 static const char main_key_BY[MAIN_LEN][4] =
385 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
386 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
387 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
388 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
392 /*** Russian keyboard layout (contributed by Pavel Roskin) */
393 static const char main_key_RU[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 /*** Russian keyboard layout (phantom key version) */
402 static const char main_key_RU_phantom[MAIN_LEN][4] =
404 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
405 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
406 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
407 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
408 "<>" /* the phantom key */
411 /*** Russian keyboard layout KOI8-R */
412 static const char main_key_RU_koi8r[MAIN_LEN][4] =
414 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
415 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
416 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
417 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
418 "<>" /* the phantom key */
421 /*** Ukrainian keyboard layout KOI8-U */
422 static const char main_key_UA[MAIN_LEN][4] =
424 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
425 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
426 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
427 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
428 "<>" /* the phantom key */
431 /*** Spanish keyboard layout (contributed by José Marcos López) */
432 static const char main_key_ES[MAIN_LEN][4] =
434 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
435 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
436 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
437 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
438 "<>"
441 /*** Belgian keyboard layout ***/
442 static const char main_key_BE[MAIN_LEN][4] =
444 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
445 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
446 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
447 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
448 "<>\\"
451 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
452 static const char main_key_HU[MAIN_LEN][4] =
454 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
455 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
456 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
457 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
458 "íÍ<"
461 /*** Polish (programmer's) keyboard layout ***/
462 static const char main_key_PL[MAIN_LEN][4] =
464 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
465 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
466 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
467 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
468 "<>|"
471 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
472 static const char main_key_SI[MAIN_LEN][4] =
474 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
475 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
476 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
477 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
478 "<>"
481 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
482 static const char main_key_HR_jelly[MAIN_LEN][4] =
484 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
485 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
486 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
487 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
488 "<>|"
491 /*** Croatian keyboard layout ***/
492 static const char main_key_HR[MAIN_LEN][4] =
494 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
495 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
496 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
497 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
498 "<>"
501 /*** Japanese 106 keyboard layout ***/
502 static const char main_key_JA_jp106[MAIN_LEN][4] =
504 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
505 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
506 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
507 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
508 "\\_",
511 /*** Japanese pc98x1 keyboard layout ***/
512 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
514 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
515 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
516 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
517 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
518 "\\_",
521 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
522 static const char main_key_PT_br[MAIN_LEN][4] =
524 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
525 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
526 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
527 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
528 "\\|"
531 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
532 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
534 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
535 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
536 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
537 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
538 "\\|"
541 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
542 static const char main_key_US_intl[MAIN_LEN][4] =
544 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
545 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
546 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
547 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
550 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
551 - dead_abovering replaced with degree - no symbol in iso8859-2
552 - brokenbar replaced with bar */
553 static const char main_key_SK[MAIN_LEN][4] =
555 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
556 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
557 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
558 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
559 "<>"
562 /*** Czech keyboard layout (setxkbmap cz) */
563 static const char main_key_CZ[MAIN_LEN][4] =
565 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
566 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
567 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
568 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
569 "\\"
572 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
573 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
575 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
576 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
577 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
578 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
579 "\\"
582 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
583 static const char main_key_SK_prog[MAIN_LEN][4] =
585 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
586 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
587 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
588 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
589 "<>"
592 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
593 static const char main_key_CS[MAIN_LEN][4] =
595 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
596 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
597 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
598 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
599 "<>\\|"
602 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
603 static const char main_key_LA[MAIN_LEN][4] =
605 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¿¡",
606 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
607 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
608 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
609 "<>"
612 /*** Lithuanian (Baltic) keyboard layout (pc/lt in XFree86 4.3.0, contributed by Nerijus Baliûnas) */
613 static const char main_key_LT_B[MAIN_LEN][4] =
615 "`~","àÀ","èÈ","æÆ","ëË","áÁ","ðÐ","øØ","ûÛ","¥(","´)","-_","þÞ","\\|",
616 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
617 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
618 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
621 /*** Turkish keyboard Layout */
622 static const char main_key_TK[MAIN_LEN][4] =
624 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
625 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
626 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
627 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
630 /*** Israeli keyboard layout */
631 static const char main_key_IL[MAIN_LEN][4] =
633 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
634 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
635 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
636 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
639 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
640 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
641 message since they have different characters in gr and el XFree86 layouts. */
642 static const char main_key_EL[MAIN_LEN][4] =
644 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
645 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
646 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
647 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
648 "<>"
651 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
652 static const char main_key_th[MAIN_LEN][4] =
654 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
655 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
656 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
657 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
660 /*** VNC keyboard layout */
661 static const WORD main_key_scan_vnc[MAIN_LEN] =
663 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
664 0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C,
665 0x56
668 static const WORD main_key_vkey_vnc[MAIN_LEN] =
670 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,VK_OEM_4,VK_OEM_6,VK_OEM_1,VK_OEM_7,VK_OEM_3,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_5,
671 VK_A,VK_B,VK_C,VK_D,VK_E,VK_F,VK_G,VK_H,VK_I,VK_J,VK_K,VK_L,VK_M,VK_N,VK_O,VK_P,VK_Q,VK_R,VK_S,VK_T,VK_U,VK_V,VK_W,VK_X,VK_Y,VK_Z,
672 VK_OEM_102
675 static const char main_key_vnc[MAIN_LEN][4] =
677 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
678 "aA","bB","cC","dD","eE","fF","gG","hH","iI","jJ","kK","lL","mM","nN","oO","pP","qQ","rR","sS","tT","uU","vV","wW","xX","yY","zZ"
681 /*** Layout table. Add your keyboard mappings to this list */
682 static const struct {
683 const char *comment;
684 const char (*key)[MAIN_LEN][4];
685 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
686 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
687 } main_key_tab[]={
688 {"United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
689 {"United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
691 {"British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
693 {"German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
694 {"German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
695 {"German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
696 {"Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
697 {"Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
698 {"Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
699 {"Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
700 {"Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
701 {"French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
702 {"Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
703 {"Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
704 {"Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
705 {"Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
706 {"Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
707 {"Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
708 {"United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
709 {"Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
710 {"Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
711 {"Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
712 {"Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
713 {"Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
714 {"Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
715 {"Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
716 {"Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
717 {"Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
718 {"Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
719 {"Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
720 {"Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
721 {"Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
722 {"Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
723 {"Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
724 {"Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
725 {"Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
726 {"Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
727 {"Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
728 {"Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
729 {"Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
730 {"Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
731 {"Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
732 {"Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
733 {"Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
734 {"Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
735 {"Israeli keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
736 {"VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
737 {"Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
738 {"Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
740 {NULL, NULL, NULL, NULL} /* sentinel */
742 static unsigned kbd_layout=0; /* index into above table of layouts */
744 /* maybe more of these scancodes should be extended? */
745 /* extended must be set for ALT_R, CTRL_R,
746 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
747 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
748 /* FIXME should we set extended bit for NumLock ? My
749 * Windows does ... DF */
750 /* Yes, to distinguish based on scan codes, also
751 for PrtScn key ... GA */
753 static const WORD nonchar_key_vkey[256] =
755 /* unused */
756 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
757 /* special keys */
758 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
759 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
760 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
761 /* unused */
762 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
763 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
764 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
765 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
766 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
767 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
768 /* cursor keys */
769 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
770 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
771 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
772 /* misc keys */
773 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
774 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
775 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
776 /* keypad keys */
777 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
778 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
779 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
780 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
781 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
782 VK_END, 0, VK_INSERT, VK_DELETE,
783 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
784 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
785 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
786 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
787 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
788 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
789 /* function keys */
790 VK_F1, VK_F2,
791 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
792 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
793 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
794 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
795 /* modifier keys */
796 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
797 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
798 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
799 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
800 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
803 static const WORD nonchar_key_scan[256] =
805 /* unused */
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
807 /* special keys */
808 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
809 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
810 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
811 /* unused */
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
818 /* cursor keys */
819 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
821 /* misc keys */
822 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
823 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
825 /* keypad keys */
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
830 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
832 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
833 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
834 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
835 /* function keys */
836 0x3B, 0x3C,
837 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
838 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
841 /* modifier keys */
842 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
843 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
844 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
849 /* Returns the Windows virtual key code associated with the X event <e> */
850 /* x11 lock must be held */
851 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
853 KeySym keysym;
855 if (xic)
856 XmbLookupString(xic, e, NULL, 0, &keysym, NULL);
857 else
858 XLookupString(e, NULL, 0, &keysym, NULL);
860 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
861 && (e->state & NumLockMask))
862 /* Only the Keypad keys 0-9 and . send different keysyms
863 * depending on the NumLock state */
864 return nonchar_key_vkey[keysym & 0xFF];
866 return keyc2vkey[e->keycode];
869 static BOOL NumState=FALSE, CapsState=FALSE;
872 /***********************************************************************
873 * send_keyboard_input
875 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
877 INPUT input;
879 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
880 input.u.ki.wVk = wVk;
881 input.u.ki.wScan = wScan;
882 input.u.ki.dwFlags = dwFlags;
883 input.u.ki.time = time;
884 input.u.ki.dwExtraInfo = 0;
885 SendInput( 1, &input, sizeof(input) );
889 /**********************************************************************
890 * KEYBOARD_GenerateMsg
892 * Generate Down+Up messages when NumLock or CapsLock is pressed.
894 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
897 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
899 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
900 DWORD up, down;
902 if (*State) {
903 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
904 don't treat it. It's from the same key press. Then the state goes to ON.
905 And from there, a 'release' event will switch off the toggle key. */
906 *State=FALSE;
907 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
908 } else
910 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
911 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
912 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
914 if (Evtype!=KeyPress)
916 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
917 send_keyboard_input( vkey, scan, down, event_time );
918 send_keyboard_input( vkey, scan, up, event_time );
919 *State=FALSE;
920 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
923 else /* it was OFF */
924 if (Evtype==KeyPress)
926 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
927 send_keyboard_input( vkey, scan, down, event_time );
928 send_keyboard_input( vkey, scan, up, event_time );
929 *State=TRUE; /* Goes to intermediary state before going to ON */
930 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
935 /***********************************************************************
936 * KEYBOARD_UpdateOneState
938 * Updates internal state for <vkey>, depending on key <state> under X
941 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
943 /* Do something if internal table state != X state for keycode */
944 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
946 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
947 vkey, pKeyStateTable[vkey]);
949 /* Fake key being pressed inside wine */
950 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
952 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
956 /***********************************************************************
957 * X11DRV_KeymapNotify
959 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
961 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
962 * from wine to another application and back.
963 * Toggle keys are handled in HandleEvent.
965 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
967 int i, j, alt, control, shift;
968 DWORD time = GetCurrentTime();
970 alt = control = shift = 0;
971 for (i = 0; i < 32; i++)
973 if (!event->key_vector[i]) continue;
974 for (j = 0; j < 8; j++)
976 if (!(event->key_vector[i] & (1<<j))) continue;
977 switch(keyc2vkey[(i * 8) + j] & 0xff)
979 case VK_MENU: alt = 1; break;
980 case VK_CONTROL: control = 1; break;
981 case VK_SHIFT: shift = 1; break;
985 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
986 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
987 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
990 /***********************************************************************
991 * X11DRV_KeyEvent
993 * Handle a X key event
995 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
997 char Str[24];
998 KeySym keysym;
999 WORD vkey = 0, bScan;
1000 DWORD dwFlags;
1001 int ascii_chars;
1002 XIC xic = X11DRV_get_ic( hwnd );
1003 DWORD event_time = event->time - X11DRV_server_startticks;
1005 wine_tsx11_lock();
1006 if (xic)
1007 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, NULL);
1008 else
1009 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1010 wine_tsx11_unlock();
1012 /* Ignore some unwanted events */
1013 if ((keysym >= XK_ISO_Lock && keysym <= XK_ISO_Last_Group_Lock) ||
1014 keysym == XK_Mode_switch)
1016 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
1017 return;
1020 TRACE_(key)("state = %X\n", event->state);
1022 /* If XKB extensions are used, the state mask for AltGr will use the group
1023 index instead of the modifier mask. The group index is set in bits
1024 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1025 pressed, look if the group index is different than 0. From XKB
1026 extension documentation, the group index for AltGr should be 2
1027 (event->state = 0x2000). It's probably better to not assume a
1028 predefined group index and find it dynamically
1030 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1031 /* Save also all possible modifier states. */
1032 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1034 Str[ascii_chars] = '\0';
1035 if (TRACE_ON(key)){
1036 char *ksname;
1038 ksname = TSXKeysymToString(keysym);
1039 if (!ksname)
1040 ksname = "No Name";
1041 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1042 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1043 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1046 wine_tsx11_lock();
1047 vkey = EVENT_event_to_vkey(xic,event);
1048 /* X returns keycode 0 for composed characters */
1049 if (!vkey && ascii_chars) vkey = VK_NONAME;
1050 wine_tsx11_unlock();
1052 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1053 event->keycode, vkey);
1055 if (vkey)
1057 switch (vkey & 0xff)
1059 case VK_NUMLOCK:
1060 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1061 break;
1062 case VK_CAPITAL:
1063 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1064 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1065 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1066 break;
1067 default:
1068 /* Adjust the NUMLOCK state if it has been changed outside wine */
1069 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1071 TRACE("Adjusting NumLock state.\n");
1072 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1073 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1075 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1076 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1078 TRACE("Adjusting Caps Lock state.\n");
1079 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1080 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1082 /* Not Num nor Caps : end of intermediary states for both. */
1083 NumState = FALSE;
1084 CapsState = FALSE;
1086 bScan = keyc2scan[event->keycode] & 0xFF;
1087 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1089 dwFlags = 0;
1090 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1091 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1093 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1098 /**********************************************************************
1099 * X11DRV_KEYBOARD_DetectLayout
1101 * Called from X11DRV_InitKeyboard
1102 * This routine walks through the defined keyboard layouts and selects
1103 * whichever matches most closely.
1104 * X11 lock must be held.
1106 static void
1107 X11DRV_KEYBOARD_DetectLayout (void)
1109 Display *display = thread_display();
1110 unsigned current, match, mismatch, seq;
1111 int score, keyc, i, key, pkey, ok, syms;
1112 KeySym keysym;
1113 const char (*lkey)[MAIN_LEN][4];
1114 unsigned max_seq = 0;
1115 int max_score = 0, ismatch = 0;
1116 char ckey[4] =
1117 {0, 0, 0, 0};
1119 syms = keysyms_per_keycode;
1120 if (syms > 4) {
1121 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1122 syms = 4;
1124 for (current = 0; main_key_tab[current].comment; current++) {
1125 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1126 match = 0;
1127 mismatch = 0;
1128 score = 0;
1129 seq = 0;
1130 lkey = main_key_tab[current].key;
1131 pkey = -1;
1132 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1133 /* get data for keycode from X server */
1134 for (i = 0; i < syms; i++) {
1135 keysym = XKeycodeToKeysym (display, keyc, i);
1136 /* Allow both one-byte and two-byte national keysyms */
1137 if ((keysym < 0x8000) && (keysym != ' '))
1139 #ifdef HAVE_XKB
1140 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1141 #endif
1143 TRACE("XKB could not translate keysym %ld\n", keysym);
1144 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1145 * with appropriate ShiftMask and Mode_switch, use XLookupString
1146 * to get character in the local encoding.
1148 ckey[i] = keysym & 0xFF;
1151 else {
1152 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1155 if (ckey[0]) {
1156 /* search for a match in layout table */
1157 /* right now, we just find an absolute match for defined positions */
1158 /* (undefined positions are ignored, so if it's defined as "3#" in */
1159 /* the table, it's okay that the X server has "3#£", for example) */
1160 /* however, the score will be higher for longer matches */
1161 for (key = 0; key < MAIN_LEN; key++) {
1162 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1163 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1164 ok++;
1165 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1166 ok = -1;
1168 if (ok > 0) {
1169 score += ok;
1170 break;
1173 /* count the matches and mismatches */
1174 if (ok > 0) {
1175 match++;
1176 /* and how much the keycode order matches */
1177 if (key > pkey) seq++;
1178 pkey = key;
1179 } else {
1180 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1181 mismatch++;
1182 score -= syms;
1186 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1187 match, mismatch, seq, score);
1188 if ((score > max_score) ||
1189 ((score == max_score) && (seq > max_seq))) {
1190 /* best match so far */
1191 kbd_layout = current;
1192 max_score = score;
1193 max_seq = seq;
1194 ismatch = !mismatch;
1197 /* we're done, report results if necessary */
1198 if (!ismatch) {
1199 FIXME(
1200 "Your keyboard layout was not found!\n"
1201 "Using closest match instead (%s) for scancode mapping.\n"
1202 "Please define your layout in dlls/x11drv/keyboard.c and submit them\n"
1203 "to us for inclusion into future Wine releases.\n"
1204 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1205 main_key_tab[kbd_layout].comment);
1208 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1211 /**********************************************************************
1212 * InitKeyboard (X11DRV.@)
1214 void X11DRV_InitKeyboard( BYTE *key_state_table )
1216 Display *display = thread_display();
1217 KeySym *ksp;
1218 XModifierKeymap *mmp;
1219 KeySym keysym;
1220 KeyCode *kcp;
1221 XKeyEvent e2;
1222 WORD scan, vkey, OEMvkey;
1223 int keyc, i, keyn, syms;
1224 char ckey[4]={0,0,0,0};
1225 const char (*lkey)[MAIN_LEN][4];
1227 pKeyStateTable = key_state_table;
1229 wine_tsx11_lock();
1230 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1231 ksp = XGetKeyboardMapping(display, min_keycode,
1232 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1233 /* We are only interested in keysyms_per_keycode.
1234 There is no need to hold a local copy of the keysyms table */
1235 XFree(ksp);
1237 mmp = XGetModifierMapping(display);
1238 kcp = mmp->modifiermap;
1239 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1241 int j;
1243 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1244 if (*kcp)
1246 int k;
1248 for (k = 0; k < keysyms_per_keycode; k += 1)
1249 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1251 NumLockMask = 1 << i;
1252 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1256 XFreeModifiermap(mmp);
1258 /* Detect the keyboard layout */
1259 X11DRV_KEYBOARD_DetectLayout();
1260 lkey = main_key_tab[kbd_layout].key;
1261 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1263 /* Now build two conversion arrays :
1264 * keycode -> vkey + scancode + extended
1265 * vkey + extended -> keycode */
1267 e2.display = display;
1268 e2.state = 0;
1270 OEMvkey = VK_OEM_7; /* next is available. */
1271 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1273 e2.keycode = (KeyCode)keyc;
1274 XLookupString(&e2, NULL, 0, &keysym, NULL);
1275 vkey = 0; scan = 0;
1276 if (keysym) /* otherwise, keycode not used */
1278 if ((keysym >> 8) == 0xFF) /* non-character key */
1280 vkey = nonchar_key_vkey[keysym & 0xff];
1281 scan = nonchar_key_scan[keysym & 0xff];
1282 /* set extended bit when necessary */
1283 if (scan & 0x100) vkey |= 0x100;
1284 } else if (keysym == 0x20) { /* Spacebar */
1285 vkey = VK_SPACE;
1286 scan = 0x39;
1287 } else {
1288 /* we seem to need to search the layout-dependent scancodes */
1289 int maxlen=0,maxval=-1,ok;
1290 for (i=0; i<syms; i++) {
1291 keysym = XKeycodeToKeysym(display, keyc, i);
1292 if ((keysym<0x8000) && (keysym!=' '))
1294 #ifdef HAVE_XKB
1295 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1296 #endif
1298 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1299 * with appropriate ShiftMask and Mode_switch, use XLookupString
1300 * to get character in the local encoding.
1302 ckey[i] = keysym & 0xFF;
1304 } else {
1305 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1308 /* find key with longest match streak */
1309 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1310 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1311 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1312 if (ok||(i>maxlen)) {
1313 maxlen=i; maxval=keyn;
1315 if (ok) break;
1317 if (maxval>=0) {
1318 /* got it */
1319 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1320 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1321 scan = (*lscan)[maxval];
1322 vkey = (*lvkey)[maxval];
1326 /* find a suitable layout-dependent VK code */
1327 /* (most Winelib apps ought to be able to work without layout tables!) */
1328 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1330 keysym = XLookupKeysym(&e2, i);
1331 if ((keysym >= VK_0 && keysym <= VK_9)
1332 || (keysym >= VK_A && keysym <= VK_Z)) {
1333 vkey = keysym;
1337 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1339 keysym = XLookupKeysym(&e2, i);
1340 switch (keysym)
1342 case ';': vkey = VK_OEM_1; break;
1343 case '/': vkey = VK_OEM_2; break;
1344 case '`': vkey = VK_OEM_3; break;
1345 case '[': vkey = VK_OEM_4; break;
1346 case '\\': vkey = VK_OEM_5; break;
1347 case ']': vkey = VK_OEM_6; break;
1348 case '\'': vkey = VK_OEM_7; break;
1349 case ',': vkey = VK_OEM_COMMA; break;
1350 case '.': vkey = VK_OEM_PERIOD; break;
1351 case '-': vkey = VK_OEM_MINUS; break;
1352 case '+': vkey = VK_OEM_PLUS; break;
1356 if (!vkey)
1358 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1359 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1360 switch (++OEMvkey)
1362 case 0xc1 : OEMvkey=0xdb; break;
1363 case 0xe5 : OEMvkey=0xe9; break;
1364 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1367 vkey = OEMvkey;
1369 if (TRACE_ON(keyboard))
1371 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1372 OEMvkey, e2.keycode);
1373 TRACE("(");
1374 for (i = 0; i < keysyms_per_keycode; i += 1)
1376 char *ksname;
1378 keysym = XLookupKeysym(&e2, i);
1379 ksname = XKeysymToString(keysym);
1380 if (!ksname)
1381 ksname = "NoSymbol";
1382 TRACE( "%lX (%s) ", keysym, ksname);
1384 TRACE(")\n");
1388 keyc2vkey[e2.keycode] = vkey;
1389 keyc2scan[e2.keycode] = scan;
1390 } /* for */
1392 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1393 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1394 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1395 char *ksname;
1396 keysym = XKeycodeToKeysym(display, keyc, 0);
1397 ksname = XKeysymToString(keysym);
1398 if (!ksname) ksname = "NoSymbol";
1400 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1402 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1403 keyc2scan[keyc]=scan++;
1406 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1407 kcControl = XKeysymToKeycode(display, XK_Control_L);
1408 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1409 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1410 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1411 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1412 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1413 wine_tsx11_unlock();
1417 /***********************************************************************
1418 * X11DRV_MappingNotify
1420 void X11DRV_MappingNotify( XMappingEvent *event )
1422 TSXRefreshKeyboardMapping(event);
1423 X11DRV_InitKeyboard( pKeyStateTable );
1427 /***********************************************************************
1428 * VkKeyScan (X11DRV.@)
1430 WORD X11DRV_VkKeyScan(CHAR cChar)
1432 Display *display = thread_display();
1433 KeyCode keycode;
1434 KeySym keysym;
1435 int i,index;
1436 int highbyte=0;
1438 /* char->keysym (same for ANSI chars) */
1439 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1440 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1442 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1443 if (!keycode)
1444 { /* It didn't work ... let's try with deadchar code. */
1445 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1448 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1449 cChar,keysym,keysym,keycode);
1451 if (keycode)
1453 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1454 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1455 switch (index) {
1456 case -1 :
1457 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1458 case 0 : break;
1459 case 1 : highbyte = 0x0100; break;
1460 case 2 : highbyte = 0x0600; break;
1461 case 3 : highbyte = 0x0700; break;
1462 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1465 index : 0 adds 0x0000
1466 index : 1 adds 0x0100 (shift)
1467 index : ? adds 0x0200 (ctrl)
1468 index : 2 adds 0x0600 (ctrl+alt)
1469 index : 3 adds 0x0700 (ctrl+alt+shift)
1472 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1473 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1476 /***********************************************************************
1477 * MapVirtualKey (X11DRV.@)
1479 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1481 Display *display = thread_display();
1483 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1485 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1486 switch(wMapType) {
1487 case 0: { /* vkey-code to scan-code */
1488 /* let's do vkey -> keycode -> scan */
1489 int keyc;
1490 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1491 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1492 returnMVK (keyc2scan[keyc] & 0xFF);
1493 TRACE("returning no scan-code.\n");
1494 return 0; }
1496 case 1: { /* scan-code to vkey-code */
1497 /* let's do scan -> keycode -> vkey */
1498 int keyc;
1499 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1500 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1501 returnMVK (keyc2vkey[keyc] & 0xFF);
1502 TRACE("returning no vkey-code.\n");
1503 return 0; }
1505 case 2: { /* vkey-code to unshifted ANSI code */
1506 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1507 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1508 * key.. Looks like something is wrong with the MS docs?
1509 * This is only true for letters, for example VK_0 returns '0' not ')'.
1510 * - hence we use the lock mask to ensure this happens.
1512 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1513 XKeyEvent e;
1514 KeySym keysym;
1515 int keyc;
1516 char s[2];
1517 e.display = display;
1519 e.state = LockMask;
1520 /* LockMask should behave exactly like caps lock - upercase
1521 * the letter keys and thats about it. */
1523 wine_tsx11_lock();
1525 e.keycode = 0;
1526 /* We exit on the first keycode found, to speed up the thing. */
1527 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1528 { /* Find a keycode that could have generated this virtual key */
1529 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1530 { /* We filter the extended bit, we don't know it */
1531 e.keycode = keyc; /* Store it temporarily */
1532 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1533 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1534 state), so set it to 0, we'll find another one */
1539 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1540 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1542 if (wCode==VK_DECIMAL)
1543 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1545 if (!e.keycode)
1547 WARN("Unknown virtual key %X !!! \n", wCode);
1548 wine_tsx11_unlock();
1549 return 0; /* whatever */
1551 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1553 if (XLookupString(&e, s, 2, &keysym, NULL))
1555 wine_tsx11_unlock();
1556 returnMVK (*s);
1559 TRACE("returning no ANSI.\n");
1560 wine_tsx11_unlock();
1561 return 0;
1564 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1565 /* left and right */
1566 FIXME(" stub for NT\n");
1567 return 0;
1569 default: /* reserved */
1570 WARN("Unknown wMapType %d !\n", wMapType);
1571 return 0;
1573 return 0;
1576 /***********************************************************************
1577 * GetKeyNameText (X11DRV.@)
1579 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1581 int vkey, ansi, scanCode;
1582 KeyCode keyc;
1583 int keyi;
1584 KeySym keys;
1585 char *name;
1587 scanCode = lParam >> 16;
1588 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1590 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1591 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1593 /* handle "don't care" bit (0x02000000) */
1594 if (!(lParam & 0x02000000)) {
1595 switch (vkey) {
1596 case VK_LSHIFT:
1597 case VK_RSHIFT:
1598 vkey = VK_SHIFT;
1599 break;
1600 case VK_LCONTROL:
1601 case VK_RCONTROL:
1602 vkey = VK_CONTROL;
1603 break;
1604 case VK_LMENU:
1605 case VK_RMENU:
1606 vkey = VK_MENU;
1607 break;
1608 default:
1609 break;
1613 ansi = X11DRV_MapVirtualKey(vkey, 2);
1614 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1616 /* first get the name of the "regular" keys which is the Upper case
1617 value of the keycap imprint. */
1618 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1619 (scanCode != 0x137) && /* PrtScn */
1620 (scanCode != 0x135) && /* numpad / */
1621 (scanCode != 0x37 ) && /* numpad * */
1622 (scanCode != 0x4a ) && /* numpad - */
1623 (scanCode != 0x4e ) ) /* numpad + */
1625 if ((nSize >= 2) && lpBuffer)
1627 *lpBuffer = toupper((char)ansi);
1628 *(lpBuffer+1) = 0;
1629 return 1;
1631 else
1632 return 0;
1635 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1636 without "extended-key" flag. However Wine generates scancode
1637 *with* "extended-key" flag. Seems to occur *only* for the
1638 function keys. Soooo.. We will leave the table alone and
1639 fudge the lookup here till the other part is found and fixed!!! */
1641 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1642 (scanCode == 0x157) || (scanCode == 0x158))
1643 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1645 /* let's do scancode -> keycode -> keysym -> String */
1647 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1648 if ((keyc2scan[keyi]) == scanCode)
1649 break;
1650 if (keyi <= max_keycode)
1652 keyc = (KeyCode) keyi;
1653 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1654 name = TSXKeysymToString(keys);
1655 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1656 scanCode, keyc, (int)keys, name);
1657 if (lpBuffer && nSize && name)
1659 lstrcpynA(lpBuffer, name, nSize);
1660 return 1;
1664 /* Finally issue FIXME for unknown keys */
1666 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1667 if (lpBuffer && nSize)
1668 *lpBuffer = 0;
1669 return 0;
1672 /***********************************************************************
1673 * X11DRV_KEYBOARD_MapDeadKeysym
1675 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1677 switch (keysym)
1679 /* symbolic ASCII is the same as defined in rfc1345 */
1680 #ifdef XK_dead_tilde
1681 case XK_dead_tilde :
1682 #endif
1683 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1684 return '~'; /* '? */
1685 #ifdef XK_dead_acute
1686 case XK_dead_acute :
1687 #endif
1688 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1689 return 0xb4; /* '' */
1690 #ifdef XK_dead_circumflex
1691 case XK_dead_circumflex:
1692 #endif
1693 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1694 return '^'; /* '> */
1695 #ifdef XK_dead_grave
1696 case XK_dead_grave :
1697 #endif
1698 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1699 return '`'; /* '! */
1700 #ifdef XK_dead_diaeresis
1701 case XK_dead_diaeresis :
1702 #endif
1703 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1704 return 0xa8; /* ': */
1705 #ifdef XK_dead_cedilla
1706 case XK_dead_cedilla :
1707 return 0xb8; /* ', */
1708 #endif
1709 #ifdef XK_dead_macron
1710 case XK_dead_macron :
1711 return '-'; /* 'm isn't defined on iso-8859-x */
1712 #endif
1713 #ifdef XK_dead_breve
1714 case XK_dead_breve :
1715 return 0xa2; /* '( */
1716 #endif
1717 #ifdef XK_dead_abovedot
1718 case XK_dead_abovedot :
1719 return 0xff; /* '. */
1720 #endif
1721 #ifdef XK_dead_abovering
1722 case XK_dead_abovering :
1723 return '0'; /* '0 isn't defined on iso-8859-x */
1724 #endif
1725 #ifdef XK_dead_doubleacute
1726 case XK_dead_doubleacute :
1727 return 0xbd; /* '" */
1728 #endif
1729 #ifdef XK_dead_caron
1730 case XK_dead_caron :
1731 return 0xb7; /* '< */
1732 #endif
1733 #ifdef XK_dead_ogonek
1734 case XK_dead_ogonek :
1735 return 0xb2; /* '; */
1736 #endif
1737 /* FIXME: I don't know this three.
1738 case XK_dead_iota :
1739 return 'i';
1740 case XK_dead_voiced_sound :
1741 return 'v';
1742 case XK_dead_semivoiced_sound :
1743 return 's';
1746 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1747 return 0;
1750 /***********************************************************************
1751 * ToUnicode (X11DRV.@)
1753 * The ToUnicode function translates the specified virtual-key code and keyboard
1754 * state to the corresponding Windows character or characters.
1756 * If the specified key is a dead key, the return value is negative. Otherwise,
1757 * it is one of the following values:
1758 * Value Meaning
1759 * 0 The specified virtual key has no translation for the current state of the keyboard.
1760 * 1 One Windows character was copied to the buffer.
1761 * 2 Two characters were copied to the buffer. This usually happens when a
1762 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1763 * be composed with the specified virtual key to form a single character.
1765 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1768 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1769 LPWSTR bufW, int bufW_size, UINT flags)
1771 Display *display = thread_display();
1772 XKeyEvent e;
1773 KeySym keysym;
1774 INT ret;
1775 int keyc;
1776 char lpChar[10];
1777 HWND focus;
1778 XIC xic;
1780 if (scanCode & 0x8000)
1782 TRACE("Key UP, doing nothing\n" );
1783 return 0;
1786 e.display = display;
1787 e.keycode = 0;
1788 e.state = 0;
1789 e.type = KeyPress;
1791 focus = GetFocus();
1792 if (focus) focus = GetAncestor( focus, GA_ROOT );
1793 if (!focus) focus = GetActiveWindow();
1794 e.window = X11DRV_get_whole_window( focus );
1795 xic = X11DRV_get_ic( focus );
1797 if (lpKeyState[VK_SHIFT] & 0x80)
1799 TRACE("ShiftMask = %04x\n", ShiftMask);
1800 e.state |= ShiftMask;
1802 if (lpKeyState[VK_CAPITAL] & 0x01)
1804 TRACE("LockMask = %04x\n", LockMask);
1805 e.state |= LockMask;
1807 if (lpKeyState[VK_CONTROL] & 0x80)
1809 TRACE("ControlMask = %04x\n", ControlMask);
1810 e.state |= ControlMask;
1812 if (lpKeyState[VK_NUMLOCK] & 0x01)
1814 TRACE("NumLockMask = %04x\n", NumLockMask);
1815 e.state |= NumLockMask;
1818 /* Restore saved AltGr state */
1819 TRACE("AltGrMask = %04x\n", AltGrMask);
1820 e.state |= AltGrMask;
1822 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1823 virtKey, scanCode, e.state);
1824 wine_tsx11_lock();
1825 /* We exit on the first keycode found, to speed up the thing. */
1826 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1827 { /* Find a keycode that could have generated this virtual key */
1828 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1829 { /* We filter the extended bit, we don't know it */
1830 e.keycode = keyc; /* Store it temporarily */
1831 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
1832 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1833 state), so set it to 0, we'll find another one */
1838 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1839 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1841 if (virtKey==VK_DECIMAL)
1842 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1844 if (!e.keycode && virtKey != VK_NONAME)
1846 WARN("Unknown virtual key %X !!! \n",virtKey);
1847 wine_tsx11_unlock();
1848 return virtKey; /* whatever */
1850 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1852 if (xic)
1853 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
1854 else
1855 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
1856 wine_tsx11_unlock();
1858 if (ret == 0)
1860 BYTE dead_char;
1862 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1863 if (dead_char)
1865 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
1866 ret = -1;
1868 else
1870 char *ksname;
1872 ksname = TSXKeysymToString(keysym);
1873 if (!ksname)
1874 ksname = "No Name";
1875 if ((keysym >> 8) != 0xff)
1877 ERR("Please report: no char for keysym %04lX (%s) :\n",
1878 keysym, ksname);
1879 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1880 virtKey, scanCode, e.keycode, e.state);
1884 else { /* ret != 0 */
1885 /* We have a special case to handle : Shift + arrow, shift + home, ...
1886 X returns a char for it, but Windows doesn't. Let's eat it. */
1887 if (!(e.state & NumLockMask) /* NumLock is off */
1888 && (e.state & ShiftMask) /* Shift is pressed */
1889 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1891 lpChar[0] = 0;
1892 ret = 0;
1895 /* more areas where X returns characters but Windows does not
1896 CTRL + number or CTRL + symbol */
1897 if (e.state & ControlMask)
1899 if (((keysym>=33) && (keysym < 'A')) ||
1900 ((keysym > 'Z') && (keysym < 'a')))
1902 lpChar[0] = 0;
1903 ret = 0;
1907 /* We have another special case for delete key (XK_Delete) on an
1908 extended keyboard. X returns a char for it, but Windows doesn't */
1909 if (keysym == XK_Delete)
1911 lpChar[0] = 0;
1912 ret = 0;
1914 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1915 && (keysym == XK_KP_Decimal))
1917 lpChar[0] = 0;
1918 ret = 0;
1921 /* perform translation to unicode */
1922 if(ret)
1924 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
1925 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
1929 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1930 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1931 return ret;
1934 /***********************************************************************
1935 * Beep (X11DRV.@)
1937 void X11DRV_Beep(void)
1939 TSXBell(thread_display(), 0);