Reenable device's default render states initialization.
[wine/multimedia.git] / dlls / x11drv / keyboard.c
blobf544cabb933ccdf491e60823076b31086f98c6ce
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 #include "windef.h"
42 #include "wingdi.h"
43 #include "wine/winuser16.h"
44 #include "winnls.h"
45 #include "win.h"
46 #include "x11drv.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
50 WINE_DECLARE_DEBUG_CHANNEL(key);
51 WINE_DECLARE_DEBUG_CHANNEL(dinput);
53 int min_keycode, max_keycode, keysyms_per_keycode;
54 WORD keyc2vkey[256], keyc2scan[256];
56 static LPBYTE pKeyStateTable;
57 static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
58 static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
59 #ifdef HAVE_XKB
60 static int is_xkb, xkb_opcode, xkb_event, xkb_error;
61 #endif
63 static char KEYBOARD_MapDeadKeysym(KeySym keysym);
65 /* Keyboard translation tables */
66 #define MAIN_LEN 49
67 static const WORD main_key_scan_qwerty[MAIN_LEN] =
69 /* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
70 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
71 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
72 /* q w e r t y u i o p [ ] */
73 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
74 /* a s d f g h j k l ; ' \ */
75 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
76 /* z x c v b n m , . / */
77 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
78 0x56 /* the 102nd key (actually to the right of l-shift) */
81 static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
83 /* ` 1 2 3 4 5 6 7 8 9 0 - = */
84 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
85 /* q w e r t y u i o p [ ] */
86 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
87 /* a s d f g h j k l ; ' \ */
88 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
89 /* \ z x c v b n m , . / */
90 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
91 0x56, /* the 102nd key (actually to the right of l-shift) */
94 static const WORD main_key_scan_dvorak[MAIN_LEN] =
96 /* ` 1 2 3 4 5 6 7 8 9 0 [ ] */
97 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
98 /* ' , . p y f g c r l / = */
99 0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
100 /* a o e u i d h t n s - \ */
101 0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
102 /* ; q j k x b m w v z */
103 0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
104 0x56 /* the 102nd key (actually to the right of l-shift) */
107 static const WORD main_key_vkey_qwerty[MAIN_LEN] =
109 /* NOTE: this layout must concur with the scan codes layout above */
110 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,
111 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,
112 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,
113 VK_Z,VK_X,VK_C,VK_V,VK_B,VK_N,VK_M,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
114 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
117 static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
119 /* NOTE: this layout must concur with the scan codes layout above */
120 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,
121 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,
122 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,
123 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,
124 VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
127 static const WORD main_key_vkey_azerty[MAIN_LEN] =
129 /* NOTE: this layout must concur with the scan codes layout above */
130 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,
131 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,
132 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,
133 VK_W,VK_X,VK_C,VK_V,VK_B,VK_N,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
134 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
137 static const WORD main_key_vkey_dvorak[MAIN_LEN] =
139 /* NOTE: this layout must concur with the scan codes layout above */
140 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,
141 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,
142 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,
143 VK_OEM_1,VK_Q,VK_J,VK_K,VK_X,VK_B,VK_M,VK_W,VK_V,VK_Z,
144 VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
147 /* FIXME: add other layouts, such as German QWERTZ */
149 /*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */
151 /* the VK mappings for the main keyboard will be auto-assigned as before,
152 so what we have here is just the character tables */
153 /* order: Normal, Shift, AltGr, Shift-AltGr */
154 /* We recommend you write just what is guaranteed to be correct (i.e. what's
155 written on the keycaps), not the bunch of special characters behind AltGr
156 and Shift-AltGr if it can vary among different X servers */
157 /* Remember that your 102nd key (to the right of l-shift) should be on a
158 separate line, see existing tables */
159 /* If Wine fails to match your new table, use -debugmsg +key to find out why */
160 /* Remember to also add your new table to the layout index table far below! */
162 /*** German Logitech Desktop Pro keyboard layout */
163 static const char main_key_DE_logitech[MAIN_LEN][4] =
165 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/{","8([","9)]","0=}","\xdf?\\","'`",
166 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*~",
167 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
168 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
169 "<>|"
172 /*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
173 static const char main_key_US[MAIN_LEN][4] =
175 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
176 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
177 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
178 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
181 /*** United States keyboard layout (phantom key version) */
182 /* (XFree86 reports the <> key even if it's not physically there) */
183 static const char main_key_US_phantom[MAIN_LEN][4] =
185 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
186 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
187 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
188 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
189 "<>" /* the phantom key */
192 /*** United States keyboard layout (dvorak version) */
193 static const char main_key_US_dvorak[MAIN_LEN][4] =
195 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
196 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
197 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
198 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
201 /*** British keyboard layout */
202 static const char main_key_UK[MAIN_LEN][4] =
204 "`","1!","2\"","3£","4$","5%","6^","7&","8*","9(","0)","-_","=+",
205 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
206 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
207 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
208 "\\|"
211 /*** French keyboard layout (contributed by Eric Pouech) */
212 static const char main_key_FR[MAIN_LEN][4] =
214 "²","&1","é2~","\"3#","'4{","(5[","-6|","è7","_8\\","ç9^±","à0@",")°]","=+}",
215 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^¨","$£¤",
216 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%","*µ",
217 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!§",
218 "<>"
221 /*** Icelandic keyboard layout (contributed by Ríkharður Egilsson) */
222 static const char main_key_IS[MAIN_LEN][4] =
224 "°","1!","2\"","3#","4$","5%","6&","7/{","8([","9)]","0=}","öÖ\\","-_",
225 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","ðÐ","'?~",
226 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","´^","+*`",
227 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","þÞ",
228 "<>|"
231 /*** German keyboard layout (contributed by Ulrich Weigand) */
232 static const char main_key_DE[MAIN_LEN][4] =
234 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
235 "qQ@","wW","eE€","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
236 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#´",
237 "yY","xX","cC","vV","bB","nN","mMµ",",;",".:","-_",
238 "<>|"
241 /*** German keyboard layout without dead keys */
242 static const char main_key_DE_nodead[MAIN_LEN][4] =
244 "^°","1!","2\"","3§","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","´",
245 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
246 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
247 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
248 "<>"
251 /*** German keyboard layout without dead keys 105 Keys (contributed by Matthias Fechner)*/
252 static const char main_key_DE_nodead_105[MAIN_LEN][4] =
254 "^°","1!","2\"²","3§³","4$","5%","6&","7/{","8([","9)]","0=}","ß?\\","'`",
255 "qQ@","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üÜ","+*~",
256 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","#'",
257 "<>|","yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
260 /*** Swiss German keyboard layout (contributed by Jonathan Naylor) */
261 static const char main_key_SG[MAIN_LEN][4] =
263 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
264 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","üè[","¨!]",
265 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öé","äà{","$£}",
266 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
267 "<>\\"
270 /*** Swiss French keyboard layout (contributed by Philippe Froidevaux) */
271 static const char main_key_SF[MAIN_LEN][4] =
273 "§°","1+|","2\"@","3*#","4ç","5%","6&¬","7/¦","8(¢","9)","0=","'?´","^`~",
274 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","èü[","¨!]",
275 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","éö","àä{","$£}",
276 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
277 "<>\\"
280 /*** Norwegian keyboard layout (contributed by Ove Kåven) */
281 static const char main_key_NO[MAIN_LEN][4] =
283 "|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\`´",
284 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
285 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
286 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
287 "<>"
290 /*** Danish keyboard layout (contributed by Bertho Stultiens) */
291 static const char main_key_DA[MAIN_LEN][4] =
293 "½§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","´`|",
294 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
295 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","æÆ","øØ","'*",
296 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
297 "<>\\"
300 /*** Swedish keyboard layout (contributed by Peter Bortas) */
301 static const char main_key_SE[MAIN_LEN][4] =
303 "§½","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
304 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
305 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*",
306 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
307 "<>|"
310 /*** Estonian keyboard layout (contributed by Raul Metsma zombi82@hot.ee) */
311 static const char main_key_ET[MAIN_LEN][4] =
313 " ~","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?\\","´`",
314 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","üÜ","õÕ§",
315 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","öÖ","äÄ","'*½",
316 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
317 "<>|"
320 /*** Canadian French keyboard layout */
321 static const char main_key_CF[MAIN_LEN][4] =
323 "#|\\","1!±","2\"@","3/£","4$¢","5%¤","6?¬","7&¦","8*²","9(³","0)¼","-_½","=+¾",
324 "qQ","wW","eE","rR","tT","yY","uU","iI","oO§","pP¶","^^[","¸¨]",
325 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
326 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","éÉ",
327 "«»°"
330 /*** Portuguese keyboard layout */
331 static const char main_key_PT[MAIN_LEN][4] =
333 "\\¦","1!","2\"@","3#£","4$§","5%","6&","7/{","8([","9)]","0=}","'?","«»",
334 "qQ", "wW","eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "+*\\¨","\\'\\`",
335 "aA", "sS","dD", "fF", "gG", "hH", "jJ", "kK", "lL", "çÇ", "ºª", "\\~\\^",
336 "zZ", "xX","cC", "vV", "bB", "nN", "mM", ",;", ".:", "-_",
337 "<>"
340 /*** Italian keyboard layout */
341 static const char main_key_IT[MAIN_LEN][4] =
343 "\\|","1!¹","2\"²","3£³","4$¼","5%½","6&¾","7/{","8([","9)]","0=}","'?`","ì^~",
344 "qQ@","wW","eE","rR","tT","yY","uU","iI","oOø","pPþ","èé[","+*]",
345 "aA","sSß","dDð","fF","gG","hH","jJ","kK","lL","òç@","à°#","ù§",
346 "zZ","xX","cC","vV","bB","nN","mMµ",",;",".:·","-_",
347 "<>|"
350 /*** Finnish keyboard layout */
351 static const char main_key_FI[MAIN_LEN][4] =
353 "","1!","2\"@","3#","4$","5%","6&","7/{","8([","9)]","0=}","+?\\","\'`",
354 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","","\"^~",
355 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","","","'*",
356 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
357 "<>|"
360 /*** Bulgarian bds keyboard layout */
361 static const char main_key_BG_bds[MAIN_LEN][4] =
363 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
364 "qQ,û","wWóÓ","eEåÅ","rRèÈ","tTøØ","yYùÙ","uUêÊ","iIñÑ","oOäÄ","pPçÇ","[{öÖ","]};",
365 "aAüÜ","sSÿß","dDàÀ","fFîÎ","gGæÆ","hHãÃ","jJòÒ","kKíÍ","lLâÂ",";:ìÌ","'\"÷×","\\|'Û",
366 "zZþÞ","xXéÉ","cCúÚ","vVýÝ","bBôÔ","nNõÕ","mMïÏ",",<ðÐ",".>ëË","/?áÁ",
367 "<>" /* the phantom key */
370 /*** Bulgarian phonetic keyboard layout */
371 static const char main_key_BG_phonetic[MAIN_LEN][4] =
373 "`~÷×","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
374 "qQÿß","wWâÂ","eEåÅ","rRðÐ","tTòÒ","yYúÚ","uUóÓ","iIèÈ","oOîÎ","pPïÏ","[{øØ","]}ùÙ",
375 "aAàÀ","sSñÑ","dDäÄ","fFôÔ","gGãÃ","hHõÕ","jJéÉ","kKêÊ","lLëË",";:","'\"","\\|þÞ",
376 "zZçÇ","xXüÜ","cCöÖ","vVæÆ","bBáÁ","nNíÍ","mMìÌ",",<",".>","/?",
377 "<>" /* the phantom key */
380 /*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
381 /*** It matches belarusian layout for XKB from Alexander Mikhailian */
382 static const char main_key_BY[MAIN_LEN][4] =
384 "`~£³","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
385 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oO®¾","pPÚú","[{Èè","]}''",
386 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|/|",
387 "zZÑñ","xXÞþ","cCÓó","vVÍí","bB¦¶","nNÔô","mMØø",",<Ââ",".>Àà","/?.,", "<>|¦",
391 /*** Russian keyboard layout (contributed by Pavel Roskin) */
392 static const char main_key_RU[MAIN_LEN][4] =
394 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
395 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
396 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
397 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?"
400 /*** Russian keyboard layout (phantom key version) */
401 static const char main_key_RU_phantom[MAIN_LEN][4] =
403 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
404 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}ßÿ",
405 "aAÆæ","sSÙù","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"Üü","\\|",
406 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?",
407 "<>" /* the phantom key */
410 /*** Russian keyboard layout KOI8-R */
411 static const char main_key_RU_koi8r[MAIN_LEN][4] =
413 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
414 "Êê","Ãã","Õõ","Ëë","Åå","Îî","Çç","Ûû","Ýý","Úú","Èè","ßÿ",
415 "Ææ","Ùù","×÷","Áá","Ðð","Òò","Ïï","Ìì","Ää","Öö","Üü","\\|",
416 "Ññ","Þþ","Óó","Íí","Éé","Ôô","Øø","Ââ","Àà","/?",
417 "<>" /* the phantom key */
420 /*** Ukrainian keyboard layout KOI8-U */
421 static const char main_key_UA[MAIN_LEN][4] =
423 "`~­½","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
424 "qQÊê","wWÃã","eEÕõ","rRËë","tTÅå","yYÎî","uUÇç","iIÛû","oOÝý","pPÚú","[{Èè","]}§·",
425 "aAÆæ","sS¦¶","dD×÷","fFÁá","gGÐð","hHÒò","jJÏï","kKÌì","lLÄä",";:Öö","'\"¤´","\\|\\|",
426 "zZÑñ","xXÞþ","cCÓó","vVÍí","bBÉé","nNÔô","mMØø",",<Ââ",".>Àà","/?/?",
427 "<>" /* the phantom key */
430 /*** Spanish keyboard layout (contributed by José Marcos López) */
431 static const char main_key_ES[MAIN_LEN][4] =
433 "ºª\\","1!|","2\"@","3·#","4$~","5%","6&¬","7/","8(","9)","0=","'?","¡¿",
434 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^[","+*]",
435 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","´¨{","çÇ}",
436 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
437 "<>"
440 /*** Belgian keyboard layout ***/
441 static const char main_key_BE[MAIN_LEN][4] =
443 "","&1|","é2@","\"3#","'4","(5","§6^","è7","!8","ç9{","à0}",")°","-_",
444 "aA","zZ","eE¤","rR","tT","yY","uU","iI","oO","pP","^¨[","$*]",
445 "qQ","sSß","dD","fF","gG","hH","jJ","kK","lL","mM","ù%´","µ£`",
446 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
447 "<>\\"
450 /*** Hungarian keyboard layout (contributed by Zoltán Kovács) */
451 static const char main_key_HU[MAIN_LEN][4] =
453 "0§","1'~","2\"·","3+^","4!¢","5%°","6/²","7=`","8(ÿ","9)´","öÖ½","üܨ","óÓ¸",
454 "qQ\\","wW|","eE","rR","tT","zZ","uU","iIÍ","oOø","pP","õÕ÷","úÚ×",
455 "aA","sSð","dDÐ","fF[","gG]","hH","jJí","kK³","lL£","éÉ$","áÁß","ûÛ¤",
456 "yY>","xX#","cC&","vV@","bB{","nN}","mM",",?;",".:·","-_*",
457 "íÍ<"
460 /*** Polish (programmer's) keyboard layout ***/
461 static const char main_key_PL[MAIN_LEN][4] =
463 "`~","1!","2@","3#","4$","5%","6^","7&§","8*","9(","0)","-_","=+",
464 "qQ","wW","eEêÊ","rR","tT","yY","uU","iI","oOóÓ","pP","[{","]}",
465 "aA±¡","sS¶¦","dD","fF","gG","hH","jJ","kK","lL³£",";:","'\"","\\|",
466 "zZ¿¯","xX¼¬","cCæÆ","vV","bB","nNñÑ","mM",",<",".>","/?",
467 "<>|"
470 /*** Slovenian keyboard layout by Rok Mandeljc <rok.mandeljc@gimb.org> ***/
471 static const char main_key_SI[MAIN_LEN][4] =
473 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
474 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
475 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
476 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_",
477 "<>"
480 /*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
481 static const char main_key_HR_jelly[MAIN_LEN][4] =
483 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
484 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{¹©","]}ðÐ",
485 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:èÈ","'\"æÆ","\\|¾®",
486 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
487 "<>|"
490 /*** Croatian keyboard layout ***/
491 static const char main_key_HR[MAIN_LEN][4] =
493 "¸¨","1!","2\"·","3#^","4$¢","5%°","6&²","7/`","8(ÿ","9)´","0=½","'?¨","+*¸",
494 "qQ\\","wW|","eE","rR","tT","zZ","uU","iI","oO","pP","¹©÷","ðÐ×",
495 "aA","sS","dD","fF[","gG]","hH","jJ","kK³","lL£","èÈ","æÆß","¾®¤",
496 "yY","xX","cC","vV@","bB{","nN}","mM§",",;",".:","-_/",
497 "<>"
500 /*** Japanese 106 keyboard layout ***/
501 static const char main_key_JA_jp106[MAIN_LEN][4] =
503 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
504 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
505 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
506 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
507 "\\_",
510 /*** Japanese pc98x1 keyboard layout ***/
511 static const char main_key_JA_pc98x1[MAIN_LEN][4] =
513 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
514 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
515 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
516 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
517 "\\_",
520 /*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
521 static const char main_key_PT_br[MAIN_LEN][4] =
523 "'\"","1!","2@","3#","4$","5%","6¨","7&","8*","9(","0)","-_","=+",
524 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","´`","[{",
525 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","çÇ","~^","]}",
526 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
527 "\\|"
530 /*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
531 static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
533 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
534 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
535 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
536 "zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0",
537 "\\|"
540 /*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
541 static const char main_key_US_intl[MAIN_LEN][4] =
543 "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
544 "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
545 "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
546 "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
549 /*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
550 - dead_abovering replaced with degree - no symbol in iso8859-2
551 - brokenbar replaced with bar */
552 static const char main_key_SK[MAIN_LEN][4] =
554 ";0","+1","µ2","¹3","è4","»5","¾6","ý7","á8","í9","é0","=%","'v",
555 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/","ä(",
556 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","ò)",
557 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
558 "<>"
561 /*** Czech keyboard layout (setxkbmap cz) */
562 static const char main_key_CZ[MAIN_LEN][4] =
564 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
565 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","ú/",")(",
566 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
567 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
568 "\\"
571 /*** Czech keyboard layout (setxkbmap cz_qwerty) */
572 static const char main_key_CZ_qwerty[MAIN_LEN][4] =
574 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0","=%","´·",
575 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","ú/",")(",
576 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",\"","§!","¨'",
577 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
578 "\\"
581 /*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
582 static const char main_key_SK_prog[MAIN_LEN][4] =
584 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
585 "qQäÄ","wWìÌ","eEéÉ","rRøØ","tT»«","yYýÝ","uUùÙ","iIíÍ","oOóÓ","pPöÖ","[{","]}",
586 "aAáÁ","sS¹©","dDïÏ","fFëË","gGàÀ","hHúÚ","jJüÜ","kKôÔ","lLµ¥",";:","'\"","\\|",
587 "zZ¾®","xX¤","cCèÈ","vVçÇ","bB","nNòÒ","mMåÅ",",<",".>","/?",
588 "<>"
591 /*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
592 static const char main_key_CS[MAIN_LEN][4] =
594 ";","+1","ì2","¹3","è4","ø5","¾6","ý7","á8","í9","é0½)","=%","",
595 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","ú/[{",")(]}",
596 "aA","sSð","dDÐ","fF[","gG]","hH","jJ","kK³","lL£",\"$","§!ß","¨'",
597 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
598 "<>\\|"
601 /*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
602 static const char main_key_LA[MAIN_LEN][4] =
604 "|°¬","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?\\","¡¿",
605 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","´¨","+*~",
606 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","ñÑ","{[^","}]`",
607 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
608 "<>"
611 /*** Lithuanian (Baltic) keyboard layout (contributed by Nerijus Baliûnas) */
612 static const char main_key_LT_B[MAIN_LEN][4] =
614 "`~","1àÀ","2èÈ","3æÆ","4ëË","5áÁ","6ðÐ","7øØ","8ûÛ","9¥(","0´)","-_","=þÞ","\\|",
615 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
616 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"",
617 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
620 /*** Turkish keyboard Layout */
621 static const char main_key_TK[MAIN_LEN][4] =
623 "\"é","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
624 "qQ@","wW","eE","rR","tT","yY","uU","ýIî","oO","pP","ðÐ","üÜ~",
625 "aAæ","sSß","dD","fF","gG","hH","jJ","kK","lL","þÞ","iÝ",",;`",
626 "zZ","xX","cC","vV","bB","nN","mM","öÖ","çÇ",".:"
629 /*** Israeli keyboard layout */
630 static const char main_key_IL[MAIN_LEN][4] =
632 "`~;","1!1","2@2","3#3","4$4","5%5","6^6","7&7","8*8","9(9","0)0","-_-","=+=",
633 "qQ/","wW'","eE÷","rRø","tTà","yYè","uUå","iIï","oOí","pPô","[{[","]}]",
634 "aAù","sSã","dDâ","fFë","gGò","hHé","jJç","kKì","lLê",";:ó","\'\",","\\|\\",
635 "zZæ","xXñ","cCá","vVä","bBð","nNî","mMö",",<ú",".>õ","/?."
638 /*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
639 Greek characters for "wW" and "sS" are omitted to not produce a mismatch
640 message since they have different characters in gr and el XFree86 layouts. */
641 static const char main_key_EL[MAIN_LEN][4] =
643 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
644 "qQ;:","wW","eEåÅ","rRñÑ","tTôÔ","yYõÕ","uUèÈ","iIéÉ","oOïÏ","pPðÐ","[{","]}",
645 "aAáÁ","sS","dDäÄ","fFöÖ","gGãÃ","hHçÇ","jJîÎ","kKêÊ","lLëË",";:´¨","'\"","\\|",
646 "zZæÆ","xX÷×","cCøØ","vVùÙ","bBâÂ","nNíÍ","mMìÌ",",<",".>","/?",
647 "<>"
650 /*** VNC keyboard layout */
651 static const WORD main_key_scan_vnc[MAIN_LEN] =
653 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
654 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,
655 0x56
658 static const WORD main_key_vkey_vnc[MAIN_LEN] =
660 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,
661 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,
662 VK_OEM_102
665 static const char main_key_vnc[MAIN_LEN][4] =
667 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
668 "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"
671 /*** Layout table. Add your keyboard mappings to this list */
672 static const struct {
673 const char *comment;
674 const UINT layout_cp; /* Code page for this layout */
675 const char (*key)[MAIN_LEN][4];
676 const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
677 const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
678 } main_key_tab[]={
679 {"United States keyboard layout", 28591, &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
680 {"United States keyboard layout (phantom key version)", 28591, &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
681 {"United States keyboard layout (dvorak)", 28591, &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
682 {"British keyboard layout", 28605, &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
683 {"German keyboard layout", 28605, &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
684 {"German keyboard layout without dead keys", 28605, &main_key_DE_nodead, &main_key_scan_qwerty, &main_key_vkey_qwerty},
685 {"German keyboard layout for logitech desktop pro", 28605, &main_key_DE_logitech, &main_key_scan_qwerty, &main_key_vkey_qwerty},
686 {"German keyboard layout without dead keys 105", 28605, &main_key_DE_nodead_105, &main_key_scan_qwerty, &main_key_vkey_qwerty},
687 {"Swiss German keyboard layout", 28605, &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwerty},
688 {"Swedish keyboard layout", 28605, &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty},
689 {"Estonian keyboard layout", 28605, &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
690 {"Norwegian keyboard layout", 28605, &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
691 {"Danish keyboard layout", 28605, &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
692 {"French keyboard layout", 28605, &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
693 {"Canadian French keyboard layout", 28591, &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
694 {"Belgian keyboard layout", 28605, &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
695 {"Swiss French keyboard layout", 28605, &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
696 {"Portuguese keyboard layout", 28605, &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
697 {"Brazilian ABNT-2 keyboard layout", 28591, &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
698 {"Brazilian ABNT-2 keyboard layout ALT GR", 28591, &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
699 {"United States International keyboard layout", 28591, &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
700 {"Finnish keyboard layout", 28605, &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
701 {"Bulgarian bds keyboard layout", 1251, &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
702 {"Bulgarian phonetic keyboard layout", 1251, &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
703 {"Belarusian keyboard layout", 1251, &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
704 {"Russian keyboard layout", 20866, &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
705 {"Russian keyboard layout (phantom key version)", 20866, &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
706 {"Russian keyboard layout KOI8-R", 20866, &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
707 {"Ukrainian keyboard layout KOI8-U", 20866, &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
708 {"Spanish keyboard layout", 28605, &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
709 {"Italian keyboard layout", 28605, &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
710 {"Icelandic keyboard layout", 28605, &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
711 {"Hungarian keyboard layout", 28592, &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
712 {"Polish (programmer's) keyboard layout", 28592, &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
713 {"Slovenian keyboard layout", 28592, &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
714 {"Croatian keyboard layout", 28592, &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
715 {"Croatian keyboard layout (specific)", 28592, &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
716 {"Japanese 106 keyboard layout", 932, &main_key_JA_jp106, &main_key_scan_qwerty, &main_key_vkey_qwerty},
717 {"Japanese pc98x1 keyboard layout", 932, &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
718 {"Slovak keyboard layout", 28592, &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
719 {"Slovak and Czech keyboard layout without dead keys", 28592, &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
720 {"Czech keyboard layout", 28592, &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
721 {"Czech keyboard layout cz", 28592, &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwerty},
722 {"Czech keyboard layout cz_qwerty", 28592, &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
723 {"Latin American keyboard layout", 28591, &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
724 {"Lithuanian (Baltic) keyboard layout", 28603, &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
725 {"Turkish keyboard layout", 28599, &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
726 {"Israeli keyboard layout", 28598, &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
727 {"VNC keyboard layout", 28605, &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
728 {"Greek keyboard layout", 28597, &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
730 {NULL, 0, NULL, NULL, NULL} /* sentinel */
732 static unsigned kbd_layout=0; /* index into above table of layouts */
734 /* maybe more of these scancodes should be extended? */
735 /* extended must be set for ALT_R, CTRL_R,
736 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
737 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
738 /* FIXME should we set extended bit for NumLock ? My
739 * Windows does ... DF */
740 /* Yes, to distinguish based on scan codes, also
741 for PrtScn key ... GA */
743 static const WORD nonchar_key_vkey[256] =
745 /* unused */
746 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
747 /* special keys */
748 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
749 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
750 0, 0, 0, VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
751 /* unused */
752 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
753 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
754 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
755 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
756 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
757 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
758 /* cursor keys */
759 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, /* FF50 */
760 VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
761 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
762 /* misc keys */
763 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
764 VK_CANCEL, VK_HELP, VK_CANCEL, VK_CANCEL, 0, 0, 0, 0, /* FF68 */
765 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
766 /* keypad keys */
767 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK, /* FF78 */
768 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
769 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
770 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP, /* FF90 */
771 VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT, /* FF98 */
772 VK_END, 0, VK_INSERT, VK_DELETE,
773 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
774 0, 0, VK_MULTIPLY, VK_ADD, /* FFA8 */
775 VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
776 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, /* FFB0 */
777 VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
778 VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
779 /* function keys */
780 VK_F1, VK_F2,
781 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
782 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, 0, 0, /* FFC8 */
783 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
784 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
785 /* modifier keys */
786 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */
787 VK_CONTROL, VK_CAPITAL, 0, VK_MENU,
788 VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
789 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
790 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */
793 static const WORD nonchar_key_scan[256] =
795 /* unused */
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
797 /* special keys */
798 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
799 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
800 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
801 /* unused */
802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
803 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
804 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
805 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
808 /* cursor keys */
809 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
811 /* misc keys */
812 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
813 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
815 /* keypad keys */
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
818 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
819 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
820 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
822 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
823 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
824 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
825 /* function keys */
826 0x3B, 0x3C,
827 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
828 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
831 /* modifier keys */
832 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
833 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
839 /* Returns the Windows virtual key code associated with the X event <e> */
840 /* x11 lock must be held */
841 static WORD EVENT_event_to_vkey( XKeyEvent *e)
843 KeySym keysym;
845 XLookupString(e, NULL, 0, &keysym, NULL);
847 if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
848 && (e->state & NumLockMask))
849 /* Only the Keypad keys 0-9 and . send different keysyms
850 * depending on the NumLock state */
851 return nonchar_key_vkey[keysym & 0xFF];
853 return keyc2vkey[e->keycode];
856 static BOOL NumState=FALSE, CapsState=FALSE;
859 /***********************************************************************
860 * send_keyboard_input
862 static void send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time )
864 INPUT input;
866 input.type = WINE_INTERNAL_INPUT_KEYBOARD;
867 input.u.ki.wVk = wVk;
868 input.u.ki.wScan = wScan;
869 input.u.ki.dwFlags = dwFlags;
870 input.u.ki.time = time;
871 input.u.ki.dwExtraInfo = 0;
872 SendInput( 1, &input, sizeof(input) );
876 /**********************************************************************
877 * KEYBOARD_GenerateMsg
879 * Generate Down+Up messages when NumLock or CapsLock is pressed.
881 * Convention : called with vkey only VK_NUMLOCK or VK_CAPITAL
884 static void KEYBOARD_GenerateMsg( WORD vkey, WORD scan, int Evtype, DWORD event_time )
886 BOOL * State = (vkey==VK_NUMLOCK? &NumState : &CapsState);
887 DWORD up, down;
889 if (*State) {
890 /* The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
891 don't treat it. It's from the same key press. Then the state goes to ON.
892 And from there, a 'release' event will switch off the toggle key. */
893 *State=FALSE;
894 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey,pKeyStateTable[vkey]);
895 } else
897 down = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0);
898 up = (vkey==VK_NUMLOCK ? KEYEVENTF_EXTENDEDKEY : 0) | KEYEVENTF_KEYUP;
899 if ( pKeyStateTable[vkey] & 0x1 ) /* it was ON */
901 if (Evtype!=KeyPress)
903 TRACE("ON + KeyRelease => generating DOWN and UP messages.\n");
904 send_keyboard_input( vkey, scan, down, event_time );
905 send_keyboard_input( vkey, scan, up, event_time );
906 *State=FALSE;
907 pKeyStateTable[vkey] &= ~0x01; /* Toggle state to off. */
910 else /* it was OFF */
911 if (Evtype==KeyPress)
913 TRACE("OFF + Keypress => generating DOWN and UP messages.\n");
914 send_keyboard_input( vkey, scan, down, event_time );
915 send_keyboard_input( vkey, scan, up, event_time );
916 *State=TRUE; /* Goes to intermediary state before going to ON */
917 pKeyStateTable[vkey] |= 0x01; /* Toggle state to on. */
922 /***********************************************************************
923 * KEYBOARD_UpdateOneState
925 * Updates internal state for <vkey>, depending on key <state> under X
928 inline static void KEYBOARD_UpdateOneState ( int vkey, int state, DWORD time )
930 /* Do something if internal table state != X state for keycode */
931 if (((pKeyStateTable[vkey] & 0x80)!=0) != state)
933 TRACE("Adjusting state for vkey %#.2x. State before %#.2x\n",
934 vkey, pKeyStateTable[vkey]);
936 /* Fake key being pressed inside wine */
937 send_keyboard_input( vkey, 0, state? 0 : KEYEVENTF_KEYUP, time );
939 TRACE("State after %#.2x\n",pKeyStateTable[vkey]);
943 /***********************************************************************
944 * X11DRV_KeymapNotify
946 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
948 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
949 * from wine to another application and back.
950 * Toggle keys are handled in HandleEvent.
952 void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event )
954 int i, j, alt, control, shift;
955 DWORD time = GetCurrentTime();
957 alt = control = shift = 0;
958 for (i = 0; i < 32; i++)
960 if (!event->key_vector[i]) continue;
961 for (j = 0; j < 8; j++)
963 if (!(event->key_vector[i] & (1<<j))) continue;
964 switch(keyc2vkey[(i * 8) + j] & 0xff)
966 case VK_MENU: alt = 1; break;
967 case VK_CONTROL: control = 1; break;
968 case VK_SHIFT: shift = 1; break;
972 KEYBOARD_UpdateOneState( VK_MENU, alt, time );
973 KEYBOARD_UpdateOneState( VK_CONTROL, control, time );
974 KEYBOARD_UpdateOneState( VK_SHIFT, shift, time );
977 /***********************************************************************
978 * X11DRV_KeyEvent
980 * Handle a X key event
982 void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event )
984 char Str[24];
985 KeySym keysym;
986 WORD vkey = 0, bScan;
987 DWORD dwFlags;
988 int ascii_chars;
990 DWORD event_time = event->time - X11DRV_server_startticks;
992 /* this allows support for dead keys */
993 if ((event->keycode >> 8) == 0x10)
994 event->keycode=(event->keycode & 0xff);
996 wine_tsx11_lock();
997 ascii_chars = XLookupString(event, Str, sizeof(Str), &keysym, NULL);
998 wine_tsx11_unlock();
1000 /* Ignore some unwanted events */
1001 if (keysym == XK_ISO_Prev_Group ||
1002 keysym == XK_ISO_Next_Group ||
1003 keysym == XK_Mode_switch)
1005 TRACE("Ignoring %s keyboard event\n", TSXKeysymToString(keysym));
1006 return;
1009 TRACE_(key)("state = %X\n", event->state);
1011 /* If XKB extensions are used, the state mask for AltGr will use the group
1012 index instead of the modifier mask. The group index is set in bits
1013 13-14 of the state field in the XKeyEvent structure. So if AltGr is
1014 pressed, look if the group index is different than 0. From XKB
1015 extension documentation, the group index for AltGr should be 2
1016 (event->state = 0x2000). It's probably better to not assume a
1017 predefined group index and find it dynamically
1019 Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1020 AltGrMask = event->state & 0x6000;
1022 Str[ascii_chars] = '\0';
1023 if (TRACE_ON(key)){
1024 char *ksname;
1026 ksname = TSXKeysymToString(keysym);
1027 if (!ksname)
1028 ksname = "No Name";
1029 TRACE_(key)("%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
1030 (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1031 keysym, ksname, ascii_chars, Str[0] & 0xff, Str);
1034 wine_tsx11_lock();
1035 vkey = EVENT_event_to_vkey(event);
1036 wine_tsx11_unlock();
1038 TRACE_(key)("keycode 0x%x converted to vkey 0x%x\n",
1039 event->keycode, vkey);
1041 if (vkey)
1043 switch (vkey & 0xff)
1045 case VK_NUMLOCK:
1046 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, event->type, event_time );
1047 break;
1048 case VK_CAPITAL:
1049 TRACE("Caps Lock event. (type %d). State before : %#.2x\n",event->type,pKeyStateTable[vkey]);
1050 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, event->type, event_time );
1051 TRACE("State after : %#.2x\n",pKeyStateTable[vkey]);
1052 break;
1053 default:
1054 /* Adjust the NUMLOCK state if it has been changed outside wine */
1055 if (!(pKeyStateTable[VK_NUMLOCK] & 0x01) != !(event->state & NumLockMask))
1057 TRACE("Adjusting NumLock state.\n");
1058 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyPress, event_time );
1059 KEYBOARD_GenerateMsg( VK_NUMLOCK, 0x45, KeyRelease, event_time );
1061 /* Adjust the CAPSLOCK state if it has been changed outside wine */
1062 if (!(pKeyStateTable[VK_CAPITAL] & 0x01) != !(event->state & LockMask))
1064 TRACE("Adjusting Caps Lock state.\n");
1065 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyPress, event_time );
1066 KEYBOARD_GenerateMsg( VK_CAPITAL, 0x3A, KeyRelease, event_time );
1068 /* Not Num nor Caps : end of intermediary states for both. */
1069 NumState = FALSE;
1070 CapsState = FALSE;
1072 bScan = keyc2scan[event->keycode] & 0xFF;
1073 TRACE_(key)("bScan = 0x%02x.\n", bScan);
1075 dwFlags = 0;
1076 if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
1077 if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
1079 send_keyboard_input( vkey & 0xff, bScan, dwFlags, event_time );
1084 /**********************************************************************
1085 * X11DRV_KEYBOARD_DetectLayout
1087 * Called from X11DRV_InitKeyboard
1088 * This routine walks through the defined keyboard layouts and selects
1089 * whichever matches most closely.
1090 * X11 lock must be held.
1092 static void
1093 X11DRV_KEYBOARD_DetectLayout (void)
1095 Display *display = thread_display();
1096 unsigned current, match, mismatch, seq;
1097 int score, keyc, i, key, pkey, ok, syms;
1098 KeySym keysym;
1099 const char (*lkey)[MAIN_LEN][4];
1100 unsigned max_seq = 0;
1101 int max_score = 0, ismatch = 0;
1102 char ckey[4] =
1103 {0, 0, 0, 0};
1105 syms = keysyms_per_keycode;
1106 if (syms > 4) {
1107 WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1108 syms = 4;
1110 for (current = 0; main_key_tab[current].comment; current++) {
1111 TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
1112 match = 0;
1113 mismatch = 0;
1114 score = 0;
1115 seq = 0;
1116 lkey = main_key_tab[current].key;
1117 pkey = -1;
1118 for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1119 /* get data for keycode from X server */
1120 for (i = 0; i < syms; i++) {
1121 keysym = XKeycodeToKeysym (display, keyc, i);
1122 /* Allow both one-byte and two-byte national keysyms */
1123 if ((keysym < 0x8000) && (keysym != ' '))
1124 ckey[i] = keysym & 0xFF;
1125 else {
1126 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1129 if (ckey[0]) {
1130 /* search for a match in layout table */
1131 /* right now, we just find an absolute match for defined positions */
1132 /* (undefined positions are ignored, so if it's defined as "3#" in */
1133 /* the table, it's okay that the X server has "3#£", for example) */
1134 /* however, the score will be higher for longer matches */
1135 for (key = 0; key < MAIN_LEN; key++) {
1136 for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1137 if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[i]))
1138 ok++;
1139 if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[i]))
1140 ok = -1;
1142 if (ok > 0) {
1143 score += ok;
1144 break;
1147 /* count the matches and mismatches */
1148 if (ok > 0) {
1149 match++;
1150 /* and how much the keycode order matches */
1151 if (key > pkey) seq++;
1152 pkey = key;
1153 } else {
1154 TRACE_(key)("mismatch for keycode %d, character %c (%02x, %02x, %02x, %02x)\n", keyc, ckey[0], ckey[0], ckey[1], ckey[2], ckey[3]);
1155 mismatch++;
1156 score -= syms;
1160 TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
1161 match, mismatch, seq, score);
1162 if ((score > max_score) ||
1163 ((score == max_score) && (seq > max_seq))) {
1164 /* best match so far */
1165 kbd_layout = current;
1166 max_score = score;
1167 max_seq = seq;
1168 ismatch = !mismatch;
1171 /* we're done, report results if necessary */
1172 if (!ismatch) {
1173 FIXME(
1174 "Your keyboard layout was not found!\n"
1175 "Using closest match instead (%s) for scancode mapping.\n"
1176 "Please define your layout in windows/x11drv/keyboard.c and submit them\n"
1177 "to us for inclusion into future Wine releases.\n"
1178 "See the Wine User Guide, chapter \"Keyboard\" for more information.\n",
1179 main_key_tab[kbd_layout].comment);
1182 TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1185 /**********************************************************************
1186 * InitKeyboard (X11DRV.@)
1188 void X11DRV_InitKeyboard( BYTE *key_state_table )
1190 #ifdef HAVE_XKB
1191 int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
1192 #endif
1193 Display *display = thread_display();
1194 KeySym *ksp;
1195 XModifierKeymap *mmp;
1196 KeySym keysym;
1197 KeyCode *kcp;
1198 XKeyEvent e2;
1199 WORD scan, vkey, OEMvkey;
1200 int keyc, i, keyn, syms;
1201 char ckey[4]={0,0,0,0};
1202 const char (*lkey)[MAIN_LEN][4];
1204 pKeyStateTable = key_state_table;
1206 wine_tsx11_lock();
1207 #ifdef HAVE_XKB
1208 is_xkb = XkbQueryExtension(display,
1209 &xkb_opcode, &xkb_event, &xkb_error,
1210 &xkb_major, &xkb_minor);
1211 if (is_xkb) {
1212 /* we have XKB, approximate Windows behaviour */
1213 XkbSetDetectableAutoRepeat(display, True, NULL);
1215 #endif
1216 XDisplayKeycodes(display, &min_keycode, &max_keycode);
1217 ksp = XGetKeyboardMapping(display, min_keycode,
1218 max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1219 /* We are only interested in keysyms_per_keycode.
1220 There is no need to hold a local copy of the keysyms table */
1221 XFree(ksp);
1223 mmp = XGetModifierMapping(display);
1224 kcp = mmp->modifiermap;
1225 for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
1227 int j;
1229 for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
1230 if (*kcp)
1232 int k;
1234 for (k = 0; k < keysyms_per_keycode; k += 1)
1235 if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
1237 NumLockMask = 1 << i;
1238 TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1242 XFreeModifiermap(mmp);
1244 /* Detect the keyboard layout */
1245 X11DRV_KEYBOARD_DetectLayout();
1246 lkey = main_key_tab[kbd_layout].key;
1247 syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
1249 /* Now build two conversion arrays :
1250 * keycode -> vkey + scancode + extended
1251 * vkey + extended -> keycode */
1253 e2.display = display;
1254 e2.state = 0;
1256 OEMvkey = VK_OEM_7; /* next is available. */
1257 for (keyc = min_keycode; keyc <= max_keycode; keyc++)
1259 e2.keycode = (KeyCode)keyc;
1260 XLookupString(&e2, NULL, 0, &keysym, NULL);
1261 vkey = 0; scan = 0;
1262 if (keysym) /* otherwise, keycode not used */
1264 if ((keysym >> 8) == 0xFF) /* non-character key */
1266 vkey = nonchar_key_vkey[keysym & 0xff];
1267 scan = nonchar_key_scan[keysym & 0xff];
1268 /* set extended bit when necessary */
1269 if (scan & 0x100) vkey |= 0x100;
1270 } else if (keysym == 0x20) { /* Spacebar */
1271 vkey = VK_SPACE;
1272 scan = 0x39;
1273 } else {
1274 /* we seem to need to search the layout-dependent scancodes */
1275 int maxlen=0,maxval=-1,ok;
1276 for (i=0; i<syms; i++) {
1277 keysym = XKeycodeToKeysym(display, keyc, i);
1278 if ((keysym<0x800) && (keysym!=' ')) {
1279 ckey[i] = keysym & 0xFF;
1280 } else {
1281 ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
1284 /* find key with longest match streak */
1285 for (keyn=0; keyn<MAIN_LEN; keyn++) {
1286 for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
1287 if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1288 if (ok||(i>maxlen)) {
1289 maxlen=i; maxval=keyn;
1291 if (ok) break;
1293 if (maxval>=0) {
1294 /* got it */
1295 const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
1296 const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
1297 scan = (*lscan)[maxval];
1298 vkey = (*lvkey)[maxval];
1302 /* find a suitable layout-dependent VK code */
1303 /* (most Winelib apps ought to be able to work without layout tables!) */
1304 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1306 keysym = XLookupKeysym(&e2, i);
1307 if ((keysym >= VK_0 && keysym <= VK_9)
1308 || (keysym >= VK_A && keysym <= VK_Z)) {
1309 vkey = keysym;
1313 for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
1315 keysym = XLookupKeysym(&e2, i);
1316 switch (keysym)
1318 case ';': vkey = VK_OEM_1; break;
1319 case '/': vkey = VK_OEM_2; break;
1320 case '`': vkey = VK_OEM_3; break;
1321 case '[': vkey = VK_OEM_4; break;
1322 case '\\': vkey = VK_OEM_5; break;
1323 case ']': vkey = VK_OEM_6; break;
1324 case '\'': vkey = VK_OEM_7; break;
1325 case ',': vkey = VK_OEM_COMMA; break;
1326 case '.': vkey = VK_OEM_PERIOD; break;
1327 case '-': vkey = VK_OEM_MINUS; break;
1328 case '+': vkey = VK_OEM_PLUS; break;
1332 if (!vkey)
1334 /* Others keys: let's assign OEM virtual key codes in the allowed range,
1335 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
1336 switch (++OEMvkey)
1338 case 0xc1 : OEMvkey=0xdb; break;
1339 case 0xe5 : OEMvkey=0xe9; break;
1340 case 0xf6 : OEMvkey=0xf5; WARN("No more OEM vkey available!\n");
1343 vkey = OEMvkey;
1345 if (TRACE_ON(keyboard))
1347 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1348 OEMvkey, e2.keycode);
1349 TRACE("(");
1350 for (i = 0; i < keysyms_per_keycode; i += 1)
1352 char *ksname;
1354 keysym = XLookupKeysym(&e2, i);
1355 ksname = XKeysymToString(keysym);
1356 if (!ksname)
1357 ksname = "NoSymbol";
1358 DPRINTF( "%lX (%s) ", keysym, ksname);
1360 DPRINTF(")\n");
1364 keyc2vkey[e2.keycode] = vkey;
1365 keyc2scan[e2.keycode] = scan;
1366 } /* for */
1368 /* If some keys still lack scancodes, assign some arbitrary ones to them now */
1369 for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
1370 if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1371 char *ksname;
1372 keysym = XKeycodeToKeysym(display, keyc, 0);
1373 ksname = XKeysymToString(keysym);
1374 if (!ksname) ksname = "NoSymbol";
1376 /* should make sure the scancode is unassigned here, but >=0x60 currently always is */
1378 TRACE_(key)("assigning scancode %02x to unidentified keycode %02x (%s)\n",scan,keyc,ksname);
1379 keyc2scan[keyc]=scan++;
1382 /* Now store one keycode for each modifier. Used to simulate keypresses. */
1383 kcControl = XKeysymToKeycode(display, XK_Control_L);
1384 kcAlt = XKeysymToKeycode(display, XK_Alt_L);
1385 if (!kcAlt) kcAlt = XKeysymToKeycode(display, XK_Meta_L);
1386 kcShift = XKeysymToKeycode(display, XK_Shift_L);
1387 kcNumLock = XKeysymToKeycode(display, XK_Num_Lock);
1388 kcCapsLock = XKeysymToKeycode(display, XK_Caps_Lock);
1389 wine_tsx11_unlock();
1393 /***********************************************************************
1394 * X11DRV_MappingNotify
1396 void X11DRV_MappingNotify( XMappingEvent *event )
1398 TSXRefreshKeyboardMapping(event);
1399 X11DRV_InitKeyboard( pKeyStateTable );
1403 /***********************************************************************
1404 * VkKeyScan (X11DRV.@)
1406 WORD X11DRV_VkKeyScan(CHAR cChar)
1408 Display *display = thread_display();
1409 KeyCode keycode;
1410 KeySym keysym;
1411 int i,index;
1412 int highbyte=0;
1414 /* char->keysym (same for ANSI chars) */
1415 keysym=(unsigned char) cChar;/* (!) cChar is signed */
1416 if (keysym<=27) keysym+=0xFF00;/*special chars : return, backspace...*/
1418 keycode = TSXKeysymToKeycode(display, keysym); /* keysym -> keycode */
1419 if (!keycode)
1420 { /* It didn't work ... let's try with deadchar code. */
1421 keycode = TSXKeysymToKeycode(display, keysym | 0xFE00);
1424 TRACE("'%c'(%#lx, %lu): got keycode %#.2x\n",
1425 cChar,keysym,keysym,keycode);
1427 if (keycode)
1429 for (index=-1, i=0; (i<8) && (index<0); i++) /* find shift state */
1430 if (TSXKeycodeToKeysym(display,keycode,i)==keysym) index=i;
1431 switch (index) {
1432 case -1 :
1433 WARN("Keysym %lx not found while parsing the keycode table\n",keysym); break;
1434 case 0 : break;
1435 case 1 : highbyte = 0x0100; break;
1436 case 2 : highbyte = 0x0600; break;
1437 case 3 : highbyte = 0x0700; break;
1438 default : ERR("index %d found by XKeycodeToKeysym. please report! \n",index);
1441 index : 0 adds 0x0000
1442 index : 1 adds 0x0100 (shift)
1443 index : ? adds 0x0200 (ctrl)
1444 index : 2 adds 0x0600 (ctrl+alt)
1445 index : 3 adds 0x0700 (ctrl+alt+shift)
1448 TRACE(" ... returning %#.2x\n", keyc2vkey[keycode]+highbyte);
1449 return keyc2vkey[keycode]+highbyte; /* keycode -> (keyc2vkey) vkey */
1452 /***********************************************************************
1453 * MapVirtualKey (X11DRV.@)
1455 UINT X11DRV_MapVirtualKey(UINT wCode, UINT wMapType)
1457 Display *display = thread_display();
1459 #define returnMVK(value) { TRACE("returning 0x%x.\n",value); return value; }
1461 TRACE("wCode=0x%x wMapType=%d ...\n", wCode,wMapType);
1462 switch(wMapType) {
1463 case 0: { /* vkey-code to scan-code */
1464 /* let's do vkey -> keycode -> scan */
1465 int keyc;
1466 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1467 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1468 returnMVK (keyc2scan[keyc] & 0xFF);
1469 TRACE("returning no scan-code.\n");
1470 return 0; }
1472 case 1: { /* scan-code to vkey-code */
1473 /* let's do scan -> keycode -> vkey */
1474 int keyc;
1475 for (keyc=min_keycode; keyc<=max_keycode; keyc++)
1476 if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
1477 returnMVK (keyc2vkey[keyc] & 0xFF);
1478 TRACE("returning no vkey-code.\n");
1479 return 0; }
1481 case 2: { /* vkey-code to unshifted ANSI code */
1482 /* we still don't know what "unshifted" means. in windows VK_W (0x57)
1483 * returns 0x57, which is upercase 'W'. So we have to return the uppercase
1484 * key.. Looks like something is wrong with the MS docs?
1485 * This is only true for letters, for example VK_0 returns '0' not ')'.
1486 * - hence we use the lock mask to ensure this happens.
1488 /* let's do vkey -> keycode -> (XLookupString) ansi char */
1489 XKeyEvent e;
1490 KeySym keysym;
1491 int keyc;
1492 char s[2];
1493 e.display = display;
1495 e.state = LockMask;
1496 /* LockMask should behave exactly like caps lock - upercase
1497 * the letter keys and thats about it. */
1499 wine_tsx11_lock();
1501 e.keycode = 0;
1502 /* We exit on the first keycode found, to speed up the thing. */
1503 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1504 { /* Find a keycode that could have generated this virtual key */
1505 if ((keyc2vkey[keyc] & 0xFF) == wCode)
1506 { /* We filter the extended bit, we don't know it */
1507 e.keycode = keyc; /* Store it temporarily */
1508 if ((EVENT_event_to_vkey(&e) & 0xFF) != wCode) {
1509 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1510 state), so set it to 0, we'll find another one */
1515 if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
1516 e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);
1518 if (wCode==VK_DECIMAL)
1519 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1521 if (!e.keycode)
1523 WARN("Unknown virtual key %X !!! \n", wCode);
1524 wine_tsx11_unlock();
1525 return 0; /* whatever */
1527 TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1529 if (XLookupString(&e, s, 2, &keysym, NULL))
1531 wine_tsx11_unlock();
1532 returnMVK (*s);
1535 TRACE("returning no ANSI.\n");
1536 wine_tsx11_unlock();
1537 return 0;
1540 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1541 /* left and right */
1542 FIXME(" stub for NT\n");
1543 return 0;
1545 default: /* reserved */
1546 WARN("Unknown wMapType %d !\n", wMapType);
1547 return 0;
1549 return 0;
1552 /***********************************************************************
1553 * GetKeyNameText (X11DRV.@)
1555 INT X11DRV_GetKeyNameText(LONG lParam, LPSTR lpBuffer, INT nSize)
1557 int vkey, ansi, scanCode;
1558 KeyCode keyc;
1559 int keyi;
1560 KeySym keys;
1561 char *name;
1563 scanCode = lParam >> 16;
1564 scanCode &= 0x1ff; /* keep "extended-key" flag with code */
1566 /* FIXME: should use MVK type 3 (NT version that distinguishes right and left */
1567 vkey = X11DRV_MapVirtualKey(scanCode, 1);
1569 /* handle "don't care" bit (0x02000000) */
1570 if (!(lParam & 0x02000000)) {
1571 switch (vkey) {
1572 case VK_LSHIFT:
1573 case VK_RSHIFT:
1574 vkey = VK_SHIFT;
1575 break;
1576 case VK_LCONTROL:
1577 case VK_RCONTROL:
1578 vkey = VK_CONTROL;
1579 break;
1580 case VK_LMENU:
1581 case VK_RMENU:
1582 vkey = VK_MENU;
1583 break;
1584 default:
1585 break;
1589 ansi = X11DRV_MapVirtualKey(vkey, 2);
1590 TRACE("scan 0x%04x, vkey 0x%04x, ANSI 0x%04x\n", scanCode, vkey, ansi);
1592 /* first get the name of the "regular" keys which is the Upper case
1593 value of the keycap imprint. */
1594 if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
1595 (scanCode != 0x137) && /* PrtScn */
1596 (scanCode != 0x135) && /* numpad / */
1597 (scanCode != 0x37 ) && /* numpad * */
1598 (scanCode != 0x4a ) && /* numpad - */
1599 (scanCode != 0x4e ) ) /* numpad + */
1601 if ((nSize >= 2) && lpBuffer)
1603 *lpBuffer = toupper((char)ansi);
1604 *(lpBuffer+1) = 0;
1605 return 1;
1607 else
1608 return 0;
1611 /* FIXME: horrible hack to fix function keys. Windows reports scancode
1612 without "extended-key" flag. However Wine generates scancode
1613 *with* "extended-key" flag. Seems to occur *only* for the
1614 function keys. Soooo.. We will leave the table alone and
1615 fudge the lookup here till the other part is found and fixed!!! */
1617 if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
1618 (scanCode == 0x157) || (scanCode == 0x158))
1619 scanCode &= 0xff; /* remove "extended-key" flag for Fx keys */
1621 /* let's do scancode -> keycode -> keysym -> String */
1623 for (keyi=min_keycode; keyi<=max_keycode; keyi++)
1624 if ((keyc2scan[keyi]) == scanCode)
1625 break;
1626 if (keyi <= max_keycode)
1628 keyc = (KeyCode) keyi;
1629 keys = TSXKeycodeToKeysym(thread_display(), keyc, 0);
1630 name = TSXKeysymToString(keys);
1631 TRACE("found scan=%04x keyc=%04x keysym=%04x string=%s\n",
1632 scanCode, keyc, (int)keys, name);
1633 if (lpBuffer && nSize && name)
1635 lstrcpynA(lpBuffer, name, nSize);
1636 return 1;
1640 /* Finally issue FIXME for unknown keys */
1642 FIXME("(%08lx,%p,%d): unsupported key, vkey=%04x, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
1643 if (lpBuffer && nSize)
1644 *lpBuffer = 0;
1645 return 0;
1648 /***********************************************************************
1649 * X11DRV_KEYBOARD_MapDeadKeysym
1651 static char KEYBOARD_MapDeadKeysym(KeySym keysym)
1653 switch (keysym)
1655 /* symbolic ASCII is the same as defined in rfc1345 */
1656 #ifdef XK_dead_tilde
1657 case XK_dead_tilde :
1658 #endif
1659 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1660 return '~'; /* '? */
1661 #ifdef XK_dead_acute
1662 case XK_dead_acute :
1663 #endif
1664 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1665 return 0xb4; /* '' */
1666 #ifdef XK_dead_circumflex
1667 case XK_dead_circumflex:
1668 #endif
1669 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1670 return '^'; /* '> */
1671 #ifdef XK_dead_grave
1672 case XK_dead_grave :
1673 #endif
1674 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1675 return '`'; /* '! */
1676 #ifdef XK_dead_diaeresis
1677 case XK_dead_diaeresis :
1678 #endif
1679 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1680 return 0xa8; /* ': */
1681 #ifdef XK_dead_cedilla
1682 case XK_dead_cedilla :
1683 return 0xb8; /* ', */
1684 #endif
1685 #ifdef XK_dead_macron
1686 case XK_dead_macron :
1687 return '-'; /* 'm isn't defined on iso-8859-x */
1688 #endif
1689 #ifdef XK_dead_breve
1690 case XK_dead_breve :
1691 return 0xa2; /* '( */
1692 #endif
1693 #ifdef XK_dead_abovedot
1694 case XK_dead_abovedot :
1695 return 0xff; /* '. */
1696 #endif
1697 #ifdef XK_dead_abovering
1698 case XK_dead_abovering :
1699 return '0'; /* '0 isn't defined on iso-8859-x */
1700 #endif
1701 #ifdef XK_dead_doubleacute
1702 case XK_dead_doubleacute :
1703 return 0xbd; /* '" */
1704 #endif
1705 #ifdef XK_dead_caron
1706 case XK_dead_caron :
1707 return 0xb7; /* '< */
1708 #endif
1709 #ifdef XK_dead_ogonek
1710 case XK_dead_ogonek :
1711 return 0xb2; /* '; */
1712 #endif
1713 /* FIXME: I don't know this three.
1714 case XK_dead_iota :
1715 return 'i';
1716 case XK_dead_voiced_sound :
1717 return 'v';
1718 case XK_dead_semivoiced_sound :
1719 return 's';
1722 TRACE("no character for dead keysym 0x%08lx\n",keysym);
1723 return 0;
1726 /***********************************************************************
1727 * ToUnicode (X11DRV.@)
1729 * The ToUnicode function translates the specified virtual-key code and keyboard
1730 * state to the corresponding Windows character or characters.
1732 * If the specified key is a dead key, the return value is negative. Otherwise,
1733 * it is one of the following values:
1734 * Value Meaning
1735 * 0 The specified virtual key has no translation for the current state of the keyboard.
1736 * 1 One Windows character was copied to the buffer.
1737 * 2 Two characters were copied to the buffer. This usually happens when a
1738 * dead-key character (accent or diacritic) stored in the keyboard layout cannot
1739 * be composed with the specified virtual key to form a single character.
1741 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
1744 INT X11DRV_ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
1745 LPWSTR bufW, int bufW_size, UINT flags)
1747 Display *display = thread_display();
1748 XKeyEvent e;
1749 KeySym keysym;
1750 INT ret;
1751 int keyc;
1752 BYTE lpChar[2];
1754 if (scanCode & 0x8000)
1756 TRACE("Key UP, doing nothing\n" );
1757 return 0;
1759 e.display = display;
1760 e.keycode = 0;
1761 e.state = 0;
1762 if (lpKeyState[VK_SHIFT] & 0x80)
1764 TRACE("ShiftMask = %04x\n", ShiftMask);
1765 e.state |= ShiftMask;
1767 if (lpKeyState[VK_CAPITAL] & 0x01)
1769 TRACE("LockMask = %04x\n", LockMask);
1770 e.state |= LockMask;
1772 if (lpKeyState[VK_CONTROL] & 0x80)
1774 TRACE("ControlMask = %04x\n", ControlMask);
1775 e.state |= ControlMask;
1777 if (lpKeyState[VK_NUMLOCK] & 0x01)
1779 TRACE("NumLockMask = %04x\n", NumLockMask);
1780 e.state |= NumLockMask;
1783 /* Restore saved AltGr state */
1784 TRACE("AltGrMask = %04x\n", AltGrMask);
1785 e.state |= AltGrMask;
1787 TRACE_(key)("(%04X, %04X) : faked state = %X\n",
1788 virtKey, scanCode, e.state);
1789 wine_tsx11_lock();
1790 /* We exit on the first keycode found, to speed up the thing. */
1791 for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
1792 { /* Find a keycode that could have generated this virtual key */
1793 if ((keyc2vkey[keyc] & 0xFF) == virtKey)
1794 { /* We filter the extended bit, we don't know it */
1795 e.keycode = keyc; /* Store it temporarily */
1796 if ((EVENT_event_to_vkey(&e) & 0xFF) != virtKey) {
1797 e.keycode = 0; /* Wrong one (ex: because of the NumLock
1798 state), so set it to 0, we'll find another one */
1803 if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
1804 e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
1806 if (virtKey==VK_DECIMAL)
1807 e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
1809 if (!e.keycode)
1811 WARN("Unknown virtual key %X !!! \n",virtKey);
1812 wine_tsx11_unlock();
1813 return virtKey; /* whatever */
1815 else TRACE("Found keycode %d (0x%2X)\n",e.keycode,e.keycode);
1817 ret = XLookupString(&e, (LPVOID)lpChar, 2, &keysym, NULL);
1818 wine_tsx11_unlock();
1820 if (ret == 0)
1822 BYTE dead_char;
1824 dead_char = KEYBOARD_MapDeadKeysym(keysym);
1825 if (dead_char)
1827 MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, &dead_char, 1, bufW, bufW_size);
1828 ret = -1;
1830 else
1832 char *ksname;
1834 ksname = TSXKeysymToString(keysym);
1835 if (!ksname)
1836 ksname = "No Name";
1837 if ((keysym >> 8) != 0xff)
1839 ERR("Please report: no char for keysym %04lX (%s) :\n",
1840 keysym, ksname);
1841 ERR("(virtKey=%X,scanCode=%X,keycode=%X,state=%X)\n",
1842 virtKey, scanCode, e.keycode, e.state);
1846 else { /* ret != 0 */
1847 /* We have a special case to handle : Shift + arrow, shift + home, ...
1848 X returns a char for it, but Windows doesn't. Let's eat it. */
1849 if (!(e.state & NumLockMask) /* NumLock is off */
1850 && (e.state & ShiftMask) /* Shift is pressed */
1851 && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
1853 *(char*)lpChar = 0;
1854 ret = 0;
1857 /* more areas where X returns characters but Windows does not
1858 CTRL + number or CTRL + symbol */
1859 if (e.state & ControlMask)
1861 if (((keysym>=33) && (keysym < 'A')) ||
1862 ((keysym > 'Z') && (keysym < 'a')))
1864 *(char*)lpChar = 0;
1865 ret = 0;
1869 /* We have another special case for delete key (XK_Delete) on an
1870 extended keyboard. X returns a char for it, but Windows doesn't */
1871 if (keysym == XK_Delete)
1873 *(char*)lpChar = 0;
1874 ret = 0;
1876 else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
1877 && (keysym == XK_KP_Decimal))
1879 *(char*)lpChar = 0;
1880 ret = 0;
1883 /* perform translation to unicode */
1884 if(ret)
1886 TRACE_(key)("Translating char 0x%02x from code page %d to unicode\n",
1887 *(BYTE *)lpChar, main_key_tab[kbd_layout].layout_cp);
1888 ret = MultiByteToWideChar(main_key_tab[kbd_layout].layout_cp, 0, (LPCSTR)lpChar, ret, bufW, bufW_size);
1892 TRACE_(key)("ToUnicode about to return %d with char %x %s\n",
1893 ret, bufW ? bufW[0] : 0, bufW ? "" : "(no buffer)");
1894 return ret;
1897 /***********************************************************************
1898 * Beep (X11DRV.@)
1900 void X11DRV_Beep(void)
1902 TSXBell(thread_display(), 0);