~ubuntu-branches/ubuntu/raring/freerdp/raring-proposed

« back to all changes in this revision

Viewing changes to libfreerdp-kbd/layouts_xkb.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt, Jeremy Bicha, Jean-Louis Dupond, Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120131100214-jaok3uwvni7sqxth
Tags: 1.0.0-0git1
Upload current Debian packaging git to get this rolling for precise.

[ Jeremy Bicha ]
* New upstream release. Closes: #647498.
* Updated symbols and bumped soname
* debian/control:
  - Added new build dependencies
  - Bump Standards-Version to 3.9.2
* debian/source/format: Set to 3.0 (quilt)
* debian/rules: Turn on strict symbols checking
* debian/watch: Watch github

[ Jean-Louis Dupond ]
* debian/control: Updated homepage
* debian/copyright: Reflect upstream switch to the Apache license

[ Martin Pitt ]
* debian/libfreerdp0.symbols: Fix version number, should
  be 1.0~beta5, not 1.0-beta5.
* debian/control: Add libavcodec-dev build dependency, upstream build system
  checks for that. Thanks Jean-Louis Dupond!

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