2
* FreeRDP: A Remote Desktop Protocol Implementation
5
* Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
* Licensed under the Apache License, Version 2.0 (the "License");
8
* you may not use this file except in compliance with the License.
9
* You may obtain a copy of the License at
11
* http://www.apache.org/licenses/LICENSE-2.0
13
* Unless required by applicable law or agreed to in writing, software
14
* distributed under the License is distributed on an "AS IS" BASIS,
15
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
* See the License for the specific language governing permissions and
17
* limitations under the License.
24
#include "keyboard_xkbfile.h"
30
#include <winpr/crt.h>
31
#include <winpr/input.h>
33
#include <freerdp/locale/keyboard.h>
35
#include "keyboard_x11.h"
36
#include "xkb_layout_ids.h"
37
#include "liblocale.h"
40
#include <X11/XKBlib.h>
41
#include <X11/extensions/XKBfile.h>
42
#include <X11/extensions/XKBrules.h>
44
struct _XKB_KEY_NAME_SCANCODE
46
const char* xkb_keyname; /* XKB keyname */
49
typedef struct _XKB_KEY_NAME_SCANCODE XKB_KEY_NAME_SCANCODE;
51
XKB_KEY_NAME_SCANCODE XKB_KEY_NAME_SCANCODE_TABLE[] =
53
{ "BKSP", RDP_SCANCODE_BACKSPACE},
54
{ "TAB", RDP_SCANCODE_TAB},
55
{ "RTRN", RDP_SCANCODE_RETURN}, // not KP
56
{ "LFSH", RDP_SCANCODE_LSHIFT},
57
{ "LALT", RDP_SCANCODE_LMENU},
58
{ "CAPS", RDP_SCANCODE_CAPSLOCK},
59
{ "ESC", RDP_SCANCODE_ESCAPE},
60
{ "SPCE", RDP_SCANCODE_SPACE},
61
{ "AE10", RDP_SCANCODE_KEY_0},
62
{ "AE01", RDP_SCANCODE_KEY_1},
63
{ "AE02", RDP_SCANCODE_KEY_2},
64
{ "AE03", RDP_SCANCODE_KEY_3},
65
{ "AE04", RDP_SCANCODE_KEY_4},
66
{ "AE05", RDP_SCANCODE_KEY_5},
67
{ "AE06", RDP_SCANCODE_KEY_6},
68
{ "AE07", RDP_SCANCODE_KEY_7},
69
{ "AE08", RDP_SCANCODE_KEY_8},
70
{ "AE09", RDP_SCANCODE_KEY_9},
71
{ "AC01", RDP_SCANCODE_KEY_A},
72
{ "AB05", RDP_SCANCODE_KEY_B},
73
{ "AB03", RDP_SCANCODE_KEY_C},
74
{ "AC03", RDP_SCANCODE_KEY_D},
75
{ "AD03", RDP_SCANCODE_KEY_E},
76
{ "AC04", RDP_SCANCODE_KEY_F},
77
{ "AC05", RDP_SCANCODE_KEY_G},
78
{ "AC06", RDP_SCANCODE_KEY_H},
79
{ "AD08", RDP_SCANCODE_KEY_I},
80
{ "AC07", RDP_SCANCODE_KEY_J},
81
{ "AC08", RDP_SCANCODE_KEY_K},
82
{ "AC09", RDP_SCANCODE_KEY_L},
83
{ "AB07", RDP_SCANCODE_KEY_M},
84
{ "AB06", RDP_SCANCODE_KEY_N},
85
{ "AD09", RDP_SCANCODE_KEY_O},
86
{ "AD10", RDP_SCANCODE_KEY_P},
87
{ "AD01", RDP_SCANCODE_KEY_Q},
88
{ "AD04", RDP_SCANCODE_KEY_R},
89
{ "AC02", RDP_SCANCODE_KEY_S},
90
{ "AD05", RDP_SCANCODE_KEY_T},
91
{ "AD07", RDP_SCANCODE_KEY_U},
92
{ "AB04", RDP_SCANCODE_KEY_V},
93
{ "AD02", RDP_SCANCODE_KEY_W},
94
{ "AB02", RDP_SCANCODE_KEY_X},
95
{ "AD06", RDP_SCANCODE_KEY_Y},
96
{ "AB01", RDP_SCANCODE_KEY_Z},
97
{ "KP0", RDP_SCANCODE_NUMPAD0},
98
{ "KP1", RDP_SCANCODE_NUMPAD1},
99
{ "KP2", RDP_SCANCODE_NUMPAD2},
100
{ "KP3", RDP_SCANCODE_NUMPAD3},
101
{ "KP4", RDP_SCANCODE_NUMPAD4},
102
{ "KP5", RDP_SCANCODE_NUMPAD5},
103
{ "KP6", RDP_SCANCODE_NUMPAD6},
104
{ "KP7", RDP_SCANCODE_NUMPAD7},
105
{ "KP8", RDP_SCANCODE_NUMPAD8},
106
{ "KP9", RDP_SCANCODE_NUMPAD9},
107
{ "KPMU", RDP_SCANCODE_MULTIPLY},
108
{ "KPAD", RDP_SCANCODE_ADD},
109
{ "KPSU", RDP_SCANCODE_SUBTRACT},
110
{ "KPDL", RDP_SCANCODE_DECIMAL},
111
{ "AB10", RDP_SCANCODE_OEM_2}, // not KP, not RDP_SCANCODE_DIVIDE
112
{ "FK01", RDP_SCANCODE_F1},
113
{ "FK02", RDP_SCANCODE_F2},
114
{ "FK03", RDP_SCANCODE_F3},
115
{ "FK04", RDP_SCANCODE_F4},
116
{ "FK05", RDP_SCANCODE_F5},
117
{ "FK06", RDP_SCANCODE_F6},
118
{ "FK07", RDP_SCANCODE_F7},
119
{ "FK08", RDP_SCANCODE_F8},
120
{ "FK09", RDP_SCANCODE_F9},
121
{ "FK10", RDP_SCANCODE_F10},
122
{ "FK11", RDP_SCANCODE_F11},
123
{ "FK12", RDP_SCANCODE_F12},
124
{ "NMLK", RDP_SCANCODE_NUMLOCK},
125
{ "SCLK", RDP_SCANCODE_SCROLLLOCK},
126
{ "RTSH", RDP_SCANCODE_RSHIFT},
127
{ "LCTL", RDP_SCANCODE_LCONTROL},
128
{ "AC10", RDP_SCANCODE_OEM_1},
129
{ "AE12", RDP_SCANCODE_OEM_PLUS},
130
{ "AB08", RDP_SCANCODE_OEM_COMMA},
131
{ "AE11", RDP_SCANCODE_OEM_MINUS},
132
{ "AB09", RDP_SCANCODE_OEM_PERIOD},
133
{ "TLDE", RDP_SCANCODE_OEM_3},
134
{ "AB11", RDP_SCANCODE_ABNT_C1},
135
{ "I129", RDP_SCANCODE_ABNT_C2},
136
{ "AD11", RDP_SCANCODE_OEM_4},
137
{ "BKSL", RDP_SCANCODE_OEM_5},
138
{ "AD12", RDP_SCANCODE_OEM_6},
139
{ "AC11", RDP_SCANCODE_OEM_7},
140
{ "LSGT", RDP_SCANCODE_OEM_102},
141
{ "KPEN", RDP_SCANCODE_RETURN_KP}, // KP!
142
{ "PAUS", RDP_SCANCODE_PAUSE},
143
{ "PGUP", RDP_SCANCODE_PRIOR},
144
{ "PGDN", RDP_SCANCODE_NEXT},
145
{ "END", RDP_SCANCODE_END},
146
{ "HOME", RDP_SCANCODE_HOME},
147
{ "LEFT", RDP_SCANCODE_LEFT},
148
{ "UP", RDP_SCANCODE_UP},
149
{ "RGHT", RDP_SCANCODE_RIGHT},
150
{ "DOWN", RDP_SCANCODE_DOWN},
151
{ "PRSC", RDP_SCANCODE_PRINTSCREEN},
152
{ "INS", RDP_SCANCODE_INSERT},
153
{ "DELE", RDP_SCANCODE_DELETE},
154
{ "LWIN", RDP_SCANCODE_LWIN},
155
{ "RWIN", RDP_SCANCODE_RWIN},
156
{ "COMP", RDP_SCANCODE_APPS},
157
{ "MENU", RDP_SCANCODE_APPS}, // WinMenu in xfree86 layout
158
{ "KPDV", RDP_SCANCODE_DIVIDE}, // KP!
159
{ "RCTL", RDP_SCANCODE_RCONTROL},
160
{ "RALT", RDP_SCANCODE_RMENU},
161
{ "AE13", RDP_SCANCODE_BACKSLASH_JP}, // JP
162
{ "HKTG", RDP_SCANCODE_HIRAGANA}, // JP
163
{ "HENK", RDP_SCANCODE_CONVERT_JP}, // JP
164
{ "MUHE", RDP_SCANCODE_NONCONVERT_JP} // JP
165
/* { "LVL3", 0x54} */
168
void* freerdp_keyboard_xkb_init()
172
Display* display = XOpenDisplay(NULL);
177
status = XkbQueryExtension(display, NULL, NULL, NULL, NULL, NULL);
182
return (void*) display;
185
int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId, DWORD x11_keycode_to_rdp_scancode[256])
189
ZeroMemory(x11_keycode_to_rdp_scancode, sizeof(DWORD) * 256);
191
display = freerdp_keyboard_xkb_init();
195
DEBUG_KBD("Error initializing xkb");
199
if (*keyboardLayoutId == 0)
201
detect_keyboard_layout_from_xkbfile(display, keyboardLayoutId);
202
DEBUG_KBD("detect_keyboard_layout_from_xkb: %X", keyboardLayoutId);
205
freerdp_keyboard_load_map_from_xkbfile(display, x11_keycode_to_rdp_scancode);
207
XCloseDisplay(display);
212
/* return substring starting after nth comma, ending at following comma */
213
static char* comma_substring(char* s, int n)
222
if (!(p = strchr(s, ',')))
228
if ((p = strchr(s, ',')))
234
int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId)
240
XKeyboardState coreKbdState;
241
XkbRF_VarDefsRec rules_names;
243
DEBUG_KBD("display: %p", display);
245
if (display && XkbRF_GetNamesProp(display, NULL, &rules_names))
247
DEBUG_KBD("layouts: %s", rules_names.layout ? rules_names.layout : "");
248
DEBUG_KBD("variants: %s", rules_names.variant ? rules_names.variant : "");
250
XGetKeyboardControl(display, &coreKbdState);
252
if (XkbGetState(display, XkbUseCoreKbd, &state) == Success)
255
DEBUG_KBD("group: %d", state.group);
257
layout = comma_substring(rules_names.layout, group);
258
variant = comma_substring(rules_names.variant, group);
260
DEBUG_KBD("layout: %s", layout ? layout : "");
261
DEBUG_KBD("variant: %s", variant ? variant : "");
263
*keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
265
free(rules_names.model);
266
free(rules_names.layout);
267
free(rules_names.variant);
268
free(rules_names.options);
274
int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD x11_keycode_to_rdp_scancode[256])
281
if (display && (xkb = XkbGetMap(display, 0, XkbUseCoreKbd)))
283
if (XkbGetNames(display, XkbKeyNamesMask, xkb) == Success)
285
char xkb_keyname[5] = { 42, 42, 42, 42, 0 }; /* end-of-string at index 5 */
287
for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
290
CopyMemory(xkb_keyname, xkb->names->keys[i].name, 4);
292
if (strlen(xkb_keyname) < 1)
295
for (j = 0; j < ARRAYSIZE(XKB_KEY_NAME_SCANCODE_TABLE); j++)
297
if (!strcmp(xkb_keyname, XKB_KEY_NAME_SCANCODE_TABLE[j].xkb_keyname))
299
DEBUG_KBD("%4s: keycode: 0x%02X -> rdp scancode: 0x%04X",
300
xkb_keyname, i, XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode);
304
DEBUG_KBD("Internal error! duplicate key %s!", xkb_keyname);
307
x11_keycode_to_rdp_scancode[i] = XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode;
314
DEBUG_KBD("%4s: keycode: 0x%02X -> no RDP scancode found", xkb_keyname, i);
321
XkbFreeKeyboard(xkb, 0, 1);