Handle string based codes

Some systems use string identifiers rather than integers.

Signed-off-by: Pierre Ossman <ossman@cendio.se>
diff --git a/tests/.gitignore b/tests/.gitignore
index cbc31ba..88e7c03 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,5 +1,9 @@
 osx2win32.*
 osx2win32_name.*
+osx2xkb.*
+osx2xkb_name.*
+html2win32.*
+html2win32_name.*
 osx.*
 osx_name.*
 stdc
diff --git a/tests/Makefile b/tests/Makefile
index 2cf5903..ccb3686 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -13,33 +13,66 @@
 
 .DELETE_ON_ERROR:
 
-stdc: stdc.c osx2win32.h osx2win32_name.h osx.h osx_name.h
+stdc: stdc.c osx2win32.h osx2win32_name.h \
+             osx2xkb.h osx2xkb_name.h \
+             html2win32.h html2win32_name.h \
+             osx.h osx_name.h
 	$(CC) -o $@ $^
 osx2win32.h: $(SOURCES)
 	$(GEN) --lang stdc code-map $(DATA) osx win32 > $@
 osx2win32_name.h: $(SOURCES)
 	$(GEN) --lang stdc name-map $(DATA) osx win32 > $@
+osx2xkb.h: $(SOURCES)
+	$(GEN) --lang stdc code-map $(DATA) osx xkb > $@
+osx2xkb_name.h: $(SOURCES)
+	$(GEN) --lang stdc name-map $(DATA) osx xkb > $@
+html2win32.h: $(SOURCES)
+	$(GEN) --lang stdc code-map $(DATA) html win32 > $@
+html2win32_name.h: $(SOURCES)
+	$(GEN) --lang stdc name-map $(DATA) html win32 > $@
 osx.h: $(SOURCES)
 	$(GEN) --lang stdc code-table $(DATA) osx > $@
 osx_name.h: $(SOURCES)
 	$(GEN) --lang stdc name-table $(DATA) osx > $@
 
-stdc++: stdc++.cc osx2win32.hh osx2win32_name.hh osx.hh osx_name.hh
+stdc++: stdc++.cc osx2win32.hh osx2win32_name.hh \
+             osx2xkb.hh osx2xkb_name.hh \
+             html2win32.hh html2win32_name.hh \
+             osx.hh osx_name.hh
 	$(CC) -o $@ $^
 osx2win32.hh: $(SOURCES)
 	$(GEN) --lang stdc++ code-map $(DATA) osx win32 > $@
 osx2win32_name.hh: $(SOURCES)
 	$(GEN) --lang stdc++ name-map $(DATA) osx win32 > $@
+osx2xkb.hh: $(SOURCES)
+	$(GEN) --lang stdc++ code-map $(DATA) osx xkb > $@
+osx2xkb_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++ name-map $(DATA) osx xkb > $@
+html2win32.hh: $(SOURCES)
+	$(GEN) --lang stdc++ code-map $(DATA) html win32 > $@
+html2win32_name.hh: $(SOURCES)
+	$(GEN) --lang stdc++ name-map $(DATA) html win32 > $@
 osx.hh: $(SOURCES)
 	$(GEN) --lang stdc++ code-table $(DATA) osx > $@
 osx_name.hh: $(SOURCES)
 	$(GEN) --lang stdc++ name-table $(DATA) osx > $@
 
-python2: osx2win32.py osx2win32_name.py osx.py osx_name.py
+python2: osx2win32.py osx2win32_name.py \
+         osx2xkb.py osx2xkb_name.py \
+         html2win32.py html2win32_name.py \
+         osx.py osx_name.py
 osx2win32.py: $(SOURCES)
 	$(GEN) --lang python2 code-map $(DATA) osx win32 > $@
 osx2win32_name.py: $(SOURCES)
 	$(GEN) --lang python2 name-map $(DATA) osx win32 > $@
+osx2xkb.py: $(SOURCES)
+	$(GEN) --lang python2 code-map $(DATA) osx xkb > $@
+osx2xkb_name.py: $(SOURCES)
+	$(GEN) --lang python2 name-map $(DATA) osx xkb > $@
+html2win32.py: $(SOURCES)
+	$(GEN) --lang python2 code-map $(DATA) html win32 > $@
+html2win32_name.py: $(SOURCES)
+	$(GEN) --lang python2 name-map $(DATA) html win32 > $@
 osx.py: $(SOURCES)
 	$(GEN) --lang python2 code-table $(DATA) osx > $@
 osx_name.py: $(SOURCES)
@@ -48,6 +81,10 @@
 clean:
 	rm -f osx2win32.*
 	rm -f osx2win32_name.*
+	rm -f osx2xkb.*
+	rm -f osx2xkb_name.*
+	rm -f html2win32.*
+	rm -f html2win32_name.*
 	rm -f osx.*
 	rm -f osx_name.*
 	rm -f stdc stdc++
diff --git a/tests/stdc++.cc b/tests/stdc++.cc
index 51e1fb0..38551f0 100644
--- a/tests/stdc++.cc
+++ b/tests/stdc++.cc
@@ -12,14 +12,43 @@
 
 #include "osx2win32.hh"
 #include "osx2win32_name.hh"
+
+#include "osx2xkb.hh"
+#include "osx2xkb_name.hh"
+
+#include "html2win32.hh"
+#include "html2win32_name.hh"
+
 #include "osx.hh"
 #include "osx_name.hh"
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
 int main(int argc, char** argv)
 {
+	unsigned i;
+
 	assert(code_map_osx_to_win32[0x1d] == 0x30);
 	assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
 
+	assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
+	assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
+
+	for (i = 0;i < ARRAY_SIZE(code_map_osx_to_win32);i++) {
+		if (strcmp(code_map_html_to_win32[i].from, "ControlLeft") == 0) {
+			assert(code_map_html_to_win32[i].to == 0x11);
+			break;
+		}
+	}
+	assert(i != ARRAY_SIZE(code_map_osx_to_win32));
+	for (i = 0;i < ARRAY_SIZE(name_map_html_to_win32);i++) {
+		if (strcmp(name_map_html_to_win32[i].from, "ControlLeft") == 0) {
+			assert(strcmp(name_map_html_to_win32[i].to, "VK_CONTROL") == 0);
+			break;
+		}
+	}
+	assert(i != ARRAY_SIZE(name_map_html_to_win32));
+
 	assert(code_table_osx[0x1d] == 0x3b);
 	assert(strcmp(name_table_osx[0x1d], "Control") == 0);
 
diff --git a/tests/stdc.c b/tests/stdc.c
index 8668b74..df65116 100644
--- a/tests/stdc.c
+++ b/tests/stdc.c
@@ -12,14 +12,43 @@
 
 #include "osx2win32.h"
 #include "osx2win32_name.h"
+
+#include "osx2xkb.h"
+#include "osx2xkb_name.h"
+
+#include "html2win32.h"
+#include "html2win32_name.h"
+
 #include "osx.h"
 #include "osx_name.h"
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
 int main(int argc, char** argv)
 {
+	unsigned i;
+
 	assert(code_map_osx_to_win32[0x1d] == 0x30);
 	assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
 
+	assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
+	assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
+
+	for (i = 0;i < ARRAY_SIZE(code_map_osx_to_win32);i++) {
+		if (strcmp(code_map_html_to_win32[i].from, "ControlLeft") == 0) {
+			assert(code_map_html_to_win32[i].to == 0x11);
+			break;
+		}
+	}
+	assert(i != ARRAY_SIZE(code_map_osx_to_win32));
+	for (i = 0;i < ARRAY_SIZE(name_map_html_to_win32);i++) {
+		if (strcmp(name_map_html_to_win32[i].from, "ControlLeft") == 0) {
+			assert(strcmp(name_map_html_to_win32[i].to, "VK_CONTROL") == 0);
+			break;
+		}
+	}
+	assert(i != ARRAY_SIZE(name_map_html_to_win32));
+
 	assert(code_table_osx[0x1d] == 0x3b);
 	assert(strcmp(name_table_osx[0x1d], "Control") == 0);
 
diff --git a/tests/test.py b/tests/test.py
index 21bcefc..f265145 100644
--- a/tests/test.py
+++ b/tests/test.py
@@ -7,11 +7,24 @@
 
 import osx2win32
 import osx2win32_name
+
+import osx2xkb
+import osx2xkb_name
+
+import html2win32
+import html2win32_name
+
 import osx
 import osx_name
 
 assert osx2win32.code_map_osx_to_win32[0x1d] == 0x30
 assert osx2win32_name.name_map_osx_to_win32[0x1d] == "VK_0"
 
+assert osx2xkb.code_map_osx_to_xkb[0x1d] == "AE10"
+assert osx2xkb_name.name_map_osx_to_xkb[0x1d] == "AE10"
+
+assert html2win32.code_map_html_to_win32["ControlLeft"] == 0x11
+assert html2win32_name.name_map_html_to_win32["ControlLeft"] == "VK_CONTROL"
+
 assert osx.code_table_osx[0x1d] == 0x3b;
 assert osx_name.name_table_osx[0x1d] == "Control";
diff --git a/tools/keymap-gen b/tools/keymap-gen
index 8663497..b59ba50 100755
--- a/tools/keymap-gen
+++ b/tools/keymap-gen
@@ -90,6 +90,8 @@
         MAP_XWINXT,
         MAP_XKBDXT,
         MAP_X11,
+        MAP_HTML,
+        MAP_XKB,
 
         # These are derived from maps above
         MAP_XTKBD,
@@ -111,6 +113,8 @@
         MAP_XWINXT: 10,
         MAP_XKBDXT: 11,
         MAP_X11: 13,
+        MAP_HTML: 14,
+        MAP_XKB: 15,
     }
 
     NAME_COLUMNS = {
@@ -201,7 +205,7 @@
 
             if val.startswith("0x"):
                 val = int(val, 16)
-            else:
+            elif val.isdigit():
                 val = int(val, 10)
 
             self.mapto[mapname][linux] = val
@@ -281,7 +285,7 @@
 
 class LanguageSrcGenerator(LanguageGenerator):
 
-    def _array_start_code(self, varname, length):
+    def _array_start_code(self, varname, length, fromtype, totype):
         raise NotImplementedError()
 
     def _array_start_name(self, varname, length):
@@ -310,13 +314,13 @@
         if varname is None:
             varname = "code_map_%s_to_%s" % (frommapname, tomapname)
 
-        frommax = 0
-        for key in tolinux.keys():
-            if key > frommax:
-                frommax = key
+        keys = tolinux.keys()
+        keys.sort()
+        if type(keys[0]) == int:
+            keys = range(keys[-1] + 1)
 
-        self._array_start_code(varname, frommax + 1)
-        for src in range(frommax + 1):
+        self._array_start_code(varname, len(keys), type(keys[0]), type(fromlinux.values()[0]))
+        for src in keys:
             linux = tolinux.get(src, None)
             if linux is None:
                 dst = None
@@ -341,7 +345,7 @@
         if varname is None:
             varname = "code_table_%s" % mapname
 
-        self._array_start_code(varname, len(keys))
+        self._array_start_code(varname, len(keys), int, type(database.mapto[mapname].values()[0]))
 
         for i in range(len(keys)):
             key = keys[i]
@@ -364,14 +368,14 @@
         if varname is None:
             varname = "name_map_%s_to_%s" % (frommapname, tomapname)
 
-        frommax = 0
-        for key in tolinux.keys():
-            if key > frommax:
-                frommax = key
+        keys = tolinux.keys()
+        keys.sort()
+        if type(keys[0]) == int:
+            keys = range(keys[-1] + 1)
 
-        self._array_start_name(varname, frommax + 1)
+        self._array_start_name(varname, len(keys), type(keys[0]))
 
-        for src in range(frommax + 1):
+        for src in keys:
             linux = tolinux.get(src, None)
             if linux is None:
                 dst = None
@@ -396,7 +400,7 @@
         if varname is None:
             varname = "name_table_%s" % mapname
 
-        self._array_start_name(varname, len(keys))
+        self._array_start_name(varname, len(keys), int)
 
         for i in range(len(keys)):
             key = keys[i]
@@ -488,37 +492,52 @@
             print(" * %s" % line)
         print("*/")
 
-    def _array_start_code(self, varname, length):
-        print("const %s %s[%d] = {" % (self.inttypename, varname, length))
+    def _array_start_code(self, varname, length, fromtype, totype):
+        totypename = self.inttypename if totype == int else self.strtypename
+        if fromtype == int:
+            print("const %s %s[%d] = {" % (totypename, varname, length))
+        else:
+            print("const struct _%s {" % varname)
+            print("  const %s from;" % self.strtypename)
+            print("  const %s to;" % totypename)
+            print("} %s[] = {" % varname)
 
-    def _array_start_name(self, varname, length):
-        print("const %s %s[%d] = {" % (self.strtypename, varname, length))
+    def _array_start_name(self, varname, length, fromtype):
+        self._array_start_code(varname, length, fromtype, str);
 
     def _array_end(self):
         print("};")
 
     def _array_entry_code(self, index, value, comment):
-        if value is not None:
-            print("  [0x%x] = 0x%x, /* %s */" % (index, value, comment))
+        if value is None:
+            return
+        if type(index) == int:
+            if type(value) == int:
+                print("  [0x%x] = 0x%x, /* %s */" % (index, value, comment))
+            else:
+                print("  [0x%x] = \"%s\", /* %s */" % (index, value, comment))
+        else:
+            if type(value) == int:
+                print("  {\"%s\", 0x%x}, /* %s */" % (index, value, comment))
+            else:
+                print("  {\"%s\", \"%s\"}, /* %s */" % (index, value, comment))
 
     def _array_entry_name(self, index, value, comment):
-        if value is not None:
-            print("  [0x%x] = \"%s\", /* %s */" % (index, value, comment))
+        self._array_entry_code(index, value, comment)
 
 class CppLanguageGenerator(CLanguageGenerator):
 
     # designated initializers not available in C++
     def _array_entry_code(self, index, value, comment):
-        if value is not None:
+        if type(index) != int:
+            return super(CppLanguageGenerator, self)._array_entry_code(index, value, comment)
+
+        if value is None:
+            print("  0, /* %s */" % comment)
+        elif type(value) == int:
             print("  0x%x, /* %s */" % (value, comment))
         else:
-            print("  0, /* %s */" % comment)
-
-    def _array_entry_name(self, index, value, comment):
-        if value is not None:
             print("  \"%s\", /* %s */" % (value, comment))
-        else:
-            print("  0, /* %s */" % comment)
 
 class StdCLanguageGenerator(CLanguageGenerator):
 
@@ -543,26 +562,40 @@
             print("# %s" % line)
         print("#")
 
-    def _array_start_code(self, varname, length):
-        print("%s = [" % varname)
+    def _array_start_code(self, varname, length, fromtype, totype):
+        self._fromtype = fromtype
+        if fromtype == int:
+            print("%s = [" % varname)
+        else:
+            print("%s = {" % varname)
 
-    def _array_start_name(self, varname, length):
-        print("%s = [" % varname)
+    def _array_start_name(self, varname, length, fromtype):
+        self._array_start_code(varname, length, fromtype, str);
 
     def _array_end(self):
-        print("]")
+        if self._fromtype == int:
+            print("]")
+        else:
+            print("}")
 
     def _array_entry_code(self, index, value, comment):
-        if value is None:
-            print("  None, # %s" % (comment))
+        if type(index) == int:
+            if value is None:
+                print("  None, # %s" % (comment))
+            elif type(value) == int:
+                print("  0x%x, # %s" % (value, comment))
+            else:
+                print("  \"%s\", # %s" % (value, comment))
         else:
-            print("  0x%x, # %s" % (value, comment))
+            if value is None:
+                print("  \"%s\": None, # %s" % (index, comment))
+            elif type(value) == int:
+                print("  \"%s\": 0x%x, # %s" % (index, value, comment))
+            else:
+                print("  \"%s\": \"%s\", # %s" % (index, value, comment))
 
     def _array_entry_name(self, index, value, comment):
-        if value is None:
-            print("  None, # %s" % (comment))
-        else:
-            print("  \"%s\", # %s" % (value, comment))
+        self._array_entry_code(index, value, comment)
 
 class PerlLanguageGenerator(LanguageSrcGenerator):
 
@@ -572,26 +605,36 @@
             print("# %s" % line)
         print("#")
 
-    def _array_start_code(self, varname, length):
-        print("my @%s = (" % varname)
+    def _array_start_code(self, varname, length, fromtype, totype):
+        if fromtype == int:
+            print("my @%s = (" % varname)
+        else:
+            print("my %%%s = (" % varname)
 
-    def _array_start_name(self, varname, length):
-        print("my @%s = (" % varname)
+    def _array_start_name(self, varname, length, fromtype):
+        self._array_start_code(varname, length, fromtype, str);
 
     def _array_end(self):
         print(");")
 
     def _array_entry_code(self, index, value, comment):
-        if value is None:
-            print("  undef, # %s" % (comment))
+        if type(index) == int:
+            if value is None:
+                print("  undef, # %s" % (comment))
+            elif type(value) == int:
+                print("  0x%x, # %s" % (value, comment))
+            else:
+                print("  \"%s\", # %s" % (value, comment))
         else:
-            print("  0x%x, # %s" % (value, comment))
+            if value is None:
+                print("  \"%s\", undef, # %s" % (index, comment))
+            elif type(value) == int:
+                print("  \"%s\", 0x%x, # %s" % (index, value, comment))
+            else:
+                print("  \"%s\", \"%s\", # %s" % (index, value, comment))
 
     def _array_entry_name(self, index, value, comment):
-        if value is None:
-            print("  undef, # %s" % (comment))
-        else:
-            print("  \"%s\", # %s" % (value, comment))
+        self._array_entry_code(index, value, comment)
 
 class PodLanguageGenerator(LanguageDocGenerator):