FreeRDP
keyboard_x11.c
1 
21 #include <string.h>
22 
23 #include <X11/X.h>
24 #include <X11/Xatom.h>
25 #include <X11/Xlib.h>
26 
27 #include "liblocale.h"
28 #include "keyboard_x11.h"
29 #include "xkb_layout_ids.h"
30 
31 static BOOL parse_xkb_rule_names(char* xkb_rule, unsigned long num_bytes, char** layout,
32  char** variant)
33 {
34  /* Sample output for "Canadian Multilingual Standard"
35  *
36  * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multi", "magic"
37  *
38  * Format: "rules", "model", "layout", "variant", "options"
39  *
40  * Where "xorg" is the set of rules
41  * "pc105" the keyboard model
42  * "ca" the keyboard layout(s) (can also be something like 'us,uk')
43  * "multi" the keyboard layout variant(s) (in the examples, “,winkeys” - which means first
44  * layout uses some “default” variant and second uses “winkeys” variant)
45  * "magic" - configuration option (in the examples,
46  * “eurosign:e,lv3:ralt_switch,grp:rctrl_toggle”
47  * - three options)
48  */
49  for (size_t i = 0, index = 0; i < num_bytes; i++, index++)
50  {
51  char* ptr = xkb_rule + i;
52 
53  switch (index)
54  {
55  case 0: // rules
56  break;
57  case 1: // model
58  break;
59  case 2: // layout
60  {
61  /* If multiple languages are present we just take the first one */
62  char* delimiter = strchr(ptr, ',');
63  if (delimiter)
64  *delimiter = '\0';
65  *layout = ptr;
66  break;
67  }
68  case 3: // variant
69  *variant = ptr;
70  break;
71  case 4: // option
72  break;
73  default:
74  break;
75  }
76  i += strlen(ptr);
77  }
78  return TRUE;
79 }
80 
81 static DWORD kbd_layout_id_from_x_property(Display* display, Window root, char* property_name)
82 {
83  char* layout = NULL;
84  char* variant = NULL;
85  char* rule = NULL;
86  Atom type = None;
87  int item_size = 0;
88  unsigned long items = 0;
89  unsigned long unread_items = 0;
90  DWORD layout_id = 0;
91 
92  Atom property = XInternAtom(display, property_name, False);
93  if (property == None)
94  return 0;
95 
96  if (XGetWindowProperty(display, root, property, 0, 1024, False, XA_STRING, &type, &item_size,
97  &items, &unread_items, (unsigned char**)&rule) != Success)
98  return 0;
99 
100  if (type != XA_STRING || item_size != 8 || unread_items != 0)
101  {
102  XFree(rule);
103  return 0;
104  }
105 
106  parse_xkb_rule_names(rule, items, &layout, &variant);
107 
108  DEBUG_KBD("%s layout: %s, variant: %s", property_name, layout, variant);
109  layout_id = find_keyboard_layout_in_xorg_rules(layout, variant);
110 
111  XFree(rule);
112 
113  return layout_id;
114 }
115 
116 int freerdp_detect_keyboard_layout_from_xkb(DWORD* keyboardLayoutId)
117 {
118  Display* display = XOpenDisplay(NULL);
119 
120  if (!display)
121  return 0;
122 
123  Window root = DefaultRootWindow(display);
124  if (!root)
125  return 0;
126 
127  /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
128  DWORD id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES_BACKUP");
129 
130  if (0 == id)
131  id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES");
132 
133  if (0 != id)
134  *keyboardLayoutId = id;
135 
136  XCloseDisplay(display);
137  return (int)id;
138 }