Set version to DirectX 7.
[wine/dcerpc.git] / dlls / x11drv / keyboard.c
blobef355ce02235954c89fff9f012fb4cdf99632b61
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 <string.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
43 #include "windef.h"
44 #include "wingdi.h"
45 #include "wine/winuser16.h"
46 #include "winnls.h"
47 #include "win.h"
48 #include "x11drv.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
52 WINE_DECLARE_DEBUG_CHANNEL(key);
53 WINE_DECLARE_DEBUG_CHANNEL(dinput);
55 int min_keycode, max_keycode, keysyms_per_keycode;
56 WORD keyc2vkey[256], keyc2scan[256];
58 static LPBYTE pKeyStateTable;
59 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
60 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
62 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
64 /* Keyboard translation tables */
65 #define MAIN_LEN 49
66 static const WORD main_key_scan_qwerty[MAIN_LEN] =
68 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
69 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
70 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
71 /* q w e r t y u i o p [ ] */
72 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
73 /* a s d f g h j k l ; ' \ */
74 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
75 /* z x c v b n m , . / */
76 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
77 0x56 /* the 102nd key (actually to the right of l-shift) */
80 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
82 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
83 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
84 /* q w e r t y u i o p [ ] */
85 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
86 /* a s d f g h j k l ; ' \ */
87 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
88 /* \ z x c v b n m , . / */
89 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
90 0x56, /* the 102nd key (actually to the right of l-shift) */
93 static const WORD main_key_scan_dvorak[MAIN_LEN] =
95 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
96 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
97 /* ' , . p y f g c r l / = */
98 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
99 /* a o e u i d h t n s - \ */
100 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
101 /* ; q j k x b m w v z */
102 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
103 0x56 /* the 102nd key (actually to the right of l-shift) */
106 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
108 /* NOTE: this layout must concur with the scan codes layout above */
109 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,
110 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,
111 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,
112 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
113 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
116 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
118 /* NOTE: this layout must concur with the scan codes layout above */
119 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,
120 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,
121 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,
122 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,
123 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
126 static const WORD main_key_vkey_azerty[MAIN_LEN] =
128 /* NOTE: this layout must concur with the scan codes layout above */
129 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,
130 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,
131 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,
132 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
133 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
136 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
138 /* NOTE: this layout must concur with the scan codes layout above */
139 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,
140 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,
141 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,
142 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
143 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
146 /* FIXME: add other layouts, such as German QWERTZ */
148 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
150 /* the VK mappings for the main keyboard will be auto-assigned as before,
151 so what we have here is just the character tables */
152 /* order: Normal, Shift, AltGr, Shift-AltGr */
153 /* We recommend you write just what is guaranteed to be correct (i.e. what's
154 written on the keycaps), not the bunch of special characters behind AltGr
155 and Shift-AltGr if it can vary among different X servers */
156 /* Remember that your 102nd key (to the right of l-shift) should be on a
157 separate line, see existing tables */
158 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
159 /* Remember to also add your new table to the layout index table far below! */
161 /*** German Logitech Desktop Pro keyboard layout */
162 static const char main_key_DE_logitech[MAIN_LEN][4] =
164 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
165 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
166 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
167 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
168 "<>|"
171 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
172 static const char main_key_US[MAIN_LEN][4] =
174 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
175 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
176 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
177 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
180 /*** United States keyboard layout (phantom key version) */
181 /* (XFree86 reports the <> key even if it's not physically there) */
182 static const char main_key_US_phantom[MAIN_LEN][4] =
184 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
185 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
186 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
187 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
188 "<>" /* the phantom key */
191 /*** United States keyboard layout (dvorak version) */
192 static const char main_key_US_dvorak[MAIN_LEN][4] =
194 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
195 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
196 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
197 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
200 /*** British keyboard layout */
201 static const char main_key_UK[MAIN_LEN][4] =
203 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
204 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
205 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
206 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
207 "\\|"
210 /*** French keyboard layout (contributed by Eric Pouech) */
211 static const char main_key_FR[MAIN_LEN][4] =
213 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7`","_8\\","ç9^±","à0@",")°]","=+}",
214 "aA","zZ","eE¿","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
215 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
216 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
217 "<>"
220 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
221 static const char main_key_IS[MAIN_LEN][4] =
223 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
224 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
225 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
226 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
227 "<>|"
230 /*** German keyboard layout (contributed by Ulrich Weigand) */
231 static const char main_key_DE[MAIN_LEN][4] =
233 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
234 "qQ@","wW","eE€","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
235 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
236 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
237 "<>|"
240 /*** German keyboard layout without dead keys */
241 static const char main_key_DE_nodead[MAIN_LEN][4] =
243 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
244 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
245 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
246 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
247 "<>"
250 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
251 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
253 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
254 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
255 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
256 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
259 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
260 static const char main_key_SG[MAIN_LEN][4] =
262 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
263 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
264 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
265 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
266 "<>\\"
269 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
270 static const char main_key_SF[MAIN_LEN][4] =
272 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
273 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
274 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
275 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
276 "<>\\"
279 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
280 static const char main_key_NO[MAIN_LEN][4] =
282 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
283 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
284 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
285 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
286 "<>"
289 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
290 static const char main_key_DA[MAIN_LEN][4] =
292 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
293 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
294 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
295 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
296 "<>\\"
299 /*** Swedish keyboard layout (contributed by Peter Bortas) */
300 static const char main_key_SE[MAIN_LEN][4] =
302 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
303 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
304 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
305 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
306 "<>|"
309 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
310 static const char main_key_ET[MAIN_LEN][4] =
312 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
313 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
314 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
315 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
316 "<>|"
319 /*** Canadian French keyboard layout */
320 static const char main_key_CF[MAIN_LEN][4] =
322 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
323 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
324 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
325 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
326 "«»°"
329 /*** Portuguese keyboard layout */
330 static const char main_key_PT[MAIN_LEN][4] =
332 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
333 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
334 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
335 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
336 "<>"
339 /*** Italian keyboard layout */
340 static const char main_key_IT[MAIN_LEN][4] =
342 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
343 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
344 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
345 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
346 "<>|"
349 /*** Finnish keyboard layout */
350 static const char main_key_FI[MAIN_LEN][4] =
352 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
353 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
354 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
355 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
356 "<>|"
359 /*** Bulgarian bds keyboard layout */
360 static const char main_key_BG_bds[MAIN_LEN][4] =
362 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
363 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
364 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
365 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
366 "<>" /* the phantom key */
369 /*** Bulgarian phonetic keyboard layout */
370 static const char main_key_BG_phonetic[MAIN_LEN][4] =
372 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
373 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
374 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
375 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
376 "<>" /* the phantom key */
379 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
380 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
381 static const char main_key_BY[MAIN_LEN][4] =
383 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
384 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
385 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
386 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
390 /*** Russian keyboard layout (contributed by Pavel Roskin) */
391 static const char main_key_RU[MAIN_LEN][4] =
393 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
394 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
395 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
396 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
399 /*** Russian keyboard layout (phantom key version) */
400 static const char main_key_RU_phantom[MAIN_LEN][4] =
402 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
403 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
404 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
405 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
406 "<>" /* the phantom key */
409 /*** Russian keyboard layout KOI8-R */
410 static const char main_key_RU_koi8r[MAIN_LEN][4] =
412 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
413 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
414 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
415 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
416 "<>" /* the phantom key */
419 /*** Ukrainian keyboard layout KOI8-U */
420 static const char main_key_UA[MAIN_LEN][4] =
422 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
423 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
424 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
425 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
426 "<>" /* the phantom key */
429 /*** Spanish keyboard layout (contributed by José Marcos López) */
430 static const char main_key_ES[MAIN_LEN][4] =
432 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
433 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
434 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
435 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
436 "<>"
439 /*** Belgian keyboard layout ***/
440 static const char main_key_BE[MAIN_LEN][4] =
442 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
443 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
444 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
445 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
446 "<>\\"
449 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
450 static const char main_key_HU[MAIN_LEN][4] =
452 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
453 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
454 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
455 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
456 "íÍ<"
459 /*** Polish (programmer's) keyboard layout ***/
460 static const char main_key_PL[MAIN_LEN][4] =
462 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
463 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
464 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
465 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
466 "<>|"
469 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
470 static const char main_key_SI[MAIN_LEN][4] =
472 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
473 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
474 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
475 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
476 "<>"
479 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
480 static const char main_key_HR_jelly[MAIN_LEN][4] =
482 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
483 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
484 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
485 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
486 "<>|"
489 /*** Croatian keyboard layout ***/
490 static const char main_key_HR[MAIN_LEN][4] =
492 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
493 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
494 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
495 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
496 "<>"
499 /*** Japanese 106 keyboard layout ***/
500 static const char main_key_JA_jp106[MAIN_LEN][4] =
502 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
503 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
504 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
505 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
506 "\\_",
509 /*** Japanese pc98x1 keyboard layout ***/
510 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
512 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
513 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
514 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
515 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
516 "\\_",
519 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
520 static const char main_key_PT_br[MAIN_LEN][4] =
522 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
523 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
524 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
525 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
526 "\\|"
529 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
530 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
532 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
533 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
534 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
535 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
536 "\\|"
539 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
540 static const char main_key_US_intl[MAIN_LEN][4] =
542 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
543 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
544 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
545 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
548 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
549 - dead_abovering replaced with degree - no symbol in iso8859-2
550 - brokenbar replaced with bar */
551 static const char main_key_SK[MAIN_LEN][4] =
553 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
554 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
555 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
556 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
557 "<>"
560 /*** Czech keyboard layout (setxkbmap cz) */
561 static const char main_key_CZ[MAIN_LEN][4] =
563 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
564 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
565 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
566 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
567 "\\"
570 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
571 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
573 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
574 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
575 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
576 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
577 "\\"
580 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
581 static const char main_key_SK_prog[MAIN_LEN][4] =
583 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
584 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
585 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
586 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
587 "<>"
590 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
591 static const char main_key_CS[MAIN_LEN][4] =
593 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
594 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
595 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
596 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
597 "<>\\|"
600 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
601 static const char main_key_LA[MAIN_LEN][4] =
603 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¿¡",
604 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
605 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
606 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
607 "<>"
610 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
611 static const char main_key_LT_B[MAIN_LEN][4] =
613 "`~","1àÀ","2èÈ","3æÆ","4ëË","5áÁ","6ðÐ","7øØ","8ûÛ","9¥(","0´)","-_","=þÞ","\\|",
614 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
615 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
616 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
619 /*** Turkish keyboard Layout */
620 static const char main_key_TK[MAIN_LEN][4] =
622 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
623 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
624 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
625 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
628 /*** Israeli keyboard layout */
629 static const char main_key_IL[MAIN_LEN][4] =
631 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
632 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
633 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
634 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
637 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
638 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
639 message since they have different characters in gr and el XFree86 layouts. */
640 static const char main_key_EL[MAIN_LEN][4] =
642 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
643 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
644 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
645 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
646 "<>"
649 /*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
650 static const char main_key_th[MAIN_LEN][4] =
652 "`~_%","1!å+","2@/ñ","3#-ò","4$Àó","5%¶ô","6^ØÙ","7&Öß","8*¤õ","9(µö","0)¨÷","-_¢ø","=+ªù",
653 "qQæð","wWä\"","eEÓ®","rR¾±","tTи","yYÑí","uUÕê","iIó","oO¹Ï","pP­","[{º°","]}Å,",
654 "aA¿Ä","sS˦","dD¡¯","fF´â","gGà¬","hHéç","jJèë","kKÒÉ","lLÊÈ",";:Ç«","\'\"§.","\\|£¥",
655 "zZ¼(","xX»)","cCá©","vVÍÎ","bBÚ","nN×ì","mM·?",",<Á²",".>ãÌ","/?½Æ"
658 /*** VNC keyboard layout */
659 static const WORD main_key_scan_vnc[MAIN_LEN] =
661 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
662 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,
663 0x56
666 static const WORD main_key_vkey_vnc[MAIN_LEN] =
668 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,
669 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,
670 VK_OEM_102
673 static const char main_key_vnc[MAIN_LEN][4] =
675 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
676 "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"
679 /*** Layout table. Add your keyboard mappings to this list */
680 static const struct {
681 const char *comment;
682 const char (*key)[MAIN_LEN][4];
683 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
684 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
685 } main_key_tab[]={
686 {"United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
687 {"United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
688 {"United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
689 {"British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
691 {"German keyboard layout without dead keys", &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"German keyboard layout for logitech desktop pro", &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
693 {"German keyboard layout without dead keys 105", &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
694 {"Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
695 {"Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
696 {"Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
697 {"Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
698 {"Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
699 {"French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
700 {"Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
701 {"Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
702 {"Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
703 {"Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
704 {"Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
705 {"Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
706 {"United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
707 {"Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
708 {"Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
709 {"Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
710 {"Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
711 {"Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
712 {"Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
713 {"Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
714 {"Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
715 {"Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
716 {"Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
717 {"Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
718 {"Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
719 {"Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
720 {"Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
721 {"Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
722 {"Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
723 {"Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
724 {"Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
725 {"Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
726 {"Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
727 {"Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
728 {"Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
729 {"Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
730 {"Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
731 {"Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
732 {"Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
733 {"Israeli keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
734 {"VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
735 {"Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
736 {"Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
738 {NULL, NULL, NULL, NULL} /* sentinel */
740 static unsigned kbd_layout=0; /* index into above table of layouts */
742 /* maybe more of these scancodes should be extended? */
743 /* extended must be set for ALT_R, CTRL_R,
744 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
745 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
746 /* FIXME should we set extended bit for NumLock ? My
747 * Windows does ... DF */
748 /* Yes, to distinguish based on scan codes, also
749 for PrtScn key ... GA */
751 static const WORD nonchar_key_vkey[256] =
753 /* unused */
754 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
755 /* special keys */
756 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
757 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
758 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
759 /* unused */
760 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
761 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
762 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
763 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
764 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
765 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
766 /* cursor keys */
767 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
768 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
769 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
770 /* misc keys */
771 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
772 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
773 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
774 /* keypad keys */
775 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
776 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
777 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
778 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
779 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
780 VK_END, 0, VK_INSERT, VK_DELETE,
781 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
782 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
783 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
784 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
785 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
786 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
787 /* function keys */
788 VK_F1, VK_F2,
789 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
790 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
791 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
792 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
793 /* modifier keys */
794 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
795 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
796 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
797 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
798 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
801 static const WORD nonchar_key_scan[256] =
803 /* unused */
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
805 /* special keys */
806 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
807 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
808 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
809 /* unused */
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
816 /* cursor keys */
817 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
819 /* misc keys */
820 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
821 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
823 /* keypad keys */
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
828 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
830 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
831 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
832 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
833 /* function keys */
834 0x3B, 0x3C,
835 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
836 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
839 /* modifier keys */
840 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
841 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
847 /* Returns the Windows virtual key code associated with the X event <e> */
848 /* x11 lock must be held */
849 static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
851 KeySym keysym;
853 if (xic)
854 XmbLookupString(xic, e, NULL, 0, &keysym, NULL);
855 else
856 XLookupString(e, NULL, 0, &keysym, NULL);
858 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
859 && (e->state & NumLockMask))
860 /* Only the Keypad keys 0-9 and . send different keysyms
861 * depending on the NumLock state */
862 return nonchar_key_vkey[keysym & 0xFF];
864 return keyc2vkey[e->keycode];
867 static BOOL NumState=FALSE, CapsState=FALSE;
870 /***********************************************************************
871 * send_keyboard_input
873 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
875 INPUT input;
877 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
878 input.u.ki.wVk = wVk;
879 input.u.ki.wScan = wScan;
880 input.u.ki.dwFlags = dwFlags;
881 input.u.ki.time = time;
882 input.u.ki.dwExtraInfo = 0;
883 SendInput( 1, &input, sizeof(input) );
887 /**********************************************************************
888 * KEYBOARD_GenerateMsg
890 * Generate Down+Up messages when NumLock or CapsLock is pressed.
892 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
895 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
897 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
898 DWORD up, down;
900 if (*State) {
901 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
902 don't treat it. It's from the same key press. Then the state goes to ON.
903 And from there, a 'release' event will switch off the toggle key. */
904 *State=FALSE;
905 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
906 } else
908 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
909 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
910 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
912 if (Evtype!=KeyPress)
914 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
915 send_keyboard_input( vkey, scan, down, event_time );
916 send_keyboard_input( vkey, scan, up, event_time );
917 *State=FALSE;
918 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
921 else /* it was OFF */
922 if (Evtype==KeyPress)
924 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
925 send_keyboard_input( vkey, scan, down, event_time );
926 send_keyboard_input( vkey, scan, up, event_time );
927 *State=TRUE; /* Goes to intermediary state before going to ON */
928 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
933 /***********************************************************************
934 * KEYBOARD_UpdateOneState
936 * Updates internal state for <vkey>, depending on key <state> under X
939 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
941 /* Do something if internal table state != X state for keycode */
942 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
944 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
945 vkey, pKeyStateTable[vkey]);
947 /* Fake key being pressed inside wine */
948 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
950 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
954 /***********************************************************************
955 * X11DRV_KeymapNotify
957 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
959 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
960 * from wine to another application and back.
961 * Toggle keys are handled in HandleEvent.
963 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
965 int i, j, alt, control, shift;
966 DWORD time = GetCurrentTime();
968 alt = control = shift = 0;
969 for (i = 0; i < 32; i++)
971 if (!event->key_vector[i]) continue;
972 for (j = 0; j < 8; j++)
974 if (!(event->key_vector[i] & (1<<j))) continue;
975 switch(keyc2vkey[(i * 8) + j] & 0xff)
977 case VK_MENU: alt = 1; break;
978 case VK_CONTROL: control = 1; break;
979 case VK_SHIFT: shift = 1; break;
983 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
984 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
985 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
988 /***********************************************************************
989 * X11DRV_KeyEvent
991 * Handle a X key event
993 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
995 char Str[24];
996 KeySym keysym;
997 WORD vkey = 0, bScan;
998 DWORD dwFlags;
999 int ascii_chars;
1000 XIC xic = X11DRV_get_ic( hwnd );
1001 DWORD event_time = event->time - X11DRV_server_startticks;
1003 wine_tsx11_lock();
1004 if (xic)
1005 ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, NULL);
1006 else
1007 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
1008 wine_tsx11_unlock();
1010 TRACE_(key)("state = %X\n", event->state);
1012 /* If XKB extensions are used, the state mask for AltGr will use the group
1013 index instead of the modifier mask. The group index is set in bits
1014 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1015 pressed, look if the group index is different than 0. From XKB
1016 extension documentation, the group index for AltGr should be 2
1017 (event->state = 0x2000). It's probably better to not assume a
1018 predefined group index and find it dynamically
1020 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1021 /* Save also all possible modifier states. */
1022 AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1024 Str[ascii_chars] = '\0';
1025 if (TRACE_ON(key)){
1026 char *ksname;
1028 ksname = TSXKeysymToString(keysym);
1029 if (!ksname)
1030 ksname = "No Name";
1031 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1032 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1033 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1036 wine_tsx11_lock();
1037 vkey = EVENT_event_to_vkey(xic,event);
1038 /* X returns keycode 0 for composed characters */
1039 if (!vkey && ascii_chars) vkey = VK_NONAME;
1040 wine_tsx11_unlock();
1042 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1043 event->keycode, vkey);
1045 if (vkey)
1047 switch (vkey & 0xff)
1049 case VK_NUMLOCK:
1050 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1051 break;
1052 case VK_CAPITAL:
1053 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1054 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1055 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1056 break;
1057 default:
1058 /* Adjust the NUMLOCK state if it has been changed outside wine */
1059 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1061 TRACE("Adjusting NumLock state.\n");
1062 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1063 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1065 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1066 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1068 TRACE("Adjusting Caps Lock state.\n");
1069 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1070 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1072 /* Not Num nor Caps : end of intermediary states for both. */
1073 NumState = FALSE;
1074 CapsState = FALSE;
1076 bScan = keyc2scan[event->keycode] & 0xFF;
1077 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1079 dwFlags = 0;
1080 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1081 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1083 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1088 /**********************************************************************
1089 * X11DRV_KEYBOARD_DetectLayout
1091 * Called from X11DRV_InitKeyboard
1092 * This routine walks through the defined keyboard layouts and selects
1093 * whichever matches most closely.
1094 * X11 lock must be held.
1096 static void
1097 X11DRV_KEYBOARD_DetectLayout (void)
1099 Display *display = thread_display();
1100 unsigned current, match, mismatch, seq;
1101 int score, keyc, i, key, pkey, ok, syms;
1102 KeySym keysym;
1103 const char (*lkey)[MAIN_LEN][4];
1104 unsigned max_seq = 0;
1105 int max_score = 0, ismatch = 0;
1106 char ckey[4] =
1107 {0, 0, 0, 0};
1109 syms = keysyms_per_keycode;
1110 if (syms > 4) {
1111 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1112 syms = 4;
1114 for (current = 0; main_key_tab[current].comment; current++) {
1115 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1116 match = 0;
1117 mismatch = 0;
1118 score = 0;
1119 seq = 0;
1120 lkey = main_key_tab[current].key;
1121 pkey = -1;
1122 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1123 /* get data for keycode from X server */
1124 for (i = 0; i < syms; i++) {
1125 keysym = XKeycodeToKeysym (display, keyc, i);
1126 /* Allow both one-byte and two-byte national keysyms */
1127 if ((keysym < 0x8000) && (keysym != ' '))
1129 #ifdef HAVE_XKB
1130 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1131 #endif
1133 TRACE("XKB could not translate keysym %ld\n", keysym);
1134 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1135 * with appropriate ShiftMask and Mode_switch, use XLookupString
1136 * to get character in the local encoding.
1138 ckey[i] = keysym & 0xFF;
1141 else {
1142 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1145 if (ckey[0]) {
1146 /* search for a match in layout table */
1147 /* right now, we just find an absolute match for defined positions */
1148 /* (undefined positions are ignored, so if it's defined as "3#" in */
1149 /* the table, it's okay that the X server has "3#£", for example) */
1150 /* however, the score will be higher for longer matches */
1151 for (key = 0; key < MAIN_LEN; key++) {
1152 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1153 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1154 ok++;
1155 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1156 ok = -1;
1158 if (ok > 0) {
1159 score += ok;
1160 break;
1163 /* count the matches and mismatches */
1164 if (ok > 0) {
1165 match++;
1166 /* and how much the keycode order matches */
1167 if (key > pkey) seq++;
1168 pkey = key;
1169 } else {
1170 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1171 mismatch++;
1172 score -= syms;
1176 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1177 match, mismatch, seq, score);
1178 if ((score > max_score) ||
1179 ((score == max_score) && (seq > max_seq))) {
1180 /* best match so far */
1181 kbd_layout = current;
1182 max_score = score;
1183 max_seq = seq;
1184 ismatch = !mismatch;
1187 /* we're done, report results if necessary */
1188 if (!ismatch) {
1189 FIXME(
1190 "Your keyboard layout was not found!\n"
1191 "Using closest match instead (%s) for scancode mapping.\n"
1192 "Please define your layout in dlls/x11drv/keyboard.c and submit them\n"
1193 "to us for inclusion into future Wine releases.\n"
1194 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1195 main_key_tab[kbd_layout].comment);
1198 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1201 /**********************************************************************
1202 * InitKeyboard (X11DRV.@)
1204 void X11DRV_InitKeyboard( BYTE *key_state_table )
1206 Display *display = thread_display();
1207 KeySym *ksp;
1208 XModifierKeymap *mmp;
1209 KeySym keysym;
1210 KeyCode *kcp;
1211 XKeyEvent e2;
1212 WORD scan, vkey, OEMvkey;
1213 int keyc, i, keyn, syms;
1214 char ckey[4]={0,0,0,0};
1215 const char (*lkey)[MAIN_LEN][4];
1217 pKeyStateTable = key_state_table;
1219 wine_tsx11_lock();
1220 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1221 ksp = XGetKeyboardMapping(display, min_keycode,
1222 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1223 /* We are only interested in keysyms_per_keycode.
1224 There is no need to hold a local copy of the keysyms table */
1225 XFree(ksp);
1227 mmp = XGetModifierMapping(display);
1228 kcp = mmp->modifiermap;
1229 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1231 int j;
1233 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1234 if (*kcp)
1236 int k;
1238 for (k = 0; k < keysyms_per_keycode; k += 1)
1239 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1241 NumLockMask = 1 << i;
1242 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1246 XFreeModifiermap(mmp);
1248 /* Detect the keyboard layout */
1249 X11DRV_KEYBOARD_DetectLayout();
1250 lkey = main_key_tab[kbd_layout].key;
1251 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1253 /* Now build two conversion arrays :
1254 * keycode -> vkey + scancode + extended
1255 * vkey + extended -> keycode */
1257 e2.display = display;
1258 e2.state = 0;
1260 OEMvkey = VK_OEM_7; /* next is available. */
1261 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1263 e2.keycode = (KeyCode)keyc;
1264 XLookupString(&e2, NULL, 0, &keysym, NULL);
1265 vkey = 0; scan = 0;
1266 if (keysym) /* otherwise, keycode not used */
1268 if ((keysym >> 8) == 0xFF) /* non-character key */
1270 vkey = nonchar_key_vkey[keysym & 0xff];
1271 scan = nonchar_key_scan[keysym & 0xff];
1272 /* set extended bit when necessary */
1273 if (scan & 0x100) vkey |= 0x100;
1274 } else if (keysym == 0x20) { /* Spacebar */
1275 vkey = VK_SPACE;
1276 scan = 0x39;
1277 } else {
1278 /* we seem to need to search the layout-dependent scancodes */
1279 int maxlen=0,maxval=-1,ok;
1280 for (i=0; i<syms; i++) {
1281 keysym = XKeycodeToKeysym(display, keyc, i);
1282 if ((keysym<0x8000) && (keysym!=' '))
1284 #ifdef HAVE_XKB
1285 if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1286 #endif
1288 /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
1289 * with appropriate ShiftMask and Mode_switch, use XLookupString
1290 * to get character in the local encoding.
1292 ckey[i] = keysym & 0xFF;
1294 } else {
1295 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1298 /* find key with longest match streak */
1299 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1300 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1301 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1302 if (ok||(i>maxlen)) {
1303 maxlen=i; maxval=keyn;
1305 if (ok) break;
1307 if (maxval>=0) {
1308 /* got it */
1309 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1310 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1311 scan = (*lscan)[maxval];
1312 vkey = (*lvkey)[maxval];
1316 /* find a suitable layout-dependent VK code */
1317 /* (most Winelib apps ought to be able to work without layout tables!) */
1318 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1320 keysym = XLookupKeysym(&e2, i);
1321 if ((keysym >= VK_0 && keysym <= VK_9)
1322 || (keysym >= VK_A && keysym <= VK_Z)) {
1323 vkey = keysym;
1327 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1329 keysym = XLookupKeysym(&e2, i);
1330 switch (keysym)
1332 case ';': vkey = VK_OEM_1; break;
1333 case '/': vkey = VK_OEM_2; break;
1334 case '`': vkey = VK_OEM_3; break;
1335 case '[': vkey = VK_OEM_4; break;
1336 case '\\': vkey = VK_OEM_5; break;
1337 case ']': vkey = VK_OEM_6; break;
1338 case '\'': vkey = VK_OEM_7; break;
1339 case ',': vkey = VK_OEM_COMMA; break;
1340 case '.': vkey = VK_OEM_PERIOD; break;
1341 case '-': vkey = VK_OEM_MINUS; break;
1342 case '+': vkey = VK_OEM_PLUS; break;
1346 if (!vkey)
1348 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1349 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1350 switch (++OEMvkey)
1352 case 0xc1 : OEMvkey=0xdb; break;
1353 case 0xe5 : OEMvkey=0xe9; break;
1354 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1357 vkey = OEMvkey;
1359 if (TRACE_ON(keyboard))
1361 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1362 OEMvkey, e2.keycode);
1363 TRACE("(");
1364 for (i = 0; i < keysyms_per_keycode; i += 1)
1366 char *ksname;
1368 keysym = XLookupKeysym(&e2, i);
1369 ksname = XKeysymToString(keysym);
1370 if (!ksname)
1371 ksname = "NoSymbol";
1372 TRACE( "%lX (%s) ", keysym, ksname);
1374 TRACE(")\n");
1378 keyc2vkey[e2.keycode] = vkey;
1379 keyc2scan[e2.keycode] = scan;
1380 } /* for */
1382 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1383 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1384 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1385 char *ksname;
1386 keysym = XKeycodeToKeysym(display, keyc, 0);
1387 ksname = XKeysymToString(keysym);
1388 if (!ksname) ksname = "NoSymbol";
1390 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1392 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1393 keyc2scan[keyc]=scan++;
1396 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1397 kcControl = XKeysymToKeycode(display, XK_Control_L);
1398 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1399 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1400 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1401 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1402 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1403 wine_tsx11_unlock();
1407 /***********************************************************************
1408 * X11DRV_MappingNotify
1410 void X11DRV_MappingNotify( XMappingEvent *event )
1412 TSXRefreshKeyboardMapping(event);
1413 X11DRV_InitKeyboard( pKeyStateTable );
1417 /***********************************************************************
1418 * VkKeyScan (X11DRV.@)
1420 WORD X11DRV_VkKeyScan(CHAR cChar)
1422 Display *display = thread_display();
1423 KeyCode keycode;
1424 KeySym keysym;
1425 int i,index;
1426 int highbyte=0;
1428 /* char->keysym (same for ANSI chars) */
1429 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1430 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1432 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1433 if (!keycode)
1434 { /* It didn't work ... let's try with deadchar code. */
1435 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1438 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1439 cChar,keysym,keysym,keycode);
1441 if (keycode)
1443 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1444 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1445 switch (index) {
1446 case -1 :
1447 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1448 case 0 : break;
1449 case 1 : highbyte = 0x0100; break;
1450 case 2 : highbyte = 0x0600; break;
1451 case 3 : highbyte = 0x0700; break;
1452 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1455 index : 0 adds 0x0000
1456 index : 1 adds 0x0100 (shift)
1457 index : ? adds 0x0200 (ctrl)
1458 index : 2 adds 0x0600 (ctrl+alt)
1459 index : 3 adds 0x0700 (ctrl+alt+shift)
1462 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1463 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1466 /***********************************************************************
1467 * MapVirtualKey (X11DRV.@)
1469 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1471 Display *display = thread_display();
1473 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1475 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1476 switch(wMapType) {
1477 case 0: { /* vkey-code to scan-code */
1478 /* let's do vkey -> keycode -> scan */
1479 int keyc;
1480 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1481 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1482 returnMVK (keyc2scan[keyc] & 0xFF);
1483 TRACE("returning no scan-code.\n");
1484 return 0; }
1486 case 1: { /* scan-code to vkey-code */
1487 /* let's do scan -> keycode -> vkey */
1488 int keyc;
1489 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1490 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1491 returnMVK (keyc2vkey[keyc] & 0xFF);
1492 TRACE("returning no vkey-code.\n");
1493 return 0; }
1495 case 2: { /* vkey-code to unshifted ANSI code */
1496 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1497 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1498 * key.. Looks like something is wrong with the MS docs?
1499 * This is only true for letters, for example VK_0 returns '0' not ')'.
1500 * - hence we use the lock mask to ensure this happens.
1502 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1503 XKeyEvent e;
1504 KeySym keysym;
1505 int keyc;
1506 char s[2];
1507 e.display = display;
1509 e.state = LockMask;
1510 /* LockMask should behave exactly like caps lock - upercase
1511 * the letter keys and thats about it. */
1513 wine_tsx11_lock();
1515 e.keycode = 0;
1516 /* We exit on the first keycode found, to speed up the thing. */
1517 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1518 { /* Find a keycode that could have generated this virtual key */
1519 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1520 { /* We filter the extended bit, we don't know it */
1521 e.keycode = keyc; /* Store it temporarily */
1522 if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
1523 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1524 state), so set it to 0, we'll find another one */
1529 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1530 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1532 if (wCode==VK_DECIMAL)
1533 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1535 if (!e.keycode)
1537 WARN("Unknown virtual key %X !!! \n", wCode);
1538 wine_tsx11_unlock();
1539 return 0; /* whatever */
1541 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1543 if (XLookupString(&e, s, 2, &keysym, NULL))
1545 wine_tsx11_unlock();
1546 returnMVK (*s);
1549 TRACE("returning no ANSI.\n");
1550 wine_tsx11_unlock();
1551 return 0;
1554 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1555 /* left and right */
1556 FIXME(" stub for NT\n");
1557 return 0;
1559 default: /* reserved */
1560 WARN("Unknown wMapType %d !\n", wMapType);
1561 return 0;
1563 return 0;
1566 /***********************************************************************
1567 * GetKeyNameText (X11DRV.@)
1569 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1571 int vkey, ansi, scanCode;
1572 KeyCode keyc;
1573 int keyi;
1574 KeySym keys;
1575 char *name;
1577 scanCode = lParam >> 16;
1578 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1580 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1581 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1583 /* handle "don't care" bit (0x02000000) */
1584 if (!(lParam & 0x02000000)) {
1585 switch (vkey) {
1586 case VK_LSHIFT:
1587 case VK_RSHIFT:
1588 vkey = VK_SHIFT;
1589 break;
1590 case VK_LCONTROL:
1591 case VK_RCONTROL:
1592 vkey = VK_CONTROL;
1593 break;
1594 case VK_LMENU:
1595 case VK_RMENU:
1596 vkey = VK_MENU;
1597 break;
1598 default:
1599 break;
1603 ansi = X11DRV_MapVirtualKey(vkey, 2);
1604 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1606 /* first get the name of the "regular" keys which is the Upper case
1607 value of the keycap imprint. */
1608 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1609 (scanCode != 0x137) && /* PrtScn */
1610 (scanCode != 0x135) && /* numpad / */
1611 (scanCode != 0x37 ) && /* numpad * */
1612 (scanCode != 0x4a ) && /* numpad - */
1613 (scanCode != 0x4e ) ) /* numpad + */
1615 if ((nSize >= 2) && lpBuffer)
1617 *lpBuffer = toupper((char)ansi);
1618 *(lpBuffer+1) = 0;
1619 return 1;
1621 else
1622 return 0;
1625 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1626 without "extended-key" flag. However Wine generates scancode
1627 *with* "extended-key" flag. Seems to occur *only* for the
1628 function keys. Soooo.. We will leave the table alone and
1629 fudge the lookup here till the other part is found and fixed!!! */
1631 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1632 (scanCode == 0x157) || (scanCode == 0x158))
1633 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1635 /* let's do scancode -> keycode -> keysym -> String */
1637 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1638 if ((keyc2scan[keyi]) == scanCode)
1639 break;
1640 if (keyi <= max_keycode)
1642 keyc = (KeyCode) keyi;
1643 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1644 name = TSXKeysymToString(keys);
1645 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1646 scanCode, keyc, (int)keys, name);
1647 if (lpBuffer && nSize && name)
1649 lstrcpynA(lpBuffer, name, nSize);
1650 return 1;
1654 /* Finally issue FIXME for unknown keys */
1656 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1657 if (lpBuffer && nSize)
1658 *lpBuffer = 0;
1659 return 0;
1662 /***********************************************************************
1663 * X11DRV_KEYBOARD_MapDeadKeysym
1665 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1667 switch (keysym)
1669 /* symbolic ASCII is the same as defined in rfc1345 */
1670 #ifdef XK_dead_tilde
1671 case XK_dead_tilde :
1672 #endif
1673 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1674 return '~'; /* '? */
1675 #ifdef XK_dead_acute
1676 case XK_dead_acute :
1677 #endif
1678 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1679 return 0xb4; /* '' */
1680 #ifdef XK_dead_circumflex
1681 case XK_dead_circumflex:
1682 #endif
1683 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1684 return '^'; /* '> */
1685 #ifdef XK_dead_grave
1686 case XK_dead_grave :
1687 #endif
1688 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1689 return '`'; /* '! */
1690 #ifdef XK_dead_diaeresis
1691 case XK_dead_diaeresis :
1692 #endif
1693 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1694 return 0xa8; /* ': */
1695 #ifdef XK_dead_cedilla
1696 case XK_dead_cedilla :
1697 return 0xb8; /* ', */
1698 #endif
1699 #ifdef XK_dead_macron
1700 case XK_dead_macron :
1701 return '-'; /* 'm isn't defined on iso-8859-x */
1702 #endif
1703 #ifdef XK_dead_breve
1704 case XK_dead_breve :
1705 return 0xa2; /* '( */
1706 #endif
1707 #ifdef XK_dead_abovedot
1708 case XK_dead_abovedot :
1709 return 0xff; /* '. */
1710 #endif
1711 #ifdef XK_dead_abovering
1712 case XK_dead_abovering :
1713 return '0'; /* '0 isn't defined on iso-8859-x */
1714 #endif
1715 #ifdef XK_dead_doubleacute
1716 case XK_dead_doubleacute :
1717 return 0xbd; /* '" */
1718 #endif
1719 #ifdef XK_dead_caron
1720 case XK_dead_caron :
1721 return 0xb7; /* '< */
1722 #endif
1723 #ifdef XK_dead_ogonek
1724 case XK_dead_ogonek :
1725 return 0xb2; /* '; */
1726 #endif
1727 /* FIXME: I don't know this three.
1728 case XK_dead_iota :
1729 return 'i';
1730 case XK_dead_voiced_sound :
1731 return 'v';
1732 case XK_dead_semivoiced_sound :
1733 return 's';
1736 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1737 return 0;
1740 /***********************************************************************
1741 * ToUnicode (X11DRV.@)
1743 * The ToUnicode function translates the specified virtual-key code and keyboard
1744 * state to the corresponding Windows character or characters.
1746 * If the specified key is a dead key, the return value is negative. Otherwise,
1747 * it is one of the following values:
1748 * Value Meaning
1749 * 0 The specified virtual key has no translation for the current state of the keyboard.
1750 * 1 One Windows character was copied to the buffer.
1751 * 2 Two characters were copied to the buffer. This usually happens when a
1752 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1753 * be composed with the specified virtual key to form a single character.
1755 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1758 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1759 LPWSTR bufW, int bufW_size, UINT flags)
1761 Display *display = thread_display();
1762 XKeyEvent e;
1763 KeySym keysym;
1764 INT ret;
1765 int keyc;
1766 char lpChar[10];
1767 HWND focus;
1768 XIC xic;
1770 if (scanCode & 0x8000)
1772 TRACE("Key UP, doing nothing\n" );
1773 return 0;
1776 e.display = display;
1777 e.keycode = 0;
1778 e.state = 0;
1779 e.type = KeyPress;
1781 focus = GetFocus();
1782 if (focus) focus = GetAncestor( focus, GA_ROOT );
1783 if (!focus) focus = GetActiveWindow();
1784 e.window = X11DRV_get_whole_window( focus );
1785 xic = X11DRV_get_ic( focus );
1787 if (lpKeyState[VK_SHIFT] & 0x80)
1789 TRACE("ShiftMask = %04x\n", ShiftMask);
1790 e.state |= ShiftMask;
1792 if (lpKeyState[VK_CAPITAL] & 0x01)
1794 TRACE("LockMask = %04x\n", LockMask);
1795 e.state |= LockMask;
1797 if (lpKeyState[VK_CONTROL] & 0x80)
1799 TRACE("ControlMask = %04x\n", ControlMask);
1800 e.state |= ControlMask;
1802 if (lpKeyState[VK_NUMLOCK] & 0x01)
1804 TRACE("NumLockMask = %04x\n", NumLockMask);
1805 e.state |= NumLockMask;
1808 /* Restore saved AltGr state */
1809 TRACE("AltGrMask = %04x\n", AltGrMask);
1810 e.state |= AltGrMask;
1812 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1813 virtKey, scanCode, e.state);
1814 wine_tsx11_lock();
1815 /* We exit on the first keycode found, to speed up the thing. */
1816 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1817 { /* Find a keycode that could have generated this virtual key */
1818 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1819 { /* We filter the extended bit, we don't know it */
1820 e.keycode = keyc; /* Store it temporarily */
1821 if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
1822 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1823 state), so set it to 0, we'll find another one */
1828 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1829 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1831 if (virtKey==VK_DECIMAL)
1832 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1834 if (!e.keycode && virtKey != VK_NONAME)
1836 WARN("Unknown virtual key %X !!! \n",virtKey);
1837 wine_tsx11_unlock();
1838 return virtKey; /* whatever */
1840 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1842 if (xic)
1843 ret = XmbLookupString(xic, &e, lpChar, sizeof(lpChar), &keysym, NULL);
1844 else
1845 ret = XLookupString(&e, lpChar, sizeof(lpChar), &keysym, NULL);
1846 wine_tsx11_unlock();
1848 if (ret == 0)
1850 BYTE dead_char;
1852 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1853 if (dead_char)
1855 MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
1856 ret = -1;
1858 else
1860 char *ksname;
1862 ksname = TSXKeysymToString(keysym);
1863 if (!ksname)
1864 ksname = "No Name";
1865 if ((keysym >> 8) != 0xff)
1867 ERR("Please report: no char for keysym %04lX (%s) :\n",
1868 keysym, ksname);
1869 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1870 virtKey, scanCode, e.keycode, e.state);
1874 else { /* ret != 0 */
1875 /* We have a special case to handle : Shift + arrow, shift + home, ...
1876 X returns a char for it, but Windows doesn't. Let's eat it. */
1877 if (!(e.state & NumLockMask) /* NumLock is off */
1878 && (e.state & ShiftMask) /* Shift is pressed */
1879 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1881 lpChar[0] = 0;
1882 ret = 0;
1885 /* more areas where X returns characters but Windows does not
1886 CTRL + number or CTRL + symbol */
1887 if (e.state & ControlMask)
1889 if (((keysym>=33) && (keysym < 'A')) ||
1890 ((keysym > 'Z') && (keysym < 'a')))
1892 lpChar[0] = 0;
1893 ret = 0;
1897 /* We have another special case for delete key (XK_Delete) on an
1898 extended keyboard. X returns a char for it, but Windows doesn't */
1899 if (keysym == XK_Delete)
1901 lpChar[0] = 0;
1902 ret = 0;
1904 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1905 && (keysym == XK_KP_Decimal))
1907 lpChar[0] = 0;
1908 ret = 0;
1911 /* perform translation to unicode */
1912 if(ret)
1914 TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
1915 ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
1919 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1920 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1921 return ret;
1924 /***********************************************************************
1925 * Beep (X11DRV.@)
1927 void X11DRV_Beep(void)
1929 TSXBell(thread_display(), 0);