[PATCH 3/4] xkbsupport: Extract translation table

Alexey Gladkov <[email protected]> Thu, 4 Jan 2024 18:15:17 +0000
Newsgroups dev.linux.lists.kbd
Message-ID <4dce50945ea36445d676780e785fba67ce47921c.1704392039.git.legion@kernel.org>
This will allow us to expand the xkb to kbd keys translation table.

Signed-off-by: Alexey Gladkov <[email protected]>
---
 data/xkbtrans/names | 154 ++++++++++++++++++++++++++++++++++++++
 src/xkbsupport.c    | 176 ++++++++++++++++++++++++--------------------
 2 files changed, 251 insertions(+), 79 deletions(-)
 create mode 100644 data/xkbtrans/names

diff --git a/data/xkbtrans/names b/data/xkbtrans/names
new file mode 100644
index 00000000..f39e8456
--- /dev/null
+++ b/data/xkbtrans/names
@@ -0,0 +1,154 @@
+0	zero
+1	one
+2	two
+3	three
+4	four
+5	five
+6	six
+7	seven
+8	eight
+9	nine
+Alt_L	Alt
+Alt_R	Alt
+Begin	Begin
+Break	Break
+Control_L	Control
+Control_R	Control
+Down	Down
+End	End
+F1	F1
+F10	F10
+F11	F11
+F12	F12
+F13	F13
+F14	F14
+F15	F15
+F16	F16
+F17	F17
+F18	F18
+F19	F19
+F2	F2
+F20	F20
+F21	F21
+F22	F22
+F23	F23
+F24	F24
+F25	F25
+F26	F26
+F27	F27
+F28	F28
+F29	F29
+F3	F3
+F30	F30
+F31	F31
+F32	F32
+F33	F33
+F34	F34
+F35	F35
+F4	F4
+F5	F5
+F6	F6
+F7	F7
+F8	F8
+F9	F9
+Find	Find
+Help	Help
+Home	Home
+Hyper_L	Alt
+Hyper_R	Alt
+ISO_First_Group	AltGr_Lock
+ISO_First_Group_Lock	AltGr_Lock
+ISO_Group_Latch	AltGr
+ISO_Group_Lock	AltGr_Lock
+ISO_Group_Shift	AltGr
+ISO_Last_Group	AltGr_Lock
+ISO_Last_Group_Lock	AltGr_Lock
+ISO_Left_Tab	Meta_Tab
+ISO_Level2_Latch	Shift
+ISO_Level3_Latch	AltGr
+ISO_Level3_Lock		AltGr_Lock
+ISO_Level3_Shift	AltGr
+ISO_Level5_Latch	AltGr
+ISO_Level5_Lock	AltGr_Lock
+ISO_Level5_Shift	AltGr
+ISO_Lock	Caps_Lock
+ISO_Next_Group	AltGr_Lock
+ISO_Next_Group_Lock	AltGr_Lock
+ISO_Prev_Group	AltGr_Lock
+ISO_Prev_Group_Lock	AltGr_Lock
+Insert	Insert
+KP_Down	KP_2
+KP_End	KP_1
+KP_Home	KP_7
+KP_Insert	KP_0
+KP_Left	KP_4
+KP_Next	KP_3
+KP_Prior	KP_9
+KP_Right	KP_6
+KP_Up	KP_8
+L1	F11
+L10	F20
+L2	F12
+L3	F13
+L4	F14
+L5	F15
+L6	F16
+L7	F17
+L8	F18
+L9	F19
+Left	Left
+Meta_L	Alt
+Meta_R	Alt
+Mode_switch	AltGr
+Multi_key	Compose
+Next	Next
+Num_Lock	Num_Lock
+Pause	Pause
+Print	Control_backslash
+Prior	Prior
+R1	F21
+R10	F30
+R11	F31
+R12	F32
+R13	F33
+R14	F34
+R15	F35
+R2	F22
+R3	F23
+R4	F24
+R5	F25
+R6	F26
+R7	F27
+R8	F28
+R9	F29
+Right	Right
+Scroll_Lock	Scroll_Lock
+Shift_L	Shift
+Shift_R	Shift
+Super_L	Alt
+Super_R	Alt
+Sys_Req	Last_Console
+Up	Up
+XF86Switch_VT_1	Console_1
+XF86Switch_VT_10	Console_10
+XF86Switch_VT_11	Console_11
+XF86Switch_VT_12	Console_12
+XF86Switch_VT_2	Console_2
+XF86Switch_VT_3	Console_3
+XF86Switch_VT_4	Console_4
+XF86Switch_VT_5	Console_5
+XF86Switch_VT_6	Console_6
+XF86Switch_VT_7	Console_7
+XF86Switch_VT_8	Console_8
+XF86Switch_VT_9	Console_9
+dead_V	dead_caron
+dead_acute	dead_acute
+dead_breve	dead_breve
+dead_caron	dead_caron
+dead_cedilla	dead_cedilla
+dead_circumflex	dead_circumflex
+dead_diaeresis	dead_diaeresis
+dead_doubleacute	dead_doubleacute
+dead_grave	dead_grave
+dead_ogonek	dead_ogonek
+dead_tilde	dead_tilde
diff --git a/src/xkbsupport.c b/src/xkbsupport.c
index 3caf8465..77abada0 100644
--- a/src/xkbsupport.c
+++ b/src/xkbsupport.c
@@ -36,11 +36,17 @@ static const unsigned int layouts[4][4] = {
 	{ 0, 1, 3, 2 },
 };
 
+struct sym_pair {
+	char *xkb_sym;
+	char *krn_sym;
+};
+
 struct xkeymap {
 	struct xkb_context *xkb;
 	struct xkb_keymap *keymap;
 	struct lk_ctx *ctx;
 	void *used_codes;
+	void *syms_map;
 };
 
 /*
@@ -83,6 +89,7 @@ static struct modifier_mapping modifier_mapping[] = {
 	{ NULL, NULL, 0 },
 };
 
+
 static struct modifier_mapping *convert_modifier(const char *xkb_name)
 {
 	struct modifier_mapping *map = modifier_mapping;
@@ -96,82 +103,32 @@ static struct modifier_mapping *convert_modifier(const char *xkb_name)
 	return NULL;
 }
 
-struct symbols_mapping {
-	const char *xkb_sym;
-	const char *krn_sym;
-};
-
-static struct symbols_mapping symbols_mapping[] = {
-	{ "0", "zero" },
-	{ "1", "one" },
-	{ "2", "two" },
-	{ "3", "three" },
-	{ "4", "four" },
-	{ "5", "five" },
-	{ "6", "six" },
-	{ "7", "seven" },
-	{ "8", "eight" },
-	{ "9", "nine" },
-	{ "KP_Insert", "KP_0" },
-	{ "KP_End", "KP_1" },
-	{ "KP_Down", "KP_2" },
-	{ "KP_Next", "KP_3" },
-	{ "KP_Left", "KP_4" },
-	{ "KP_Right", "KP_6" },
-	{ "KP_Home", "KP_7" },
-	{ "KP_Up", "KP_8" },
-	{ "KP_Prior", "KP_9" },
-	{ "KP_Begin", "VoidSymbol" },
-	{ "KP_Delete", "VoidSymbol" },
-	{ "Alt_R", "Alt" },
-	{ "Alt_L", "Alt" },
-	{ "Control_R", "Control" },
-	{ "Control_L", "Control" },
-	{ "Super_R", "Alt" },
-	{ "Super_L", "Alt" },
-	{ "Hyper_R", "Alt" },
-	{ "Hyper_L", "Alt" },
-	{ "Mode_switch", "AltGr" },
-	{ "ISO_Group_Shift", "AltGr" },
-	{ "ISO_Group_Latch", "AltGr" },
-	{ "ISO_Group_Lock", "AltGr_Lock" },
-	{ "ISO_Next_Group", "AltGr_Lock" },
-	{ "ISO_Next_Group_Lock", "AltGr_Lock" },
-	{ "ISO_Prev_Group", "AltGr_Lock" },
-	{ "ISO_Prev_Group_Lock", "AltGr_Lock" },
-	{ "ISO_First_Group", "AltGr_Lock" },
-	{ "ISO_First_Group_Lock", "AltGr_Lock" },
-	{ "ISO_Last_Group", "AltGr_Lock" },
-	{ "ISO_Last_Group_Lock", "AltGr_Lock" },
-	{ "ISO_Level3_Shift", "AltGr" },
-	{ "ISO_Left_Tab", "Meta_Tab" },
-	{ "XF86Switch_VT_1", "Console_1" },
-	{ "XF86Switch_VT_2", "Console_2" },
-	{ "XF86Switch_VT_3", "Console_3" },
-	{ "XF86Switch_VT_4", "Console_4" },
-	{ "XF86Switch_VT_5", "Console_5" },
-	{ "XF86Switch_VT_6", "Console_6" },
-	{ "XF86Switch_VT_7", "Console_7" },
-	{ "XF86Switch_VT_8", "Console_8" },
-	{ "XF86Switch_VT_9", "Console_9" },
-	{ "XF86Switch_VT_10", "Console_10" },
-	{ "XF86Switch_VT_11", "Console_11" },
-	{ "XF86Switch_VT_12", "Console_12" },
-	{ "Sys_Req", "Last_Console" },
-	{ "Print", "Control_backslash" },
-	{ NULL, NULL },
-};
+static void xkeymap_pair_free(void *pa)
+{
+	struct sym_pair *pair = pa;
+	if (!pair)
+		return;
+	free(pair->xkb_sym);
+	free(pair->krn_sym);
+	free(pair);
+}
 
-static const char *map_xkbsym_to_ksym(const char *xkb_sym)
+static int compare_by_xkbsym(const void *pa, const void *pb)
 {
-	struct symbols_mapping *map = symbols_mapping;
+	return strcmp(((struct sym_pair *)pa)->xkb_sym,
+		      ((struct sym_pair *)pb)->xkb_sym);
+}
 
-	while (map->xkb_sym) {
-		if (!strcmp(map->xkb_sym, xkb_sym))
-			return map->krn_sym;
-		map++;
-	}
+static const char *map_xkbsym_to_ksym(struct xkeymap *xkeymap, char *xkb_sym)
+{
+	struct sym_pair **val;
+	struct sym_pair pair = {
+		.xkb_sym = xkb_sym,
+	};
 
+	val = tfind(&pair, &xkeymap->syms_map, compare_by_xkbsym);
+	if (val)
+		return ((struct sym_pair *) *val)->krn_sym;
 	return NULL;
 }
 
@@ -236,7 +193,7 @@ static void xkeymap_walk_printer(struct xkeymap *xkeymap,
 		return;
 	}
 
-	if (!(symname = map_xkbsym_to_ksym(s)))
+	if (!(symname = map_xkbsym_to_ksym(xkeymap, s)))
 		symname = s;
 
 	if (unicode == 0) {
@@ -303,7 +260,7 @@ static int parse_hexcode(const char *symname)
 	return 0;
 }
 
-static int xkeymap_get_code(struct lk_ctx *ctx, xkb_keysym_t symbol)
+static int xkeymap_get_code(struct xkeymap *xkeymap, xkb_keysym_t symbol)
 {
 	uint32_t xkb_unicode;
 	int ret, unicode;
@@ -321,10 +278,10 @@ static int xkeymap_get_code(struct lk_ctx *ctx, xkb_keysym_t symbol)
 
 	if ((unicode = parse_hexcode(symbuf)) != 0) {
 		;
-	} else if ((symname = map_xkbsym_to_ksym(symbuf)) != NULL) {
+	} else if ((symname = map_xkbsym_to_ksym(xkeymap, symbuf)) != NULL) {
 		unicode = parse_hexcode(symname);
 		if (!unicode)
-			unicode = lk_ksym_to_unicode(ctx, symname);
+			unicode = lk_ksym_to_unicode(xkeymap->ctx, symname);
 
 	} else if ((xkb_unicode = xkb_keysym_to_utf32(symbol)) > 0) {
 		unicode = (int) xkb_unicode;
@@ -335,7 +292,7 @@ static int xkeymap_get_code(struct lk_ctx *ctx, xkb_keysym_t symbol)
 	ret = CODE_FOR_UNKNOWN_KSYM;
 
 	if (unicode > 0)
-		ret = lk_convert_code(ctx, unicode, TO_AUTO);
+		ret = lk_convert_code(xkeymap->ctx, unicode, TO_AUTO);
 
 	if (ret == CODE_FOR_UNKNOWN_KSYM) {
 		kbd_warning(0, "unable to convert code <%s> and replace it with VoidSymbol", symbuf);
@@ -451,7 +408,7 @@ static int xkeymap_walk(struct xkeymap *xkeymap)
 					goto process_keycode;
 				}
 
-				if ((value = xkeymap_get_code(xkeymap->ctx, sym)) < 0)
+				if ((value = xkeymap_get_code(xkeymap, sym)) < 0)
 					continue;
 
 				xkeymap_keycode_mask(xkeymap->keymap, layout, level, keycode, &keycode_mask);
@@ -506,10 +463,60 @@ err:
 	return -1;
 }
 
+static int parsemap(struct xkeymap *xkeymap, FILE *fp)
+{
+	char buffer[BUFSIZ];
+	char *p, *q, *xkb_sym = NULL, *krn_sym = NULL;
+	struct sym_pair **val, *pair = NULL;
+
+	while (fgets(buffer, sizeof(buffer) - 1, fp)) {
+		for (p = buffer; isspace(*p); p++);
+
+		if (*p == '#' || *p == '\0')
+			continue;
+
+		for (q = p; *q != '\0' && !isspace(*q); q++);
+		*q = '\0';
+
+		xkb_sym = p;
+
+		if (p != q)
+			for(p = ++q; isspace(*p); p++);
+
+		for (q = p; *q != '\0' && !isspace(*q); q++);
+		*q = '\0';
+
+		krn_sym = p;
+
+		pair = calloc(1, sizeof(*pair));
+		if (!pair)
+			goto err;
+
+		pair->xkb_sym = strdup(xkb_sym);
+		pair->krn_sym = strdup(krn_sym);
+
+		if (!pair->xkb_sym || !pair->krn_sym)
+			goto err;
+
+		val = tsearch(pair, &xkeymap->syms_map, compare_by_xkbsym);
+		if (!val)
+			goto err;
+
+		if (*val != pair)
+			xkeymap_pair_free(pair);
+
+		pair = NULL;
+	}
+	return 0;
+err:
+	xkeymap_pair_free(pair);
+	return -1;
+}
 
 int convert_xkb_keymap(struct lk_ctx *ctx, struct xkeymap_params *params, int options)
 {
-	struct xkeymap xkeymap;
+	FILE *fp;
+	struct xkeymap xkeymap = { 0 };
 	int ret = -1;
 
 	struct xkb_rule_names names = {
@@ -541,6 +548,14 @@ int convert_xkb_keymap(struct lk_ctx *ctx, struct xkeymap_params *params, int op
 		goto end;
 	}
 
+	if ((fp = fopen(DATADIR "/xkbtrans/names", "r")) != NULL) {
+		if (parsemap(&xkeymap, fp) < 0) {
+			kbd_warning(0, "unable to parse xkb translation names");
+			goto end;
+		}
+		fclose(fp);
+	}
+
 	if (!(ret = xkeymap_walk(&xkeymap))) {
 		if (options & OPT_P)
 			lk_dump_keymap(ctx, stdout, LK_SHAPE_SEPARATE_LINES, 0);
@@ -550,6 +565,9 @@ end:
 	if (xkeymap.used_codes)
 		tdestroy(xkeymap.used_codes, free);
 
+	if (xkeymap.syms_map)
+		tdestroy(xkeymap.syms_map, xkeymap_pair_free);
+
 	xkb_keymap_unref(xkeymap.keymap);
 	xkb_context_unref(xkeymap.xkb);
 
-- 
2.43.0