Add XkbcCanonicaliseComponents Canonicalises two sets of components (new and old), e.g.: new: +bar old: foo result: foo+bar This is required as part of the spec, so clients can reuse part of the device's old keymap. Signed-off-by: Daniel Stone <daniel@fooishbar.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
diff --git a/include/X11/extensions/XKBcommon.h b/include/X11/extensions/XKBcommon.h
index 090c22b..1057895 100644
--- a/include/X11/extensions/XKBcommon.h
+++ b/include/X11/extensions/XKBcommon.h
@@ -144,6 +144,24 @@ extern XkbComponentListPtr
XkbcListComponents(XkbComponentNamesPtr ptrns, int *maxMatch);
/*
+ * Canonicalises component names by prepending the relevant component from
+ * 'old' to the one in 'names' when the latter has a leading '+' or '|', and
+ * by replacing a '%' with the relevant component, e.g.:
+ *
+ * names old output
+ * ------------------------------------------
+ * +bar foo foo+bar
+ * |quux baz baz|quux
+ * foo+%|baz bar foo+bar|baz
+ *
+ * If a component in names needs to be modified, the existing value will be
+ * free()d, and a new one allocated with malloc().
+ */
+extern void
+XkbcCanonicaliseComponents(XkbComponentNamesPtr names,
+ const XkbComponentNamesPtr old);
+
+/*
* Converts a keysym to a string; will return unknown Unicode codepoints
* as "Ua1b2", and other unknown keysyms as "0xabcd1234".
*
diff --git a/src/xkb.c b/src/xkb.c
index b0b0de6..7ebe856 100644
--- a/src/xkb.c
+++ b/src/xkb.c
@@ -31,6 +31,72 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "X11/extensions/XKBcommon.h"
#include "XKBcommonint.h"
+static char *
+XkbcCanonicaliseComponent(char *name, const char *old)
+{
+ char *tmp;
+ int i;
+
+ if (!name)
+ return NULL;
+
+ /* Treachery. */
+ if (old && strchr(old, '%'))
+ return NULL;
+
+ if (name[0] == '+' || name[0] == '|') {
+ if (old) {
+ tmp = malloc(strlen(name) + strlen(old) + 1);
+ if (!tmp)
+ return NULL;
+ sprintf(tmp, "%s%s", old, name);
+ free(name);
+ name = tmp;
+ }
+ else {
+ memmove(name, &name[1], strlen(&name[1]) + 1);
+ }
+ }
+
+ for (i = 0; name[i]; i++) {
+ if (name[i] == '%') {
+ if (old) {
+ tmp = malloc(strlen(name) + strlen(old));
+ if (!tmp)
+ return NULL;
+ strncpy(tmp, name, i);
+ strcat(tmp + i, old);
+ strcat(tmp + i + strlen(old), &name[i + 1]);
+ free(name);
+ name = tmp;
+ i--;
+ }
+ else {
+ memmove(&name[i - 1], &name[i + 1], strlen(&name[i + 1]) + 1);
+ i -= 2;
+ }
+ }
+ }
+
+ return name;
+}
+
+void
+XkbcCanonicaliseComponents(XkbComponentNamesPtr names,
+ const XkbComponentNamesPtr old)
+{
+ names->keycodes = XkbcCanonicaliseComponent(names->keycodes,
+ old ? old->keycodes : NULL);
+ names->compat = XkbcCanonicaliseComponent(names->compat,
+ old ? old->compat : NULL);
+ names->geometry = XkbcCanonicaliseComponent(names->geometry,
+ old ? old->geometry : NULL);
+ names->symbols = XkbcCanonicaliseComponent(names->symbols,
+ old ? old->symbols : NULL);
+ names->types = XkbcCanonicaliseComponent(names->types,
+ old ? old->types : NULL);
+}
+
Bool
XkbcComputeEffectiveMap(XkbcDescPtr xkb, XkbKeyTypePtr type,
unsigned char *map_rtrn)