~ubuntu-branches/ubuntu/vivid/freerdp/vivid

« back to all changes in this revision

Viewing changes to libfreerdp-kbd/layouts_xkb.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2014-11-11 12:20:50 UTC
  • mfrom: (1.2.5)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20141111122050-7z628f4ab38qxad5
Tags: upstream-1.1.0~git20140921.1.440916e+dfsg1
ImportĀ upstreamĀ versionĀ 1.1.0~git20140921.1.440916e+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * FreeRDP: A Remote Desktop Protocol Client
3
 
 * XKB-based Keyboard Mapping to Microsoft Keyboard System
4
 
 *
5
 
 * Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 
 *
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
10
 
 *
11
 
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 
 *
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.
18
 
 */
19
 
 
20
 
#include <stdio.h>
21
 
#include <stdlib.h>
22
 
#include <string.h>
23
 
 
24
 
#ifdef WITH_XKBFILE
25
 
#include <X11/Xlib.h>
26
 
#include <X11/XKBlib.h>
27
 
#include <X11/extensions/XKBfile.h>
28
 
#include <X11/extensions/XKBrules.h>
29
 
#endif
30
 
 
31
 
#include "libkbd.h"
32
 
#include <freerdp/kbd/vkcodes.h>
33
 
#include "x_layout_id_table.h"
34
 
 
35
 
#include "layouts_xkb.h"
36
 
 
37
 
#ifndef KEYMAP_PATH
38
 
#define KEYMAP_PATH     "/usr/local/freerdp/keymaps"
39
 
#endif
40
 
 
41
 
#ifdef WITH_XKBFILE
42
 
 
43
 
int init_xkb(void* dpy)
44
 
{
45
 
        return XkbQueryExtension(dpy, NULL, NULL, NULL, NULL, NULL);
46
 
}
47
 
 
48
 
/* return substring starting after nth comma, ending at following comma */
49
 
static char* comma_substring(char* s, int n)
50
 
{
51
 
        char *p;
52
 
 
53
 
        if (!s)
54
 
                return "";
55
 
 
56
 
        while (n-- > 0)
57
 
        {
58
 
                if (!(p = strchr(s, ',')))
59
 
                        break;
60
 
 
61
 
                s = p + 1;
62
 
        }
63
 
 
64
 
        if ((p = strchr(s, ',')))
65
 
                *p = 0;
66
 
 
67
 
        return s;
68
 
}
69
 
 
70
 
unsigned int detect_keyboard_layout_from_xkb(void* dpy)
71
 
{
72
 
        char *layout, *variant;
73
 
        unsigned int keyboard_layout = 0, group = 0;
74
 
        XkbRF_VarDefsRec rules_names;
75
 
        XKeyboardState coreKbdState;
76
 
        XkbStateRec state;
77
 
 
78
 
        DEBUG_KBD("display: %p", dpy);
79
 
 
80
 
        if (dpy && XkbRF_GetNamesProp(dpy, NULL, &rules_names))
81
 
        {
82
 
                DEBUG_KBD("layouts: %s", rules_names.layout ? rules_names.layout : "");
83
 
                DEBUG_KBD("variants: %s", rules_names.variant ? rules_names.variant : "");
84
 
 
85
 
                XGetKeyboardControl(dpy, &coreKbdState);
86
 
 
87
 
                if (XkbGetState(dpy, XkbUseCoreKbd, &state) == Success)
88
 
                        group = state.group;
89
 
 
90
 
                DEBUG_KBD("group: %d", state.group);
91
 
 
92
 
                layout = comma_substring(rules_names.layout, group);
93
 
                variant = comma_substring(rules_names.variant, group);
94
 
 
95
 
                DEBUG_KBD("layout: %s", layout ? layout : "");
96
 
                DEBUG_KBD("variant: %s", variant ? variant : "");
97
 
 
98
 
                keyboard_layout = find_keyboard_layout_in_xorg_rules(layout, variant);
99
 
 
100
 
                free(rules_names.model);
101
 
                free(rules_names.layout);
102
 
                free(rules_names.variant);
103
 
                free(rules_names.options);
104
 
        }
105
 
 
106
 
        return keyboard_layout;
107
 
}
108
 
 
109
 
int init_keycodes_from_xkb(void* dpy, RdpScancodes x_keycode_to_rdp_scancode, uint8 rdp_scancode_to_x_keycode[256][2])
110
 
{
111
 
        int ret = 0;
112
 
        XkbDescPtr xkb;
113
 
 
114
 
        if (dpy && (xkb = XkbGetMap(dpy, 0, XkbUseCoreKbd)))
115
 
        {
116
 
                if (XkbGetNames(dpy, XkbKeyNamesMask, xkb) == Success)
117
 
                {
118
 
                        int i, j;
119
 
                        char buf[5] = {42, 42, 42, 42, 0}; /* end-of-string at pos 5 */
120
 
 
121
 
                        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
122
 
                        {
123
 
                                memcpy(buf, xkb->names->keys[i].name, 4);
124
 
 
125
 
                                /* TODO: Use more efficient search ... but it is so fast that it doesn't matter */
126
 
                                j = sizeof(virtualKeyboard) / sizeof(virtualKeyboard[0]) - 1;
127
 
 
128
 
                                while (j >= 0)
129
 
                                {
130
 
                                        if (virtualKeyboard[j].x_keyname && !strcmp(buf, virtualKeyboard[j].x_keyname))
131
 
                                                break;
132
 
                                        j--;
133
 
                                }
134
 
 
135
 
                                if (j >= 0)
136
 
                                {
137
 
                                        DEBUG_KBD("X keycode %3d has keyname %-4s -> RDP scancode %d/%d",
138
 
                                                        i, buf, virtualKeyboard[j].extended, virtualKeyboard[j].scancode);
139
 
 
140
 
                                        x_keycode_to_rdp_scancode[i].extended = virtualKeyboard[j].extended;
141
 
                                        x_keycode_to_rdp_scancode[i].keycode = virtualKeyboard[j].scancode;
142
 
                                        x_keycode_to_rdp_scancode[i].keyname = virtualKeyboard[j].x_keyname;
143
 
 
144
 
                                        if (x_keycode_to_rdp_scancode[i].extended)
145
 
                                                rdp_scancode_to_x_keycode[virtualKeyboard[j].scancode][1] = i;
146
 
                                        else
147
 
                                                rdp_scancode_to_x_keycode[virtualKeyboard[j].scancode][0] = i;
148
 
                                }
149
 
                                else
150
 
                                {
151
 
                                        DEBUG_KBD("X key code %3d has keyname %-4s -> ??? - not found", i, buf);
152
 
                                }
153
 
                        }
154
 
                        ret = 1;
155
 
                }
156
 
                XkbFreeKeyboard(xkb, 0, 1);
157
 
        }
158
 
        return ret;
159
 
}
160
 
 
161
 
#else
162
 
 
163
 
/* Default built-in keymap */
164
 
static const KeycodeToVkcode defaultKeycodeToVkcode =
165
 
{
166
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
167
 
        0x37, 0x38, 0x39, 0x30, 0xBD, 0xBB, 0x08, 0x09, 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49,
168
 
        0x4F, 0x50, 0xDB, 0xDD, 0x0D, 0xA2, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0xBA,
169
 
        0xDE, 0xC0, 0xA0, 0x00, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0xBC, 0xBE, 0xBF, 0xA1, 0x6A,
170
 
        0x12, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x67,
171
 
        0x68, 0x69, 0x6D, 0x64, 0x65, 0x66, 0x6B, 0x61, 0x62, 0x63, 0x60, 0x6E, 0x00, 0x00, 0x00, 0x7A,
172
 
        0x7B, 0x24, 0x26, 0x21, 0x25, 0x00, 0x27, 0x23, 0x28, 0x22, 0x2D, 0x2E, 0x0D, 0xA3, 0x13, 0x2C,
173
 
        0x6F, 0x12, 0x00, 0x5B, 0x5C, 0x5D, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
174
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179
 
        0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
182
 
};
183
 
 
184
 
static int load_xkb_keyboard(KeycodeToVkcode map, char* kbd)
185
 
{
186
 
        char* pch;
187
 
        char *beg, *end;
188
 
        char* home;
189
 
        char buffer[1024] = "";
190
 
        char xkbfile[256] = "";
191
 
        char xkbfilepath[512] = "";
192
 
        char xkbmap[256] = "";
193
 
        char xkbinc[256] = "";
194
 
 
195
 
        FILE* fp;
196
 
        int kbdFound = 0;
197
 
 
198
 
        int i = 0;
199
 
        int keycode = 0;
200
 
        char keycodeString[32] = "";
201
 
        char vkcodeName[128] = "";
202
 
 
203
 
        beg = kbd;
204
 
 
205
 
        /* Extract file name and keymap name */
206
 
        if ((end = strrchr(kbd, '(')) != NULL)
207
 
        {
208
 
                strncpy(xkbfile, &kbd[beg - kbd], end - beg);
209
 
 
210
 
                beg = end + 1;
211
 
                if ((end = strrchr(kbd, ')')) != NULL)
212
 
                {
213
 
                        strncpy(xkbmap, &kbd[beg - kbd], end - beg);
214
 
                        xkbmap[end - beg] = '\0';
215
 
                }
216
 
        }
217
 
        else
218
 
        {
219
 
                /* The keyboard name is the same as the file name */
220
 
                strcpy(xkbfile, kbd);
221
 
                strcpy(xkbmap, kbd);
222
 
        }
223
 
 
224
 
        /* Get path to file relative to freerdp's directory */
225
 
        snprintf(xkbfilepath, sizeof(xkbfilepath), "keymaps/%s", xkbfile);
226
 
        DEBUG_KBD("Loading keymap %s, first trying %s", kbd, xkbfilepath);
227
 
 
228
 
        /*
229
 
         *  Open the file for reading only
230
 
         * It can happen that the same file is opened twice at the same time
231
 
         * in order to load multiple keyboard maps from the same file, but
232
 
         * it does not matter: files can be opened as many times as we want
233
 
         * when it is for reading only.
234
 
         */
235
 
 
236
 
        if ((fp = fopen(xkbfilepath, "r")) == NULL)
237
 
        {
238
 
                /* Look first in path given at compile time (install path) */
239
 
                snprintf(xkbfilepath, sizeof(xkbfilepath), "%s/%s", KEYMAP_PATH, xkbfile);
240
 
 
241
 
                if ((fp = fopen(xkbfilepath, "r")) == NULL)
242
 
                {
243
 
                        /* If ran from the root of the source tree */
244
 
                        snprintf(xkbfilepath, sizeof(xkbfilepath), "./keymaps/%s", xkbfile);
245
 
 
246
 
                        /* If ran from the client directory */
247
 
                        if((fp = fopen(xkbfilepath, "r")) == NULL)
248
 
                                snprintf(xkbfilepath, sizeof(xkbfilepath), "../../keymaps/%s", xkbfile);
249
 
 
250
 
                        if ((fp = fopen(xkbfilepath, "r")) == NULL)
251
 
                        {
252
 
                                /* File wasn't found in the source tree, try ~/.freerdp/ folder */
253
 
                                if ((home = getenv("HOME")) == NULL)
254
 
                                        return 0;
255
 
 
256
 
                                /* Get path to file in ~/.freerdp/ folder */
257
 
                                snprintf(xkbfilepath, sizeof(xkbfilepath), "%s/.freerdp/keymaps/%s", home, xkbfile);
258
 
 
259
 
                                if ((fp = fopen(xkbfilepath, "r")) == NULL)
260
 
                                {
261
 
                                        /* Try /usr/share/freerdp folder */
262
 
                                        snprintf(xkbfilepath, sizeof(xkbfilepath), "/usr/share/freerdp/keymaps/%s", xkbfile);
263
 
 
264
 
                                        if ((fp = fopen(xkbfilepath, "r")) == NULL)
265
 
                                        {
266
 
                                                /* Try /usr/local/share/freerdp folder */
267
 
                                                snprintf(xkbfilepath, sizeof(xkbfilepath), "/usr/local/share/freerdp/keymaps/%s", xkbfile);
268
 
 
269
 
                                                if ((fp = fopen(xkbfilepath, "r")) == NULL)
270
 
                                                {
271
 
                                                        /* Error: Could not find keymap */
272
 
                                                        DEBUG_KBD("keymaps for %s not found", xkbfile);
273
 
                                                        return 0;
274
 
                                                }
275
 
                                        }
276
 
                                }
277
 
                        }
278
 
                }
279
 
        }
280
 
 
281
 
        DEBUG_KBD("xkbfilepath: %s", xkbfilepath);
282
 
 
283
 
        while(fgets(buffer, sizeof(buffer), fp) != NULL)
284
 
        {
285
 
                if (buffer[0] == '#')
286
 
                {
287
 
                        continue; /* Skip comments */
288
 
                }
289
 
 
290
 
                if (kbdFound)
291
 
                {
292
 
                        /* Closing curly bracket and semicolon */
293
 
                        if ((pch = strstr(buffer, "};")) != NULL)
294
 
                        {
295
 
                                break;
296
 
                        }
297
 
                        else if ((pch = strstr(buffer, "VK_")) != NULL)
298
 
                        {
299
 
                                /* The end is delimited by the first white space */
300
 
                                end = strcspn(pch, " \t\n\0") + pch;
301
 
 
302
 
                                /* We copy the virtual key code name in a string */
303
 
                                beg = pch;
304
 
                                strncpy(vkcodeName, beg, end - beg);
305
 
                                vkcodeName[end - beg] = '\0';
306
 
 
307
 
                                /* Now we want to extract the virtual key code itself which is in between '<' and '>' */
308
 
                                if ((beg = strchr(pch + 3, '<')) == NULL)
309
 
                                        break;
310
 
                                else
311
 
                                        beg++;
312
 
 
313
 
                                if ((end = strchr(beg, '>')) == NULL)
314
 
                                        break;
315
 
 
316
 
                                /* We copy the string representing the number in a string */
317
 
                                strncpy(keycodeString, beg, end - beg);
318
 
                                keycodeString[end - beg] = '\0';
319
 
 
320
 
                                /* Convert the string representing the code to an integer */
321
 
                                keycode = atoi(keycodeString);
322
 
 
323
 
                                /* Make sure it is a valid keycode */
324
 
                                if (keycode < 0 || keycode > 255)
325
 
                                        break;
326
 
 
327
 
                                /* Load this key mapping in the keyboard mapping */
328
 
                                for(i = 0; i < sizeof(virtualKeyboard) / sizeof(virtualKey); i++)
329
 
                                {
330
 
                                        if (strcmp(vkcodeName, virtualKeyboard[i].name) == 0)
331
 
                                        {
332
 
                                                map[keycode] = i;
333
 
                                        }
334
 
                                }
335
 
                        }
336
 
                        else if ((pch = strstr(buffer, ": extends")) != NULL)
337
 
                        {
338
 
                                /*
339
 
                                 * This map extends another keymap We extract its name
340
 
                                 * and we recursively load the keymap we need to include.
341
 
                                 */
342
 
 
343
 
                                if ((beg = strchr(pch + sizeof(": extends"), '"')) == NULL)
344
 
                                        break;
345
 
                                beg++;
346
 
 
347
 
                                if ((end = strchr(beg, '"')) == NULL)
348
 
                                        break;
349
 
 
350
 
                                strncpy(xkbinc, beg, end - beg);
351
 
                                xkbinc[end - beg] = '\0';
352
 
 
353
 
                                load_xkb_keyboard(map, xkbinc); /* Load included keymap */
354
 
                        }
355
 
                }
356
 
                else if ((pch = strstr(buffer, "keyboard")) != NULL)
357
 
                {
358
 
                        /* Keyboard map identifier */
359
 
                        if ((beg = strchr(pch + sizeof("keyboard"), '"')) == NULL)
360
 
                                break;
361
 
                        beg++;
362
 
 
363
 
                        if ((end = strchr(beg, '"')) == NULL)
364
 
                                break;
365
 
 
366
 
                        pch = beg;
367
 
                        buffer[end - beg] = '\0';
368
 
 
369
 
                        /* Does it match our keymap name? */
370
 
                        if (strncmp(xkbmap, pch, strlen(xkbmap)) == 0)
371
 
                                kbdFound = 1;
372
 
                }
373
 
        }
374
 
 
375
 
        fclose(fp); /* Don't forget to close file */
376
 
 
377
 
        return 1;
378
 
}
379
 
 
380
 
void load_keyboard_map(KeycodeToVkcode keycodeToVkcode, char *xkbfile)
381
 
{
382
 
        char* kbd;
383
 
        char* xkbfileEnd;
384
 
        int keymapLoaded = 0;
385
 
 
386
 
        memset(keycodeToVkcode, 0, sizeof(keycodeToVkcode));
387
 
 
388
 
        kbd = xkbfile;
389
 
        xkbfileEnd = xkbfile + strlen(xkbfile);
390
 
 
391
 
#ifdef __APPLE__
392
 
        /* Apple X11 breaks XKB detection */
393
 
        keymapLoaded += load_xkb_keyboard(keycodeToVkcode, "macosx(macosx)");
394
 
#else
395
 
        do
396
 
        {
397
 
                /* Multiple maps are separated by '+' */
398
 
                int kbdlen = strcspn(kbd + 1, "+") + 1;
399
 
                kbd[kbdlen] = '\0';
400
 
 
401
 
                /* Load keyboard map */
402
 
                keymapLoaded += load_xkb_keyboard(keycodeToVkcode, kbd);
403
 
 
404
 
                kbd += kbdlen + 1;
405
 
        }
406
 
        while (kbd < xkbfileEnd);
407
 
#endif
408
 
 
409
 
        DEBUG_KBD("loaded %d keymaps", keymapLoaded);
410
 
        if (keymapLoaded <= 0)
411
 
        {
412
 
                /* No keymap was loaded, load default hard-coded keymap */
413
 
                DEBUG_KBD("using default keymap");
414
 
                memcpy(keycodeToVkcode, defaultKeycodeToVkcode, sizeof(keycodeToVkcode));
415
 
        }
416
 
}
417
 
 
418
 
#endif