summaryrefslogtreecommitdiffstats
path: root/libfreerdp/locale/keyboard_x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/locale/keyboard_x11.c')
-rw-r--r--libfreerdp/locale/keyboard_x11.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/libfreerdp/locale/keyboard_x11.c b/libfreerdp/locale/keyboard_x11.c
new file mode 100644
index 0000000..3f3f574
--- /dev/null
+++ b/libfreerdp/locale/keyboard_x11.c
@@ -0,0 +1,139 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * X11 Keyboard Mapping
+ *
+ * Copyright 2009-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2023 Bernhard Miklautz <bernhard.miklautz@thincast.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+#include "liblocale.h"
+#include "keyboard_x11.h"
+#include "xkb_layout_ids.h"
+
+static BOOL parse_xkb_rule_names(char* xkb_rule, unsigned long num_bytes, char** layout,
+ char** variant)
+{
+ /* Sample output for "Canadian Multilingual Standard"
+ *
+ * _XKB_RULES_NAMES_BACKUP(STRING) = "xorg", "pc105", "ca", "multi", "magic"
+ *
+ * Format: "rules", "model", "layout", "variant", "options"
+ *
+ * Where "xorg" is the set of rules
+ * "pc105" the keyboard model
+ * "ca" the keyboard layout(s) (can also be something like 'us,uk')
+ * "multi" the keyboard layout variant(s) (in the examples, “,winkeys” - which means first
+ * layout uses some “default” variant and second uses “winkeys” variant)
+ * "magic" - configuration option (in the examples,
+ * “eurosign:e,lv3:ralt_switch,grp:rctrl_toggle”
+ * - three options)
+ */
+ for (size_t i = 0, index = 0; i < num_bytes; i++, index++)
+ {
+ char* ptr = xkb_rule + i;
+
+ switch (index)
+ {
+ case 0: // rules
+ break;
+ case 1: // model
+ break;
+ case 2: // layout
+ {
+ /* If multiple languages are present we just take the first one */
+ char* delimiter = strchr(ptr, ',');
+ if (delimiter)
+ *delimiter = '\0';
+ *layout = ptr;
+ break;
+ }
+ case 3: // variant
+ *variant = ptr;
+ break;
+ case 4: // option
+ break;
+ default:
+ break;
+ }
+ i += strlen(ptr);
+ }
+ return TRUE;
+}
+
+static DWORD kbd_layout_id_from_x_property(Display* display, Window root, char* property_name)
+{
+ char* layout = NULL;
+ char* variant = NULL;
+ char* rule = NULL;
+ Atom property = None;
+ Atom type = None;
+ int item_size = 0;
+ unsigned long items = 0;
+ unsigned long unread_items = 0;
+ DWORD layout_id = 0;
+
+ property = XInternAtom(display, property_name, False);
+
+ if (XGetWindowProperty(display, root, property, 0, 1024, False, XA_STRING, &type, &item_size,
+ &items, &unread_items, (unsigned char**)&rule) != Success)
+ {
+ return 0;
+ }
+
+ if (type != XA_STRING || item_size != 8 || unread_items != 0)
+ {
+ XFree(rule);
+ return 0;
+ }
+
+ parse_xkb_rule_names(rule, items, &layout, &variant);
+
+ DEBUG_KBD("%s layout: %s, variant: %s", property_name, layout, variant);
+ layout_id = find_keyboard_layout_in_xorg_rules(layout, variant);
+
+ XFree(rule);
+
+ return layout_id;
+}
+
+int freerdp_detect_keyboard_layout_from_xkb(DWORD* keyboardLayoutId)
+{
+ Display* display = XOpenDisplay(NULL);
+
+ if (!display)
+ return 0;
+
+ Window root = DefaultRootWindow(display);
+ if (!root)
+ return 0;
+
+ /* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
+ DWORD id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES_BACKUP");
+
+ if (0 == id)
+ id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES");
+
+ if (0 != id)
+ *keyboardLayoutId = id;
+
+ XCloseDisplay(display);
+ return (int)id;
+}