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