keyboard.c 108 KB
Newer Older
1
/*
2
 * X11 keyboard driver
3 4
 *
 * Copyright 1993 Bob Amstadt
5
 * Copyright 1996 Albrecht Kleine
6 7 8
 * Copyright 1997 David Faure
 * Copyright 1998 Morten Welinder
 * Copyright 1998 Ulrich Weigand
9
 * Copyright 1999 Ove Kåven
10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 25 26 27 28 29
 */

#include "config.h"

#include <X11/Xatom.h>
#include <X11/keysym.h>
30
#include <X11/Xlib.h>
31 32
#include <X11/Xresource.h>
#include <X11/Xutil.h>
33
#ifdef HAVE_X11_XKBLIB_H
34 35
#include <X11/XKBlib.h>
#endif
36

37
#include <ctype.h>
38
#include <stdarg.h>
39 40
#include <string.h>

41
#define NONAMELESSUNION
42

43
#include "windef.h"
44
#include "winbase.h"
45
#include "wingdi.h"
46
#include "winuser.h"
47
#include "winreg.h"
48
#include "winnls.h"
49
#include "ime.h"
50
#include "x11drv.h"
51
#include "wine/server.h"
52
#include "wine/unicode.h"
53
#include "wine/debug.h"
54

55 56 57 58 59 60
/* log format (add 0-padding as appropriate):
    keycode  %u  as in output from xev
    keysym   %lx as in X11/keysymdef.h
    vkey     %X  as in winuser.h
    scancode %x
*/
61 62
WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
WINE_DECLARE_DEBUG_CHANNEL(key);
63

64
static int min_keycode, max_keycode, keysyms_per_keycode;
65
static KeySym *key_mapping;
66
static WORD keyc2vkey[256], keyc2scan[256];
67

68
static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */
69

70 71 72 73 74 75 76 77 78
static CRITICAL_SECTION kbd_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &kbd_section,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": kbd_section") }
};
static CRITICAL_SECTION kbd_section = { &critsect_debug, -1, 0, 0, 0, 0 };

79 80
static char KEYBOARD_MapDeadKeysym(KeySym keysym);

81
/* Keyboard translation tables */
82
#define MAIN_LEN 49
83
static const WORD main_key_scan_qwerty[MAIN_LEN] =
84 85
{
/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
86
 /* `    1    2    3    4    5    6    7    8    9    0    -    = */
87
   0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
88
 /* q    w    e    r    t    y    u    i    o    p    [    ] */
89
   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
90
 /* a    s    d    f    g    h    j    k    l    ;    '    \ */
91
   0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
92
 /* z    x    c    v    b    n    m    ,    .    / */
93
   0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
94
   0x56 /* the 102nd key (actually to the right of l-shift) */
95 96
};

97 98 99 100 101 102 103 104 105 106 107 108 109
static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] =
{
 /* `    1    2    3    4    5    6    7    8    9    0    -    = */
   0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
 /* q    w    e    r    t    y    u    i    o    p    [    ] */
   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
 /* a    s    d    f    g    h    j    k    l    ;    '    \ */
   0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
 /* \      z    x    c    v    b    n    m    ,    .    / */
   0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
   0x56, /* the 102nd key (actually to the right of l-shift) */
};

110 111 112 113 114 115 116 117 118 119 120 121 122
static const WORD main_key_scan_dvorak[MAIN_LEN] =
{
 /* `    1    2    3    4    5    6    7    8    9    0    [    ] */
   0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x1A,0x1B,
 /* '    ,    .    p    y    f    g    c    r    l    /    = */
   0x28,0x33,0x34,0x19,0x15,0x21,0x22,0x2E,0x13,0x26,0x35,0x0D,
 /* a    o    e    u    i    d    h    t    n    s    -    \ */
   0x1E,0x18,0x12,0x16,0x17,0x20,0x23,0x14,0x31,0x1F,0x0C,0x2B,
 /* ;    q    j    k    x    b    m    w    v    z */
   0x27,0x10,0x24,0x25,0x2D,0x30,0x32,0x11,0x2F,0x2C,
   0x56 /* the 102nd key (actually to the right of l-shift) */
};

Aric Cyr's avatar
Aric Cyr committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136
static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] =
{
  /* this is my (106-key) keyboard layout, sorry if it doesn't quite match yours */
 /* 1    2    3    4    5    6    7    8    9    0    -    ^    \ */
   0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x29,
 /* q    w    e    r    t    y    u    i    o    p    @    [ */
   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
 /* a    s    d    f    g    h    j    k    l    ;    :    ] */
   0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
 /* z    x    c    v    b    n    m    ,    .    / */
   0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
   0x56 /* the 102nd key (actually to the right of l-shift) */
};

137 138 139 140 141 142 143 144 145 146 147 148 149
static const WORD main_key_scan_qwerty_macjp[MAIN_LEN] =
{
 /* 1    2    3    4    5    6    7    8    9    0    -    ^    \ */
   0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7d,
 /* q    w    e    r    t    y    u    i    o    p    @    [ */
   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
 /* a    s    d    f    g    h    j    k    l    ;    :    ] */
   0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
 /* z    x    c    v    b    n    m    ,    .    / */
   0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
   0x73 /* the 102nd key (actually to the right of l-shift) */
};

Aric Cyr's avatar
Aric Cyr committed
150

151 152
static const WORD main_key_vkey_qwerty[MAIN_LEN] =
{
153
/* NOTE: this layout must concur with the scan codes layout above */
154 155 156 157
   VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
   'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
   'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
   'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
158 159 160
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

Aric Cyr's avatar
Aric Cyr committed
161 162 163 164 165 166 167 168 169 170
static const WORD main_key_vkey_qwerty_jp106[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
   '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_3,
   'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
   'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
   'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

171 172 173 174 175 176 177 178 179 180
static const WORD main_key_vkey_qwerty_macjp[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
   '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_7,VK_OEM_5,
   'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_3,VK_OEM_4,
   'A','S','D','F','G','H','J','K','L',VK_OEM_PLUS,VK_OEM_1,VK_OEM_6,
   'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

181 182 183
static const WORD main_key_vkey_qwerty_v2[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
184 185 186 187
   VK_OEM_5,'1','2','3','4','5','6','7','8','9','0',VK_OEM_PLUS,VK_OEM_4,
   'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
   'A','S','D','F','G','H','J','K','L',VK_OEM_3,VK_OEM_7,VK_OEM_2,
   'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_MINUS,
188 189 190
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

191 192 193
static const WORD main_key_vkey_qwertz[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
194 195 196 197
   VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
   'Q','W','E','R','T','Z','U','I','O','P',VK_OEM_4,VK_OEM_6,
   'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_7,VK_OEM_5,
   'Y','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
198 199 200
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

201 202 203
static const WORD main_key_vkey_abnt_qwerty[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
204 205 206 207
   VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,
   'Q','W','E','R','T','Y','U','I','O','P',VK_OEM_4,VK_OEM_6,
   'A','S','D','F','G','H','J','K','L',VK_OEM_1,VK_OEM_8,VK_OEM_5,
   VK_OEM_7,'Z','X','C','V','B','N','M',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,
208 209 210
   VK_OEM_102, /* the 102nd key (actually to the right of l-shift) */
};

211 212 213
static const WORD main_key_vkey_azerty[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
214 215 216 217
   VK_OEM_7,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_PLUS,
   'A','Z','E','R','T','Y','U','I','O','P',VK_OEM_6,VK_OEM_1,
   'Q','S','D','F','G','H','J','K','L','M',VK_OEM_3,VK_OEM_5,
   'W','X','C','V','B','N',VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_8,
218 219 220
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

221 222 223
static const WORD main_key_vkey_dvorak[MAIN_LEN] =
{
/* NOTE: this layout must concur with the scan codes layout above */
224 225 226 227
   VK_OEM_3,'1','2','3','4','5','6','7','8','9','0',VK_OEM_4,VK_OEM_6,
   VK_OEM_7,VK_OEM_COMMA,VK_OEM_PERIOD,'P','Y','F','G','C','R','L',VK_OEM_2,VK_OEM_PLUS,
   'A','O','E','U','I','D','H','T','N','S',VK_OEM_MINUS,VK_OEM_5,
   VK_OEM_1,'Q','J','K','X','B','M','W','V','Z',
228 229 230
   VK_OEM_102 /* the 102nd key (actually to the right of l-shift) */
};

231 232
/*** DEFINE YOUR NEW LANGUAGE-SPECIFIC MAPPINGS BELOW, SEE EXISTING TABLES */

233 234
/* the VK mappings for the main keyboard will be auto-assigned as before,
   so what we have here is just the character tables */
235
/* order: Normal, Shift, AltGr, Shift-AltGr */
236 237 238
/* We recommend you write just what is guaranteed to be correct (i.e. what's
   written on the keycaps), not the bunch of special characters behind AltGr
   and Shift-AltGr if it can vary among different X servers */
239 240
/* These tables serve to guess the keyboard type and scancode mapping.
   Complete modeling is not important, identification/discrimination is. */
241 242
/* Remember that your 102nd key (to the right of l-shift) should be on a
   separate line, see existing tables */
243
/* If Wine fails to match your new table, use WINEDEBUG=+key to find out why */
244 245 246
/* Remember to also add your new table to the layout index table far below! */

/*** United States keyboard layout (mostly contributed by Uwe Bonnes) */
247 248
static const char main_key_US[MAIN_LEN][4] =
{
249 250 251 252 253 254
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?"
};

255 256 257 258 259 260 261
/*** United States keyboard layout (phantom key version) */
/* (XFree86 reports the <> key even if it's not physically there) */
static const char main_key_US_phantom[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
Mike McCormack's avatar
Mike McCormack committed
262
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
263 264 265
 "<>" /* the phantom key */
};

266 267 268 269 270 271 272 273 274
/*** United States keyboard layout (dvorak version) */
static const char main_key_US_dvorak[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","[{","]}",
 "'\"",",<",".>","pP","yY","fF","gG","cC","rR","lL","/?","=+",
 "aA","oO","eE","uU","iI","dD","hH","tT","nN","sS","-_","\\|",
 ";:","qQ","jJ","kK","xX","bB","mM","wW","vV","zZ"
};

275 276 277
/*** British keyboard layout */
static const char main_key_UK[MAIN_LEN][4] =
{
278
 "`","1!","2\"","3\xa3","4$","5%","6^","7&","8*","9(","0)","-_","=+",
279 280 281 282 283 284
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'@","#~",
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
 "\\|"
};

285
/*** French keyboard layout (setxkbmap fr) */
286 287
static const char main_key_FR[MAIN_LEN][4] =
{
288 289 290 291
 "\xb2","&1","\xe9""2","\"3","'4","(5","-6","\xe8""7","_8","\xe7""9","\xe0""0",")\xb0","=+",
 "aA","zZ","eE","rR","tT","yY","uU","iI","oO","pP","^\xa8","$\xa3",
 "qQ","sS","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%","*\xb5",
 "wW","xX","cC","vV","bB","nN",",?",";.",":/","!\xa7",
292 293 294
 "<>"
};

295
/*** Icelandic keyboard layout (setxkbmap is) */
296 297
static const char main_key_IS[MAIN_LEN][4] =
{
298 299 300 301
 "\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","\xf6\xd6","-_",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xf0\xd0","'?",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xb4\xc4","+*",
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","\xfe\xde",
302
 "<>"
303 304
};

305 306 307 308 309 310 311 312 313 314
/* All german keyb layout tables have the acute/apostrophe symbol next to
 * the BACKSPACE key removed (replaced with NULL which is ignored by the
 * detection code).
 * This was done because the mapping of the acute (and apostrophe) is done
 * differently in various xkb-data/xkeyboard-config versions. Some replace
 * the acute with a normal apostrophe, so that the apostrophe is found twice
 * on the keyboard (one next to BACKSPACE and one next to ENTER).
 * Others put the acute and grave accents on the key left of BACKSPACE.
 * More information on the fd.o bugtracker:
 * https://bugs.freedesktop.org/show_bug.cgi?id=11514
315 316
 * Keys reachable via AltGr (@, [], ~, \, |, {}) differ completely
 * among PC and Mac keyboards, so these are not listed.
317 318
 */

319
/*** German keyboard layout (setxkbmap de [-variant nodeadkeys|deadacute etc.]) */
320 321
static const char main_key_DE[MAIN_LEN][4] =
{
322 323 324
 "^\xb0","1!","2\"","3\xa7","4$","5%","6&","7/","8(","9)","0=","\xdf?","",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xdc","+*",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","#'",
325
 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
326 327 328
 "<>"
};

329
/*** Swiss German keyboard layout (setxkbmap ch -variant de) */
330 331
static const char main_key_SG[MAIN_LEN][4] =
{
332 333 334
 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfc\xe8","\xa8!",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xe9","\xe4\xe0","$\xa3",
335
 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
336
 "<>"
337 338
};

339
/*** Swiss French keyboard layout (setxkbmap ch -variant fr) */
340 341
static const char main_key_SF[MAIN_LEN][4] =
{
342 343 344
 "\xa7\xb0","1+","2\"","3*","4\xe7","5%","6&","7/","8(","9)","0=","'?","^`",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xe8\xfc","\xa8!",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xf6","\xe0\xe4","$\xa3",
345
 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
346
 "<>"
347 348
};

349
/*** Norwegian keyboard layout (contributed by Ove Kåven) */
350 351
static const char main_key_NO[MAIN_LEN][4] =
{
352 353 354
 "|\xa7","1!","2\"@","3#\xa3","4\xa4$","5%","6&","7/{","8([","9)]","0=}","+?","\\`\xb4",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^~",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf8\xd8","\xe6\xc6","'*",
355 356 357 358
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
 "<>"
};

359
/*** Danish keyboard layout (setxkbmap dk) */
360 361
static const char main_key_DA[MAIN_LEN][4] =
{
362 363 364
 "\xbd\xa7","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe6\xc6","\xf8\xd8","'*",
365
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
366
 "<>"
367 368
};

369
/*** Swedish keyboard layout (setxkbmap se) */
370 371
static const char main_key_SE[MAIN_LEN][4] =
{
372 373 374
 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
375
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
376
 "<>"
377 378
};

379
/*** Estonian keyboard layout (setxkbmap ee) */
380 381
static const char main_key_ET[MAIN_LEN][4] =
{
382 383 384
 "\xb7~","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfc\xdc","\xf5\xd5",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
385
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
386
 "<>"
387 388
};

389
/*** Canadian French keyboard layout (setxkbmap ca_enhanced) */
390 391
static const char main_key_CF[MAIN_LEN][4] =
{
392 393
 "#|\\","1!\xb1","2\"@","3/\xa3","4$\xa2","5%\xa4","6?\xac","7&\xa6","8*\xb2","9(\xb3","0)\xbc","-_\xbd","=+\xbe",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xa7","pP\xb6","^^[","\xb8\xa8]",
394
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:~","``{","<>}",
395 396
 "zZ","xX","cC","vV","bB","nN","mM",",'-",".","\xe9\xc9",
 "\xab\xbb\xb0"
397 398
};

399 400 401 402
/*** Canadian French keyboard layout (setxkbmap ca -variant fr) */
static const char main_key_CA_fr[MAIN_LEN][4] =
{
 "#|","1!","2\"","3/","4$","5%","6?","7&","8*","9(","0)","-_","=+",
403
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","^^","\xb8\xa8",
404
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","``","<>",
405 406
 "zZ","xX","cC","vV","bB","nN","mM",",'",".","\xe9\xc9",
 "\xab\xbb"
407 408
};

409
/*** Canadian keyboard layout (setxkbmap ca) */
410 411
static const char main_key_CA[MAIN_LEN][4] =
{
412 413 414 415 416
 "/\\","1!\xb9\xa1","2@\xb2","3#\xb3\xa3","4$\xbc\xa4","5%\xbd","6?\xbe","7&","8*","9(","0)","-_","=+",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO\xf8\xd8","pP\xfe\xde","^\xa8\xa8","\xe7\xc7~",
 "aA\xe6\xc6","sS\xdf\xa7","dD\xf0\xd0","fF","gG","hH","jJ","kK","lL",";:\xb4","\xe8\xc8","\xe0\xc0",
 "zZ","xX","cC\xa2\xa9","vV","bB","nN","mM\xb5\xba",",'",".\"\xb7\xf7","\xe9\xc9",
 "\xf9\xd9"
417 418
};

419
/*** Portuguese keyboard layout (setxkbmap pt) */
420 421
static const char main_key_PT[MAIN_LEN][4] =
{
422 423 424
 "\\|","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xab\xbb",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","+*","\xb4`",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","\xba\xaa","~^",
425
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
426 427 428
 "<>"
};

429
/*** Italian keyboard layout (setxkbmap it) */
's avatar
committed
430 431
static const char main_key_IT[MAIN_LEN][4] =
{
432 433 434
 "\\|","1!","2\"","3\xa3","4$","5%","6&","7/","8(","9)","0=","'?","\xec^",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe8\xe9","+*",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf2\xe7","\xe0\xb0","\xf9\xa7",
435 436
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
 "<>"
's avatar
committed
437 438
};

439
/*** Finnish keyboard layout (setxkbmap fi) */
440 441
static const char main_key_FI[MAIN_LEN][4] =
{
442 443 444
 "\xa7\xbd","1!","2\"","3#","4\xa4","5%","6&","7/","8(","9)","0=","+?","\xb4`",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xe5\xc5","\xa8^",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf6\xd6","\xe4\xc4","'*",
445
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
446
 "<>"
447 448
};

449 450 451 452
/*** Bulgarian bds keyboard layout */
static const char main_key_BG_bds[MAIN_LEN][4] =
{
 "`~()","1!","2@2?","3#3+","4$4\"","5%","6^6=","7&7:","8*8/","9(","0)","-_-I","=+.V",
453 454 455
 "qQ,\xfb","wW\xf3\xd3","eE\xe5\xc5","rR\xe8\xc8","tT\xf8\xd8","yY\xf9\xd9","uU\xea\xca","iI\xf1\xd1","oO\xe4\xc4","pP\xe7\xc7","[{\xf6\xd6","]};",
 "aA\xfc\xdc","sS\xff\xdf","dD\xe0\xc0","fF\xee\xce","gG\xe6\xc6","hH\xe3\xc3","jJ\xf2\xd2","kK\xed\xcd","lL\xe2\xc2",";:\xec\xcc","'\"\xf7\xd7","\\|'\xdb",
 "zZ\xfe\xde","xX\xe9\xc9","cC\xfa\xda","vV\xfd\xdd","bB\xf4\xd4","nN\xf5\xd5","mM\xef\xcf",",<\xf0\xd0",".>\xeb\xcb","/?\xe1\xc1",
456 457 458 459 460 461
 "<>" /* the phantom key */
};

/*** Bulgarian phonetic keyboard layout */
static const char main_key_BG_phonetic[MAIN_LEN][4] =
{
462 463 464 465
 "`~\xf7\xd7","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
 "qQ\xff\xdf","wW\xe2\xc2","eE\xe5\xc5","rR\xf0\xd0","tT\xf2\xd2","yY\xfa\xda","uU\xf3\xd3","iI\xe8\xc8","oO\xee\xce","pP\xef\xcf","[{\xf8\xd8","]}\xf9\xd9",
 "aA\xe0\xc0","sS\xf1\xd1","dD\xe4\xc4","fF\xf4\xd4","gG\xe3\xc3","hH\xf5\xd5","jJ\xe9\xc9","kK\xea\xca","lL\xeb\xcb",";:","'\"","\\|\xfe\xde",
 "zZ\xe7\xc7","xX\xfc\xdc","cC\xf6\xd6","vV\xe6\xc6","bB\xe1\xc1","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
466 467 468
 "<>" /* the phantom key */
};

469
/*** Belarusian standard keyboard layout (contributed by Hleb Valoska) */
470
/*** It matches Belarusian layout for XKB from Alexander Mikhailian    */
471 472
static const char main_key_BY[MAIN_LEN][4] =
{
473 474 475 476
 "`~\xa3\xb3","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xae\xbe","pP\xda\xfa","[{\xc8\xe8","]}''",
 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|/|",
 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xa6\xb6","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?.,", "<>|\xa6",
477 478 479
};


480 481 482 483
/*** Russian keyboard layout (contributed by Pavel Roskin) */
static const char main_key_RU[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
484 485 486
 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?"
487 488
};

489 490 491 492
/*** Russian keyboard layout (phantom key version) */
static const char main_key_RU_phantom[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
493 494 495
 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xdf\xff",
 "aA\xc6\xe6","sS\xd9\xf9","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xdc\xfc","\\|",
 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?",
496 497 498
 "<>" /* the phantom key */
};

499 500 501 502
/*** Russian keyboard layout KOI8-R */
static const char main_key_RU_koi8r[MAIN_LEN][4] =
{
 "()","1!","2\"","3/","4$","5:","6,","7.","8;","9?","0%","-_","=+",
503 504 505
 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\|",
 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0","/?",
506 507 508
 "<>" /* the phantom key */
};

509 510 511 512
/*** Russian keyboard layout cp1251 */
static const char main_key_RU_cp1251[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
513 514 515
 "qQ\xe9\xc9","wW\xf6\xd6","eE\xf3\xd3","rR\xea\xca","tT\xe5\xc5","yY\xed\xcd","uU\xe3\xc3","iI\xf8\xd8","oO\xf9\xd9","pP\xe7\xc7","[{\xf5\xd5","]}\xfa\xda",
 "aA\xf4\xd4","sS\xfb\xdb","dD\xe2\xc2","fF\xe0\xc0","gG\xef\xcf","hH\xf0\xd0","jJ\xee\xce","kK\xeb\xcb","lL\xe4\xc4",";:\xe6\xc6","'\"\xfd\xdd","\\|",
 "zZ\xff\xdf","xX\xf7\xd7","cC\xf1\xd1","vV\xec\xcc","bB\xe8\xc8","nN\xf2\xd2","mM\xfc\xdc",",<\xe1\xc1",".>\xfe\xde","/?",
516 517 518 519 520 521 522
 "<>" /* the phantom key */
};

/*** Russian phonetic keyboard layout */
static const char main_key_RU_phonetic[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
523 524 525
 "qQ\xd1\xf1","wW\xd7\xf7","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xd9\xf9","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}\xdd\xfd",
 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xca\xea","kK\xcb\xeb","lL\xcc\xec",";:","'\"","\\|",
 "zZ\xda\xfa","xX\xd8\xf8","cC\xc3\xe3","vV\xd6\xf6","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<",".>","/?",
526 527 528
 "<>" /* the phantom key */
};

529 530 531
/*** Ukrainian keyboard layout KOI8-U */
static const char main_key_UA[MAIN_LEN][4] =
{
532 533 534 535
 "`~\xad\xbd","1!1!","2@2\"","3#3'","4$4*","5%5:","6^6,","7&7.","8*8;","9(9(","0)0)","-_-_","=+=+",
 "qQ\xca\xea","wW\xc3\xe3","eE\xd5\xf5","rR\xcb\xeb","tT\xc5\xe5","yY\xce\xee","uU\xc7\xe7","iI\xdb\xfb","oO\xdd\xfd","pP\xda\xfa","[{\xc8\xe8","]}\xa7\xb7",
 "aA\xc6\xe6","sS\xa6\xb6","dD\xd7\xf7","fF\xc1\xe1","gG\xd0\xf0","hH\xd2\xf2","jJ\xcf\xef","kK\xcc\xec","lL\xc4\xe4",";:\xd6\xf6","'\"\xa4\xb4","\\|\\|",
 "zZ\xd1\xf1","xX\xde\xfe","cC\xd3\xf3","vV\xcd\xed","bB\xc9\xe9","nN\xd4\xf4","mM\xd8\xf8",",<\xc2\xe2",".>\xc0\xe0","/?/?",
536 537 538
 "<>" /* the phantom key */
};

539 540 541 542
/*** Ukrainian keyboard layout KOI8-U by O. Nykyforchyn */
/***  (as it appears on most of keyboards sold today)   */
static const char main_key_UA_std[MAIN_LEN][4] =
{
543 544 545 546
 "\xad\xbd","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xa7\xb7",
 "\xc6\xe6","\xa6\xb6","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xa4\xb4","\\/",
 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
547 548 549 550 551 552
 "<>" /* the phantom key */
};

/*** Russian keyboard layout KOI8-R (pair to the previous) */
static const char main_key_RU_std[MAIN_LEN][4] =
{
553 554 555 556
 "\xa3\xb3","1!","2\"","3'","4;","5%","6:","7?","8*","9(","0)","-_","=+",
 "\xca\xea","\xc3\xe3","\xd5\xf5","\xcb\xeb","\xc5\xe5","\xce\xee","\xc7\xe7","\xdb\xfb","\xdd\xfd","\xda\xfa","\xc8\xe8","\xdf\xff",
 "\xc6\xe6","\xd9\xf9","\xd7\xf7","\xc1\xe1","\xd0\xf0","\xd2\xf2","\xcf\xef","\xcc\xec","\xc4\xe4","\xd6\xf6","\xdc\xfc","\\/",
 "\xd1\xf1","\xde\xfe","\xd3\xf3","\xcd\xed","\xc9\xe9","\xd4\xf4","\xd8\xf8","\xc2\xe2","\xc0\xe0",".,",
557 558 559
 "<>" /* the phantom key */
};

560
/*** Spanish keyboard layout (setxkbmap es) */
561 562
static const char main_key_ES[MAIN_LEN][4] =
{
563
 "\xba\xaa","1!","2\"","3\xb7","4$","5%","6&","7/","8(","9)","0=","'?","\xa1\xbf",
564
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","`^","+*",
565
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","\xb4\xa8","\xe7\xc7",
566 567 568 569
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
 "<>"
};

570 571 572
/*** Belgian keyboard layout ***/
static const char main_key_BE[MAIN_LEN][4] =
{
573 574 575
 "","&1|","\xe9""2@","\"3#","'4","(5","\xa7""6^","\xe8""7","!8","\xe7""9{","\xe0""0}",")\xb0","-_",
 "aA","zZ","eE\xa4","rR","tT","yY","uU","iI","oO","pP","^\xa8[","$*]",
 "qQ","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","mM","\xf9%\xb4","\xb5\xa3`",
576 577 578 579
 "wW","xX","cC","vV","bB","nN",",?",";.",":/","=+~",
 "<>\\"
};

580
/*** Hungarian keyboard layout (setxkbmap hu) */
581 582
static const char main_key_HU[MAIN_LEN][4] =
{
583 584 585
 "0\xa7","1'","2\"","3+","4!","5%","6/","7=","8(","9)","\xf6\xd6","\xfc\xdc","\xf3\xd3",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xf5\xd5","\xfa\xda",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe9\xc9","\xe1\xc1","\xfb\xdb",
586
 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
587
 "\xed\xcd"
588 589
};

590 591 592
/*** Polish (programmer's) keyboard layout ***/
static const char main_key_PL[MAIN_LEN][4] =
{
593 594 595 596
 "`~","1!","2@","3#","4$","5%","6^","7&\xa7","8*","9(","0)","-_","=+",
 "qQ","wW","eE\xea\xca","rR","tT","yY","uU","iI","oO\xf3\xd3","pP","[{","]}",
 "aA\xb1\xa1","sS\xb6\xa6","dD","fF","gG","hH","jJ","kK","lL\xb3\xa3",";:","'\"","\\|",
 "zZ\xbf\xaf","xX\xbc\xac","cC\xe6\xc6","vV","bB","nN\xf1\xd1","mM",",<",".>","/?",
597 598 599
 "<>|"
};

600
/*** Slovenian keyboard layout (setxkbmap si) ***/
Rok Mandeljc's avatar
Rok Mandeljc committed
601 602
static const char main_key_SI[MAIN_LEN][4] =
{
603 604 605
 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
606
 "yY","xX","cC","vV","bB","nN","mM",",;",".:","-_",
Rok Mandeljc's avatar
Rok Mandeljc committed
607 608 609
 "<>"
};

610 611 612 613
/*** Serbian keyboard layout (setxkbmap sr) ***/
static const char main_key_SR[MAIN_LEN][4] =
{
 "`~","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
614 615 616
 "\xa9\xb9","\xaa\xba","\xc5\xe5","\xd2\xf2","\xd4\xf4","\xda\xfa","\xd5\xf5","\xc9\xe9","\xcf\xef","\xd0\xf0","\xdb\xfb","[]",
 "\xc1\xe1","\xd3\xf3","\xc4\xe4","\xc6\xe6","\xc7\xe7","\xc8\xe8","\xa8\xb8","\xcb\xeb","\xcc\xec","\xde\xfe","\xab\xbb","-_",
 "\xa1\xb1","\xaf\xbf","\xc3\xe3","\xd7\xf7","\xc2\xe2","\xce\xee","\xcd\xed",",;",".:","\xd6\xf6",
617 618 619 620 621 622 623
 "<>" /* the phantom key */
};

/*** Serbian keyboard layout (setxkbmap us,sr) ***/
static const char main_key_US_SR[MAIN_LEN][4] =
{
 "`~","1!","2@2\"","3#","4$","5%","6^6&","7&7/","8*8(","9(9)","0)0=","-_'?","=++*",
624 625 626
 "qQ\xa9\xb9","wW\xaa\xba","eE\xc5\xe5","rR\xd2\xf2","tT\xd4\xf4","yY\xda\xfa","uU\xd5\xf5","iI\xc9\xe9","oO\xcf\xef","pP\xd0\xf0","[{\xdb\xfb","]}[]",
 "aA\xc1\xe1","sS\xd3\xf3","dD\xc4\xe4","fF\xc6\xe6","gG\xc7\xe7","hH\xc8\xe8","jJ\xa8\xb8","kK\xcb\xeb","lL\xcc\xec",";:\xde\xfe","'\"\xab\xbb","\\|-_",
 "zZ\xa1\xb1","xX\xaf\xbf","cC\xc3\xe3","vV\xd7\xf7","bB\xc2\xe2","nN\xce\xee","mM\xcd\xed",",<,;",".>.:","/?\xd6\xf6",
627 628 629
 "<>" /* the phantom key */
};

630 631 632 633
/*** Croatian keyboard layout specific for me <jelly@srk.fer.hr> ***/
static const char main_key_HR_jelly[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
634 635
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{\xb9\xa9","]}\xf0\xd0",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:\xe8\xc8","'\"\xe6\xc6","\\|\xbe\xae",
636 637 638 639
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
 "<>|"
};

640
/*** Croatian keyboard layout (setxkbmap hr) ***/
641 642
static const char main_key_HR[MAIN_LEN][4] =
{
643 644 645
 "\xb8\xa8","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","+*",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xb9\xa9","\xf0\xd0",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe8\xc8","\xe6\xc6","\xbe\xae",
646
 "yY","xX","cC","vV","bB","nN","mM",",;",".:","/?",
647 648 649
 "<>"
};

650 651 652 653 654 655 656 657 658 659
/*** Japanese 106 keyboard layout ***/
static const char main_key_JA_jp106[MAIN_LEN][4] =
{
 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0~","-=","^~","\\|",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
 "\\_",
};

660 661 662 663 664 665 666 667 668
static const char main_key_JA_macjp[MAIN_LEN][4] =
{
 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^~","\\|",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@`","[{",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
 "__",
};

669 670 671 672 673 674 675 676 677 678
/*** Japanese pc98x1 keyboard layout ***/
static const char main_key_JA_pc98x1[MAIN_LEN][4] =
{
 "1!","2\"","3#","4$","5%","6&","7'","8(","9)","0","-=","^`","\\|",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","@~","[{",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";+",":*","]}",
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
 "\\_",
};

679 680 681
/*** Brazilian ABNT-2 keyboard layout (contributed by Raul Gomes Fernandes) */
static const char main_key_PT_br[MAIN_LEN][4] =
{
682 683 684
 "'\"","1!","2@","3#","4$","5%","6\xa8","7&","8*","9(","0)","-_","=+",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4`","[{",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xe7\xc7","~^","]}",
685
 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?",
686 687 688 689 690 691 692 693
};

/*** Brazilian ABNT-2 keyboard layout with <ALT GR> (contributed by Mauro Carvalho Chehab) */
static const char main_key_PT_br_alt_gr[MAIN_LEN][4] =
{
 "'\"","1!9","2@2","3#3","4$#","5%\"","6(,","7&","8*","9(","0)","-_","=+'",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","4`","[{*",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","gG","~^","]}:",
694
 "\\|","zZ","xX","cC","vV","bB","nN","mM",",<",".>",";:","/?0"
695
};
696

697 698 699 700 701 702 703 704 705
/*** US international keyboard layout (contributed by Gustavo Noronha (kov@debian.org)) */
static const char main_key_US_intl[MAIN_LEN][4] =
{
  "`~", "1!", "2@", "3#", "4$", "5%", "6^", "7&", "8*", "9(", "0)", "-_", "=+", "\\|",
  "qQ", "wW", "eE", "rR", "tT", "yY", "uU", "iI", "oO", "pP", "[{", "]}",
  "aA", "sS", "dD", "fF", "gG", "hH", "jJ", "kK", "lL", ";:", "'\"",
  "zZ", "xX", "cC", "vV", "bB", "nN", "mM", ",<", ".>", "/?"
};

706 707 708 709 710
/*** Slovak keyboard layout (see cssk_ibm(sk_qwerty) in xkbsel)
  - dead_abovering replaced with degree - no symbol in iso8859-2
  - brokenbar replaced with bar					*/
static const char main_key_SK[MAIN_LEN][4] =
{
711 712 713
 ";0","+1","\xb5""2","\xb9""3","\xe8""4","\xbb""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","'v",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/","\xe4(",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf4\"","\xa7!","\xf2)",
714 715
 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
 "<>"
716 717
};

718 719 720
/*** Czech keyboard layout (setxkbmap cz) */
static const char main_key_CZ[MAIN_LEN][4] =
{
721 722 723
 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
 "qQ","wW","eE","rR","tT","zZ","uU","iI","oO","pP","\xfa/",")(",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
724 725 726 727 728 729 730
 "yY","xX","cC","vV","bB","nN","mM",",?",".:","-_",
 "\\"
};

/*** Czech keyboard layout (setxkbmap cz_qwerty) */
static const char main_key_CZ_qwerty[MAIN_LEN][4] =
{
731 732 733
 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0","=%","\xb4\xb7",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/",")(",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf9\"","\xa7!","\xa8'",
734 735 736 737
 "zZ","xX","cC","vV","bB","nN","mM",",?",".:","-_",
 "\\"
};

738 739 740 741
/*** Slovak and Czech (programmer's) keyboard layout (see cssk_dual(cs_sk_ucw)) */
static const char main_key_SK_prog[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
742 743 744
 "qQ\xe4\xc4","wW\xec\xcc","eE\xe9\xc9","rR\xf8\xd8","tT\xbb\xab","yY\xfd\xdd","uU\xf9\xd9","iI\xed\xcd","oO\xf3\xd3","pP\xf6\xd6","[{","]}",
 "aA\xe1\xc1","sS\xb9\xa9","dD\xef\xcf","fF\xeb\xcb","gG\xe0\xc0","hH\xfa\xda","jJ\xfc\xdc","kK\xf4\xd4","lL\xb5\xa5",";:","'\"","\\|",
 "zZ\xbe\xae","xX\xa4","cC\xe8\xc8","vV\xe7\xc7","bB","nN\xf2\xd2","mM\xe5\xc5",",<",".>","/?",
745 746 747 748 749 750
 "<>"
};

/*** Czech keyboard layout (see cssk_ibm(cs_qwerty) in xkbsel) */
static const char main_key_CS[MAIN_LEN][4] =
{
751 752 753
 ";","+1","\xec""2","\xb9""3","\xe8""4","\xf8""5","\xbe""6","\xfd""7","\xe1""8","\xed""9","\xe9""0\xbd)","=%","",
 "qQ\\","wW|","eE","rR","tT","yY","uU","iI","oO","pP","\xfa/[{",")(]}",
 "aA","sS\xf0","dD\xd0","fF[","gG]","hH","jJ","kK\xb3","lL\xa3","\xf9\"$","\xa7!\xdf","\xa8'",
754 755 756 757
 "zZ>","xX#","cC&","vV@","bB{","nN}","mM",",?<",".:>","-_*",
 "<>\\|"
};

758 759 760
/*** Latin American keyboard layout (contributed by Gabriel Orlando Garcia) */
static const char main_key_LA[MAIN_LEN][4] =
{
761 762 763
 "|\xb0","1!","2\"","3#","4$","5%","6&","7/","8(","9)","0=","'?","\xbf\xa1",
 "qQ@","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xb4\xa8","+*",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xf1\xd1","{[^","}]",
764 765 766
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
 "<>"
};
767

768
/*** Lithuanian keyboard layout (setxkbmap lt) */
769 770
static const char main_key_LT_B[MAIN_LEN][4] =
{
771
 "`~","\xe0\xc0","\xe8\xc8","\xe6\xc6","\xeb\xcb","\xe1\xc1","\xf0\xd0","\xf8\xd8","\xfb\xdb","\xa5(","\xb4)","-_","\xfe\xde",
772
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","[{","]}",
773
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL",";:","'\"","\\|",
774
 "zZ","xX","cC","vV","bB","nN","mM",",<",".>","/?",
775
 "\xaa\xac"
776 777
};

778 779 780
/*** Turkish keyboard Layout */
static const char main_key_TK[MAIN_LEN][4] =
{
781 782 783 784
"\"\xe9","1!","2'","3^#","4+$","5%","6&","7/{","8([","9)]","0=}","*?\\","-_",
"qQ@","wW","eE","rR","tT","yY","uU","\xfdI\xee","oO","pP","\xf0\xd0","\xfc\xdc~",
"aA\xe6","sS\xdf","dD","fF","gG","hH","jJ","kK","lL","\xfe\xde","i\xdd",",;`",
"zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:"
785 786
};

787 788 789 790
/*** Turkish keyboard layout (setxkbmap tr) */
static const char main_key_TR[MAIN_LEN][4] =
{
"\"\\","1!","2'","3^","4+","5%","6&","7/","8(","9)","0=","*?","-_",
791
"qQ","wW","eE","rR","tT","yY","uU","\xb9I","oO","pP","\xbb\xab","\xfc\xdc",
792
"aA","sS","dD","fF","gG","hH","jJ","kK","lL","\xba\xaa","i\0",",;",
793
"zZ","xX","cC","vV","bB","nN","mM","\xf6\xd6","\xe7\xc7",".:",
794 795 796
"<>"
};

797 798 799 800
/*** Turkish F keyboard layout (setxkbmap trf) */
static const char main_key_TR_F[MAIN_LEN][4] =
{
"+*","1!","2\"","3^#","4$","5%","6&","7'","8(","9)","0=","/?","-_",
801
"fF","gG","\xbb\xab","\xb9I","oO","dD","rR","nN","hH","pP","qQ","wW",
802 803
"uU","i\0","eE","aA","\xfc\xdc","tT","kK","mM","lL","yY","\xba\xaa","xX",
"jJ","\xf6\xd6","vV","cC","\xe7\xc7","zZ","sS","bB",".:",",;",
804 805 806
"<>"
};

807
/*** Israelian keyboard layout (setxkbmap us,il) */
808 809
static const char main_key_IL[MAIN_LEN][4] =
{
810
 "`~;","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
811 812 813
 "qQ/","wW'","eE\xf7","rR\xf8","tT\xe0","yY\xe8","uU\xe5","iI\xef","oO\xed","pP\xf4","[{","]}",
 "aA\xf9","sS\xe3","dD\xe2","fF\xeb","gG\xf2","hH\xe9","jJ\xe7","kK\xec","lL\xea",";:\xf3","\'\",","\\|",
 "zZ\xe6","xX\xf1","cC\xe1","vV\xe4","bB\xf0","nN\xee","mM\xf6",",<\xfa",".>\xf5","/?.",
814 815 816 817 818 819 820
 "<>"
};

/*** Israelian phonetic keyboard layout (setxkbmap us,il_phonetic) */
static const char main_key_IL_phonetic[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
821 822 823
 "qQ\xf7","wW\xe5","eE\xe0","rR\xf8","tT\xfa","yY\xf2","uU\xe5","iI\xe9","oO\xf1","pP\xf4","[{","]}",
 "aA\xe0","sS\xf9","dD\xe3","fF\xf4","gG\xe2","hH\xe4","jJ\xe9","kK\xeb","lL\xec",";:","'\"","\\|",
 "zZ\xe6","xX\xe7","cC\xf6","vV\xe5","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
824 825 826 827 828 829 830
 "<>"
};

/*** Israelian Saharon keyboard layout (setxkbmap -symbols "us(pc105)+il_saharon") */
static const char main_key_IL_saharon[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
831 832 833
 "qQ\xf7","wW\xf1","eE","rR\xf8","tT\xe8","yY\xe3","uU","iI","oO","pP\xf4","[{","]}",
 "aA\xe0","sS\xe5","dD\xec","fF\xfa","gG\xe2","hH\xe4","jJ\xf9","kK\xeb","lL\xe9",";:","'\"","\\|",
 "zZ\xe6","xX\xe7","cC\xf6","vV\xf2","bB\xe1","nN\xf0","mM\xee",",<",".>","/?",
834
 "<>"
835 836
};

837 838 839 840 841 842
/*** Greek keyboard layout (contributed by Kriton Kyrimis <kyrimis@cti.gr>)
  Greek characters for "wW" and "sS" are omitted to not produce a mismatch
  message since they have different characters in gr and el XFree86 layouts. */
static const char main_key_EL[MAIN_LEN][4] =
{
 "`~","1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+",
843 844 845
 "qQ;:","wW","eE\xe5\xc5","rR\xf1\xd1","tT\xf4\xd4","yY\xf5\xd5","uU\xe8\xc8","iI\xe9\xc9","oO\xef\xcf","pP\xf0\xd0","[{","]}",
 "aA\xe1\xc1","sS","dD\xe4\xc4","fF\xf6\xd6","gG\xe3\xc3","hH\xe7\xc7","jJ\xee\xce","kK\xea\xca","lL\xeb\xcb",";:\xb4\xa8","'\"","\\|",
 "zZ\xe6\xc6","xX\xf7\xd7","cC\xf8\xd8","vV\xf9\xd9","bB\xe2\xc2","nN\xed\xcd","mM\xec\xcc",",<",".>","/?",
846 847 848
 "<>"
};

849 850 851
/*** Thai (Kedmanee) keyboard layout by Supphachoke Suntiwichaya <mrchoke@opentle.org> */
static const char main_key_th[MAIN_LEN][4] =
{
852 853 854 855
 "`~_%","1!\xe5+","2@/\xf1","3#-\xf2","4$\xc0\xf3","5%\xb6\xf4","6^\xd8\xd9","7&\xd6\xdf","8*\xa4\xf5","9(\xb5\xf6","0)\xa8\xf7","-_\xa2\xf8","=+\xaa\xf9",
 "qQ\xe6\xf0","wW\xe4\"","eE\xd3\xae","rR\xbe\xb1","tT\xd0\xb8","yY\xd1\xed","uU\xd5\xea","iI\xc3\xb3","oO\xb9\xcf","pP\xc2\xad","[{\xba\xb0","]}\xc5,",
 "aA\xbf\xc4","sS\xcb\xa6","dD\xa1\xaf","fF\xb4\xe2","gG\xe0\xac","hH\xe9\xe7","jJ\xe8\xeb","kK\xd2\xc9","lL\xca\xc8",";:\xc7\xab","\'\"\xa7.","\\|\xa3\xa5",
 "zZ\xbc(","xX\xbb)","cC\xe1\xa9","vV\xcd\xce","bB\xda","nN\xd7\xec","mM\xb7?",",<\xc1\xb2",".>\xe3\xcc","/?\xbd\xc6"
856 857
}; 

858 859 860 861 862 863 864 865 866 867
/*** VNC keyboard layout */
static const WORD main_key_scan_vnc[MAIN_LEN] =
{
   0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B,
   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,
   0x56
};

static const WORD main_key_vkey_vnc[MAIN_LEN] =
{
868 869
   '1','2','3','4','5','6','7','8','9','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,
   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
870 871 872 873 874 875 876 877 878
   VK_OEM_102
};

static const char main_key_vnc[MAIN_LEN][4] =
{
 "1!","2@","3#","4$","5%","6^","7&","8*","9(","0)","-_","=+","[{","]}",";:","'\"","`~",",<",".>","/?","\\|",
 "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"
};

879 880 881
/*** Dutch keyboard layout (setxkbmap nl) ***/
static const char main_key_NL[MAIN_LEN][4] =
{
882 883 884
 "@\xa7","1!","2\"","3#","4$","5%","6&","7_","8(","9)","0'","/?","\xb0~",
 "qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","\xa8~","*|",
 "aA","sS","dD","fF","gG","hH","jJ","kK","lL","+\xb1","'`","<>",
885 886 887 888 889 890
 "zZ","xX","cC","vV","bB","nN","mM",",;",".:","-=",
 "[]"
};



891
/*** Layout table. Add your keyboard mappings to this list */
892
static const struct {
893 894
    LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
                 in the appropriate dlls/kernel/nls/.nls file */
895 896 897 898
    const char *comment;
    const char (*key)[MAIN_LEN][4];
    const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
    const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
899
} main_key_tab[]={
900 901 902 903 904 905 906 907 908 909 910 911 912 913
 {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
 {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
 {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
 {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
914
 {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
915
 {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
916 917 918 919 920 921 922 923 924 925 926 927 928 929
 {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
 {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
 {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
 {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
930 931
 {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
932 933 934 935 936 937
 {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
938 939
 {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
 {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
940 941
 {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
Aric Cyr's avatar
Aric Cyr committed
942
 {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
943
 {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_macjp, &main_key_vkey_qwerty_macjp},
944
 {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
945 946 947 948 949 950 951 952
 {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
 {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
953
 {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
954
 {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
955 956 957 958 959 960
 {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
 {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 {0x041e, "Thai (Kedmanee)  keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
961
 {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
962 963

 {0, NULL, NULL, NULL, NULL} /* sentinel */
964 965 966 967 968 969 970 971 972
};
static unsigned kbd_layout=0; /* index into above table of layouts */

/* maybe more of these scancodes should be extended? */
                /* extended must be set for ALT_R, CTRL_R,
                   INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
                   keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
                /* FIXME should we set extended bit for NumLock ? My
                 * Windows does ... DF */
973 974 975
                /* Yes, to distinguish based on scan codes, also
                   for PrtScn key ... GA */

976
static const WORD nonchar_key_vkey[256] =
977
{
978 979 980
    /* unused */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF00 */
    /* special keys */
981 982
    VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
    0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
983
    0, 0, 0, VK_ESCAPE, 0, 0, 0, 0,                             /* FF18 */
984 985 986 987 988 989
    /* Japanese special keys */
    0, VK_KANJI, VK_NONCONVERT, VK_CONVERT,                     /* FF20 */
    VK_DBE_ROMAN, 0, 0, VK_DBE_HIRAGANA,
    0, 0, VK_DBE_SBCSCHAR, 0, 0, 0, 0, 0,                       /* FF28 */
    /* Korean special keys (FF31-) */
    VK_DBE_ALPHANUMERIC, VK_HANGUL, 0, 0, VK_HANJA, 0, 0, 0,    /* FF30 */
990
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF38 */
991
    /* unused */
992 993 994 995 996 997 998
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF40 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF48 */
    /* cursor keys */
    VK_HOME, VK_LEFT, VK_UP, VK_RIGHT,                          /* FF50 */
    VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF58 */
    /* misc keys */
999
    VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0,0,0, VK_APPS, /* FF60 */
1000
    0, VK_CANCEL, VK_HELP, VK_CANCEL, 0, 0, 0, 0,               /* FF68 */
1001 1002 1003
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF70 */
    /* keypad keys */
    0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK,                            /* FF78 */
1004 1005 1006
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
    0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
    0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,                     /* FF90 */
1007
    VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT,                       /* FF98 */
1008
    VK_END, VK_CLEAR, VK_INSERT, VK_DELETE,
1009
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
1010
    0, 0, VK_MULTIPLY, VK_ADD,                                  /* FFA8 */
1011 1012 1013 1014 1015
    /* Windows always generates VK_DECIMAL for Del/. on keypad while some
     * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
     * in order to produce a locale dependent numeric separator.
     */
    VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
1016 1017
    VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,             /* FFB0 */
    VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
1018
    VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, VK_OEM_NEC_EQUAL,          /* FFB8 */
1019 1020
    /* function keys */
    VK_F1, VK_F2,
1021
    VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
1022 1023
    VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, /* FFC8 */
    VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,       /* FFD0 */
1024 1025
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFD8 */
    /* modifier keys */
1026
    0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL,                       /* FFE0 */
1027 1028
    VK_RCONTROL, VK_CAPITAL, 0, VK_LMENU,
    VK_RMENU, VK_LMENU, VK_RMENU, VK_LWIN, VK_RWIN, 0, 0, 0,    /* FFE8 */
1029 1030
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFF0 */
    0, 0, 0, 0, 0, 0, 0, VK_DELETE                              /* FFF8 */
1031
};
1032

1033 1034 1035 1036 1037 1038 1039 1040
static const WORD nonchar_key_scan[256] =
{
    /* unused */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF00 */
    /* special keys */
    0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00,           /* FF08 */
    0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00,              /* FF10 */
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,              /* FF18 */
1041 1042 1043 1044 1045
    /* Japanese special keys */
    0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70,              /* FF20 */
    0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF28 */
    /* Korean special keys (FF31-) */
    0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF30 */
1046
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF38 */
1047
    /* unused */
1048 1049 1050 1051 1052 1053
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF40 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF48 */
    /* cursor keys */
    0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F,      /* FF50 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF58 */
    /* misc keys */
1054
    /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D,     /* FF60 */
1055 1056 1057
    /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00,       /* FF68 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF70 */
    /* keypad keys */
1058
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145,             /* FF78 */
1059 1060 1061 1062 1063
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FF80 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00,             /* FF88 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48,              /* FF90 */
    0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53,              /* FF98 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFA0 */
1064
    0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135,             /* FFA8 */
1065 1066 1067 1068 1069
    0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47,              /* FFB0 */
    0x48, 0x49, 0x00, 0x00, 0x00, 0x00,                          /* FFB8 */
    /* function keys */
    0x3B, 0x3C,
    0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44,              /* FFC0 */
1070
    0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00,              /* FFC8 */
1071 1072 1073
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFD0 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFD8 */
    /* modifier keys */
1074
    0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38,            /* FFE0 */
1075
    0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00,          /* FFE8 */
1076 1077
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,              /* FFF0 */
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153              /* FFF8 */
1078
};
1079

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
static const WORD xfree86_vendor_key_vkey[256] =
{
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF00 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF08 */
    0, VK_VOLUME_DOWN, VK_VOLUME_MUTE, VK_VOLUME_UP,            /* 1008FF10 */
    VK_MEDIA_PLAY_PAUSE, VK_MEDIA_STOP,
    VK_MEDIA_PREV_TRACK, VK_MEDIA_NEXT_TRACK,
    0, VK_LAUNCH_MAIL, 0, VK_BROWSER_SEARCH,                    /* 1008FF18 */
    0, 0, 0, VK_BROWSER_HOME,
    0, 0, 0, 0, 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD,      /* 1008FF20 */
    VK_BROWSER_STOP, VK_BROWSER_REFRESH, 0, 0, 0, 0, 0, 0,      /* 1008FF28 */
    VK_BROWSER_FAVORITES, 0, VK_LAUNCH_MEDIA_SELECT, 0,         /* 1008FF30 */
    0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF38 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF40 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF48 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF50 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF58 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF60 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF68 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF70 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF78 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF80 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF88 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF90 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FF98 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFA0 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFA8 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFB0 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFB8 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFC0 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFC8 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFD0 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFD8 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFE0 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFE8 */
    0, 0, 0, 0, 0, 0, 0, 0,                                     /* 1008FFF0 */
    0, 0, 0, 0, 0, 0, 0, 0                                      /* 1008FFF8 */
};
1119

1120 1121 1122 1123 1124
static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index )
{
#ifdef HAVE_XKB
    if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index);
#endif
1125
    return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index];
1126 1127
}

1128
/* Returns the Windows virtual key code associated with the X event <e> */
1129
/* kbd_section must be held */
1130
static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
1131
{
1132
    KeySym keysym = 0;
1133 1134
    Status status;
    char buf[24];
1135

1136 1137
    /* Clients should pass only KeyPress events to XmbLookupString */
    if (xic && e->type == KeyPress)
1138
        XmbLookupString(xic, e, buf, sizeof(buf), &keysym, &status);
1139
    else
1140
        XLookupString(e, buf, sizeof(buf), &keysym, NULL);
1141

1142 1143 1144
    if ((e->state & NumLockMask) &&
        (keysym == XK_KP_Separator || keysym == XK_KP_Decimal ||
         (keysym >= XK_KP_0 && keysym <= XK_KP_9)))
1145 1146
        /* Only the Keypad keys 0-9 and . send different keysyms
         * depending on the NumLock state */
1147
        return nonchar_key_vkey[keysym & 0xFF];
1148

1149 1150 1151 1152 1153
    /* Pressing the Pause/Break key alone produces VK_PAUSE vkey, while
     * pressing Ctrl+Pause/Break produces VK_CANCEL. */
    if ((e->state & ControlMask) && (keysym == XK_Break))
        return VK_CANCEL;

1154
    TRACE_(key)("e->keycode = %u\n", e->keycode);
1155

1156 1157 1158
    return keyc2vkey[e->keycode];
}

1159 1160

/***********************************************************************
1161
 *           X11DRV_send_keyboard_input
1162
 */
1163
static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time )
1164
{
1165
    INPUT input;
1166

1167
    TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags );
1168

1169
    input.type             = INPUT_KEYBOARD;
1170 1171 1172
    input.u.ki.wVk         = vkey;
    input.u.ki.wScan       = scan;
    input.u.ki.dwFlags     = flags;
1173
    input.u.ki.time        = time;
1174
    input.u.ki.dwExtraInfo = 0;
1175

1176
    __wine_send_input( hwnd, &input );
1177 1178 1179
}


1180
/***********************************************************************
1181
 *           get_async_key_state
1182
 */
1183
static BOOL get_async_key_state( BYTE state[256] )
1184
{
1185
    BOOL ret;
1186

1187 1188 1189 1190 1191 1192
    SERVER_START_REQ( get_key_state )
    {
        req->tid = 0;
        req->key = -1;
        wine_server_set_reply( req, state, 256 );
        ret = !wine_server_call( req );
1193
    }
1194 1195
    SERVER_END_REQ;
    return ret;
1196 1197
}

1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
/***********************************************************************
 *           set_async_key_state
 */
static void set_async_key_state( const BYTE state[256] )
{
    SERVER_START_REQ( set_key_state )
    {
        req->tid = GetCurrentThreadId();
        req->async = 1;
        wine_server_add_data( req, state, 256 );
        wine_server_call( req );
    }
    SERVER_END_REQ;
}

static void update_key_state( BYTE *keystate, BYTE key, int down )
{
    if (down)
    {
        if (!(keystate[key] & 0x80)) keystate[key] ^= 0x01;
        keystate[key] |= 0x80;
    }
    else keystate[key] &= ~0x80;
}

1223
/***********************************************************************
1224
 *           X11DRV_KeymapNotify
1225
 *
1226
 * Update modifiers state (Ctrl, Alt, Shift) when window is activated.
1227 1228 1229
 *
 * This handles the case where one uses Ctrl+... Alt+... or Shift+.. to switch
 * from wine to another application and back.
1230
 * Toggle keys are handled in HandleEvent.
1231
 */
1232
BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
1233
{
1234
    int i, j;
1235
    BYTE keystate[256];
1236
    WORD vkey;
1237
    BOOL changed = FALSE;
1238 1239 1240 1241
    struct {
        WORD vkey;
        BOOL pressed;
    } modifiers[6]; /* VK_LSHIFT through VK_RMENU are contiguous */
1242
    BOOL lwin_pressed = FALSE, rwin_pressed = FALSE;
1243

1244
    if (!get_async_key_state( keystate )) return FALSE;
1245

1246 1247
    memset(modifiers, 0, sizeof(modifiers));

1248 1249
    EnterCriticalSection( &kbd_section );

1250 1251 1252 1253
    /* the minimum keycode is always greater or equal to 8, so we can
     * skip the first 8 values, hence start at 1
     */
    for (i = 1; i < 32; i++)
1254 1255 1256
    {
        for (j = 0; j < 8; j++)
        {
1257 1258 1259
            int m;

            vkey = keyc2vkey[(i * 8) + j];
1260 1261

            switch(vkey & 0xff)
1262
            {
1263 1264 1265 1266 1267 1268
            case VK_LMENU:
            case VK_RMENU:
            case VK_LCONTROL:
            case VK_RCONTROL:
            case VK_LSHIFT:
            case VK_RSHIFT:
1269
                m = (vkey & 0xff) - VK_LSHIFT;
1270 1271 1272
                /* Take the vkey from the first keycode we encounter for this modifier */
                if (!modifiers[m].vkey) modifiers[m].vkey = vkey;
                if (event->xkeymap.key_vector[i] & (1<<j)) modifiers[m].pressed = TRUE;
1273
                break;
1274 1275 1276 1277 1278 1279
            case VK_LWIN:
                if (event->xkeymap.key_vector[i] & (1<<j)) lwin_pressed = TRUE;
                break;
            case VK_RWIN:
                if (event->xkeymap.key_vector[i] & (1<<j)) rwin_pressed = TRUE;
                break;
1280 1281
            }
        }
1282
    }
1283 1284 1285 1286 1287 1288 1289 1290 1291

    for (vkey = VK_LSHIFT; vkey <= VK_RMENU; vkey++)
    {
        int m = vkey - VK_LSHIFT;
        if (modifiers[m].vkey && !(keystate[vkey] & 0x80) != !modifiers[m].pressed)
        {
            TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n",
                   modifiers[m].vkey, keystate[vkey]);

1292 1293
            update_key_state( keystate, vkey, modifiers[m].pressed );
            changed = TRUE;
1294 1295
        }
    }
1296

1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
    if (!(keystate[VK_LWIN] & 0x80) != !lwin_pressed)
    {
        TRACE( "Adjusting state for VK_LWIN. State before %#.2x\n", keystate[VK_LWIN]);
        update_key_state( keystate, VK_LWIN, lwin_pressed );
        changed = TRUE;
    }
    if (!(keystate[VK_RWIN] & 0x80) != !rwin_pressed)
    {
        TRACE( "Adjusting state for VK_RWIN. State before %#.2x\n", keystate[VK_RWIN]);
        update_key_state( keystate, VK_RWIN, rwin_pressed );
        changed = TRUE;
    }

1310
    LeaveCriticalSection( &kbd_section );
1311
    if (!changed) return FALSE;
1312 1313 1314 1315

    update_key_state( keystate, VK_CONTROL, (keystate[VK_LCONTROL] | keystate[VK_RCONTROL]) & 0x80 );
    update_key_state( keystate, VK_MENU, (keystate[VK_LMENU] | keystate[VK_RMENU]) & 0x80 );
    update_key_state( keystate, VK_SHIFT, (keystate[VK_LSHIFT] | keystate[VK_RSHIFT]) & 0x80 );
1316 1317
    update_key_state( keystate, VK_LWIN, keystate[VK_LWIN] & 0x80 );
    update_key_state( keystate, VK_RWIN, keystate[VK_RWIN] & 0x80 );
1318
    set_async_key_state( keystate );
1319
    return TRUE;
1320 1321
}

1322
static void update_lock_state( HWND hwnd, WORD vkey, UINT state, DWORD time )
1323
{
1324
    BYTE keystate[256];
1325

1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
    /* Note: X sets the below states on key down and clears them on key up.
       Windows triggers them on key down. */

    if (!get_async_key_state( keystate )) return;

    /* Adjust the CAPSLOCK state if it has been changed outside wine */
    if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL)
    {
        DWORD flags = 0;
        if (keystate[VK_CAPITAL] & 0x80) flags ^= KEYEVENTF_KEYUP;
        TRACE("Adjusting CapsLock state (%#.2x)\n", keystate[VK_CAPITAL]);
1337 1338
        X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags, time );
        X11DRV_send_keyboard_input( hwnd, VK_CAPITAL, 0x3a, flags ^ KEYEVENTF_KEYUP, time );
1339 1340 1341 1342 1343 1344 1345 1346
    }

    /* Adjust the NUMLOCK state if it has been changed outside wine */
    if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & NumLockMask) && (vkey & 0xff) != VK_NUMLOCK)
    {
        DWORD flags = KEYEVENTF_EXTENDEDKEY;
        if (keystate[VK_NUMLOCK] & 0x80) flags ^= KEYEVENTF_KEYUP;
        TRACE("Adjusting NumLock state (%#.2x)\n", keystate[VK_NUMLOCK]);
1347 1348
        X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags, time );
        X11DRV_send_keyboard_input( hwnd, VK_NUMLOCK, 0x45, flags ^ KEYEVENTF_KEYUP, time );
1349
    }
1350

1351 1352 1353 1354 1355 1356
    /* Adjust the SCROLLLOCK state if it has been changed outside wine */
    if (!(keystate[VK_SCROLL] & 0x01) != !(state & ScrollLockMask) && vkey != VK_SCROLL)
    {
        DWORD flags = 0;
        if (keystate[VK_SCROLL] & 0x80) flags ^= KEYEVENTF_KEYUP;
        TRACE("Adjusting ScrLock state (%#.2x)\n", keystate[VK_SCROLL]);
1357 1358
        X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags, time );
        X11DRV_send_keyboard_input( hwnd, VK_SCROLL, 0x46, flags ^ KEYEVENTF_KEYUP, time );
1359
    }
1360 1361
}

1362
/***********************************************************************
1363
 *           X11DRV_KeyEvent
1364 1365 1366
 *
 * Handle a X key event
 */
1367
BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
1368
{
1369
    XKeyEvent *event = &xev->xkey;
1370 1371
    char buf[24];
    char *Str = buf;
1372
    KeySym keysym = 0;
1373 1374 1375
    WORD vkey = 0, bScan;
    DWORD dwFlags;
    int ascii_chars;
1376
    XIC xic = X11DRV_get_ic( hwnd );
1377
    DWORD event_time = EVENT_x11_time_to_win32_time(event->time);
1378 1379
    Status status = 0;

1380
    TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
1381
		event->type, event->window, event->state, event->keycode);
1382

1383 1384
    if (event->type == KeyPress) update_user_time( event->time );

1385 1386
    /* Clients should pass only KeyPress events to XmbLookupString */
    if (xic && event->type == KeyPress)
1387 1388
    {
        ascii_chars = XmbLookupString(xic, event, buf, sizeof(buf), &keysym, &status);
1389
        TRACE_(key)("XmbLookupString needs %i byte(s)\n", ascii_chars);
1390 1391 1392 1393 1394
        if (status == XBufferOverflow)
        {
            Str = HeapAlloc(GetProcessHeap(), 0, ascii_chars);
            if (Str == NULL)
            {
1395
                ERR_(key)("Failed to allocate memory!\n");
1396
                return FALSE;
1397 1398 1399 1400
            }
            ascii_chars = XmbLookupString(xic, event, Str, ascii_chars, &keysym, &status);
        }
    }
1401
    else
1402
        ascii_chars = XLookupString(event, buf, sizeof(buf), &keysym, NULL);
1403

1404
    TRACE_(key)("nbyte = %d, status %d\n", ascii_chars, status);
1405 1406 1407 1408

    if (status == XLookupChars)
    {
        X11DRV_XIMLookupChars( Str, ascii_chars );
1409 1410
        if (buf != Str)
            HeapFree(GetProcessHeap(), 0, Str);
1411
        return TRUE;
1412
    }
1413

1414 1415
    EnterCriticalSection( &kbd_section );

Andreas Mohr's avatar
Andreas Mohr committed
1416
    /* If XKB extensions are used, the state mask for AltGr will use the group
1417 1418
       index instead of the modifier mask. The group index is set in bits
       13-14 of the state field in the XKeyEvent structure. So if AltGr is
Andreas Mohr's avatar
Andreas Mohr committed
1419 1420 1421
       pressed, look if the group index is different than 0. From XKB
       extension documentation, the group index for AltGr should be 2
       (event->state = 0x2000). It's probably better to not assume a
1422
       predefined group index and find it dynamically
1423 1424

       Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */
1425 1426
    /* Save also all possible modifier states. */
    AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask);
1427 1428

    if (TRACE_ON(key)){
1429
	const char *ksname;
1430

1431
        ksname = XKeysymToString(keysym);
1432 1433
	if (!ksname)
	  ksname = "No Name";
1434
	TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
1435
                    (event->type == KeyPress) ? "KeyPress" : "KeyRelease",
1436
                    keysym, ksname, ascii_chars, debugstr_an(Str, ascii_chars));
1437
    }
1438 1439
    if (buf != Str)
        HeapFree(GetProcessHeap(), 0, Str);
1440

1441 1442 1443
    vkey = EVENT_event_to_vkey(xic,event);
    /* X returns keycode 0 for composed characters */
    if (!vkey && ascii_chars) vkey = VK_NONAME;
1444
    bScan = keyc2scan[event->keycode] & 0xFF;
1445

1446 1447
    TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n",
                event->keycode, vkey, bScan);
1448

1449
    LeaveCriticalSection( &kbd_section );
1450

1451
    if (!vkey) return FALSE;
1452

1453 1454 1455 1456 1457
    dwFlags = 0;
    if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
    if ( vkey & 0x100 )              dwFlags |= KEYEVENTF_EXTENDEDKEY;

    update_lock_state( hwnd, vkey, event->state, event_time );
1458

1459
    X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time );
1460
    return TRUE;
1461 1462
}

1463 1464 1465
/**********************************************************************
 *		X11DRV_KEYBOARD_DetectLayout
 *
1466
 * Called from X11DRV_InitKeyboard
1467 1468
 *  This routine walks through the defined keyboard layouts and selects
 *  whichever matches most closely.
1469
 * kbd_section must be held.
1470
 */
Patrik Stridvall's avatar
Patrik Stridvall committed
1471
static void
1472
X11DRV_KEYBOARD_DetectLayout( Display *display )
1473
{
1474 1475
  unsigned current, match, mismatch, seq, i, syms;
  int score, keyc, key, pkey, ok;
1476
  KeySym keysym = 0;
1477
  const char (*lkey)[MAIN_LEN][4];
1478
  unsigned max_seq = 0;
1479
  int max_score = 0, ismatch = 0;
1480
  char ckey[256][4];
1481 1482 1483

  syms = keysyms_per_keycode;
  if (syms > 4) {
1484
    WARN("%d keysyms per keycode not supported, set to 4\n", syms);
1485 1486
    syms = 4;
  }
1487 1488 1489

  memset( ckey, 0, sizeof(ckey) );
  for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
1490 1491
      /* get data for keycode from X server */
      for (i = 0; i < syms; i++) {
1492
        if (!(keysym = keycode_to_keysym (display, keyc, i))) continue;
1493
	/* Allow both one-byte and two-byte national keysyms */
1494
	if ((keysym < 0x8000) && (keysym != ' '))
1495 1496
        {
#ifdef HAVE_XKB
1497
            if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL))
1498 1499
#endif
            {
1500
                TRACE("XKB could not translate keysym %04lx\n", keysym);
1501 1502 1503 1504
                /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
                 * with appropriate ShiftMask and Mode_switch, use XLookupString
                 * to get character in the local encoding.
                 */
1505
                ckey[keyc][i] = keysym & 0xFF;
1506 1507
            }
        }
1508
	else {
1509
	  ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym);
1510
	}
1511
      }
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
  }

  for (current = 0; main_key_tab[current].comment; current++) {
    TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
    match = 0;
    mismatch = 0;
    score = 0;
    seq = 0;
    lkey = main_key_tab[current].key;
    pkey = -1;
    for (keyc = min_keycode; keyc <= max_keycode; keyc++) {
      if (ckey[keyc][0]) {
1524 1525 1526
	/* search for a match in layout table */
	/* right now, we just find an absolute match for defined positions */
	/* (undefined positions are ignored, so if it's defined as "3#" in */
1527
	/* the table, it's okay that the X server has "3#£", for example) */
1528 1529 1530
	/* however, the score will be higher for longer matches */
	for (key = 0; key < MAIN_LEN; key++) {
	  for (ok = 0, i = 0; (ok >= 0) && (i < syms); i++) {
1531
	    if ((*lkey)[key][i] && ((*lkey)[key][i] == ckey[keyc][i]))
1532
	      ok++;
1533
	    if ((*lkey)[key][i] && ((*lkey)[key][i] != ckey[keyc][i]))
1534
	      ok = -1;
1535
	  }
1536 1537 1538
	  if (ok > 0) {
	    score += ok;
	    break;
1539 1540
	  }
	}
1541
	/* count the matches and mismatches */
1542
	if (ok > 0) {
1543
	  match++;
1544 1545 1546 1547
	  /* and how much the keycode order matches */
	  if (key > pkey) seq++;
	  pkey = key;
	} else {
1548
          /* print spaces instead of \0's */
1549 1550 1551
          char str[5];
          for (i = 0; i < 4; i++) str[i] = ckey[keyc][i] ? ckey[keyc][i] : ' ';
          str[4] = 0;
1552
          TRACE_(key)("mismatch for keycode %u, got %s\n", keyc, str);
1553 1554
          mismatch++;
          score -= syms;
1555
	}
1556 1557
      }
    }
1558 1559
    TRACE("matches=%d, mismatches=%d, seq=%d, score=%d\n",
	   match, mismatch, seq, score);
1560 1561
    if ((score > max_score) ||
	((score == max_score) && (seq > max_seq))) {
1562 1563 1564
      /* best match so far */
      kbd_layout = current;
      max_score = score;
1565
      max_seq = seq;
1566
      ismatch = !mismatch;
1567
    }
1568 1569
  }
  /* we're done, report results if necessary */
1570 1571 1572
  if (!ismatch)
    WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
        main_key_tab[kbd_layout].comment);
1573 1574

  TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
1575 1576
}

1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
static HKL get_locale_kbd_layout(void)
{
    ULONG_PTR layout;
    LANGID langid;

    /* FIXME:
     *
     * layout = main_key_tab[kbd_layout].lcid;
     *
     * Winword uses return value of GetKeyboardLayout as a codepage
     * to translate ANSI keyboard messages to unicode. But we have
     * a problem with it: for instance Polish keyboard layout is
     * identical to the US one, and therefore instead of the Polish
     * locale id we return the US one.
     */

    layout = GetUserDefaultLCID();

    /*
     * Microsoft Office expects this value to be something specific
     * for Japanese and Korean Windows with an IME the value is 0xe001
     * We should probably check to see if an IME exists and if so then
     * set this word properly.
     */
    langid = PRIMARYLANGID(LANGIDFROMLCID(layout));
    if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1603
        layout = MAKELONG( layout, 0xe001 ); /* IME */
1604 1605 1606 1607 1608 1609
    else
        layout |= layout << 16;

    return (HKL)layout;
}

1610 1611 1612 1613 1614
/***********************************************************************
 *     GetKeyboardLayoutName (X11DRV.@)
 */
BOOL CDECL X11DRV_GetKeyboardLayoutName(LPWSTR name)
{
1615
    static const WCHAR formatW[] = {'%','0','8','x',0};
1616 1617
    DWORD layout;

1618 1619
    layout = HandleToUlong( get_locale_kbd_layout() );
    if (HIWORD(layout) == LOWORD(layout)) layout = LOWORD(layout);
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
    sprintfW(name, formatW, layout);
    TRACE("returning %s\n", debugstr_w(name));
    return TRUE;
}

static void set_kbd_layout_preload_key(void)
{
    static const WCHAR preload[] =
        {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d',0};
    static const WCHAR one[] = {'1',0};

    HKEY hkey;
    WCHAR layout[KL_NAMELENGTH];

    if (RegCreateKeyExW(HKEY_CURRENT_USER, preload, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL))
        return;

    if (!RegQueryValueExW(hkey, one, NULL, NULL, NULL, NULL))
    {
        RegCloseKey(hkey);
        return;
    }
    if (X11DRV_GetKeyboardLayoutName(layout))
        RegSetValueExW(hkey, one, 0, REG_SZ, (const BYTE *)layout, sizeof(layout));

    RegCloseKey(hkey);
}
1647

1648
/**********************************************************************
1649
 *		X11DRV_InitKeyboard
1650
 */
1651
void X11DRV_InitKeyboard( Display *display )
1652 1653 1654 1655 1656
{
    XModifierKeymap *mmp;
    KeySym keysym;
    KeyCode *kcp;
    XKeyEvent e2;
1657
    WORD scan, vkey;
1658 1659 1660
    int keyc, i, keyn, syms;
    char ckey[4]={0,0,0,0};
    const char (*lkey)[MAIN_LEN][4];
1661
    char vkey_used[256] = { 0 };
1662 1663 1664 1665

    /* Ranges of OEM, function key, and character virtual key codes.
     * Don't include those handled specially in X11DRV_ToUnicodeEx and
     * X11DRV_MapVirtualKeyEx, like VK_NUMPAD0 - VK_DIVIDE. */
1666 1667 1668 1669 1670 1671 1672
    static const struct {
        WORD first, last;
    } vkey_ranges[] = {
        { VK_OEM_1, VK_OEM_3 },
        { VK_OEM_4, VK_ICO_00 },
        { 0xe6, 0xe6 },
        { 0xe9, 0xf5 },
1673 1674 1675 1676
        { VK_OEM_NEC_EQUAL, VK_OEM_NEC_EQUAL },
        { VK_F1, VK_F24 },
        { 0x30, 0x39 }, /* VK_0 - VK_9 */
        { 0x41, 0x5a }, /* VK_A - VK_Z */
1677 1678 1679
        { 0, 0 }
    };
    int vkey_range;
1680

1681 1682
    set_kbd_layout_preload_key();

1683
    EnterCriticalSection( &kbd_section );
1684
    XDisplayKeycodes(display, &min_keycode, &max_keycode);
1685 1686 1687
    if (key_mapping) XFree( key_mapping );
    key_mapping = XGetKeyboardMapping(display, min_keycode,
                                      max_keycode + 1 - min_keycode, &keysyms_per_keycode);
1688 1689

    mmp = XGetModifierMapping(display);
1690 1691 1692 1693
    kcp = mmp->modifiermap;
    for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */
    {
        int j;
1694

1695 1696 1697 1698
        for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1)
	    if (*kcp)
            {
		int k;
1699

1700
		for (k = 0; k < keysyms_per_keycode; k += 1)
1701
                    if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock)
1702 1703
		    {
                        NumLockMask = 1 << i;
1704
                        TRACE_(key)("NumLockMask is %x\n", NumLockMask);
1705
		    }
1706
                    else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock)
1707 1708 1709 1710
		    {
                        ScrollLockMask = 1 << i;
                        TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
		    }
1711 1712
            }
    }
1713
    XFreeModifiermap(mmp);
1714

1715
    /* Detect the keyboard layout */
1716
    X11DRV_KEYBOARD_DetectLayout( display );
1717 1718 1719
    lkey = main_key_tab[kbd_layout].key;
    syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;

1720
    /* Now build two conversion arrays :
1721
     * keycode -> vkey + scancode + extended
1722 1723 1724 1725
     * vkey + extended -> keycode */

    e2.display = display;
    e2.state = 0;
1726
    e2.type = KeyPress;
1727

1728
    memset(keyc2vkey, 0, sizeof(keyc2vkey));
1729 1730
    for (keyc = min_keycode; keyc <= max_keycode; keyc++)
    {
1731 1732 1733
        char buf[30];
        int have_chars;

1734
        keysym = 0;
1735
        e2.keycode = (KeyCode)keyc;
1736
        have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL);
1737
        vkey = 0; scan = 0;
1738 1739 1740 1741
        if (keysym)  /* otherwise, keycode not used */
        {
            if ((keysym >> 8) == 0xFF)         /* non-character key */
            {
1742 1743
                vkey = nonchar_key_vkey[keysym & 0xff];
                scan = nonchar_key_scan[keysym & 0xff];
1744 1745
		/* set extended bit when necessary */
		if (scan & 0x100) vkey |= 0x100;
1746 1747 1748 1749 1750
            } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
                vkey = xfree86_vendor_key_vkey[keysym & 0xff];
                /* All vendor keys are extended with a scan code of 0 per testing on WinXP */
                scan = 0x100;
		vkey |= 0x100;
1751 1752 1753
            } else if (keysym == 0x20) {                 /* Spacebar */
	        vkey = VK_SPACE;
		scan = 0x39;
1754
	    } else if (have_chars) {
1755 1756 1757
	      /* we seem to need to search the layout-dependent scancodes */
	      int maxlen=0,maxval=-1,ok;
	      for (i=0; i<syms; i++) {
1758
		keysym = keycode_to_keysym(display, keyc, i);
1759
		if ((keysym<0x8000) && (keysym!=' '))
1760 1761
                {
#ifdef HAVE_XKB
1762
                    if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[i], 1, NULL))
1763 1764 1765 1766 1767 1768
#endif
                    {
                        /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent
                         * with appropriate ShiftMask and Mode_switch, use XLookupString
                         * to get character in the local encoding.
                         */
1769
                        ckey[i] = (keysym <= 0x7F) ? keysym : 0;
1770
                    }
1771 1772 1773
		} else {
		  ckey[i] = KEYBOARD_MapDeadKeysym(keysym);
		}
1774 1775 1776 1777 1778
	      }
	      /* find key with longest match streak */
	      for (keyn=0; keyn<MAIN_LEN; keyn++) {
		for (ok=(*lkey)[keyn][i=0]; ok&&(i<4); i++)
		  if ((*lkey)[keyn][i] && (*lkey)[keyn][i]!=ckey[i]) ok=0;
1779
		if (!ok) i--; /* we overshot */
1780 1781 1782 1783 1784 1785 1786
		if (ok||(i>maxlen)) {
		  maxlen=i; maxval=keyn;
		}
		if (ok) break;
	      }
	      if (maxval>=0) {
		/* got it */
1787 1788 1789 1790
		const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
		const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
		scan = (*lscan)[maxval];
		vkey = (*lvkey)[maxval];
1791 1792
	      }
	    }
1793
        }
1794
        TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1795 1796 1797
        keyc2vkey[e2.keycode] = vkey;
        keyc2scan[e2.keycode] = scan;
        if ((vkey & 0xff) && vkey_used[(vkey & 0xff)])
1798
            WARN("vkey %04X is being used by more than one keycode\n", vkey);
1799 1800 1801
        vkey_used[(vkey & 0xff)] = 1;
    } /* for */

1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813
#define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
    for (keyc = min_keycode; keyc <= max_keycode; keyc++)
    {
        vkey = keyc2vkey[keyc] & 0xff;
        if (vkey)
            continue;

        e2.keycode = (KeyCode)keyc;
        keysym = XLookupKeysym(&e2, 0);
        if (!keysym)
           continue;

1814 1815 1816 1817 1818 1819 1820
        /* find a suitable layout-dependent VK code */
        /* (most Winelib apps ought to be able to work without layout tables!) */
        for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
        {
            keysym = XLookupKeysym(&e2, i);
            if ((keysym >= XK_0 && keysym <= XK_9)
                || (keysym >= XK_A && keysym <= XK_Z)) {
1821
                vkey = VKEY_IF_NOT_USED(keysym);
1822
            }
1823
        }
1824

1825 1826 1827 1828
        for (i = 0; (i < keysyms_per_keycode) && (!vkey); i++)
        {
            keysym = XLookupKeysym(&e2, i);
            switch (keysym)
1829
            {
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
            case ';':             vkey = VKEY_IF_NOT_USED(VK_OEM_1); break;
            case '/':             vkey = VKEY_IF_NOT_USED(VK_OEM_2); break;
            case '`':             vkey = VKEY_IF_NOT_USED(VK_OEM_3); break;
            case '[':             vkey = VKEY_IF_NOT_USED(VK_OEM_4); break;
            case '\\':            vkey = VKEY_IF_NOT_USED(VK_OEM_5); break;
            case ']':             vkey = VKEY_IF_NOT_USED(VK_OEM_6); break;
            case '\'':            vkey = VKEY_IF_NOT_USED(VK_OEM_7); break;
            case ',':             vkey = VKEY_IF_NOT_USED(VK_OEM_COMMA); break;
            case '.':             vkey = VKEY_IF_NOT_USED(VK_OEM_PERIOD); break;
            case '-':             vkey = VKEY_IF_NOT_USED(VK_OEM_MINUS); break;
            case '+':             vkey = VKEY_IF_NOT_USED(VK_OEM_PLUS); break;
1841 1842
            }
        }
1843

1844
        if (vkey)
1845
        {
1846
            TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1847 1848 1849 1850
            keyc2vkey[e2.keycode] = vkey;
        }
    } /* for */

1851 1852
    /* For any keycodes which still don't have a vkey, assign any spare
     * character, function key, or OEM virtual key code. */
1853 1854
    vkey_range = 0;
    vkey = vkey_ranges[vkey_range].first;
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864
    for (keyc = min_keycode; keyc <= max_keycode; keyc++)
    {
        if (keyc2vkey[keyc] & 0xff)
            continue;

        e2.keycode = (KeyCode)keyc;
        keysym = XLookupKeysym(&e2, 0);
        if (!keysym)
           continue;

1865
        while (vkey && vkey_used[vkey])
1866
        {
1867
            if (vkey == vkey_ranges[vkey_range].last)
1868
            {
1869 1870
                vkey_range++;
                vkey = vkey_ranges[vkey_range].first;
1871
            }
1872 1873 1874
            else
                vkey++;
        }
1875

1876 1877 1878 1879 1880
        if (!vkey)
        {
            WARN("No more vkeys available!\n");
            break;
        }
1881

1882 1883
        if (TRACE_ON(keyboard))
        {
1884
            TRACE("spare virtual key %04X assigned to keycode %u:\n",
1885
                             vkey, e2.keycode);
1886 1887
            TRACE("(");
            for (i = 0; i < keysyms_per_keycode; i += 1)
1888
            {
1889 1890 1891 1892 1893 1894
                const char *ksname;

                keysym = XLookupKeysym(&e2, i);
                ksname = XKeysymToString(keysym);
                if (!ksname)
                    ksname = "NoSymbol";
1895
                TRACE( "%lx (%s) ", keysym, ksname);
1896
            }
1897
            TRACE(")\n");
1898
        }
1899

1900
        TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey);
1901 1902
        keyc2vkey[e2.keycode] = vkey;
        vkey_used[vkey] = 1;
1903 1904
    } /* for */
#undef VKEY_IF_NOT_USED
1905 1906 1907 1908

    /* If some keys still lack scancodes, assign some arbitrary ones to them now */
    for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++)
      if (keyc2vkey[keyc]&&!keyc2scan[keyc]) {
1909
	const char *ksname;
1910
	keysym = keycode_to_keysym(display, keyc, 0);
1911
	ksname = XKeysymToString(keysym);
1912 1913 1914 1915
	if (!ksname) ksname = "NoSymbol";

	/* should make sure the scancode is unassigned here, but >=0x60 currently always is */

1916
	TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname);
1917 1918 1919
	keyc2scan[keyc]=scan++;
      }

1920
    LeaveCriticalSection( &kbd_section );
1921 1922
}

1923 1924 1925
static BOOL match_x11_keyboard_layout(HKL hkl)
{
    const DWORD isIME = 0xE0000000;
1926
    HKL xHkl = get_locale_kbd_layout();
1927 1928 1929 1930 1931 1932 1933

    /* if the layout is an IME, only match the low word (LCID) */
    if (((ULONG_PTR)hkl & isIME) == isIME)
        return (LOWORD(hkl) == LOWORD(xHkl));
    else
        return (hkl == xHkl);
}
1934

1935

1936 1937 1938
/***********************************************************************
 *		GetKeyboardLayout (X11DRV.@)
 */
1939
HKL CDECL X11DRV_GetKeyboardLayout(DWORD dwThreadid)
1940
{
1941 1942 1943 1944 1945
    if (!dwThreadid || dwThreadid == GetCurrentThreadId())
    {
        struct x11drv_thread_data *thread_data = x11drv_thread_data();
        if (thread_data && thread_data->kbd_layout) return thread_data->kbd_layout;
    }
1946
    else
1947
        FIXME("couldn't return keyboard layout for thread %04x\n", dwThreadid);
1948

1949
    return get_locale_kbd_layout();
1950 1951 1952 1953 1954 1955
}


/***********************************************************************
 *		LoadKeyboardLayout (X11DRV.@)
 */
1956
HKL CDECL X11DRV_LoadKeyboardLayout(LPCWSTR name, UINT flags)
1957
{
1958 1959
    FIXME("%s, %04x: semi-stub! Returning default layout.\n", debugstr_w(name), flags);
    return get_locale_kbd_layout();
1960 1961 1962 1963 1964 1965
}


/***********************************************************************
 *		UnloadKeyboardLayout (X11DRV.@)
 */
1966
BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
{
    FIXME("%p: stub!\n", hkl);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
}


/***********************************************************************
 *		ActivateKeyboardLayout (X11DRV.@)
 */
1977
HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
1978
{
1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
    HKL oldHkl = 0;
    struct x11drv_thread_data *thread_data = x11drv_init_thread_data();

    FIXME("%p, %04x: semi-stub!\n", hkl, flags);
    if (flags & KLF_SETFORPROCESS)
    {
        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
        FIXME("KLF_SETFORPROCESS not supported\n");
        return 0;
    }

    if (flags)
        FIXME("flags %x not supported\n",flags);

    if (hkl == (HKL)HKL_NEXT || hkl == (HKL)HKL_PREV)
    {
        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
        FIXME("HKL_NEXT and HKL_PREV not supported\n");
        return 0;
    }

    if (!match_x11_keyboard_layout(hkl))
    {
        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
        FIXME("setting keyboard of different locales not supported\n");
        return 0;
    }

    oldHkl = thread_data->kbd_layout;
    if (!oldHkl) oldHkl = get_locale_kbd_layout();

    thread_data->kbd_layout = hkl;

    return oldHkl;
2013 2014 2015
}


2016 2017 2018
/***********************************************************************
 *           X11DRV_MappingNotify
 */
2019
BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event )
2020
{
2021 2022
    HWND hwnd;

2023
    XRefreshKeyboardMapping(&event->xmapping);
2024
    X11DRV_InitKeyboard( event->xmapping.display );
2025 2026 2027 2028 2029

    hwnd = GetFocus();
    if (!hwnd) hwnd = GetActiveWindow();
    PostMessageW(hwnd, WM_INPUTLANGCHANGEREQUEST,
                 0 /*FIXME*/, (LPARAM)X11DRV_GetKeyboardLayout(0));
2030
    return TRUE;
2031 2032 2033
}


2034
/***********************************************************************
2035 2036 2037
 *		VkKeyScanEx (X11DRV.@)
 *
 * Note: Windows ignores HKL parameter and uses current active layout instead
2038
 */
2039
SHORT CDECL X11DRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
2040
{
2041
    Display *display = thread_init_display();
2042 2043
    KeyCode keycode;
    KeySym keysym;
2044
    int index;
2045
    CHAR cChar;
2046 2047
    SHORT ret;

2048 2049 2050
    /* FIXME: what happens if wChar is not a Latin1 character and CP_UNIXCP
     * is UTF-8 (multibyte encoding)?
     */
2051 2052 2053 2054 2055 2056 2057 2058
    if (!WideCharToMultiByte(CP_UNIXCP, 0, &wChar, 1, &cChar, 1, NULL, NULL))
    {
        WARN("no translation from unicode to CP_UNIXCP for 0x%02x\n", wChar);
        return -1;
    }

    TRACE("wChar 0x%02x -> cChar '%c'\n", wChar, cChar);

2059 2060 2061 2062
    /* char->keysym (same for ANSI chars) */
    keysym = (unsigned char)cChar; /* (!) cChar is signed */
    if (keysym <= 27) keysym += 0xFF00; /* special chars : return, backspace... */

2063
    keycode = XKeysymToKeycode(display, keysym);  /* keysym -> keycode */
2064
    if (!keycode)
2065 2066 2067 2068 2069 2070 2071 2072
    {
        if (keysym >= 0xFF00) /* Windows returns 0x0240 + cChar in this case */
        {
            ret = 0x0240 + cChar; /* 0x0200 indicates a control character */
            TRACE(" ... returning ctrl char %#.2x\n", ret);
            return ret;
        }
        /* It didn't work ... let's try with deadchar code. */
2073
        TRACE("retrying with | 0xFE00\n");
2074
        keycode = XKeysymToKeycode(display, keysym | 0xFE00);
2075
    }
2076

2077
    TRACE("'%c'(%lx): got keycode %u\n", cChar, keysym, keycode);
2078 2079 2080
    if (!keycode) return -1;

    EnterCriticalSection( &kbd_section );
2081

2082 2083
    /* keycode -> (keyc2vkey) vkey */
    ret = keyc2vkey[keycode];
2084
    if (!ret)
2085
    {
2086
        LeaveCriticalSection( &kbd_section );
2087 2088 2089 2090
        TRACE("keycode for '%c' not found, returning -1\n", cChar);
        return -1;
    }

2091 2092 2093 2094
    for (index = 0; index < 4; index++) /* find shift state */
        if (keycode_to_keysym(display, keycode, index) == keysym) break;

    LeaveCriticalSection( &kbd_section );
2095 2096 2097 2098 2099 2100 2101

    switch (index)
    {
        case 0: break;
        case 1: ret += 0x0100; break;
        case 2: ret += 0x0600; break;
        case 3: ret += 0x0700; break;
2102 2103 2104
        default:
            WARN("Keysym %lx not found while parsing the keycode table\n", keysym);
            return -1;
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115
    }
    /*
      index : 0     adds 0x0000
      index : 1     adds 0x0100 (shift)
      index : ?     adds 0x0200 (ctrl)
      index : 2     adds 0x0600 (ctrl+alt)
      index : 3     adds 0x0700 (ctrl+alt+shift)
     */

    TRACE(" ... returning %#.2x\n", ret);
    return ret;
2116 2117 2118
}

/***********************************************************************
2119
 *		MapVirtualKeyEx (X11DRV.@)
2120
 */
2121
UINT CDECL X11DRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
2122
{
2123 2124
    UINT ret = 0;
    int keyc;
2125
    Display *display = thread_init_display();
2126

2127
    TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl);
2128
    if (!match_x11_keyboard_layout(hkl))
2129 2130
        FIXME("keyboard layout %p is not supported\n", hkl);

2131 2132
    EnterCriticalSection( &kbd_section );

2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
    switch(wMapType)
    {
        case MAPVK_VK_TO_VSC: /* vkey-code to scan-code */
        case MAPVK_VK_TO_VSC_EX:
            switch (wCode)
            {
                case VK_SHIFT: wCode = VK_LSHIFT; break;
                case VK_CONTROL: wCode = VK_LCONTROL; break;
                case VK_MENU: wCode = VK_LMENU; break;
            }

            /* let's do vkey -> keycode -> scan */
            for (keyc = min_keycode; keyc <= max_keycode; keyc++)
            {
2147 2148 2149 2150 2151
                if ((keyc2vkey[keyc] & 0xFF) == wCode)
                {
                    ret = keyc2scan[keyc] & 0xFF;
                    break;
                }
2152
            }
2153 2154
            break;

2155 2156 2157 2158 2159
        case MAPVK_VSC_TO_VK: /* scan-code to vkey-code */
        case MAPVK_VSC_TO_VK_EX:

            /* let's do scan -> keycode -> vkey */
            for (keyc = min_keycode; keyc <= max_keycode; keyc++)
2160 2161
                if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF))
                {
2162
                    ret = keyc2vkey[keyc] & 0xFF;
2163 2164
                    /* Only stop if it's not a numpad vkey; otherwise keep
                       looking for a potential better vkey. */
2165
                    if (ret && (ret < VK_NUMPAD0 || VK_DIVIDE < ret))
2166 2167
                        break;
                }
2168 2169

            if (wMapType == MAPVK_VSC_TO_VK)
2170
                switch (ret)
2171 2172 2173
                {
                    case VK_LSHIFT:
                    case VK_RSHIFT:
2174
                        ret = VK_SHIFT; break;
2175 2176
                    case VK_LCONTROL:
                    case VK_RCONTROL:
2177
                        ret = VK_CONTROL; break;
2178 2179
                    case VK_LMENU:
                    case VK_RMENU:
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
                        ret = VK_MENU; break;
                }

            break;

        case MAPVK_VK_TO_CHAR: /* vkey-code to unshifted ANSI code */
        {
            /* we still don't know what "unshifted" means. in windows VK_W (0x57)
             * returns 0x57, which is uppercase 'W'. So we have to return the uppercase
             * key.. Looks like something is wrong with the MS docs?
             * This is only true for letters, for example VK_0 returns '0' not ')'.
             * - hence we use the lock mask to ensure this happens.
             */
            /* let's do vkey -> keycode -> (XLookupString) ansi char */
            XKeyEvent e;
            KeySym keysym;
            int len;
            char s[10];

            e.display = display;
            e.state = 0;
            e.keycode = 0;
            e.type = KeyPress;

            /* We exit on the first keycode found, to speed up the thing. */
            for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
            { /* Find a keycode that could have generated this virtual key */
                if  ((keyc2vkey[keyc] & 0xFF) == wCode)
                { /* We filter the extended bit, we don't know it */
                    e.keycode = keyc; /* Store it temporarily */
                    if ((EVENT_event_to_vkey(0,&e) & 0xFF) != wCode) {
                        e.keycode = 0; /* Wrong one (ex: because of the NumLock
                                          state), so set it to 0, we'll find another one */
                    }
2214
                }
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236
            }

            if ((wCode>=VK_NUMPAD0) && (wCode<=VK_NUMPAD9))
                e.keycode = XKeysymToKeycode(e.display, wCode-VK_NUMPAD0+XK_KP_0);

            /* Windows always generates VK_DECIMAL for Del/. on keypad while some
             * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
             * in order to produce a locale dependent numeric separator.
             */
            if (wCode == VK_DECIMAL || wCode == VK_SEPARATOR)
            {
                e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
                if (!e.keycode)
                    e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
            }

            if (!e.keycode)
            {
                WARN("Unknown virtual key %X !!!\n", wCode);
                break;
            }
            TRACE("Found keycode %u\n",e.keycode);
2237

2238 2239 2240 2241 2242 2243 2244
            len = XLookupString(&e, s, sizeof(s), &keysym, NULL);
            if (len)
            {
                WCHAR wch;
                if (MultiByteToWideChar(CP_UNIXCP, 0, s, len, &wch, 1)) ret = toupperW(wch);
            }
            break;
2245
        }
2246 2247 2248 2249 2250 2251 2252 2253 2254

        default: /* reserved */
            FIXME("Unknown wMapType %d !\n", wMapType);
            break;
    }

    LeaveCriticalSection( &kbd_section );
    TRACE( "returning 0x%x.\n", ret );
    return ret;
2255 2256 2257
}

/***********************************************************************
2258
 *		GetKeyNameText (X11DRV.@)
2259
 */
2260
INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
2261
{
2262
  Display *display = thread_init_display();
2263
  int vkey, ansi, scanCode;
2264
  KeyCode keyc;
2265
  int keyi;
2266 2267
  KeySym keys;
  char *name;
2268

2269
  scanCode = lParam >> 16;
2270 2271
  scanCode &= 0x1ff;  /* keep "extended-key" flag with code */

2272
  vkey = X11DRV_MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, X11DRV_GetKeyboardLayout(0));
2273 2274 2275 2276 2277

  /*  handle "don't care" bit (0x02000000) */
  if (!(lParam & 0x02000000)) {
    switch (vkey) {
         case VK_RSHIFT:
2278 2279
                          /* R-Shift is "special" - it is an extended key with separate scan code */
                          scanCode |= 0x100;
2280
                          /* fall through */
2281
         case VK_LSHIFT:
2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293
                          vkey = VK_SHIFT;
                          break;
       case VK_LCONTROL:
       case VK_RCONTROL:
                          vkey = VK_CONTROL;
                          break;
          case VK_LMENU:
          case VK_RMENU:
                          vkey = VK_MENU;
                          break;
    }
  }
2294

2295
  ansi = X11DRV_MapVirtualKeyEx(vkey, MAPVK_VK_TO_CHAR, X11DRV_GetKeyboardLayout(0));
2296
  TRACE("scan 0x%04x, vkey 0x%04X, ANSI 0x%04x\n", scanCode, vkey, ansi);
2297

2298 2299 2300 2301 2302 2303 2304 2305
  /* first get the name of the "regular" keys which is the Upper case
     value of the keycap imprint.                                     */
  if ( ((ansi >= 0x21) && (ansi <= 0x7e)) &&
       (scanCode != 0x137) &&   /* PrtScn   */
       (scanCode != 0x135) &&   /* numpad / */
       (scanCode != 0x37 ) &&   /* numpad * */
       (scanCode != 0x4a ) &&   /* numpad - */
       (scanCode != 0x4e ) )    /* numpad + */
2306
      {
2307
        if (nSize >= 2)
2308
	{
2309
          *lpBuffer = toupperW((WCHAR)ansi);
2310 2311
          *(lpBuffer+1) = 0;
          return 1;
2312
        }
2313 2314
     else
        return 0;
2315 2316
  }

2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328
  /* FIXME: horrible hack to fix function keys. Windows reports scancode
            without "extended-key" flag. However Wine generates scancode
            *with* "extended-key" flag. Seems to occur *only* for the
            function keys. Soooo.. We will leave the table alone and
            fudge the lookup here till the other part is found and fixed!!! */

  if ( ((scanCode >= 0x13b) && (scanCode <= 0x144)) ||
       (scanCode == 0x157) || (scanCode == 0x158))
    scanCode &= 0xff;   /* remove "extended-key" flag for Fx keys */

  /* let's do scancode -> keycode -> keysym -> String */

2329 2330
  EnterCriticalSection( &kbd_section );

2331 2332
  for (keyi=min_keycode; keyi<=max_keycode; keyi++)
      if ((keyc2scan[keyi]) == scanCode)
2333
         break;
2334
  if (keyi <= max_keycode)
2335
  {
2336 2337
      INT rc;

2338
      keyc = (KeyCode) keyi;
2339
      keys = keycode_to_keysym(display, keyc, 0);
2340
      name = XKeysymToString(keys);
2341 2342 2343 2344 2345 2346

      if (name && (vkey == VK_SHIFT || vkey == VK_CONTROL || vkey == VK_MENU))
      {
          char* idx = strrchr(name, '_');
          if (idx && (strcasecmp(idx, "_r") == 0 || strcasecmp(idx, "_l") == 0))
          {
2347
              LeaveCriticalSection( &kbd_section );
2348 2349
              TRACE("found scan=%04x keyc=%u keysym=%lx modified_string=%s\n",
                    scanCode, keyc, keys, debugstr_an(name,idx-name));
2350 2351 2352
              rc = MultiByteToWideChar(CP_UNIXCP, 0, name, idx-name+1, lpBuffer, nSize);
              if (!rc) rc = nSize;
              lpBuffer[--rc] = 0;
2353 2354 2355 2356
              return rc;
          }
      }

2357 2358
      if (name)
      {
2359
          LeaveCriticalSection( &kbd_section );
2360 2361 2362 2363 2364 2365 2366
          TRACE("found scan=%04x keyc=%u keysym=%04x vkey=%04x string=%s\n",
                scanCode, keyc, (int)keys, vkey, debugstr_a(name));
          rc = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, lpBuffer, nSize);
          if (!rc) rc = nSize;
          lpBuffer[--rc] = 0;
          return rc;
      }
2367
  }
2368

2369
  /* Finally issue WARN for unknown keys   */
2370

2371
  LeaveCriticalSection( &kbd_section );
2372
  WARN("(%08x,%p,%d): unsupported key, vkey=%04X, ansi=%04x\n",lParam,lpBuffer,nSize,vkey,ansi);
2373
  *lpBuffer = 0;
2374 2375 2376
  return 0;
}

2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
/***********************************************************************
 *		X11DRV_KEYBOARD_MapDeadKeysym
 */
static char KEYBOARD_MapDeadKeysym(KeySym keysym)
{
	switch (keysym)
	    {
	/* symbolic ASCII is the same as defined in rfc1345 */
#ifdef XK_dead_tilde
	    case XK_dead_tilde :
#endif
	    case 0x1000FE7E : /* Xfree's XK_Dtilde */
		return '~';	/* '? */
#ifdef XK_dead_acute
	    case XK_dead_acute :
#endif
	    case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
		return 0xb4;	/* '' */
#ifdef XK_dead_circumflex
	    case XK_dead_circumflex:
#endif
	    case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
		return '^';	/* '> */
#ifdef XK_dead_grave
	    case XK_dead_grave :
#endif
	    case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
		return '`';	/* '! */
#ifdef XK_dead_diaeresis
	    case XK_dead_diaeresis :
#endif
	    case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
		return 0xa8;	/* ': */
#ifdef XK_dead_cedilla
	    case XK_dead_cedilla :
	        return 0xb8;	/* ', */
#endif
#ifdef XK_dead_macron
	    case XK_dead_macron :
	        return '-';	/* 'm isn't defined on iso-8859-x */
#endif
#ifdef XK_dead_breve
	    case XK_dead_breve :
	        return 0xa2;	/* '( */
#endif
#ifdef XK_dead_abovedot
	    case XK_dead_abovedot :
	        return 0xff;	/* '. */
#endif
#ifdef XK_dead_abovering
	    case XK_dead_abovering :
	        return '0';	/* '0 isn't defined on iso-8859-x */
#endif
#ifdef XK_dead_doubleacute
	    case XK_dead_doubleacute :
	        return 0xbd;	/* '" */
#endif
#ifdef XK_dead_caron
	    case XK_dead_caron :
	        return 0xb7;	/* '< */
#endif
#ifdef XK_dead_ogonek
	    case XK_dead_ogonek :
	        return 0xb2;	/* '; */
#endif
/* FIXME: I don't know this three.
	    case XK_dead_iota :
2444
	        return 'i';
2445 2446 2447 2448 2449 2450
	    case XK_dead_voiced_sound :
	        return 'v';
	    case XK_dead_semivoiced_sound :
	        return 's';
*/
	    }
2451
	TRACE("no character for dead keysym 0x%08lx\n",keysym);
2452 2453 2454
	return 0;
}

2455
/***********************************************************************
2456
 *		ToUnicodeEx (X11DRV.@)
2457
 *
2458
 * The ToUnicode function translates the specified virtual-key code and keyboard
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
 * state to the corresponding Windows character or characters.
 *
 * If the specified key is a dead key, the return value is negative. Otherwise,
 * it is one of the following values:
 * Value	Meaning
 * 0	The specified virtual key has no translation for the current state of the keyboard.
 * 1	One Windows character was copied to the buffer.
 * 2	Two characters were copied to the buffer. This usually happens when a
 *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
 *      be composed with the specified virtual key to form a single character.
 *
 * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
 *
 */
2473 2474
INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
                             LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
2475
{
2476
    Display *display = thread_init_display();
2477
    XKeyEvent e;
2478
    KeySym keysym = 0;
2479
    INT ret;
2480
    int keyc;
2481 2482
    char buf[10];
    char *lpChar = buf;
2483 2484
    HWND focus;
    XIC xic;
2485
    Status status = 0;
2486

2487 2488
    if (scanCode & 0x8000)
    {
2489
        TRACE_(key)("Key UP, doing nothing\n" );
2490 2491
        return 0;
    }
2492

2493
    if (!match_x11_keyboard_layout(hkl))
2494
        FIXME_(key)("keyboard layout %p is not supported\n", hkl);
2495

2496 2497
    if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80))
    {
2498
        TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n");
2499 2500 2501
        return 0;
    }

2502 2503 2504
    e.display = display;
    e.keycode = 0;
    e.state = 0;
2505 2506
    e.type = KeyPress;

2507 2508 2509 2510 2511 2512 2513
    focus = x11drv_thread_data()->last_xic_hwnd;
    if (!focus)
    {
        focus = GetFocus();
        if (focus) focus = GetAncestor( focus, GA_ROOT );
        if (!focus) focus = GetActiveWindow();
    }
2514 2515 2516
    e.window = X11DRV_get_whole_window( focus );
    xic = X11DRV_get_ic( focus );

2517 2518
    EnterCriticalSection( &kbd_section );

2519
    if (lpKeyState[VK_SHIFT] & 0x80)
2520
    {
2521
	TRACE_(key)("ShiftMask = %04x\n", ShiftMask);
2522
	e.state |= ShiftMask;
2523
    }
2524
    if (lpKeyState[VK_CAPITAL] & 0x01)
2525
    {
2526
	TRACE_(key)("LockMask = %04x\n", LockMask);
2527
	e.state |= LockMask;
2528
    }
2529
    if (lpKeyState[VK_CONTROL] & 0x80)
2530
    {
2531
	TRACE_(key)("ControlMask = %04x\n", ControlMask);
2532
	e.state |= ControlMask;
2533
    }
2534
    if (lpKeyState[VK_NUMLOCK] & 0x01)
2535
    {
2536
	TRACE_(key)("NumLockMask = %04x\n", NumLockMask);
2537
	e.state |= NumLockMask;
2538
    }
2539 2540

    /* Restore saved AltGr state */
2541
    TRACE_(key)("AltGrMask = %04x\n", AltGrMask);
2542 2543
    e.state |= AltGrMask;

2544
    TRACE_(key)("(%04X, %04X) : faked state = 0x%04x\n",
2545
		virtKey, scanCode, e.state);
2546

2547 2548 2549 2550 2551 2552
    /* We exit on the first keycode found, to speed up the thing. */
    for (keyc=min_keycode; (keyc<=max_keycode) && (!e.keycode) ; keyc++)
      { /* Find a keycode that could have generated this virtual key */
          if  ((keyc2vkey[keyc] & 0xFF) == virtKey)
          { /* We filter the extended bit, we don't know it */
              e.keycode = keyc; /* Store it temporarily */
2553
              if ((EVENT_event_to_vkey(xic,&e) & 0xFF) != virtKey) {
2554 2555 2556 2557 2558 2559
                  e.keycode = 0; /* Wrong one (ex: because of the NumLock
                         state), so set it to 0, we'll find another one */
              }
	  }
      }

2560 2561 2562
    if (virtKey >= VK_LEFT && virtKey <= VK_DOWN)
        e.keycode = XKeysymToKeycode(e.display, virtKey - VK_LEFT + XK_Left);

2563
    if ((virtKey>=VK_NUMPAD0) && (virtKey<=VK_NUMPAD9))
2564
        e.keycode = XKeysymToKeycode(e.display, virtKey-VK_NUMPAD0+XK_KP_0);
2565

2566 2567 2568 2569 2570
    /* Windows always generates VK_DECIMAL for Del/. on keypad while some
     * X11 keyboard layouts generate XK_KP_Separator instead of XK_KP_Decimal
     * in order to produce a locale dependent numeric separator.
     */
    if (virtKey == VK_DECIMAL || virtKey == VK_SEPARATOR)
2571
    {
2572
        e.keycode = XKeysymToKeycode(e.display, XK_KP_Separator);
2573 2574 2575
        if (!e.keycode)
            e.keycode = XKeysymToKeycode(e.display, XK_KP_Decimal);
    }
2576

2577 2578 2579 2580 2581 2582 2583 2584
    /* Ctrl-Space generates space on Windows */
    if (e.state == ControlMask && virtKey == VK_SPACE)
    {
        bufW[0] = ' ';
        ret = 1;
        goto found;
    }

2585
    if (!e.keycode && virtKey != VK_NONAME)
2586
      {
2587
	WARN_(key)("Unknown virtual key %X !!!\n", virtKey);
2588
        LeaveCriticalSection( &kbd_section );
2589
	return 0;
2590
      }
2591
    else TRACE_(key)("Found keycode %u\n",e.keycode);
2592

2593
    TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n",
2594 2595
		e.type, e.window, e.state, e.keycode);

2596 2597 2598
    /* Clients should pass only KeyPress events to XmbLookupString,
     * e.type was set to KeyPress above.
     */
2599
    if (xic)
2600 2601
    {
        ret = XmbLookupString(xic, &e, buf, sizeof(buf), &keysym, &status);
2602
        TRACE_(key)("XmbLookupString needs %d byte(s)\n", ret);
2603 2604 2605 2606 2607
        if (status == XBufferOverflow)
        {
            lpChar = HeapAlloc(GetProcessHeap(), 0, ret);
            if (lpChar == NULL)
            {
2608
                ERR_(key)("Failed to allocate memory!\n");
2609
                LeaveCriticalSection( &kbd_section );
2610 2611 2612 2613 2614
                return 0;
            }
            ret = XmbLookupString(xic, &e, lpChar, ret, &keysym, &status);
        }
    }
2615
    else
2616
        ret = XLookupString(&e, buf, sizeof(buf), &keysym, NULL);
2617

2618 2619 2620 2621 2622 2623 2624 2625
    TRACE_(key)("nbyte = %d, status 0x%x\n", ret, status);

    if (TRACE_ON(key))
    {
        const char *ksname;

        ksname = XKeysymToString(keysym);
        if (!ksname) ksname = "No Name";
2626
        TRACE_(key)("%s : keysym=%lx (%s), # of chars=%d / %s\n",
2627 2628 2629 2630
                    (e.type == KeyPress) ? "KeyPress" : "KeyRelease",
                    keysym, ksname, ret, debugstr_an(lpChar, ret));
    }

2631
    if (ret == 0)
2632
    {
Mike McCormack's avatar
Mike McCormack committed
2633
	char dead_char;
2634

2635
#ifdef XK_EuroSign
2636 2637 2638 2639 2640 2641 2642 2643
        /* An ugly hack for EuroSign: X can't translate it to a character
           for some locales. */
        if (keysym == XK_EuroSign)
        {
            bufW[0] = 0x20AC;
            ret = 1;
            goto found;
        }
2644
#endif
2645 2646
        /* Special case: X turns shift-tab into ISO_Left_Tab. */
        /* Here we change it back. */
2647
        if (keysym == XK_ISO_Left_Tab && !(e.state & ControlMask))
2648 2649 2650 2651 2652 2653
        {
            bufW[0] = 0x09;
            ret = 1;
            goto found;
        }

2654
	dead_char = KEYBOARD_MapDeadKeysym(keysym);
2655
	if (dead_char)
2656
        {
2657
	    MultiByteToWideChar(CP_UNIXCP, 0, &dead_char, 1, bufW, bufW_size);
2658
	    ret = -1;
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668
            goto found;
        }

        if (keysym >= 0x01000100 && keysym <= 0x0100ffff)
        {
            /* Unicode direct mapping */
            bufW[0] = keysym & 0xffff;
            ret = 1;
            goto found;
        }
2669 2670 2671 2672 2673
        else if ((keysym >> 8) == 0x1008FF) {
            bufW[0] = 0;
            ret = 0;
            goto found;
        }
2674 2675
	else
	    {
2676
	    const char *ksname;
2677

2678
	    ksname = XKeysymToString(keysym);
2679 2680 2681 2682
	    if (!ksname)
		ksname = "No Name";
	    if ((keysym >> 8) != 0xff)
		{
2683
		WARN_(key)("no char for keysym %04lx (%s) :\n",
2684
                    keysym, ksname);
2685
		WARN_(key)("virtKey=%X, scanCode=%X, keycode=%u, state=%X\n",
2686
                    virtKey, scanCode, e.keycode, e.state);
2687 2688 2689
		}
	    }
	}
2690
    else {  /* ret != 0 */
2691 2692
        /* We have a special case to handle : Shift + arrow, shift + home, ...
           X returns a char for it, but Windows doesn't. Let's eat it. */
2693 2694
        if (!(e.state & NumLockMask)  /* NumLock is off */
            && (e.state & ShiftMask) /* Shift is pressed */
2695 2696
            && (keysym>=XK_KP_0) && (keysym<=XK_KP_9))
        {
2697
            lpChar[0] = 0;
2698 2699
            ret = 0;
        }
2700

2701
        /* more areas where X returns characters but Windows does not
Andreas Mohr's avatar
Andreas Mohr committed
2702
           CTRL + number or CTRL + symbol */
2703
        if (e.state & ControlMask)
2704
        {
2705 2706
            if (((keysym>=33) && (keysym < '@')) ||
                (keysym == '`') ||
2707
                (keysym == XK_Tab))
2708
            {
2709
                lpChar[0] = 0;
2710 2711
                ret = 0;
            }
2712
        }
2713

2714 2715 2716 2717
        /* We have another special case for delete key (XK_Delete) on an
         extended keyboard. X returns a char for it, but Windows doesn't */
        if (keysym == XK_Delete)
        {
2718
            lpChar[0] = 0;
2719 2720
            ret = 0;
        }
2721 2722 2723
	else if((lpKeyState[VK_SHIFT] & 0x80) /* Shift is pressed */
		&& (keysym == XK_KP_Decimal))
        {
2724
            lpChar[0] = 0;
2725 2726
            ret = 0;
        }
2727 2728 2729
	else if((lpKeyState[VK_CONTROL] & 0x80) /* Control is pressed */
		&& (keysym == XK_Return || keysym == XK_KP_Enter))
        {
2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
            if (lpKeyState[VK_SHIFT] & 0x80)
            {
                lpChar[0] = 0;
                ret = 0;
            }
            else
            {
                lpChar[0] = '\n';
                ret = 1;
            }
2740
        }
2741

2742 2743 2744 2745 2746 2747 2748
        /* Hack to detect an XLookupString hard-coded to Latin1 */
        if (ret == 1 && keysym >= 0x00a0 && keysym <= 0x00ff && (BYTE)lpChar[0] == keysym)
        {
            bufW[0] = (BYTE)lpChar[0];
            goto found;
        }

2749 2750
	/* perform translation to unicode */
	if(ret)
2751
	{
2752 2753
	    TRACE_(key)("Translating char 0x%02x to unicode\n", *(BYTE *)lpChar);
	    ret = MultiByteToWideChar(CP_UNIXCP, 0, lpChar, ret, bufW, bufW_size);
2754
	}
2755 2756
    }

2757
found:
2758 2759
    if (buf != lpChar)
        HeapFree(GetProcessHeap(), 0, lpChar);
2760

2761 2762
    LeaveCriticalSection( &kbd_section );

2763 2764 2765 2766 2767
    /* Null-terminate the buffer, if there's room.  MSDN clearly states that the
       caller must not assume this is done, but some programs (e.g. Audiosurf) do. */
    if (1 <= ret && ret < bufW_size)
        bufW[ret] = 0;

2768
    TRACE_(key)("returning %d with %s\n", ret, debugstr_wn(bufW, ret));
2769 2770 2771
    return ret;
}

2772
/***********************************************************************
2773
 *		Beep (X11DRV.@)
2774
 */
2775
void CDECL X11DRV_Beep(void)
2776
{
2777
    XBell(gdi_display, 0);
2778
}