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
28 #include <X11/Xatom.h>
29 #include <X11/keysym.h>
32 #include <X11/Xresource.h>
33 #include <X11/Xutil.h>
35 #include <X11/XKBlib.h>
43 #include "wine/winuser16.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 */
60 static int is_xkb
, xkb_opcode
, xkb_event
, xkb_error
;
63 static char KEYBOARD_MapDeadKeysym(KeySym keysym
);
65 /* Keyboard translation tables */
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",",;",".:","-_",
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",",<",".>","/?",
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",",?",";.",":/","!§",
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",",;",".:","þÞ",
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µ",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",'-",".","éÉ",
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", ",;", ".:", "-_",
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µ",",;",".:·","-_",
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",",;",".:","-_",
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",",;",".:","-_",
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",",?",";.",":/","=+~",
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",",?;",".:·","-_*",
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",",<",".>","/?",
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§",",;",".:","-_",
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",",<",".>","/?",
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§",",;",".:","-_/",
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",",<",".>","/?",
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",",<",".>","/?",
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",",<",".>",";:","/?",
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",
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",",?",".:","-_",
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",",?",".:","-_",
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",",?",".:","-_",
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åÅ",",<",".>","/?",
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",",?<",".:>","-_*",
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",",;",".:","-_",
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ìÌ",",<",".>","/?",
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,
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
,
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 {
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 */
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] =
746 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
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 */
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 */
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 */
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 */
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 */
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 */
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] =
796 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
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 */
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 */
809 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
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 */
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 */
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 */
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
)
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
)
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
);
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. */
894 TRACE("INTERM : don\'t treat release of toggle key. InputKeyStateTable[%#x] = %#x\n",vkey
,pKeyStateTable
[vkey
]);
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
);
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 /***********************************************************************
980 * Handle a X key event
982 void X11DRV_KeyEvent( HWND hwnd
, XKeyEvent
*event
)
986 WORD vkey
= 0, bScan
;
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);
997 ascii_chars
= XLookupString(event
, Str
, sizeof(Str
), &keysym
, NULL
);
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
));
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';
1026 ksname
= TSXKeysymToString(keysym
);
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
);
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
);
1043 switch (vkey
& 0xff)
1046 KEYBOARD_GenerateMsg( VK_NUMLOCK
, 0x45, event
->type
, event_time
);
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
]);
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. */
1072 bScan
= keyc2scan
[event
->keycode
] & 0xFF;
1073 TRACE_(key
)("bScan = 0x%02x.\n", bScan
);
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.
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
;
1099 const char (*lkey
)[MAIN_LEN
][4];
1100 unsigned max_seq
= 0;
1101 int max_score
= 0, ismatch
= 0;
1105 syms
= keysyms_per_keycode
;
1107 WARN("%d keysyms per keycode not supported, set to 4\n", syms
);
1110 for (current
= 0; main_key_tab
[current
].comment
; current
++) {
1111 TRACE("Attempting to match against \"%s\"\n", main_key_tab
[current
].comment
);
1116 lkey
= main_key_tab
[current
].key
;
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;
1126 ckey
[i
] = KEYBOARD_MapDeadKeysym(keysym
);
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
]))
1139 if ((*lkey
)[key
][i
] && ((*lkey
)[key
][i
] != ckey
[i
]))
1147 /* count the matches and mismatches */
1150 /* and how much the keycode order matches */
1151 if (key
> pkey
) seq
++;
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]);
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
;
1168 ismatch
= !mismatch
;
1171 /* we're done, report results if necessary */
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
)
1191 int xkb_major
= XkbMajorVersion
, xkb_minor
= XkbMinorVersion
;
1193 Display
*display
= thread_display();
1195 XModifierKeymap
*mmp
;
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
;
1208 is_xkb
= XkbQueryExtension(display
,
1209 &xkb_opcode
, &xkb_event
, &xkb_error
,
1210 &xkb_major
, &xkb_minor
);
1212 /* we have XKB, approximate Windows behaviour */
1213 XkbSetDetectableAutoRepeat(display
, True
, NULL
);
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 */
1223 mmp
= XGetModifierMapping(display
);
1224 kcp
= mmp
->modifiermap
;
1225 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
1229 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
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
;
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
);
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 */
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;
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
;
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
)) {
1313 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
1315 keysym
= XLookupKeysym(&e2
, i
);
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;
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]) */
1338 case 0xc1 : OEMvkey
=0xdb; break;
1339 case 0xe5 : OEMvkey
=0xe9; break;
1340 case 0xf6 : OEMvkey
=0xf5; WARN("No more OEM vkey available!\n");
1345 if (TRACE_ON(keyboard
))
1347 TRACE("OEM specific virtual key %X assigned to keycode %X:\n",
1348 OEMvkey
, e2
.keycode
);
1350 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
1354 keysym
= XLookupKeysym(&e2
, i
);
1355 ksname
= XKeysymToString(keysym
);
1357 ksname
= "NoSymbol";
1358 DPRINTF( "%lX (%s) ", keysym
, ksname
);
1364 keyc2vkey
[e2
.keycode
] = vkey
;
1365 keyc2scan
[e2
.keycode
] = scan
;
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
]) {
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();
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 */
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
);
1429 for (index
=-1, i
=0; (i
<8) && (index
<0); i
++) /* find shift state */
1430 if (TSXKeycodeToKeysym(display
,keycode
,i
)==keysym
) index
=i
;
1433 WARN("Keysym %lx not found while parsing the keycode table\n",keysym
); 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
);
1463 case 0: { /* vkey-code to scan-code */
1464 /* let's do vkey -> keycode -> scan */
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");
1472 case 1: { /* scan-code to vkey-code */
1473 /* let's do scan -> keycode -> vkey */
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");
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 */
1493 e
.display
= display
;
1496 /* LockMask should behave exactly like caps lock - upercase
1497 * the letter keys and thats about it. */
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
);
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();
1535 TRACE("returning no ANSI.\n");
1536 wine_tsx11_unlock();
1540 case 3: /* **NT only** scan-code to vkey-code but distinguish between */
1541 /* left and right */
1542 FIXME(" stub for NT\n");
1545 default: /* reserved */
1546 WARN("Unknown wMapType %d !\n", wMapType
);
1552 /***********************************************************************
1553 * GetKeyNameText (X11DRV.@)
1555 INT
X11DRV_GetKeyNameText(LONG lParam
, LPSTR lpBuffer
, INT nSize
)
1557 int vkey
, ansi
, scanCode
;
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)) {
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
);
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
)
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
);
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
)
1648 /***********************************************************************
1649 * X11DRV_KEYBOARD_MapDeadKeysym
1651 static char KEYBOARD_MapDeadKeysym(KeySym keysym
)
1655 /* symbolic ASCII is the same as defined in rfc1345 */
1656 #ifdef XK_dead_tilde
1657 case XK_dead_tilde
:
1659 case 0x1000FE7E : /* Xfree's XK_Dtilde */
1660 return '~'; /* '? */
1661 #ifdef XK_dead_acute
1662 case XK_dead_acute
:
1664 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
1665 return 0xb4; /* '' */
1666 #ifdef XK_dead_circumflex
1667 case XK_dead_circumflex
:
1669 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
1670 return '^'; /* '> */
1671 #ifdef XK_dead_grave
1672 case XK_dead_grave
:
1674 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
1675 return '`'; /* '! */
1676 #ifdef XK_dead_diaeresis
1677 case XK_dead_diaeresis
:
1679 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
1680 return 0xa8; /* ': */
1681 #ifdef XK_dead_cedilla
1682 case XK_dead_cedilla
:
1683 return 0xb8; /* ', */
1685 #ifdef XK_dead_macron
1686 case XK_dead_macron
:
1687 return '-'; /* 'm isn't defined on iso-8859-x */
1689 #ifdef XK_dead_breve
1690 case XK_dead_breve
:
1691 return 0xa2; /* '( */
1693 #ifdef XK_dead_abovedot
1694 case XK_dead_abovedot
:
1695 return 0xff; /* '. */
1697 #ifdef XK_dead_abovering
1698 case XK_dead_abovering
:
1699 return '0'; /* '0 isn't defined on iso-8859-x */
1701 #ifdef XK_dead_doubleacute
1702 case XK_dead_doubleacute
:
1703 return 0xbd; /* '" */
1705 #ifdef XK_dead_caron
1706 case XK_dead_caron
:
1707 return 0xb7; /* '< */
1709 #ifdef XK_dead_ogonek
1710 case XK_dead_ogonek
:
1711 return 0xb2; /* '; */
1713 /* FIXME: I don't know this three.
1716 case XK_dead_voiced_sound :
1718 case XK_dead_semivoiced_sound :
1722 TRACE("no character for dead keysym 0x%08lx\n",keysym
);
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:
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();
1754 if (scanCode
& 0x8000)
1756 TRACE("Key UP, doing nothing\n" );
1759 e
.display
= display
;
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
);
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
);
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();
1824 dead_char
= KEYBOARD_MapDeadKeysym(keysym
);
1827 MultiByteToWideChar(main_key_tab
[kbd_layout
].layout_cp
, 0, &dead_char
, 1, bufW
, bufW_size
);
1834 ksname
= TSXKeysymToString(keysym
);
1837 if ((keysym
>> 8) != 0xff)
1839 ERR("Please report: no char for keysym %04lX (%s) :\n",
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
))
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')))
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
)
1876 else if((lpKeyState
[VK_SHIFT
] & 0x80) /* Shift is pressed */
1877 && (keysym
== XK_KP_Decimal
))
1883 /* perform translation to unicode */
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)");
1897 /***********************************************************************
1900 void X11DRV_Beep(void)
1902 TSXBell(thread_display(), 0);