libfreerdp: add proper config.h inclusions
[platform/upstream/freerdp.git] / libfreerdp / locale / keyboard_x11.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * X11 Keyboard Mapping
4  *
5  * Copyright 2009-2012 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "liblocale.h"
29 #include <freerdp/utils/memory.h>
30 #include <freerdp/locale/locale.h>
31 #include <freerdp/locale/keyboard.h>
32
33 #include "keyboard_x11.h"
34 #include "keyboard_keymap.h"
35 #include "xkb_layout_ids.h"
36
37 #ifdef WITH_SUN
38 #include "keyboard_sun.h"
39 #endif
40
41
42 extern const RDP_SCANCODE VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[256];
43
44
45 uint32 freerdp_detect_keyboard_layout_from_xkb(char** xkb_layout, char** xkb_variant)
46 {
47         char* pch;
48         char* beg;
49         char* end;
50         FILE* xprop;
51         char buffer[1024];
52         char* layout = NULL;
53         char* variant = NULL;
54         uint32 keyboardLayoutId = 0;
55
56         /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
57
58         xprop = popen("xprop -root _XKB_RULES_NAMES_BACKUP", "r");
59
60         /* Sample output for "Canadian Multilingual Standard"
61          *
62          * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multix", ""
63          * Where "xorg" is the set of rules
64          * "pc105" the keyboard type
65          * "ca" the keyboard layout
66          * "multi" the keyboard layout variant
67          */
68
69         while(fgets(buffer, sizeof(buffer), xprop) != NULL)
70         {
71                 if((pch = strstr(buffer, "_XKB_RULES_NAMES_BACKUP(STRING) = ")) != NULL)
72                 {
73                         /* "rules" */
74                         pch = strchr(&buffer[34], ','); // We assume it is xorg
75                         pch += 1;
76
77                         /* "type" */
78                         pch = strchr(pch, ',');
79
80                         /* "layout" */
81                         beg = strchr(pch + 1, '"');
82                         beg += 1;
83
84                         end = strchr(beg, '"');
85                         *end = '\0';
86
87                         layout = beg;
88
89                         /* "variant" */
90                         beg = strchr(end + 1, '"');
91                         beg += 1;
92
93                         end = strchr(beg, '"');
94                         *end = '\0';
95
96                         variant = beg;
97                 }
98         }
99         pclose(xprop);
100
101         DEBUG_KBD("_XKB_RULES_NAMES_BACKUP layout: %s, variant: %s", layout, variant);
102         keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
103
104         if (keyboardLayoutId > 0)
105         {
106                 *xkb_layout = xstrdup(layout);
107                 *xkb_variant = xstrdup(variant);
108                 return keyboardLayoutId;
109         }
110
111         /* Check _XKB_RULES_NAMES if _XKB_RULES_NAMES_BACKUP fails */
112
113         xprop = popen("xprop -root _XKB_RULES_NAMES", "r");
114
115         while(fgets(buffer, sizeof(buffer), xprop) != NULL)
116         {
117                 if((pch = strstr(buffer, "_XKB_RULES_NAMES(STRING) = ")) != NULL)
118                 {
119                         /* "rules" */
120                         pch = strchr(&buffer[27], ','); // We assume it is xorg
121                         pch += 1;
122
123                         /* "type" */
124                         pch = strchr(pch, ',');
125
126                         /* "layout" */
127                         beg = strchr(pch + 1, '"');
128                         beg += 1;
129
130                         end = strchr(beg, '"');
131                         *end = '\0';
132
133                         layout = beg;
134
135                         /* "variant" */
136                         beg = strchr(end + 1, '"');
137                         beg += 1;
138
139                         end = strchr(beg, '"');
140                         *end = '\0';
141
142                         variant = beg;
143                 }
144         }
145         pclose(xprop);
146
147         DEBUG_KBD("_XKB_RULES_NAMES layout: %s, variant: %s", layout, variant);
148         keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
149
150         if (keyboardLayoutId > 0)
151         {
152                 *xkb_layout = xstrdup(layout);
153                 *xkb_variant = xstrdup(variant);
154                 return keyboardLayoutId;
155         }
156
157         return 0;
158 }
159
160 char* freerdp_detect_keymap_from_xkb()
161 {
162         char* pch;
163         char* beg;
164         char* end;
165         int length;
166         FILE* setxkbmap;
167         char buffer[1024];
168         char* keymap = NULL;
169
170         /* this tells us about the current XKB configuration, if XKB is available */
171         setxkbmap = popen("setxkbmap -print", "r");
172
173         while (fgets(buffer, sizeof(buffer), setxkbmap) != NULL)
174         {
175                 /* the line with xkb_keycodes is what interests us */
176                 pch = strstr(buffer, "xkb_keycodes");
177
178                 if (pch != NULL)
179                 {
180                         pch = strstr(pch, "include");
181
182                         if (pch != NULL)
183                         {
184                                 /* check for " " delimiter presence */
185                                 if ((beg = strchr(pch, '"')) == NULL)
186                                         break;
187                                 else
188                                         beg++;
189
190                                 if ((pch = strchr(beg + 1, '"')) == NULL)
191                                         break;
192
193                                 end = strcspn(beg + 1, "\"") + beg + 1;
194                                 *end = '\0';
195
196                                 length = (end - beg);
197                                 keymap = (char*) xmalloc(length + 1);
198                                 strncpy(keymap, beg, length);
199                                 keymap[length] = '\0';
200
201                                 break;
202                         }
203                 }
204         }
205
206         pclose(setxkbmap);
207
208         return keymap;
209 }
210
211 uint32 freerdp_keyboard_init_x11(uint32 keyboardLayoutId, RDP_SCANCODE x11_keycode_to_rdp_scancode[256])
212 {
213         uint32 vkcode;
214         uint32 keycode;
215         uint32 keycode_to_vkcode[256];
216
217         memset(keycode_to_vkcode, 0, sizeof(keycode_to_vkcode));
218         memset(x11_keycode_to_rdp_scancode, 0, sizeof(x11_keycode_to_rdp_scancode));
219
220 #ifdef __APPLE__
221         /* Apple X11 breaks XKB detection */
222         freerdp_keyboard_load_map(keycode_to_vkcode, "macosx(macosx)");
223 #elif defined(WITH_SUN)
224         {
225                 char sunkeymap[32];
226
227                 freerdp_detect_keyboard_type_and_layout_solaris(sunkeymap, sizeof(sunkeymap));
228                 freerdp_keyboard_load_map(keycode_to_vkcode, sunkeymap);
229         }
230 #else
231         {
232                 char* keymap;
233                 char* xkb_layout;
234                 char* xkb_variant;
235
236                 if (keyboardLayoutId == 0)
237                 {
238                         keyboardLayoutId = freerdp_detect_keyboard_layout_from_xkb(&xkb_layout, &xkb_variant);
239                         xfree(xkb_layout);
240                         xfree(xkb_variant);
241                 }
242
243                 keymap = freerdp_detect_keymap_from_xkb();
244
245                 if (keymap != NULL)
246                 {
247                         freerdp_keyboard_load_maps(keycode_to_vkcode, keymap);
248                         xfree(keymap);
249                 }
250         }
251 #endif
252
253         for (keycode = 0; keycode < 256; keycode++)
254         {
255                 vkcode = keycode_to_vkcode[keycode];
256
257                 if (!(vkcode > 0 && vkcode < 256))
258                         continue;
259
260                 x11_keycode_to_rdp_scancode[keycode] = VIRTUAL_KEY_CODE_TO_DEFAULT_RDP_SCANCODE_TABLE[vkcode];
261         }
262
263         return keyboardLayoutId;
264 }