FreeRDP
keyboard_sun.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 
27 #include <winpr/crt.h>
28 
29 #include "liblocale.h"
30 
31 #include <freerdp/locale/keyboard.h>
32 
33 #include "keyboard_x11.h"
34 
35 #include "keyboard_sun.h"
36 
37 /* OpenSolaris 2008.11 and 2009.06 keyboard layouts
38  *
39  * While OpenSolaris comes with Xorg and XKB, it maintains a set of keyboard layout
40  * names that map directly to a particular keyboard layout in XKB. Fortunately for us,
41  * this way of doing things comes from Solaris, which is XKB unaware. The same keyboard
42  * layout naming system is used in Solaris, so we can use the same XKB configuration as
43  * we would on OpenSolaris and get an accurate keyboard layout detection :)
44  *
45  * We can check for the current keyboard layout using the "kbd -l" command:
46  *
47  * type=6
48  * layout=33 (0x21)
49  * delay(ms)=500
50  * rate(ms)=40
51  *
52  * We can check at runtime if the kbd utility is present, parse the output, and use the
53  * keyboard layout indicated by the index given (in this case, 33, or US-English).
54  */
55 
56 typedef struct
57 {
58  UINT32 type; /* Solaris keyboard type */
59  UINT32 layout; /* Layout */
60  char* xkbType; /* XKB keyboard */
61  UINT32 keyboardLayoutId; /* XKB keyboard layout */
62 } SOLARIS_KEYBOARD;
63 
64 static const SOLARIS_KEYBOARD SOLARIS_KEYBOARD_TABLE[] = {
65  { 4, 0, "sun(type4)", KBD_US }, /* US4 */
66  { 4, 1, "sun(type4)", KBD_US }, /* US4 */
67  { 4, 2, "sun(type4tuv)", KBD_FRENCH }, /* FranceBelg4 */
68  { 4, 3, "sun(type4_ca)", KBD_US }, /* Canada4 */
69  { 4, 4, "sun(type4tuv)", KBD_DANISH }, /* Denmark4 */
70  { 4, 5, "sun(type4tuv)", KBD_GERMAN }, /* Germany4 */
71  { 4, 6, "sun(type4tuv)", KBD_ITALIAN }, /* Italy4 */
72  { 4, 7, "sun(type4tuv)", KBD_DUTCH }, /* Netherland4 */
73  { 4, 8, "sun(type4tuv)", KBD_NORWEGIAN }, /* Norway4 */
74  { 4, 9, "sun(type4tuv)", KBD_PORTUGUESE }, /* Portugal4 */
75  { 4, 10, "sun(type4tuv)", KBD_SPANISH }, /* SpainLatAm4 */
76  { 4, 11, "sun(type4tuv)", KBD_SWEDISH }, /* SwedenFin4 */
77  { 4, 12, "sun(type4tuv)", KBD_SWISS_FRENCH }, /* Switzer_Fr4 */
78  { 4, 13, "sun(type4tuv)", KBD_SWISS_GERMAN }, /* Switzer_Ge4 */
79  { 4, 14, "sun(type4tuv)", KBD_UNITED_KINGDOM }, /* UK4 */
80  { 4, 16, "sun(type4)", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* Korea4 */
81  { 4, 17, "sun(type4)", KBD_CHINESE_TRADITIONAL_PHONETIC }, /* Taiwan4 */
82  { 4, 32, "sun(type4jp)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan4 */
83  { 4, 19, "sun(type5)", KBD_US }, /* US101A_PC */
84  { 4, 33, "sun(type5)", KBD_US }, /* US5 */
85  { 4, 34, "sun(type5unix)", KBD_US }, /* US_UNIX5 */
86  { 4, 35, "sun(type5tuv)", KBD_FRENCH }, /* France5 */
87  { 4, 36, "sun(type5tuv)", KBD_DANISH }, /* Denmark5 */
88  { 4, 37, "sun(type5tuv)", KBD_GERMAN }, /* Germany5 */
89  { 4, 38, "sun(type5tuv)", KBD_ITALIAN }, /* Italy5 */
90  { 4, 39, "sun(type5tuv)", KBD_DUTCH }, /* Netherland5 */
91  { 4, 40, "sun(type5tuv)", KBD_NORWEGIAN }, /* Norway5 */
92  { 4, 41, "sun(type5tuv)", KBD_PORTUGUESE }, /* Portugal5 */
93  { 4, 42, "sun(type5tuv)", KBD_SPANISH }, /* Spain5 */
94  { 4, 43, "sun(type5tuv)", KBD_SWEDISH }, /* Sweden5 */
95  { 4, 44, "sun(type5tuv)", KBD_SWISS_FRENCH }, /* Switzer_Fr5 */
96  { 4, 45, "sun(type5tuv)", KBD_SWISS_GERMAN }, /* Switzer_Ge5 */
97  { 4, 46, "sun(type5tuv)", KBD_UNITED_KINGDOM }, /* UK5 */
98  { 4, 47, "sun(type5)", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* Korea5 */
99  { 4, 48, "sun(type5)", KBD_CHINESE_TRADITIONAL_PHONETIC }, /* Taiwan5 */
100  { 4, 49, "sun(type5jp)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan5 */
101  { 4, 50, "sun(type5tuv)", KBD_CANADIAN_FRENCH }, /* Canada_Fr5 */
102  { 4, 51, "sun(type5tuv)", KBD_HUNGARIAN }, /* Hungary5 */
103  { 4, 52, "sun(type5tuv)", KBD_POLISH_214 }, /* Poland5 */
104  { 4, 53, "sun(type5tuv)", KBD_CZECH }, /* Czech5 */
105  { 4, 54, "sun(type5tuv)", KBD_RUSSIAN }, /* Russia5 */
106  { 4, 55, "sun(type5tuv)", KBD_LATVIAN }, /* Latvia5 */
107  { 4, 57, "sun(type5tuv)", KBD_GREEK }, /* Greece5 */
108  { 4, 59, "sun(type5tuv)", KBD_LITHUANIAN }, /* Lithuania5 */
109  { 4, 63, "sun(type5tuv)", KBD_CANADIAN_FRENCH }, /* Canada_Fr5_TBITS5 */
110  { 4, 56, "sun(type5tuv)", KBD_TURKISH_Q }, /* TurkeyQ5 */
111  { 4, 58, "sun(type5tuv)", KBD_ARABIC_101 }, /* Arabic5 */
112  { 4, 60, "sun(type5tuv)", KBD_BELGIAN_FRENCH }, /* Belgian5 */
113  { 4, 62, "sun(type5tuv)", KBD_TURKISH_F }, /* TurkeyF5 */
114  { 4, 80, "sun(type5hobo)", KBD_US }, /* US5_Hobo */
115  { 4, 81, "sun(type5hobo)", KBD_US }, /* US_UNIX5_Hobo */
116  { 4, 82, "sun(type5tuvhobo)", KBD_FRENCH }, /* France5_Hobo */
117  { 4, 83, "sun(type5tuvhobo)", KBD_DANISH }, /* Denmark5_Hobo */
118  { 4, 84, "sun(type5tuvhobo)", KBD_GERMAN }, /* Germany5_Hobo */
119  { 4, 85, "sun(type5tuvhobo)", KBD_ITALIAN }, /* Italy5_Hobo */
120  { 4, 86, "sun(type5tuvhobo)", KBD_DUTCH }, /* Netherland5_Hobo */
121  { 4, 87, "sun(type5tuvhobo)", KBD_NORWEGIAN }, /* Norway5_Hobo */
122  { 4, 88, "sun(type5tuvhobo)", KBD_PORTUGUESE }, /* Portugal5_Hobo */
123  { 4, 89, "sun(type5tuvhobo)", KBD_SPANISH }, /* Spain5_Hobo */
124  { 4, 90, "sun(type5tuvhobo)", KBD_SWEDISH }, /* Sweden5_Hobo */
125  { 4, 91, "sun(type5tuvhobo)", KBD_SWISS_FRENCH }, /* Switzer_Fr5_Hobo */
126  { 4, 92, "sun(type5tuvhobo)", KBD_SWISS_GERMAN }, /* Switzer_Ge5_Hobo */
127  { 4, 93, "sun(type5tuvhobo)", KBD_UNITED_KINGDOM }, /* UK5_Hobo */
128  { 4, 94, "sun(type5hobo)", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* Korea5_Hobo */
129  { 4, 95, "sun(type5hobo)", KBD_CHINESE_TRADITIONAL_PHONETIC }, /* Taiwan5_Hobo */
130  { 4, 96, "sun(type5jphobo)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan5_Hobo */
131  { 4, 97, "sun(type5tuvhobo)", KBD_CANADIAN_FRENCH }, /* Canada_Fr5_Hobo */
132  { 101, 1, "digital_vndr/pc(pc104)", KBD_US }, /* US101A_x86 */
133  { 101, 34, "digital_vndr/pc(pc104)", KBD_US }, /* J3100_x86 */
134  { 101, 35, "digital_vndr/pc(pc104)", KBD_FRENCH }, /* France_x86 */
135  { 101, 36, "digital_vndr/pc(pc104)", KBD_DANISH }, /* Denmark_x86 */
136  { 101, 37, "digital_vndr/pc(pc104)", KBD_GERMAN }, /* Germany_x86 */
137  { 101, 38, "digital_vndr/pc(pc104)", KBD_ITALIAN }, /* Italy_x86 */
138  { 101, 39, "digital_vndr/pc(pc104)", KBD_DUTCH }, /* Netherland_x86 */
139  { 101, 40, "digital_vndr/pc(pc104)", KBD_NORWEGIAN }, /* Norway_x86 */
140  { 101, 41, "digital_vndr/pc(pc104)", KBD_PORTUGUESE }, /* Portugal_x86 */
141  { 101, 42, "digital_vndr/pc(pc104)", KBD_SPANISH }, /* Spain_x86 */
142  { 101, 43, "digital_vndr/pc(pc104)", KBD_SWEDISH }, /* Sweden_x86 */
143  { 101, 44, "digital_vndr/pc(pc104)", KBD_SWISS_FRENCH }, /* Switzer_Fr_x86 */
144  { 101, 45, "digital_vndr/pc(pc104)", KBD_SWISS_GERMAN }, /* Switzer_Ge_x86 */
145  { 101, 46, "digital_vndr/pc(pc104)", KBD_UNITED_KINGDOM }, /* UK_x86 */
146  { 101, 47, "digital_vndr/pc(pc104)", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* Korea_x86 */
147  { 101, 48, "digital_vndr/pc(pc104)", KBD_CHINESE_TRADITIONAL_PHONETIC }, /* Taiwan_x86 */
148  { 101, 49, "digital_vndr/pc(lk411jj)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan_x86 */
149  { 101, 50, "digital_vndr/pc(pc104)", KBD_CANADIAN_FRENCH }, /* Canada_Fr2_x86 */
150  { 101, 51, "digital_vndr/pc(pc104)", KBD_HUNGARIAN }, /* Hungary_x86 */
151  { 101, 52, "digital_vndr/pc(pc104)", KBD_POLISH_214 }, /* Poland_x86 */
152  { 101, 53, "digital_vndr/pc(pc104)", KBD_CZECH }, /* Czech_x86 */
153  { 101, 54, "digital_vndr/pc(pc104)", KBD_RUSSIAN }, /* Russia_x86 */
154  { 101, 55, "digital_vndr/pc(pc104)", KBD_LATVIAN }, /* Latvia_x86 */
155  { 101, 56, "digital_vndr/pc(pc104)", KBD_TURKISH_Q }, /* Turkey_x86 */
156  { 101, 57, "digital_vndr/pc(pc104)", KBD_GREEK }, /* Greece_x86 */
157  { 101, 59, "digital_vndr/pc(pc104)", KBD_LITHUANIAN }, /* Lithuania_x86 */
158  { 101, 1001, "digital_vndr/pc(pc104)", KBD_US }, /* MS_US101A_x86 */
159  { 6, 6, "sun(type6tuv)", KBD_DANISH }, /* Denmark6_usb */
160  { 6, 7, "sun(type6tuv)", KBD_FINNISH }, /* Finnish6_usb */
161  { 6, 8, "sun(type6tuv)", KBD_FRENCH }, /* France6_usb */
162  { 6, 9, "sun(type6tuv)", KBD_GERMAN }, /* Germany6_usb */
163  { 6, 14, "sun(type6tuv)", KBD_ITALIAN }, /* Italy6_usb */
164  { 6, 15, "sun(type6jp)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan7_usb */
165  { 6, 16, "sun(type6)", KBD_KOREAN_INPUT_SYSTEM_IME_2000 }, /* Korea6_usb */
166  { 6, 18, "sun(type6tuv)", KBD_DUTCH }, /* Netherland6_usb */
167  { 6, 19, "sun(type6tuv)", KBD_NORWEGIAN }, /* Norway6_usb */
168  { 6, 22, "sun(type6tuv)", KBD_PORTUGUESE }, /* Portugal6_usb */
169  { 6, 23, "sun(type6tuv)", KBD_RUSSIAN }, /* Russia6_usb */
170  { 6, 25, "sun(type6tuv)", KBD_SPANISH }, /* Spain6_usb */
171  { 6, 26, "sun(type6tuv)", KBD_SWEDISH }, /* Sweden6_usb */
172  { 6, 27, "sun(type6tuv)", KBD_SWISS_FRENCH }, /* Switzer_Fr6_usb */
173  { 6, 28, "sun(type6tuv)", KBD_SWISS_GERMAN }, /* Switzer_Ge6_usb */
174  { 6, 30, "sun(type6)", KBD_CHINESE_TRADITIONAL_PHONETIC }, /* Taiwan6_usb */
175  { 6, 32, "sun(type6tuv)", KBD_UNITED_KINGDOM }, /* UK6_usb */
176  { 6, 33, "sun(type6)", KBD_US }, /* US6_usb */
177  { 6, 1, "sun(type6tuv)", KBD_ARABIC_101 }, /* Arabic6_usb */
178  { 6, 2, "sun(type6tuv)", KBD_BELGIAN_FRENCH }, /* Belgian6_usb */
179  { 6, 31, "sun(type6tuv)", KBD_TURKISH_Q }, /* TurkeyQ6_usb */
180  { 6, 35, "sun(type6tuv)", KBD_TURKISH_F }, /* TurkeyF6_usb */
181  { 6, 271, "sun(type6jp)", KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002 }, /* Japan6_usb */
182  { 6, 264, "sun(type6tuv)", KBD_ALBANIAN }, /* Albanian6_usb */
183  { 6, 261, "sun(type6tuv)", KBD_BELARUSIAN }, /* Belarusian6_usb */
184  { 6, 260, "sun(type6tuv)", KBD_BULGARIAN }, /* Bulgarian6_usb */
185  { 6, 259, "sun(type6tuv)", KBD_CROATIAN }, /* Croatian6_usb */
186  { 6, 5, "sun(type6tuv)", KBD_CZECH }, /* Czech6_usb */
187  { 6, 4, "sun(type6tuv)", KBD_CANADIAN_FRENCH }, /* French-Canadian6_usb */
188  { 6, 12, "sun(type6tuv)", KBD_HUNGARIAN }, /* Hungarian6_usb */
189  { 6, 10, "sun(type6tuv)", KBD_GREEK }, /* Greek6_usb */
190  { 6, 17, "sun(type6)", KBD_LATIN_AMERICAN }, /* Latin-American6_usb */
191  { 6, 265, "sun(type6tuv)", KBD_LITHUANIAN }, /* Lithuanian6_usb */
192  { 6, 266, "sun(type6tuv)", KBD_LATVIAN }, /* Latvian6_usb */
193  { 6, 267, "sun(type6tuv)", KBD_FYRO_MACEDONIAN }, /* Macedonian6_usb */
194  { 6, 263, "sun(type6tuv)", KBD_MALTESE_47_KEY }, /* Malta_UK6_usb */
195  { 6, 262, "sun(type6tuv)", KBD_MALTESE_48_KEY }, /* Malta_US6_usb */
196  { 6, 21, "sun(type6tuv)", KBD_POLISH_214 }, /* Polish6_usb */
197  { 6, 257, "sun(type6tuv)", KBD_SERBIAN_LATIN }, /* Serbia-And-Montenegro6_usb */
198  { 6, 256, "sun(type6tuv)", KBD_SLOVENIAN }, /* Slovenian6_usb */
199  { 6, 24, "sun(type6tuv)", KBD_SLOVAK }, /* Slovakian6_usb */
200  { 6, 3, "sun(type6)", KBD_CANADIAN_MULTILINGUAL_STANDARD }, /* Canada_Bi6_usb */
201  { 6, 272, "sun(type6)", KBD_PORTUGUESE_BRAZILIAN_ABNT } /* Brazil6_usb */
202 };
203 
204 int freerdp_get_solaris_keyboard_layout_and_type(int* type, int* layout)
205 {
206  FILE* kbd;
207  char* pch;
208  char* beg;
209  char* end;
210  int rc = -1;
211  char buffer[1024];
212  /*
213  Sample output for "kbd -t -l" :
214 
215  USB keyboard
216  type=6
217  layout=3 (0x03)
218  delay(ms)=500
219  rate(ms)=40
220  */
221  *type = 0;
222  *layout = 0;
223  kbd = popen("kbd -t -l", "r");
224 
225  if (!kbd)
226  return -1;
227 
228  while (fgets(buffer, sizeof(buffer), kbd) != NULL)
229  {
230  long val;
231 
232  if ((pch = strstr(buffer, "type=")) != NULL)
233  {
234  beg = pch + sizeof("type=") - 1;
235  end = strchr(beg, '\n');
236  end[0] = '\0';
237  errno = 0;
238  val = strtol(beg, NULL, 0);
239 
240  if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
241  goto fail;
242 
243  *type = val;
244  }
245  else if ((pch = strstr(buffer, "layout=")) != NULL)
246  {
247  beg = pch + sizeof("layout=") - 1;
248  end = strchr(beg, ' ');
249  end[0] = '\0';
250  errno = 0;
251  val = strtol(beg, NULL, 0);
252 
253  if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
254  goto fail;
255 
256  *layout = val;
257  }
258  }
259 
260  rc = 0;
261 fail:
262  pclose(kbd);
263  return rc;
264 }
265 
266 DWORD freerdp_detect_solaris_keyboard_layout()
267 {
268  int type;
269  int layout;
270 
271  if (freerdp_get_solaris_keyboard_layout_and_type(&type, &layout) < 0)
272  return 0;
273 
274  for (size_t i = 0; i < ARRAYSIZE(SOLARIS_KEYBOARD_TABLE); i++)
275  {
276  if (SOLARIS_KEYBOARD_TABLE[i].type == type)
277  {
278  if (SOLARIS_KEYBOARD_TABLE[i].layout == layout)
279  return SOLARIS_KEYBOARD_TABLE[i].keyboardLayoutId;
280  }
281  }
282 
283  return 0;
284 }