keymapper (0.5.3-10.1) direct (non packaging) changes

Summary

 Makefile                     |    4 
 README                       |    8 
 changelog                    |  739 +++++++++++++++++++++
 data/equivs                  |  153 ++++
 data/symbols                 | 1468 ++++++++++++++++++++++++++++++++-----------
 data/xkeys                   |   58 +
 gen_keymap                   |   88 ++
 gen_keymap.1                 |   62 +
 keymapper/equiv.py           |  101 ++
 keymapper/fakemaps.py        |    8 
 keymapper/fakequery.py       |   54 +
 keymapper/file.py            |   42 +
 keymapper/graph.py           |   57 +
 keymapper/keymap.py          |   86 ++
 keymapper/parse/Makefile     |    6 
 keymapper/parse/linux.g      |   21 
 keymapper/parse/linuxsyms.py |   13 
 keymapper/parse/maps.py      |    4 
 keymapper/parse/x11.g        |  262 +++++++
 keymapper/script.py          |  121 ++-
 keymapper/tree.py            |  449 +++++++++++--
 test_gen_map.py              |   15 
 test_x11.py                  |   74 ++
 x2console_keymap             |   67 +
 24 files changed, 3415 insertions(+), 545 deletions(-)

    
download this patch

Patch contents

--- keymapper-0.5.3.orig/gen_keymap
+++ keymapper-0.5.3/gen_keymap
@@ -22,12 +22,13 @@
 from keymapper.script import Script
 from keymapper.fakequery import FakeQuery
 from keymapper.parse.linux import parse_file as parse_linux
-from keymapper.parse.linux import FileProblem
+from keymapper.parse.linux import FileProblem, add_dir
+from keymapper.fakequery import FakeQuery
 
 import sys
 import codecs
 from optparse import OptionParser, OptParseError
-from subprocess import Popen,PIPE
+#from subprocess import Popen,PIPE
 try:
 	from cStringIO import StringIO
 except ImportError:
@@ -39,42 +40,78 @@
 parser.add_option("-?","--help", action="help", help="show this help text")
 parser.add_option("-v","--verbose", action="count", dest="verbose", help="be more verbose")
 parser.add_option("-m","--minlen", action="store", dest="minlen", type="int", default=30, help="Too-short Keymaps are skipped (default: 30 entries)")
-parser.add_option("-g","--graph", action="store_const", dest="format", const="graphviz",
-	help="generate a hopefully-nice-looking .dot file")
-parser.add_option("--maps", action="store_const", dest="format", const="mapdump",
-	help="print the to-be-processed keymaps")
+parser.add_option("-g","--graph", action="store_const", dest="format",
+	const="graphviz", help="generate a hopefully-nice-looking .dot file")
+parser.add_option("--maps", action="store_const", dest="format",
+	const="mapdump", help="print the to-be-processed keymaps")
+parser.add_option("-i","--installer", action="store_const", dest="iformat",
+	const="d-i", help="Input files are in d-i map form")
+parser.add_option("-I","--inc","--include", action="append", dest="dirs",
+	help="add a directory to the search path")
 parser.add_option("-o","--output", action="store", dest="filename",
 	help="output file (default: stdout)")
+parser.add_option("-f","--filter", action="store", dest="filter",
+	help="Include only the branches leading to these keymaps")
+parser.add_option("-u","--useonly", action="store", dest="useonly",
+	help="Start generating the tree based only on these keymaps")
+parser.add_option("-s","--skip", action="store", dest="skip",
+	help="keymaps to skip")
+parser.add_option("-t","--test", action="store_true", dest="test",
+	help="Test the generated maps")
+parser.add_option("--interactive", action="store_true", dest="interactive",
+	help="Ask user to choose among indistinguishable keymaps")
+parser.add_option("--no-altgr", action="store_false", dest="altgr",
+	help="Do not consider AltGr keys", default=True)
 
 (opts, args) = parser.parse_args()
 if not args:
 	parser.error("no arguments supplied")
 	sys.exit(1)
+if opts.test and opts.format:
+	parser.error("You can only test scripts")
+	sys.exit(1)
+if opts.test and not opts.filename:
+	parser.error("You can only test scripts if you write them to a file")
+	sys.exit(1)
 
 t = Tree()
 
 keymapper.tree.trace = opts.verbose
+keymapper.tree.interactive = opts.interactive
+
+if opts.dirs:
+	for d in opts.dirs:
+		add_dir(d)
 
 if opts.filename:
-	out=open(opts.filename,"w")
+	out = open(opts.filename,"w")
 else:
-	out=sys.stdout
+	out = sys.stdout
 if opts.format == "graphviz":
 	out = codecs.getwriter("latin1")(out,"replace")
 else:
 	out = codecs.getwriter("utf-8")(out)
 
+known={}
 for f in args:
 	for l in open(f):
 		comment = l.find('#')
 		if comment > -1: l = l[:comment]
 		l = l.strip()
 		if l == "": continue
-		if " " in l or "\t" in l:
-			(name,code) = l.split()
+		name = l.split()
+		if opts.iformat == "d-i":
+			name = name[1]
 		else:
-			name = l
-			code = "utf-8"
+			name = name[0]
+		if opts.useonly and name not in opts.useonly.split(","):
+			continue
+		if opts.skip and name in opts.skip.split(","):
+			continue
+		if name in known:
+			continue
+		known[name]=1
+
 #		code = codecs.getreader(code)
 #		pipe = Popen(("loadkeys","-q","-M",name), stdout=PIPE).stdout
 #		pipe = code(pipe)
@@ -83,8 +120,8 @@
 		try:
 			if opts.verbose:
 				print "Parsing:",name
-#			map = parse_map(name,pipe)
-			map = parse_linux(name)
+#			map = parse_map(name,pipe,opts.altgr)
+			map = parse_linux(name,opts.altgr)
 		except EmptyMapError:
 			print >>sys.stderr,"Map '%s' skipped: empty" % name
 		except MapInputError,exc:
@@ -107,11 +144,32 @@
 if opts.format == "mapdump":
 	sys.exit(0)
 
-t.gen_tree()
+l=()
+if opts.filter:
+	l = opts.filter.split(",")
+t.gen_tree(*l)
 
 if opts.format == "graphviz":
 	gen_report(t,GraphReporter(out))
 else:
 	gen_report(t,FileReporter(out))
 
+if opts.test:
+	buf=codecs.getreader("utf-8")(open(opts.filename))
+	err=0
+	for i in range(0,3):
+		for k in t:
+			buf.seek(0,0)
+			print "Testing keymap %s" % (k.dump(),)
+			s = Script(buf,FakeQuery(k))
+			name = s.run()
+			if name != k.name:
+				print "SCRIPT ERROR: %s != %s" % (name,k.name)
+				err += 1
+			else:
+				print "... OK."
+			print
+	if err:
+		print >>sys.stderr,"There are problems!"
+		sys.exit(1)
 # done!
--- keymapper-0.5.3.orig/test_x11.py
+++ keymapper-0.5.3/test_x11.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+
+# Copyright (c) 2005 by Matthias Urlichs <smurf@smurf.noris.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of Version 2 of the GNU General Public License as
+# published by the Free Software Foundation. See the file COPYING.txt
+# or (on Debian systems) /usr/share/common-licenses/GPL-2 for details.
+
+"""\
+This test script grabs a number of interesting key maps from
+keymapper.fakemaps, generates a decision tree, saves that in an
+in-memory file, and then runs each key map against the file's
+interpreter to see if the correct map is returned.
+"""
+
+from keymapper.parse.x11 import parse_file as parse_x11
+from keymapper.tree import Tree, gen_report
+from keymapper.file import FileReporter
+from keymapper.graph import GraphReporter
+from keymapper.script import Script
+from keymapper.fakequery import FakeQuery
+
+import sys
+import codecs
+
+import keymapper.tree
+keymapper.tree.trace = 1
+
+try:
+	from cStringIO import StringIO
+except ImportError:
+	from StringIO import StringIO
+
+keymaps = []
+t = Tree()
+for k in sys.argv[1:]:
+	k = parse_x11(k)
+	t.add(k)
+	print k.rdump()
+	keymaps.append(k)
+t.gen_tree()
+
+buf = StringIO()
+gen_report(t,FileReporter(codecs.getwriter("utf-8")(buf)))
+
+g = codecs.getwriter("latin1")(open("test.dot","w"),"replace")
+gen_report(t,GraphReporter(g))
+
+# 'buf' now contains our script.
+
+buf.seek(0,0)
+print buf.read(),
+
+err = 0
+for k in keymaps:
+	buf.seek(0,0)
+	print "Testing keymap %s" % (k.rdump(),)
+	s = Script(codecs.getreader("utf-8")(buf))
+	name = s.run(FakeQuery(k))
+	if name != k.name:
+		print "SCRIPT ERROR: %s != %s" % (name,k.name)
+		err += 1
+	else:
+		print "... OK."
+	print
+
+if err:
+	print "%d errors found!" % err
+	sys.exit(1)
+else:
+	print "Everything works."
+	sys.exit(0)
+
--- keymapper-0.5.3.orig/x2console_keymap
+++ keymapper-0.5.3/x2console_keymap
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+
+# Copyright (c) 2005 by Matthias Urlichs <smurf@smurf.noris.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of Version 2 of the GNU General Public License as
+# published by the Free Software Foundation. See the file COPYING.txt
+# or (on Debian systems) /usr/share/common-licenses/GPL-2 for details.
+
+"""\
+This script analyzes an X11 keymap and prints the equivalent console
+keymap name, based on a decision tree.
+"""
+
+from keymapper.parse.x11 import parse_file as parse_x11
+from keymapper.fakequery import FakeQuery
+from keymapper.script import Script,DupMap,NoMap
+from optparse import OptionParser, OptParseError
+from sets import Set
+
+import sys
+import codecs
+
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
+
+import keymapper.tree
+keymapper.tree.trace = 1
+
+try:
+	from cStringIO import StringIO
+except ImportError:
+	from StringIO import StringIO
+
+parser = OptionParser(usage="%prog tree_file x11name...", version="%prog 0.1")
+parser.remove_option("-h")
+#parser.remove_option("--help")
+parser.add_option("-?","--help", action="help", help="show this help text")
+parser.add_option("-v","--verbose", action="count", dest="verbose",
+	help="be more verbose")
+parser.add_option("-g","--graph", action="store_const", dest="format",
+	const="graphviz", help="generate a hopefully-nice-looking .dot file")
+(opts, args) = parser.parse_args()
+
+script = Script(codecs.getreader("utf-8")(open(args[0])), verbose=opts.verbose)
+rev = {}
+def rev_add(b,a):
+	if a not in rev:
+		rev[a] = Set()
+	rev[a].add(b)
+
+for x11map in args[1:]:
+	km = parse_x11(x11map)
+	if km is None: continue
+	try:
+		consolemap = script.run(FakeQuery(km, verbose=opts.verbose))
+	except DupMap,err:
+		for m in err.args[0]:
+			rev_add(km.name,m)
+	except NoMap:
+		print "# %s could not be mapped." % (km.name,)
+	else:
+		rev_add(km.name,consolemap)
+
+for a,b in rev.iteritems():
+	print a," ".join(b)
+
+
--- keymapper-0.5.3.orig/test_gen_map.py
+++ keymapper-0.5.3/test_gen_map.py
@@ -22,6 +22,12 @@
 from keymapper.fakequery import FakeQuery
 
 import sys
+import codecs
+
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
+
+import keymapper.tree
+keymapper.tree.trace = 1
 
 try:
 	from cStringIO import StringIO
@@ -32,13 +38,14 @@
 t = Tree()
 for k in maps():
 	t.add(k)
+	print k.dump()
 	keymaps.append(k)
 t.gen_tree()
 
 buf = StringIO()
-gen_report(t,FileReporter(buf))
+gen_report(t,FileReporter(codecs.getwriter("utf-8")(buf)))
 
-g = open("test.dot","w")
+g = codecs.getwriter("latin1")(open("test.dot","w"),"replace")
 gen_report(t,GraphReporter(g))
 
 # 'buf' now contains our script.
@@ -50,8 +57,8 @@
 for k in keymaps:
 	buf.seek(0,0)
 	print "Testing keymap %s" % (k.dump(),)
-	s = Script(buf,FakeQuery(k))
-	name = s.run()
+	s = Script(codecs.getreader("utf-8")(buf))
+	name = s.run(FakeQuery(k))
 	if name != k.name:
 		print "SCRIPT ERROR: %s != %s" % (name,k.name)
 		err += 1
--- keymapper-0.5.3.orig/Makefile
+++ keymapper-0.5.3/Makefile
@@ -3,3 +3,7 @@
 compile:
 	# python setup.py
 	$(MAKE) -C keymapper/parse
+
+clean:
+	# python setup.py clean --all
+	$(MAKE) -C keymapper/parse clean
--- keymapper-0.5.3.orig/README
+++ keymapper-0.5.3/README
@@ -162,7 +162,13 @@
 This is a question of last resort; it's asked only if keymaps cannot be
 distinguished otherwise.
 
-This command will be accompanied by one YES and one GOTO command.
+This command will be accompanied by one YES and one NO command.
+
+FINDP char
+++++++++++
+
+Equivalent to FIND, except that the user is asked to consider only the
+primary symbols (i.e. Plain and Shift).
 
 YES ##
 ++++++
--- keymapper-0.5.3.orig/changelog
+++ keymapper-0.5.3/changelog
@@ -1,4 +1,743 @@
 ChangeSet
+  1.69 05/04/01 13:35:59 smurf@smurf.noris.de +2 -0
+  fixed heuristics
+
+  keymapper/tree.py
+    1.17 05/04/01 13:35:59 smurf@smurf.noris.de +12 -10
+    fixed heuristics
+
+  keymapper/keymap.py
+    1.14 05/04/01 13:35:59 smurf@smurf.noris.de +1 -1
+    comment added
+
+ChangeSet
+  1.68 05/04/01 12:26:19 smurf@smurf.noris.de +5 -0
+  Ignore control, spacing, and unassigned characters.
+
+  keymapper/tree.py
+    1.16 05/04/01 12:26:19 smurf@smurf.noris.de +3 -3
+    Ignore control, spacing, and unassigned characters.
+
+  keymapper/keymap.py
+    1.13 05/04/01 12:26:19 smurf@smurf.noris.de +6 -2
+    Ignore control, spacing, and unassigned characters.
+
+  keymapper/equiv.py
+    1.5 05/04/01 12:26:19 smurf@smurf.noris.de +12 -1
+    Ignore control, spacing, and unassigned characters.
+
+  debian/changelog
+    1.27 05/04/01 12:26:19 smurf@smurf.noris.de +7 -0
+    Ignore control, spacing, and unassigned characters.
+
+ChangeSet
+  1.67 05/04/01 12:25:48 smurf@smurf.noris.de +1 -0
+  broken bar == solid bar
+  unified angle brackets
+
+  data/equivs
+    1.10 05/04/01 12:25:47 smurf@smurf.noris.de +3 -5
+    broken bar == solid bar
+    unified angle brackets
+
+  BitKeeper/deleted/.del-maps.py~ce085e4573381ab2
+    1.9 05/03/30 22:13:12 smurf@smurf.noris.de +0 -0
+    Delete: keymapper/parse/maps.py
+
+ChangeSet
+  1.66 05/03/30 18:43:06 smurf@smurf.noris.de +2 -0
+  Added shortcuts to break excessively-broad recursion
+
+  keymapper/tree.py
+    1.15 05/03/30 18:43:06 smurf@smurf.noris.de +61 -10
+    Added shortcuts to break excessively-broad recursion
+
+  debian/changelog
+    1.26 05/03/30 18:43:06 smurf@smurf.noris.de +2 -1
+    Added shortcuts to break excessively-broad recursion
+
+ChangeSet
+  1.65 05/03/30 18:41:19 smurf@smurf.noris.de +2 -0
+  Increased the penalty for ALT-key combinations
+
+  keymapper/keymap.py
+    1.12 05/03/30 18:41:19 smurf@smurf.noris.de +1 -1
+    Increased the penalty for ALT-key combinations
+
+  debian/changelog
+    1.25 05/03/30 18:41:19 smurf@smurf.noris.de +2 -1
+    Increased the penalty for ALT-key combinations
+
+ChangeSet
+  1.64 05/03/30 18:28:03 smurf@smurf.noris.de +2 -0
+  more character stuff
+
+  debian/changelog
+    1.24 05/03/30 18:28:03 smurf@smurf.noris.de +3 -1
+    more character stuff
+
+  data/equivs
+    1.9 05/03/30 18:28:03 smurf@smurf.noris.de +3 -3
+    more stuff
+
+ChangeSet
+  1.63 05/03/30 10:53:24 smurf@smurf.noris.de +2 -0
+  Adjust heuristics
+
+  keymapper/tree.py
+    1.14 05/03/30 10:53:24 smurf@smurf.noris.de +2 -2
+    Adjust heuristics
+
+  debian/changelog
+    1.23 05/03/30 10:53:24 smurf@smurf.noris.de +2 -1
+    Adjust heuristics
+
+ChangeSet
+  1.62 05/03/30 10:30:39 smurf@smurf.noris.de +4 -0
+  Fix a crash generating sparse mapping trees
+
+  keymapper/tree.py
+    1.13 05/03/30 10:30:38 smurf@smurf.noris.de +5 -3
+    Fix a crash generating sparse mapping trees
+
+  keymapper/graph.py
+    1.11 05/03/30 10:30:38 smurf@smurf.noris.de +6 -4
+    Fix a crash generating sparse mapping trees
+
+  keymapper/file.py
+    1.9 05/03/30 10:30:38 smurf@smurf.noris.de +4 -2
+    Fix a crash generating sparse mapping trees
+
+  debian/changelog
+    1.22 05/03/30 10:30:38 smurf@smurf.noris.de +1 -0
+    Fix a crash generating sparse mapping trees
+
+ChangeSet
+  1.61 05/03/30 10:30:09 smurf@smurf.noris.de +2 -0
+  Another round of lookalike characters
+
+  debian/changelog
+    1.21 05/03/30 10:30:08 smurf@smurf.noris.de +6 -0
+    Another round of lookalike characters
+
+  data/equivs
+    1.8 05/03/30 10:30:08 smurf@smurf.noris.de +4 -5
+    Another round of lookalike characters
+
+ChangeSet
+  1.60 05/03/25 01:08:37 smurf@smurf.noris.de +1 -0
+  more debugging
+
+  keymapper/script.py
+    1.9 05/03/25 01:08:37 smurf@smurf.noris.de +6 -0
+    more debugging
+
+ChangeSet
+  1.59 05/03/25 01:06:53 smurf@smurf.noris.de +2 -0
+  Aliased cedilla and comma
+
+  debian/changelog
+    1.20 05/03/25 01:06:53 smurf@smurf.noris.de +1 -0
+    Aliased cedilla and comma
+
+  data/equivs
+    1.7 05/03/25 01:06:53 smurf@smurf.noris.de +2 -2
+    Aliased cedilla and comma
+
+ChangeSet
+  1.58 05/03/25 01:01:34 smurf@smurf.noris.de +3 -0
+  add filter option
+
+  keymapper/tree.py
+    1.12 05/03/25 01:01:34 smurf@smurf.noris.de +29 -1
+    add filter option
+
+  gen_keymap
+    1.17 05/03/25 01:01:34 smurf@smurf.noris.de +6 -1
+    add filter option
+
+  debian/changelog
+    1.19 05/03/25 01:01:34 smurf@smurf.noris.de +7 -0
+    add filter option
+
+ChangeSet
+  1.57 05/02/27 20:36:24 smurf@smurf.noris.de +1 -0
+  ignore more test stuff
+
+  BitKeeper/etc/ignore
+    1.14 05/02/27 17:41:32 smurf@smurf.noris.de +2 -0
+    added map_equiv.py seektester
+
+ChangeSet
+  1.56 05/02/27 17:40:58 smurf@smurf.noris.de +2 -0
+  Install scripts
+
+  debian/rules
+    1.5 05/02/27 17:40:58 smurf@smurf.noris.de +2 -0
+    Install scripts
+
+  debian/changelog
+    1.18 05/02/27 17:40:58 smurf@smurf.noris.de +2 -1
+    Added script
+
+ChangeSet
+  1.55 05/02/27 17:37:59 smurf@smurf.noris.de +1 -0
+  Map comparison for X
+
+  x2console_keymap
+    1.4 05/02/27 17:37:59 smurf@smurf.noris.de +38 -45
+    Map comparison for X
+
+ChangeSet
+  1.54 05/02/27 17:37:31 smurf@smurf.noris.de +4 -0
+  Query parser refactoring
+
+  test_x11.py
+    1.2 05/02/27 17:37:31 smurf@smurf.noris.de +2 -2
+    Query parser refactoring
+
+  test_gen_map.py
+    1.10 05/02/27 17:37:31 smurf@smurf.noris.de +2 -2
+    Query parser refactoring
+
+  keymapper/script.py
+    1.8 05/02/27 17:37:31 smurf@smurf.noris.de +23 -10
+    Query parser refactoring
+
+  keymapper/fakequery.py
+    1.10 05/02/27 17:37:31 smurf@smurf.noris.de +17 -7
+    Query parser refactoring
+
+ChangeSet
+  1.53 05/02/27 17:37:08 smurf@smurf.noris.de +1 -0
+  Ignore Hyper_* symbols
+
+  keymapper/parse/linuxsyms.py
+    1.6 05/02/27 17:37:08 smurf@smurf.noris.de +2 -1
+    Ignore Hyper_ too
+
+ChangeSet
+  1.52 05/02/27 17:36:14 smurf@smurf.noris.de +2 -0
+  X11 parser extensions
+
+  keymapper/parse/x11.g
+    1.2 05/02/27 17:36:14 smurf@smurf.noris.de +30 -15
+    X11 parser extensions, bugfix for subdirectories
+
+  data/symbols
+    1.3 05/02/27 17:36:14 smurf@smurf.noris.de +173 -32
+    More symbols, some of them typos, for X11.
+
+ChangeSet
+  1.51 05/02/27 17:34:50 smurf@smurf.noris.de +2 -0
+  More equivalents.
+
+  debian/changelog
+    1.17 05/02/27 17:34:50 smurf@smurf.noris.de +2 -1
+    Various small bugfixes.
+
+  data/equivs
+    1.6 05/02/27 17:34:50 smurf@smurf.noris.de +2 -1
+    More equivalent characters.
+
+  x2console_keymap
+    1.3 05/02/27 13:16:26 smurf@smurf.noris.de +0 -0
+    Rename: x2c_keymap -> x2console_keymap
+
+  x2c_keymap
+    1.2 05/02/27 13:16:11 smurf@smurf.noris.de +0 -0
+    bk cp test_x11.py x2c_keymap
+
+ChangeSet
+  1.50 05/02/27 13:14:44 smurf@smurf.noris.de +1 -0
+  reverse keymap output for the tester
+
+  keymapper/keymap.py
+    1.11 05/02/27 13:14:44 smurf@smurf.noris.de +30 -6
+    reverse keymap output for the tester
+
+ChangeSet
+  1.49 05/02/27 13:13:22 smurf@smurf.noris.de +1 -0
+  Skip meta and alt tags
+
+  keymapper/parse/linuxsyms.py
+    1.5 05/02/27 13:13:22 smurf@smurf.noris.de +2 -3
+    Skip meta and alt tags
+
+ChangeSet
+  1.48 05/02/27 13:12:54 smurf@smurf.noris.de +2 -0
+  Speed up keymap filtering when keymaps have subsets.
+
+  keymapper/tree.py
+    1.11 05/02/27 13:12:54 smurf@smurf.noris.de +13 -5
+    Speed up keymap filtering when keymaps have subsets.
+
+  debian/changelog
+    1.16 05/02/27 13:12:54 smurf@smurf.noris.de +2 -1
+    Speed up keymap filtering when keymaps have subsets.
+
+ChangeSet
+  1.47 05/02/27 13:11:43 smurf@smurf.noris.de +2 -0
+  Fix color/style assignment in graph output.
+
+  keymapper/graph.py
+    1.10 05/02/27 13:11:43 smurf@smurf.noris.de +5 -2
+    Fix color/style assignment in graph output.
+
+  debian/changelog
+    1.15 05/02/27 13:11:43 smurf@smurf.noris.de +2 -1
+    Fix color/style assignment in graph output.
+
+  x2c_keymap
+    1.1 05/02/27 13:10:39 smurf@smurf.noris.de +74 -0
+
+  test_x11.py
+    1.1 05/02/27 13:10:39 smurf@smurf.noris.de +74 -0
+
+  keymapper/parse/x11.g
+    1.1 05/02/27 13:10:39 smurf@smurf.noris.de +247 -0
+
+  data/xkeys
+    1.1 05/02/27 13:10:39 smurf@smurf.noris.de +58 -0
+
+ChangeSet
+  1.46 05/02/27 13:10:39 smurf@smurf.noris.de +8 -0
+  Added an analyzer for X11 keymaps.
+
+  x2c_keymap
+    1.0 05/02/27 13:10:39 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/test_x11.py
+
+  test_x11.py
+    1.0 05/02/27 13:10:39 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/test_x11.py
+
+  keymapper/parse/x11.g
+    1.0 05/02/27 13:10:39 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/keymapper/parse/x11.g
+
+  debian/rules
+    1.4 05/02/27 13:10:39 smurf@smurf.noris.de +1 -0
+    Install keycode table for X => console.
+
+  debian/control
+    1.7 05/02/27 13:10:39 smurf@smurf.noris.de +1 -1
+    depend on X keymaps.
+
+  debian/changelog
+    1.14 05/02/27 13:10:39 smurf@smurf.noris.de +1 -0
+    Added an analyzer for X11 keymaps.
+
+  data/xkeys
+    1.0 05/02/27 13:10:39 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/data/xkeys
+
+  data/symbols
+    1.2 05/02/27 13:10:39 smurf@smurf.noris.de +945 -338
+    Lots of new stuff for X.
+
+  BitKeeper/etc/ignore
+    1.13 05/02/27 13:10:39 smurf@smurf.noris.de +1 -0
+    added keymapper/parse/x11.py
+
+ChangeSet
+  1.45 05/02/27 13:07:11 smurf@smurf.noris.de +1 -0
+  utf-8-ize sys.stdout
+
+  test_gen_map.py
+    1.9 05/02/27 13:07:11 smurf@smurf.noris.de +2 -0
+    utf-8-ize sys.stdout
+
+ChangeSet
+  1.44 05/02/27 13:06:05 smurf@smurf.noris.de +2 -0
+  Added lots of new lookalike Unicode characters,
+  from Unicode's NamesList.txt.
+
+  debian/changelog
+    1.13 05/02/27 13:06:05 smurf@smurf.noris.de +2 -0
+    Added lots of new lookalike Unicode characters,
+    from Unicode's NamesList.txt.
+
+  data/equivs
+    1.5 05/02/27 13:06:05 smurf@smurf.noris.de +142 -28
+    Added lots of new lookalike Unicode characters,
+    from Unicode's NamesList.txt.
+
+ChangeSet
+  1.43 05/02/27 13:01:17 smurf@smurf.noris.de +3 -0
+  Reworked the step file interpreter to process multiple possible choices in parallel
+
+  keymapper/script.py
+    1.7 05/02/27 13:01:17 smurf@smurf.noris.de +37 -31
+    Reworked the step file interpreter to process multiple possible choices in parallel
+
+  keymapper/fakequery.py
+    1.9 05/02/27 13:01:17 smurf@smurf.noris.de +9 -5
+    Reworked the step file interpreter to process multiple possible choices in parallel
+
+  debian/changelog
+    1.12 05/02/27 13:01:17 smurf@smurf.noris.de +7 -0
+    Reworked the step file interpreter to process multiple possible choices in parallel
+
+ChangeSet
+  1.42 05/02/15 20:27:44 smurf@smurf.noris.de +3 -0
+  Version 0.4.3-1
+  change search path logic to allow arbitrary paths
+
+  keymapper/parse/linux.g
+    1.3 05/02/15 20:27:43 smurf@smurf.noris.de +8 -15
+    change search path logic to allow arbitrary paths
+
+  gen_keymap
+    1.16 05/02/15 20:27:43 smurf@smurf.noris.de +6 -5
+    change search path logic to allow arbitrary paths
+
+  debian/changelog
+    1.11 05/02/15 20:27:43 smurf@smurf.noris.de +3 -2
+    Version 0.4.3-1
+    change search path logic to allow arbitrary paths
+
+ChangeSet
+  1.41 05/02/14 22:52:07 smurf@smurf.noris.de +2 -0
+  Fix dependency on python-dev.
+
+  debian/control
+    1.6 05/02/14 22:51:57 smurf@smurf.noris.de +1 -1
+    Fix dependency on python-dev.
+
+  debian/changelog
+    1.10 05/02/14 22:51:57 smurf@smurf.noris.de +6 -0
+    Fix dependency on python-dev.
+
+ChangeSet
+  1.40 05/02/14 18:53:31 smurf@smurf.noris.de +1 -0
+  ignore unicode files
+
+  BitKeeper/etc/ignore
+    1.12 05/02/14 18:53:20 smurf@smurf.noris.de +2 -0
+    added NamesList.txt UnicodeData.txt
+
+ChangeSet
+  1.39 05/02/14 18:52:52 smurf@smurf.noris.de +1 -0
+  depend on current Python 2.4
+
+  debian/control
+    1.5 05/02/14 18:52:52 smurf@smurf.noris.de +1 -1
+    depend on current Python 2.4
+
+ChangeSet
+  1.38 05/02/14 18:49:16 smurf@smurf.noris.de +1 -0
+  unstable => hoary
+
+  debian/changelog
+    1.9 05/02/14 18:49:15 smurf@smurf.noris.de +6 -6
+    unstable => hoary
+
+ChangeSet
+  1.37 05/02/04 23:45:32 smurf@smurf.noris.de +1 -0
+  colorize the graph
+
+  keymapper/graph.py
+    1.9 05/02/04 23:45:28 smurf@smurf.noris.de +20 -13
+    colorize
+
+ChangeSet
+  1.36 05/02/04 23:45:10 smurf@smurf.noris.de +2 -0
+  Small test fixes
+
+  test_gen_map.py
+    1.8 05/02/04 23:45:08 smurf@smurf.noris.de +1 -1
+    Use utf-8 in map reader
+
+  gen_keymap
+    1.15 05/02/04 23:45:07 smurf@smurf.noris.de +27 -0
+    Add test option to run the generated maps
+
+ChangeSet
+  1.35 05/02/04 23:44:27 smurf@smurf.noris.de +7 -0
+  Fix a couple of annoying bugs
+
+  keymapper/tree.py
+    1.10 05/02/04 23:44:20 smurf@smurf.noris.de +30 -4
+    Use SymSet from keymapper.keymap
+    Check char type to prioritize better
+    Complain when a symbol doesn't print
+
+  keymapper/script.py
+    1.6 05/02/04 23:44:19 smurf@smurf.noris.de +31 -5
+    fix multi-char "ask"
+    evaluate printed spacing symbols and control chars
+
+  keymapper/keymap.py
+    1.10 05/02/04 23:44:19 smurf@smurf.noris.de +11 -4
+    Use NFC internally
+    add Set type to enfoce that
+
+  keymapper/file.py
+    1.8 05/02/04 23:44:18 smurf@smurf.noris.de +21 -2
+    Print spacing symbols and some control chars
+
+  keymapper/fakequery.py
+    1.8 05/02/04 23:44:17 smurf@smurf.noris.de +9 -8
+    Fix multi-char "ask"
+
+  keymapper/fakemaps.py
+    1.7 05/02/04 23:44:17 smurf@smurf.noris.de +1 -1
+    Fix coding: header
+
+  keymapper/equiv.py
+    1.4 05/02/04 23:44:15 smurf@smurf.noris.de +9 -3
+    Switch to NFC encoding internally
+
+ChangeSet
+  1.34 05/02/03 13:57:10 smurf@smurf.noris.de +1 -0
+  fix priorities
+
+  keymapper/tree.py
+    1.9 05/02/03 13:57:09 smurf@smurf.noris.de +38 -25
+    priority adjust
+
+ChangeSet
+  1.33 05/02/03 11:39:16 smurf@smurf.noris.de +5 -0
+  Cleanup: The main programs are responsible for equipping the streams
+           passed into keymapper.* with appropriate codecs.
+
+  test_gen_map.py
+    1.7 05/02/03 11:39:13 smurf@smurf.noris.de +4 -3
+    codec-ize the file streams here
+
+  keymapper/file.py
+    1.7 05/02/03 11:39:13 smurf@smurf.noris.de +2 -2
+    don't encode, that's supposed to be done in the file
+
+  keymapper/fakequery.py
+    1.7 05/02/03 11:39:13 smurf@smurf.noris.de +1 -1
+    don't utf8-decode here, input is supposed to be Unicode already
+
+  keymapper/fakemaps.py
+    1.6 05/02/03 11:39:13 smurf@smurf.noris.de +2 -2
+    add a nice utf-8 character to the test to make it mroe interesting
+
+  debian/changelog
+    1.8 05/02/03 11:39:13 smurf@smurf.noris.de +3 -1
+    Cleanup: The main programs are responsible for equipping the streams
+             passed into keymapper.* with appropriate codecs.
+
+ChangeSet
+  1.32 05/02/03 11:31:42 smurf@smurf.noris.de +1 -0
+  cleanup, now works with Python 2.3
+
+  gen_keymap
+    1.14 05/02/03 11:31:41 smurf@smurf.noris.de +3 -3
+    drop the subprocess import
+    syntax niceties
+
+ChangeSet
+  1.31 05/02/03 11:31:16 smurf@smurf.noris.de +2 -0
+  added more interesting letters
+
+  debian/changelog
+    1.7 05/02/03 11:31:15 smurf@smurf.noris.de +6 -0
+    added more interesting letters
+
+  data/equivs
+    1.4 05/02/03 11:31:15 smurf@smurf.noris.de +22 -21
+    more interesting letters
+
+ChangeSet
+  1.30 05/02/02 19:30:45 smurf@smurf.noris.de +2 -0
+  Add one and zero.
+  Conflate L and I.
+
+  debian/changelog
+    1.6 05/02/02 19:30:44 smurf@smurf.noris.de +7 -0
+    Add one and zero.
+    Conflate L and I.
+
+  data/equivs
+    1.3 05/02/02 19:30:44 smurf@smurf.noris.de +2 -3
+    Add one and zero.
+    Conflate L and I.
+
+ChangeSet
+  1.29 05/02/02 19:28:52 smurf@smurf.noris.de +7 -0
+  Extension: We print only those characters under consideration in the present step.
+
+  keymapper/tree.py
+    1.8 05/02/02 19:28:52 smurf@smurf.noris.de +30 -11
+    core code to display only those characters that actually appear on the keys
+
+  keymapper/keymap.py
+    1.9 05/02/02 19:28:52 smurf@smurf.noris.de +4 -1
+    add list of symbols actually present
+
+  keymapper/graph.py
+    1.8 05/02/02 19:28:52 smurf@smurf.noris.de +4 -3
+    fix output code to deal with symbol stuff
+
+  keymapper/file.py
+    1.6 05/02/02 19:28:52 smurf@smurf.noris.de +5 -4
+    There may be more than one symbol -- print correctly
+
+  keymapper/fakequery.py
+    1.6 05/02/02 19:28:52 smurf@smurf.noris.de +3 -3
+    fixed processing for symbols that aren't present
+
+  keymapper/equiv.py
+    1.3 05/02/02 19:28:52 smurf@smurf.noris.de +5 -2
+    add lowercase and uppercase versions
+
+  debian/changelog
+    1.5 05/02/02 19:28:52 smurf@smurf.noris.de +7 -0
+    print only those characters under consideration at this step.
+
+ChangeSet
+  1.28 05/02/02 17:08:40 smurf@smurf.noris.de +1 -0
+  add more lookalike characters
+
+  data/equivs
+    1.2 05/02/02 17:08:40 smurf@smurf.noris.de +33 -22
+    even more lookalike characters
+
+ChangeSet
+  1.27 05/02/02 16:17:08 smurf@smurf.noris.de +1 -0
+  bad file name in keymapper/equiv.py
+
+  keymapper/equiv.py
+    1.2 05/02/02 16:17:08 smurf@smurf.noris.de +2 -2
+    bad file name
+
+  keymapper/equiv.py
+    1.1 05/02/02 16:14:49 smurf@smurf.noris.de +79 -0
+
+  data/equivs
+    1.1 05/02/02 16:14:49 smurf@smurf.noris.de +30 -0
+
+ChangeSet
+  1.26 05/02/02 16:14:49 smurf@smurf.noris.de +13 -0
+  Add character equivalence table.
+
+  test_gen_map.py
+    1.6 05/02/02 16:14:49 smurf@smurf.noris.de +4 -0
+    Add character equivalence table.
+
+  keymapper/tree.py
+    1.7 05/02/02 16:14:49 smurf@smurf.noris.de +19 -8
+    Add character equivalence table.
+
+  keymapper/script.py
+    1.5 05/02/02 16:14:49 smurf@smurf.noris.de +2 -2
+    Add character equivalence table.
+
+  keymapper/parse/linuxsyms.py
+    1.4 05/02/02 16:14:49 smurf@smurf.noris.de +5 -0
+    Add character equivalence table.
+
+  keymapper/keymap.py
+    1.8 05/02/02 16:14:49 smurf@smurf.noris.de +3 -1
+    Add character equivalence table.
+
+  keymapper/graph.py
+    1.7 05/02/02 16:14:49 smurf@smurf.noris.de +9 -2
+    Add character equivalence table.
+
+  keymapper/file.py
+    1.5 05/02/02 16:14:49 smurf@smurf.noris.de +4 -2
+    Add character equivalence table.
+
+  keymapper/fakequery.py
+    1.5 05/02/02 16:14:49 smurf@smurf.noris.de +13 -6
+    Add character equivalence table.
+
+  keymapper/fakemaps.py
+    1.5 05/02/02 16:14:49 smurf@smurf.noris.de +2 -2
+    Add character equivalence table.
+
+  keymapper/equiv.py
+    1.0 05/02/02 16:14:49 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/keymapper/equiv.py
+
+  debian/rules
+    1.3 05/02/02 16:14:49 smurf@smurf.noris.de +1 -0
+    Install character equivalence table.
+
+  debian/changelog
+    1.4 05/02/02 16:14:49 smurf@smurf.noris.de +6 -0
+    Add character equivalence table.
+
+  data/equivs
+    1.0 05/02/02 16:14:49 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/data/equivs
+
+ChangeSet
+  1.25 05/02/02 16:14:28 smurf@smurf.noris.de +1 -0
+  Add option to skip tables (if they're identical to other tables)
+
+  gen_keymap
+    1.13 05/02/02 16:14:28 smurf@smurf.noris.de +8 -0
+    Add option to skip tables (if they're identical to other tables)
+
+ChangeSet
+  1.24 05/02/02 09:50:40 smurf@smurf.noris.de +1 -0
+  ignore changelog
+
+  BitKeeper/etc/ignore
+    1.11 05/02/02 09:50:30 smurf@smurf.noris.de +1 -0
+    added changelog
+
+ChangeSet
+  1.23 05/02/02 09:50:27 smurf@smurf.noris.de +3 -0
+  more build and installation stuff
+
+  keymapper/parse/linuxsyms.py
+    1.3 05/02/02 09:50:27 smurf@smurf.noris.de +1 -1
+    read the symfile from somewhere sane
+
+  gen_keymap
+    1.12 05/02/02 09:50:27 smurf@smurf.noris.de +11 -8
+    input file format option
+
+  debian/rules
+    1.2 05/02/02 09:50:27 smurf@smurf.noris.de +6 -1
+    build the parser
+    install the symbol map
+
+ChangeSet
+  1.22 05/02/02 09:29:22 smurf@smurf.noris.de +3 -0
+  Added option to set the file system root.
+
+  keymapper/parse/linux.g
+    1.2 05/02/02 09:29:22 smurf@smurf.noris.de +5 -1
+    Added option to set the file system root.
+
+  gen_keymap
+    1.11 05/02/02 09:29:22 smurf@smurf.noris.de +6 -1
+    Added option to set the file system root.
+
+  debian/changelog
+    1.3 05/02/02 09:29:22 smurf@smurf.noris.de +1 -0
+    Added option to set the file system root.
+
+ChangeSet
+  1.21 05/02/02 08:58:42 smurf@smurf.noris.de +1 -0
+  fixed the dependencies
+
+  debian/control
+    1.4 05/02/02 08:58:42 smurf@smurf.noris.de +1 -1
+    dependency
+
+  debian/exporter
+    1.1 05/02/02 08:56:54 smurf@smurf.noris.de +10 -0
+
+ChangeSet
+  1.20 05/02/02 08:56:54 smurf@smurf.noris.de +1 -0
+  added exporter for changelog
+
+  debian/exporter
+    1.0 05/02/02 08:56:54 smurf@smurf.noris.de +0 -0
+    BitKeeper file /daten/src/debian/keymapper/debian/exporter
+
+ChangeSet
   1.19 05/02/02 08:54:14 smurf@smurf.noris.de +1 -0
   ignore stuff
 
--- keymapper-0.5.3.orig/gen_keymap.1
+++ keymapper-0.5.3/gen_keymap.1
@@ -0,0 +1,62 @@
+.Dd September 5, 2006
+.Os Ubuntu
+.ds volume-operating-system Ubuntu
+.Dt GEN_KEYMAP 1
+.Sh NAME
+.Nm gen_keymap
+.Nd generate a keyboard map decision tree
+.Sh SYNOPSIS
+.Nm
+.Ar list ...
+.Sh DESCRIPTION
+.Nm
+generates a decision tree from a set of keyboard maps which can be used to
+help a user decide which keyboard map to use.
+The program using the decision tree typically asks the user to press some
+keys; at each step, it examines the returned keycode and uses it to prune
+the list of possible keyboard maps until there is only one left.
+.Sh OPTIONS
+.Bl -tag -width 4n
+.It Fl Fl version
+Show program's version number and exit.
+.It Fl ? , Fl Fl help
+Show help text.
+.It Fl v , Fl Fl verbose
+Be more verbose.
+.It Fl m Ns Ar MINLEN , Fl Fl minlen Ns = Ns Ar MINLEN
+Too-short keymaps are skipped (default: 30 entries).
+.It Fl g , Fl Fl graph
+Generate a hopefully-nice-looking .dot file.
+.It Fl Fl maps
+Print the to-be-processed keymaps
+.It Fl i , Fl Fl installer
+Input files are in d-i map form.
+.It Fl I Ns Ar DIRS , Fl Fl inc Ns = Ns Ar DIRS , Fl Fl include Ns = Ns Ar DIRS
+Add a directory to the search path.
+.It Fl o Ns Ar FILENAME , Fl Fl output Ns = Ns Ar FILENAME
+Set output file (default: stdout).
+.It Fl f Ns Ar FILTER , Fl Fl filter Ns = Ns Ar FILTER
+Include only the branches leading to these keymaps.
+.It Fl u Ns Ar USEONLY , Fl Fl useonly Ns = Ns Ar USEONLY
+Start generating the tree based only on these keymaps.
+(The difference between
+.Fl Fl filter
+and
+.Fl Fl useonly
+is that the former generates the whole tree and then prunes it, while the
+latter only generates a reduced tree to begin with.
+This may have implications for performance on large trees.)
+.It Fl s Ns Ar SKIP , Fl Fl skip Ns = Ns Ar SKIP
+Keymaps to skip.
+.It Fl t , Fl Fl test
+Test the generated maps.
+.It Fl Fl interactive
+Ask user to choose among indistinguishable keymaps.
+.El
+.Sh AUTHORS
+.An -nosplit
+.Nm
+was written by
+.An "Matthias Urlichs" Aq smurf@debian.org .
+This manual page was written by
+.An "Colin Watson" Aq cjwatson@ubuntu.com .
--- keymapper-0.5.3.orig/keymapper/graph.py
+++ keymapper-0.5.3/keymapper/graph.py
@@ -16,15 +16,26 @@
 from keymapper.tree import Reporter
 import sys
 import unicodedata
+from keymapper.equiv import get_sym, looks_like
+from random import uniform
+
+colors = ("red","green","blue","magenta","black","grey","yellowgreen","purple","plum")
+styles = ("solid","dotted","dashed")
 
 def uname(sym):
 	try:
+		sym=unicodedata.normalize("NFC",sym)
 		return unicodedata.name(unicode(sym)).lower()
 	except ValueError:
 		return "U+%4x" % ord(sym)
+	except TypeError:
+		return sym
+
+#def uname(sym):
+#	return ", ".join([_uname(s) for s in sym])
 
 def symnums(syms):
-	return ".".join([str(ord(s)) for s in syms])
+	return ".".join([str(looks_like(s)) for s in syms])
 
 class GraphReporter(Reporter):
 	"""Report the result as a graphviz .dot file"""
@@ -43,32 +54,54 @@
 
 	def keymap(self,map):
 		"""This steps selects a unique keymap"""
-		print >>self.file, '"Step %d" [label="Map: %s"]' % (self.nr,map.name)
+		print >>self.file, '"Step %d" [label="Map: %s", shape="box"]' % (self.nr,map.name)
 		
 
 	def symbols(self,symbols):
 		"""Start a choice: display these symbols"""
-		self.syms = symbols
+		self.syms = [ (s,c) for s,c in symbols ]
+		self.color=colors[int(uniform(0,len(colors)))]
+		self.style=styles[int(uniform(0,len(styles)))]
+		# copy, for we need it more than once
 
 	def choice(self,code,nextstep):
 		"""Choice: This keycode leads to that step"""
 		syms=[]
-		for s,c in self.syms.items():
+		for s,c in self.syms:
 			if code in c:
 				syms.append(s)
 
-		print >>self.file, '"Step %d" -> "S_%d_%s_%d"' % (self.nr,self.nr, symnums(syms), code)
-		print >>self.file, '"S_%d_%s_%d" -> "Step %d"' % (self.nr,symnums(syms), code, nextstep.step)
-		print >>self.file, '"S_%d_%s_%d" [ label="%s -> %d" ]' % (self.nr, symnums(syms), code, "\\n".join([uname(s) for s in syms]), code)
+		print >>self.file, '"Step %d" [ color="%s", shape="box" ] ' % (self.nr, self.color)
+		print >>self.file, '"Step %d" -> "S_%d_%s_%d" [ color="%s", style="%s", weight=2 ] ' % (self.nr,self.nr, symnums(syms), code, self.color,self.style)
+		print >>self.file, '"S_%d_%s_%d" -> "Step %d" [ color="%s", style="%s" ] ' % (self.nr,symnums(syms), code, nextstep.step, self.color,self.style)
+		print >>self.file, '"S_%d_%s_%d" [ label="%s -> %d", color="%s" ]' % (self.nr, symnums(syms), code, "\\n".join([uname(s) for s in syms]), code, self.color)
 
 
 	def ask(self,sym,no,yes):
 		"""Ask whether that symbol is visible"""
-		print >>self.file, '"Step %d" [ label="Step %d\\nCheck for %s" ]' % (self.nr,self.nr,uname(sym))
-		print >>self.file, '"Step %d" -> "AY-%d" -> "Step %d"' % (self.nr,self.nr,yes.step)
-		print >>self.file, '"AY-%d" [ label="Yes" ]' % (self.nr,)
-		print >>self.file, '"Step %d" -> "AN-%d" -> "Step %d"' % (self.nr,self.nr,no.step)
-		print >>self.file, '"AN-%d" [ label="No" ]' % (self.nr,)
+		self.color=colors[int(uniform(0,len(colors)))]
+		self.style=styles[int(uniform(0,len(styles)))]
+
+		print >>self.file, '"Step %d" [ shape="box", label="Step %d\\nCheck for %s", color="%s" ]' % (self.nr,self.nr,"\\nor ".join([uname(s) for s in sym]), self.color)
+		if yes:
+			print >>self.file, '"Step %d" -> "AY-%d" -> "Step %d" [ color="%s", style="%s", weight=2 ]' % (self.nr,self.nr,yes.step, self.color,self.style)
+			print >>self.file, '"AY-%d" [ label="Yes", color="%s" ]' % (self.nr,self.color)
+		if no:
+			print >>self.file, '"Step %d" -> "AN-%d" -> "Step %d" [ color="%s", style="%s", weight=2 ]' % (self.nr,self.nr,no.step, self.color,self.style)
+			print >>self.file, '"AN-%d" [ label="No", color="%s" ]' % (self.nr,self.color)
+
+	def ask_no_alt(self,sym,no,yes):
+		"""Ask whether that symbol is visible on primary keys"""
+		self.color=colors[int(uniform(0,len(colors)))]
+		self.style=styles[int(uniform(0,len(styles)))]
+
+		print >>self.file, '"Step %d" [ shape="box", label="Step %d\\nCheck for %s\\n(no Alt*)", color="%s" ]' % (self.nr,self.nr,"\\nor ".join([uname(s) for s in sym]), self.color)
+		if yes:
+			print >>self.file, '"Step %d" -> "AY-%d" -> "Step %d" [ color="%s", style="%s", weight=2 ]' % (self.nr,self.nr,yes.step, self.color,self.style)
+			print >>self.file, '"AY-%d" [ label="Yes", color="%s" ]' % (self.nr,self.color)
+		if no:
+			print >>self.file, '"Step %d" -> "AN-%d" -> "Step %d" [ color="%s", style="%s", weight=2 ]' % (self.nr,self.nr,no.step, self.color,self.style)
+			print >>self.file, '"AN-%d" [ label="No", color="%s" ]' % (self.nr,self.color)
 
 	def finish(self):
 		"""Conclude this step"""
--- keymapper-0.5.3.orig/keymapper/tree.py
+++ keymapper-0.5.3/keymapper/tree.py
@@ -35,12 +35,28 @@
 """
 
 from sets import Set,ImmutableSet
+from keymapper.equiv import get_sym,chartype
+from keymapper.keymap import SymSet
+from unicodedata import category
 
 # follow what's happening?
 trace=False
 last_trace=0
 from time import time
 
+interactive=False
+
+charhash={}
+def chartype(c):
+	if c in charhash:
+		return charhash[c]
+	charhash[c] = h = category(c)[0]
+	return h
+	
+class NoShownSyms(Exception):
+	"""A step doesn't actually display anything"""
+	pass
+
 class DupKeycode(Exception):
 	"""A key code has been added to a Choice node twice"""
 	pass
@@ -73,6 +89,9 @@
 	def ask(self,sym,no,yes):
 		"""Ask whether that symbol is visible"""
 		raise NotImplementedError
+	def ask_no_alt(self,sym,no,yes):
+		"""Ask whether that symbol is visible on primary keys"""
+		raise NotImplementedError
 	def finish(self):
 		"""Conclude this step"""
 		pass
@@ -86,8 +105,9 @@
 class Node(object):
 	"""a generic node in the keymap decision tree"""
 
-	def __init__(self):
+	def __init__(self,maps):
 		self.delay = 0
+		self.maps = maps
 
 	def __eq__(self,other):
 		"""Compare this node to another"""
@@ -102,6 +122,7 @@
 	def simplify(self,cache):
 		"""Check whether this node is redundant"""
 		self = self._simplify(cache)
+		if self is None: return None
 		key = self.key()
 		if key in cache: return cache[key]
 		cache[key] = self
@@ -143,7 +164,8 @@
 		self.step = nr
 		nr += 1
 		for c in self: # iterates the children
-			nr = c.seq1(nr)
+			if c is not None:
+				nr = c.seq1(nr)
 		self.maxstep = nr
 		return nr
 
@@ -158,15 +180,35 @@
 			return
 		yield self
 		for c in self: # iterates over child nodes
-			for n in c.seq2():
-				yield n
+			if c is not None:
+				for n in c.seq2():
+					yield n
+
+	def visible_syms(self, keys):
+		"""List symbols which actually correspond to keycodes"""
+		num=0
+		for sym,codes in keys:
+			seen = SymSet()
+			for s in get_sym(sym):
+				for m in self.maps:
+					if s not in m.seen: continue
+					if s in seen: continue
+					seen.add(s)
+					break
+			for s in seen:
+				num += 1
+				yield s,codes
+		if not num:
+			raise NoShownSyms
+
+
 
 class Choice(Node):
 	"""a node in the keymap decision tree which asks for one of a number
 		of symbols and selects by the keycode that's returned"""
 	
-	def __init__(self, sym2codes, code2map):
-		Node.__init__(self)
+	def __init__(self, maps, sym2codes, code2map):
+		Node.__init__(self, maps)
 		self.sym2codes = sym2codes # list of symbols to display => key codes
 		self.children = code2map # key code => node or keymap
 	
@@ -195,7 +237,7 @@
 	def key(self):
 		syms = [ sym for sym in self.sym2codes ]
 		syms.sort()
-		ret = "Q:"+":".join(self.sym2codes.keys())+":"
+		ret = "Q:"+":".join(["".join(get_sym(s)) for s in self.sym2codes.keys()])+":"
 		codes = self.children.keys()
 		codes.sort()
 		for code in codes:
@@ -221,9 +263,23 @@
 				return self
 		return uniq
 	
+	def filter(self,maps):
+		"""Drop branches not in map list"""
+		for code,node in self.children.items():
+			if node:
+				node = node.filter(maps)
+			if not node:
+				del self.children[code]
+
+		# Throw this node away if it doesn't decide anything any more
+		if not self.children:
+			return None
+		return self
+
 	def report(self,gen):
 		gen.step(self.step)
-		gen.symbols(self.sym2codes)
+
+		gen.symbols(self.visible_syms(self.sym2codes.iteritems()))
 		for code,node in self.children.items():
 			gen.choice(code,node)
 		gen.finish()
@@ -231,8 +287,8 @@
 
 class Ask(Node):
 	"""a node in the keymap decision tree which asks whether a given keyboard symbol exists"""
-	def __init__(self, sym,no,yes):
-		Node.__init__(self)
+	def __init__(self, maps, sym,no,yes):
+		Node.__init__(self,maps)
 		self.sym = sym
 		self.no = no
 		self.yes = yes
@@ -265,16 +321,32 @@
 		if self.no: return self.no
 		return self.yes
 
+	def filter(self,maps):
+		if self.yes:
+			self.yes = self.yes.filter(maps)
+		if self.no:
+			self.no = self.no.filter(maps)
+		if not self.yes and not self.no: return None
+		return self
+
+	def report(self,gen):
+		gen.step(self.step)
+		gen.ask([s for s,c in self.visible_syms([(self.sym,None)])], self.no, self.yes)
+		gen.finish()
+
+class AskNoAlt(Ask):
+	"""same as Ask, not without Alt* keys"""
 	def report(self,gen):
 		gen.step(self.step)
-		gen.ask(self.sym, self.no, self.yes)
+		gen.ask_no_alt([s for s,c in self.visible_syms([(self.sym,None)])], self.no, self.yes)
 		gen.finish()
 
 class Found(Node):
 	"""A node which resolves to a single keymap"""
 	def __init__(self, node):
-		Node.__init__(self)
+		Node.__init__(self,[node])
 		self.node = node
+		self.maps = [node]
 
 	def __iter__(self):
 		return ().__iter__()
@@ -290,6 +362,11 @@
 		if self.node is None: return None
 		return self
 	
+	def filter(self,maps):
+		print "%s %s" % (self.node,maps)
+		if self.node.name not in maps: return None
+		return self
+	
 	def report(self,gen):
 		gen.step(self.step)
 		gen.keymap(self.node)
@@ -306,6 +383,9 @@
 class SingleMapping(Exception):
 	pass
 
+class SingleMappingNoAlt(Exception):
+	pass
+
 
 # The main code starts here.
 
@@ -316,23 +396,32 @@
 		self.maps=Set() # list of keyboards
 		self.symbols={} # symbol => [nummaps,sumpriority]
 		self._id = 0
+		self.interactively_skipped = Set()
 	
 	def add(self,map):
 		"""add a keymap to the list"""
 		self.maps.add(map)
 	
-	def gen_tree(self):
+	def __iter__(self):
+		return iter(self.maps)
+	
+	def gen_tree(self, *filter):
 		"""generate a decision tree"""
 		cache={}
 
 		self.tree = self._gen_tree(self.maps)
 		self.tree = self.tree.simplify(cache)
+		if self.tree and filter:
+			self.tree.filter(filter)
 	
 	def report(self,gen):
 		"""Emit the generated nodes by passing them to a generator."""
 		self.tree.seq1(0)
 		for n in self.tree.seq2():
 			n.report(gen)
+		if interactive and self.interactively_skipped:
+			print >>sys.stderr, "Skipped these keymaps interactively:",
+			print >>sys.stderr, ' '.join(self.interactively_skipped)
 
 	def _gen_tree(self, maps, xsyms=None):
 		"""One step of the selection algorithm."""
@@ -354,11 +443,14 @@
 		syms = ImmutableSet() # selected symbols
 		codes = {} # keycode => number of selected keymaps
 		for alt in range(2): # Try to get one alternate mapping
+			steps=0 # for reporting
+			bt_steps=0 # for limiting backtracks
+			bt_level=None
 			if trace>1:
 				if alt:
-					print "*** Alternate:",syms
+					print "*** Alternate:"," ".join(["".join(get_sym(s)) for s in syms]).encode("utf-8")
 				else:
-					print "*** Start:",_id,len(maps),"maps:",",".join([m.name for m in maps])
+					print "*** Start:",_id,len(maps),"maps:",",".join([m.name for m in maps]).encode("utf-8")
 			try:
 				open_map = ImmutableSet(maps)
 				track = []
@@ -369,12 +461,17 @@
 
 				chooser=None
 				while open_map:
+					# Check if we overdid it
+					steps += 1
+					if alt and steps>1000:
+						break
+
 					if not chooser:
 						global last_trace
 						if trace>2 or trace and time()-last_trace > 3 and len(open_map)>2:
-							print "choose from",",".join([m.name for m in open_map])
+							print "Step %d %d: choose from %s" % (steps, len(track), ",".join([m.name for m in open_map]))
 							last_trace=time()
-						chooser = choose_sym(open_map, syms.union(xsyms), xcode=codes, all_maps=maps, alt=alt)
+						chooser = choose_sym(open_map, syms.union(xsyms), xcode=codes, all_maps=maps, alt=alt, depth=len(track))
 
 					while True:
 						# Loop invariant:
@@ -392,9 +489,27 @@
 							# This chooser is unable to return a
 							# suitable choice, so backtrack.
 							if trace>1: print "exhausted",",".join([m.name for m in open_map])
-
 							if not track:
 								raise AlgorithmProblem(syms,maps,open_map)
+
+							# Check if we need to backtrack more aggressively.
+							# Otherwise we run for *ages*.
+							bt_steps += 1
+							if bt_steps > 100000:
+								bt_steps=0
+								if bt_level is None or bt_level > len(track):
+									bt_level = len(track)
+									if trace>1: print "Backtrack stepup",bt_level
+								else:
+									track = track[0:bt_level]
+									# Drop off if we stepped way back
+									# one and two levels
+									if bt_level <= 1:
+										bt_level = None
+									else:
+										bt_level = bt_level-1
+								if trace>1: print "Backtrack stepdown",bt_level
+
 							chooser,syms,codes,open_map = track.pop()
 							if trace>1: print "... back to",",".join([m.name for m in open_map])
 
@@ -402,7 +517,7 @@
 							raise AlgorithmProblem(syms,maps,open_map)
 
 						else:
-							if trace>2: print "got",sym.encode("utf-8"),
+							if trace>2: print "got",str(sym).encode("utf-8"),
 							# We have a possible candidate.
 							try:
 								# Get the list of keymaps chosen by it
@@ -417,13 +532,23 @@
 								if trace>2: print "no mapping"
 								continue
 
-							except SingleMapping,exc:
+							except (SingleMapping,SingleMappingNoAlt),exc:
 								# This is a possible yes/no question.
 								# If that's the best we can do, OK.
 								map_yes,map_no = exc.args
-								if trace>2: print "single mapping: yes",len(map_yes),"no",len(map_no)
+								if trace>2:
+									if exc == SingleMapping:
+										print "single mapping:",
+									else:
+										print "single mapping no alt:",
+									print "yes",len(map_yes),"no",len(map_no),"open",len(open_map),"track",len(track)
 								if not track:
-									return Ask(sym,
+									if exc == SingleMapping:
+										return Ask(maps, sym,
+											yes=self._gen_tree(map_yes),
+											no=self._gen_tree(map_no))
+									else:
+										return AskNoAlt(maps, sym,
 											yes=self._gen_tree(map_yes),
 											no=self._gen_tree(map_no))
 
@@ -477,6 +602,24 @@
 				if trace:
 					for m in open_map:
 						print >>sys.stderr, m.dump().encode("utf-8")
+				if interactive:
+					print >>sys.stderr, "Enter a preferred keymap (or nothing to quit):"
+					while True:
+						line = sys.stdin.readline().strip()
+						if line:
+							for m in open_map:
+								if m.name == line:
+									for other in open_map:
+										if other.name != line:
+											self.interactively_skipped.add(other.name)
+									return Found(m)
+							else:
+								print >>sys.stderr, "%s not found." % line
+						else:
+							print >>sys.stderr, "OK, giving up."
+							print >>sys.stderr, "Skipped these keymaps interactively:",
+							print >>sys.stderr, ' '.join(self.interactively_skipped)
+							break
 				sys.exit(1)
 
 		# Now build a Choice node from what we have found.
@@ -500,39 +643,59 @@
 			for code,map in codes.items():
 				print code,map
 			print "*** end ***",_id,len(maps),"***", \
-				" ".join(["%s:%s" % (s,",".join([str(cc) for cc in c])) for s,c in sym2codes.items()]).encode("utf-8")
+				" ".join(["%s:%s" % (s,",".join(["".join(get_sym(cc)) for cc in c])) for s,c in sym2codes.items()]).encode("utf-8")
 			print
 		for code,map in codes.items():
 			codes[code] = self._gen_tree(map)
 
-		ch = Choice(sym2codes, codes)
+		ch = Choice(maps, sym2codes, codes)
 		return ch
 		
 		
 
-def choose_sym(maps, xsym=(), xcode=(), all_maps=(), alt=0):
+def choose_sym(maps, xsym=(), xcode=(), all_maps=(), alt=0, depth=None):
 	"""Find the 'best' symbol in a set of keymaps"""
 	symdata={} # symbol => [ preference, number of keymaps with that symbol,
 	           #             mapping keycode => number of keyboards with that mapping
+	symdata_no_alt={} # same, but without "alt" keys
+
+	supermaps = Set()
+	do_log=0
+	if depth is not None:
+		if depth >= 2:
+			depth = None # 10*depth
+		elif depth == 1:
+			do_log=2
+			depth = 30
+		else: # 0
+			do_log=1
+			depth = 10
 
 	# If any of these maps is a subset of one of all_maps, drop out.
 	# Reason: We can't put up a "do you have this key" question now.
 	for m in maps:
 		for am in all_maps:
-			if am not in maps and m.is_submap(am):
-				return
+			if m.is_submap(am):
+				if am not in maps:
+					return
+				supermaps.add(am)
+
+	# Otherwise, filter supermaps
+	if len(maps)-len(supermaps) <= 1:
+		supermaps = ()
 
 	for map in maps:
+		if map in supermaps: continue
 		for sym in map.symbols():
 			if sym in xsym: continue
 			if sym not in symdata:
 				symdata[sym] = [ 0, 0, {} ]
 			data = symdata[sym]
+			pri = 0
 
 			# Heuristic: We try to block keys on ALT mappings, which
 			# have values smaller than zero, by never raising the value
 			# if it ever goes below zero
-			pri = map.priority(sym)
 #			if data[0] >= 0:
 #				if pri is None:
 #					pass
@@ -543,27 +706,39 @@
 #				if pri < 0:
 #					data[0] += pri
 
-			if ord(sym) > 0x40 and ord(sym) <= 0x5a:
-				if alt:
-					pri += 300
-				else:
-					pri += 5000
-			elif ord(sym) > 0x60 and ord(sym) <= 0x7a:
-				if alt:
-					pri += 300
-				else:
-					pri += 5000
-			elif ord(sym) > 128:
-				pri += 800
-			elif ord(sym) < 32 or ord(sym) == 127:
-				pri += -300
-			else:
-				if alt:
-					pri += 600
+			for s in get_sym(sym):
+
+				if len(s) != 1:
+					pri += 100
+				elif ord(s) > 0x40 and ord(s) <= 0x5a:
+					if alt:
+						pri += 300
+					else:
+						pri += 2000
+				elif ord(s) > 0x60 and ord(s) <= 0x7a:
+					if alt:
+						pri += 300
+					else:
+						pri += 2000
+				elif ord(s) <= 32 or ord(s) == 127:
+					pri += -100000 # ... likewise ...
 				else:
-					pri += 1000
+					cat = chartype(s)[0]
+					if cat == "L":
+						if alt:
+							pri += 600
+						else:
+							pri += 1500
+					elif cat == "Z" or cat == "C" or cat == "U":
+						pri -= 100000 # shouldn't happen, but ...
+					elif cat == "M":
+						pri -= 10000 # non-spacing modifiers
+					elif cat == "S":
+						pri += 100 # includes spacing modifiers
+					else:
+						pri += 200 # whatever's left
 
-			data[0] += pri
+			data[0] += pri/len(get_sym(sym)) + map.priority(sym)
 
 			for code in map.sym2cod[sym]:
 				# This check must not be done here.
@@ -579,8 +754,72 @@
 				data[1] += 1
 				data[2][code] += 1
 
+		# Duplicate of the same, for the non-alt case
+		for sym in map.symbols_no_alt():
+			if sym in xsym: continue
+			if sym not in symdata_no_alt:
+				symdata_no_alt[sym] = [ 0, 0, {} ]
+			data_no_alt = symdata_no_alt[sym]
+			pri = 0
+
+			# Heuristic: We try to block keys on ALT mappings, which
+			# have values smaller than zero, by never raising the value
+			# if it ever goes below zero
+#			if data_no_alt[0] >= 0:
+#				if pri is None:
+#					pass
+#				data_no_alt[0] += pri
+#				if pri >= 0 and data_no_alt[0] < 0:
+#					data_no_alt[0] = 0
+#			else:
+#				if pri < 0:
+#					data_no_alt[0] += pri
+
+			for s in get_sym(sym):
+
+				if len(s) != 1:
+					pri += 100
+				elif ord(s) > 0x40 and ord(s) <= 0x5a:
+					if alt:
+						pri += 300
+					else:
+						pri += 2000
+				elif ord(s) > 0x60 and ord(s) <= 0x7a:
+					if alt:
+						pri += 300
+					else:
+						pri += 2000
+				elif ord(s) <= 32 or ord(s) == 127:
+					pri += -100000 # ... likewise ...
+				else:
+					cat = chartype(s)[0]
+					if cat == "L":
+						if alt:
+							pri += 600
+						else:
+							pri += 1500
+					elif cat == "Z" or cat == "C" or cat == "U":
+						pri -= 100000 # shouldn't happen, but ...
+					elif cat == "M":
+						pri -= 10000 # non-spacing modifiers
+					elif cat == "S":
+						pri += 100 # includes spacing modifiers
+					else:
+						pri += 200 # whatever's left
+
+			data_no_alt[0] += pri/len(get_sym(sym)) + map.priority(sym)
+
+			for code in map.sym2cod_no_alt[sym]:
+				if code not in data_no_alt[2]:
+					data_no_alt[2][code] = 0
+
+				data_no_alt[1] += 1
+				data_no_alt[2][code] += 1
+
 	syms=[]
+	syms_no_alt=[]
 	xxsyms=Set()
+
 	for sym,(pri,sum,codes) in symdata.iteritems():
 		if not codes.values():
 			continue
@@ -596,26 +835,68 @@
 		maxcodes = reduce(max,[ num for num in codes.values() ])
 		nfull=0
 		for map in all_maps:
-			if sym in map.sym2code:
+			if sym in map.sym2cod:
 				nfull += 1
 
-		# more heuristics:
-		# Prefer symbols that appear in all maps.
+		# Count the number of symbols which actually appear
+		nsym=0
+		for c in get_sym(sym):
+			for m in all_maps:
+				if c in m.seen:
+					nsym += 1
+					break
+		# adjust for capital letters
+		if nsym == 2:
+			nsym = 1
+
+		# heuristics:
+		# Prefer symbols that appear in all maps (slightly).
 		# Prefer symbols that don't appear in maps we already selected.
 		# Prefer symbols that appear in many keyboards.
 		# Prefer symbols which result in many small subtrees,
 		#   i.e. the number of maps having that symbol on the same
 		#        keycode is small. 
-		#pri -= 100*(len(maps)-sum)
+		# Prefer non-ambiguous symbols.
+		pri -= 50*(len(maps)-sum)
 		pri -= 500*(nfull-sum)
 		pri += 100*len(codes)
-		pri -= 500*maxcodes
+		pri -= 1000*maxcodes
+		pri -= 500*nsym
 		syms.append((-pri,sym))
 
-	if len(maps) > 1 and not syms:
-		raise AlgorithmProblem
+	# Duplicate of the same, for the non-alt case
+	for sym,(pri,sum,codes) in symdata_no_alt.iteritems():
+		if not codes.values():
+			continue
+		for c in codes:
+			if c in xcode:
+				xxsyms.add(sym)
+				break
+
+		maxcodes = reduce(max,[ num for num in codes.values() ])
+		nfull=0
+		for map in all_maps:
+			if sym in map.sym2cod_no_alt:
+				nfull += 1
+
+		nsym=0
+		for c in get_sym(sym):
+			for m in all_maps:
+				if c in m.seen:
+					nsym += 1
+					break
+		if nsym == 2:
+			nsym = 1
+
+		pri -= 50*(len(maps)-sum)
+		pri -= 500*(nfull-sum)
+		pri += 100*len(codes)
+		pri -= 1000*maxcodes
+		pri -= 500*nsym
+		syms_no_alt.append((-pri,sym))
 
 	syms.sort()
+	syms_no_alt.sort()
 	# print
 	# print syms
 	# for m in maps:
@@ -623,23 +904,49 @@
 	# print
 
 	# First, generate normal "press a key" choices.
+	nret=0
 	for pri,sym in syms:
 		if sym not in xxsyms:
-			if trace>2: print "check",sym.encode("utf-8"),
-			yield sym,False
+			if trace>2: print "check",str(sym).encode("utf-8"),
+			if do_log and trace>1:
+				print "Return1",do_log,"".join(get_sym(sym)).encode("utf-8")
+			yield sym,None
+			if depth:
+				nret += 1
+				if nret > depth:
+					break
 
 	# If that didn't work, use excluded keycodes
 	if not alt:
+		nret=0
 		for pri,sym in syms:
 			if sym in xxsyms:
-				if trace>2: print "check",sym.encode("utf-8"),
-				yield sym,False
+				if trace>2: print "check",str(sym).encode("utf-8"),
+				if do_log and trace>1:
+					print "Return2",do_log,"".join(get_sym(sym)).encode("utf-8")
+				yield sym,None
+				if depth:
+					nret += 1
+					if nret > depth:
+						break
+
+	# If that didn't work, generate yes/no questions for non-ALT keys.
+	for pri,sym in syms_no_alt:
+		if symdata_no_alt[sym][1] < len(maps)-len(supermaps):
+			# ... but only if there are keyboards for which the answer is 'no'.
+			if do_log and trace>1:
+				print "Return3",do_log,"".join(get_sym(sym)).encode("utf-8")
+			yield sym,SingleMappingNoAlt
 
 	# If that didn't work, generate yes/no questions.
 	for pri,sym in syms:
-		if symdata[sym][1] < len(maps):
+		if symdata[sym][1] < len(maps)-len(supermaps):
 			# ... but only if there are keyboards for which the answer is 'no'.
-			yield sym,True
+			if do_log and trace>1:
+				print "Return4",do_log,"".join(get_sym(sym)).encode("utf-8")
+			yield sym,SingleMapping
+
+	if do_log and trace>1: print "ReturnEnd",do_log
 
 def drop_sym(maps, xsym):
 	"""Find those symbol in a set of keymaps"""
@@ -649,12 +956,16 @@
 	"""Returns a list keycode => maps with the symbol on that key"""
 	codes = Set()
 	xmaps = Set()
+	xmaps_no_alt = Set()
 	altmaps = Set()
 
 	for map in maps:
-		if not sym in map.sym2code:
+		if not sym in map.sym2cod:
 			xmaps.add(map)
+			xmaps_no_alt.add(map)
 			continue
+		if not sym in map.sym2cod_no_alt:
+			xmaps_no_alt.add(map)
 		for code,pri in map.sym2code[sym]:
 			codes.add(code)
 			if pri < 0:
@@ -662,12 +973,22 @@
 	
 	# If there's less than two choices, return via an exception.
 	if len(codes) == 0:
+		if trace>3: print "unknown,",
 		raise NoMapping(sym)
-	if len(codes) == 1:
-		if not xmaps:
+	if choose or len(codes) == 1:
+		if not xmaps or (choose == SingleMappingNoAlt and not xmaps_no_alt):
+			if trace>3:
+				if len(codes) == 1:
+					print "same,",
+				else:
+					print "choice,",
 			raise NoMapping(sym)
 		if choose:
-			raise SingleMapping(maps-xmaps, xmaps)
+			if trace>3: print "single,",
+			if choose == SingleMappingNoAlt:
+				raise choose(maps-xmaps_no_alt, xmaps_no_alt)
+			else:
+				raise choose(maps-xmaps, xmaps)
 
 	# If the symbol occurs with normal AND AltGr mappings,
 	# ignore the AltGr stuff -- the symbol may not actually be
--- keymapper-0.5.3.orig/keymapper/equiv.py
+++ keymapper-0.5.3/keymapper/equiv.py
@@ -0,0 +1,101 @@
+
+# equiv.py
+# find equivalent glyphs
+
+# Copyright (c) 2005 by Matthias Urlichs <smurf@smurf.noris.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of Version 2 of the GNU General Public License as
+# published by the Free Software Foundation. See the file COPYING.txt
+# or (on Debian systems) /usr/share/common-licenses/GPL-2 for details.
+
+"""\
+This module exports a 'looks_like()' function. it accepts a Unicode
+symbol and returns a list of symbols which look the same, in either
+upper or lower case.
+
+It also exports a chartype() function which returns the first letter
+of the Unicode category (e.g., 'C' for control characters, or 'Z' for
+spacing).
+
+"""
+
+from os.path import exists
+import codecs
+from unicodedata import normalize,category
+
+equivfile = "/usr/share/misc/keysym.equiv";
+if exists("data/equivs") and exists("gen_keymap"):
+	equivfile = "data/equivs";
+
+map = {}
+cache = {}
+syms = []
+
+charhash={}
+def chartype(c):
+	if c in charhash:
+		return charhash[c]
+	charhash[c] = h = category(c)[0]
+	return h
+
+def read_map():
+	for l in codecs.getreader("utf-8")(open(equivfile,"r")):
+		r = []
+		for c in l.strip():
+			cc = normalize("NFC",c.lower())
+			if cc not in r: r.append(cc)
+			cc = normalize("NFC",c.upper())
+			if cc not in r: r.append(cc)
+		found=1
+		while found:
+			found=0
+			for c in r:
+				if c in map:
+					for cc in map[c]:
+						if cc not in r:
+							found=1
+							r.append(cc)
+		r.sort()
+		r = tuple(r)
+		for c in r:
+			map[c] = r
+			cache[c] = len(syms)
+		syms.append(r)
+
+def looks_like(sym):
+	"""Return a symbol number for something looking like sym"""
+
+	if not map:
+		read_map()
+
+	if sym in cache:
+		return cache[sym]
+
+	s = normalize("NFC",sym.lower())
+	if s in cache:
+		s = cache[s]
+		cache[sym] = s
+		return s
+
+	if s in map:
+		res = map[s]
+	else:
+		res = [s]
+	for c in res:
+		if c in cache:
+			res = cache[c]
+			cache[sym] = res
+			return res
+
+	syms.append(res)
+	res = len(syms)-1
+	cache[sym] = res
+	if sym != s:
+		cache[s] = res
+	return res
+
+def get_sym(pos):
+	"""Return the symbols at that position"""
+	return syms[pos]
+
--- keymapper-0.5.3.orig/keymapper/file.py
+++ keymapper-0.5.3/keymapper/file.py
@@ -14,8 +14,29 @@
 """
 
 from keymapper.tree import Reporter
+from keymapper.equiv import get_sym
+from unicodedata import normalize
 import sys
 
+def nsym(s):
+	if len(s) != 1:
+		return s
+	elif ord(s) == 127:
+		return "<del>"
+	elif ord(s) == 32:
+		return "<spc>"
+	elif ord(s) == 10:
+		return "<lf>"
+	elif ord(s) == 13:
+		return "<cr>"
+	elif ord(s) == 8:
+		return "<bs>"
+	elif ord(s) == 9:
+		return "<tab>"
+	else:
+		return s
+
+
 class FileReporter(Reporter):
 	"""Report the result as a list of steps to a file"""
 	def __init__(self,file=sys.stdout):
@@ -31,8 +52,8 @@
 		
 	def symbols(self,symbols):
 		"""Start a choice: display these symbols"""
-		for sym in symbols:
-			print >>self.file,"PRESS %s" % sym
+		for sym,c in symbols:
+			print >>self.file,"PRESS %s" % nsym(normalize("NFC",sym))
 
 	def choice(self,code,nextstep):
 		"""Choice: This keycode leads to that step"""
@@ -40,11 +61,22 @@
 
 	def ask(self,sym,no,yes):
 		"""Ask whether that symbol is visible"""
-		print >>self.file,"FIND %s" % sym
-		print >>self.file,"YES %s" % yes.step
-		print >>self.file,"NO %s" % no.step
+		print >>self.file,"FIND %s" % " ".join([nsym(normalize("NFC",s)) for s in sym])
+		if yes:
+			print >>self.file,"YES %s" % yes.step
+		if no:
+			print >>self.file,"NO %s" % no.step
+
+	def ask_no_alt(self,sym,no,yes):
+		"""Ask whether that symbol is visible on primary keys"""
+		print >>self.file,"FINDP %s" % " ".join([nsym(normalize("NFC",s)) for s in sym])
+		if yes:
+			print >>self.file,"YES %s" % yes.step
+		if no:
+			print >>self.file,"NO %s" % no.step
 
 	def finish(self):
 		"""Conclude this step"""
 		pass
 
+
--- keymapper-0.5.3.orig/keymapper/fakequery.py
+++ keymapper-0.5.3/keymapper/fakequery.py
@@ -14,31 +14,53 @@
 """
 
 from keymapper.query import Query
+from keymapper.equiv import looks_like,get_sym
 from random import uniform
 
 class FakeQuery(Query):
 	"""A fake keyboard inquiry which actually looks at a keymap.
 	   Used for testing."""
 
-	def __init__(self, map):
+	def __init__(self, map, verbose=1):
 		Query.__init__(self)
 		self.map = map
+		self.verbose = verbose
 
 	def press(self,syms):
-		print "* Press one of '"+"' '".join(syms)+"' !"
-		syms = [ sym for sym in syms if sym in self.map.sym2code ]
-		print "I have '"+"' '".join(syms)+"'."
-		sym = syms[int(uniform(0,len(syms)))]
-		code = self.map.sym2code[sym]
-		code = code[int(uniform(0,len(code)))][0]
-		print "I choose %s => %d" % (sym,code)
-		return code
-
-	def ask(self,sym):
-		print "* Do I see '"+sym+"' ?"
-		if sym in self.map.sym2code:
-			print "Yes"
-		else:
+		if self.verbose:
+			print "* Press one of '"+"' '".join(syms)+"' !"
+		like=[]
+		for s in syms:
+			s = looks_like(s)
+			for ss in get_sym(s):
+				if ss not in like and ss in self.map.seen:
+					like.append(ss)
+		if self.verbose:
+			print "I have '"+"' '".join(like)+"'."
+		codes = []
+		for sym in like:
+			code = self.map.sym2code[looks_like(sym)]
+			for code in code:
+				code = code[0]
+				if self.verbose:
+					print "I can press %s => %d" % (sym,code)
+				if code not in codes:
+					codes.append(code)
+		return codes
+
+	def ask(self,syms):
+		if self.verbose:
+			print "* Do I see '"+"' or '".join(syms)+"' ?"
+		for sym in syms:
+			if looks_like(unicode(sym)) in self.map.sym2code \
+					and sym in self.map.seen:
+				if self.verbose:
+					print "Yes"
+				return True
+		if self.verbose:
 			print "No"
-		return sym in self.map.sym2code
+		return False
 
+	def message(self,msg):
+		if self.verbose:
+			print msg
--- keymapper-0.5.3.orig/keymapper/script.py
+++ keymapper-0.5.3/keymapper/script.py
@@ -17,46 +17,81 @@
 exception will be raised.
 
 """
+from sets import Set
+
+def osym(s):
+	if s == "<del>":
+		return u"\x7F"
+	elif s == "<spc>":
+		return u" "
+	elif s == "<lf>":
+		return u"\x0A"
+	elif s == "<cr>":
+		return u"\x0D"
+	elif s == "<bs>":
+		return u"\x08"
+	elif s == "<tab>":
+		return u"\x09"
+	else:
+		return s
 
-class FoundMap(Exception):
-	"""Pseudo-exception, raised when the script terminates with a unique keyboard map"""
-	pass
 class UnknownLine(Exception):
 	"""The script file contains a line that's not parseable"""
 	pass
 class BadFile(Exception):
 	"""The script file isn't well-formed"""
 	pass
+class NoMap(Exception):
+	"""No result!"""
+	pass
+class DupMap(Exception):
+	"""Inconclusive result!"""
+	pass
 
 class Script(object):
 	"""Run this script with that query. Return the result."""
 
-	def __init__(self,file,query):
+	def __init__(self,file, verbose=1):
 		self.file = file
 		self.in_step = -1
-		self.query = query
+		self.verbose = verbose
 
-	def get_step(self,nr):
+	def get_step(self,nrs):
 		"""Return the data for step NR."""
+		reported=False
+		if self.verbose > 1:
+			print "want",nrs,", have",self.in_step
 		for f in self.file:
 			f = f.strip()
 			if f == "" or f.startswith("#"):
 				continue
 			if f.startswith("STEP"):
+				if self.verbose > 1:
+					print f
 				f = f[4:]
 				f = int(f.strip())
-				if self.in_step == nr: # done
+				if self.in_step in nrs:
+					nrs.remove(self.in_step) # done with this one
 					self.in_step = f
 					return
 				self.in_step = f
-			elif self.in_step == nr:
+			elif self.in_step in nrs:
+				if self.verbose:
+					if not reported:
+						print "Step",self.in_step
+					reported=True
+				if self.verbose > 1:
+					print "have",f
 				yield f
+			elif self.verbose > 1:
+				print "skip",f
 
 		# ran off the end of the file?
-		if nr != self.in_step:
-			raise BadFile
+		if self.in_step not in nrs:
+			raise BadFile,nrs
+		nrs.remove(self.in_step) # done, at EOF
 
-	def run_step(self,step):
+	def run_step(self,query,step,res):
 		"""Run a singe step.
 		   Returns the next step's number, or raise an exception."""
 		what = None
@@ -67,47 +102,63 @@
 		for line in self.get_step(step):
 			if line.startswith("PRESS") and what in (None,"press"):
 				what="press"
-				syms.append(line[5:].strip())
+				syms.append(osym(line[5:].strip()))
 			elif line.startswith("CODE") and what in (None,"press"):
 				what="press"
-				code,goal = line[4:].strip().split()
+				try:
+					code,goal = line[4:].strip().split()
+				except ValueError:
+					print "BAD LINE <"+line.strip()+">"
+					continue
 				keys[int(code)] = int(goal)
 			elif line.startswith("MAP") and what in (None,):
-				raise FoundMap(line[3:].strip())
+				res.add(line[3:].strip())
 			elif line.startswith("FIND") and what in (None,):
 				what="find1"
-				find = line[4:].strip()
+				find = line[4:].strip().split()
 			elif line.startswith("YES") and what in ("find1",):
 				what="find2"
-				dest_yes = int(line[3:].strip())
+				dest_yes = int(line[4:].strip())
 			elif line.startswith("NO") and what in ("find2",):
 				what="find3"
-				dest_no = int(line[4:].strip())
+				dest_no = int(line[3:].strip())
 			else:
 				raise UnknownLine(line.strip())
 
 		# Second, decide what to do
 		if what == "press" and syms and keys:
-			while True:
-				code = self.query.press(syms)
+			codes = query.press(syms)
+			for code in codes:
 				if code in keys:
-					return keys[code]
-				self.query.message("Unexpected key code: <%d>" % code)
+					step.add(keys[code])
+					if self.verbose:
+						print "Goto step step",keys[code]
+				else:
+					query.message("Unexpected key code: <%d>" % code)
 		elif what == "find3":
-			if self.query.ask(find):
-				return dest_yes
+			if query.ask([osym(f) for f in find]):
+				step.add(dest_yes)
+				if self.verbose:
+					print "Goto step step",dest_yes
 			else:
-				return dest_no
-
-		else:
-			raise BadFile
+				step.add(dest_no)
+				if self.verbose:
+					print "Goto step step",dest_no
 		
-	def run(self):
+	def run(self,query):
 		"""Run this script, starting with step 0."""
-		step=0
-		while True:
-			try:
-				step = self.run_step(step)
-			except FoundMap,exc:
-				return exc.args[0]
-		
+		self.file.seek(0,1) ## Python 2.4 regression workaround:
+		self.file.read()    ## flush codec's input buffers
+		self.file.seek(0,0)
+		self.in_step = -1
+		step=Set((0,))
+		maps = Set()
+		while step:
+			self.run_step(query,step,maps)
+		if not maps:
+			raise NoMap
+		if len(maps) != 1:
+			raise DupMap(list(maps))
+		return list(maps)[0]
+
+
--- keymapper-0.5.3.orig/keymapper/fakemaps.py
+++ keymapper-0.5.3/keymapper/fakemaps.py
@@ -1,4 +1,4 @@
-
+# -*- coding: utf-8 -*- 
 # fakemaps.py
 # invent fake keyboard maps for testing
 
@@ -28,7 +28,7 @@
 	"""synthesize a Keymap"""
 	map=Keymap(name)
 	for sym,code,mod in keys:
-		map.add(sym,code,mod)
+		map.add(unicode(sym),code,mod)
 	return map
 
 def maps():
@@ -42,7 +42,7 @@
 
     # Remove a key
 	yield gen_map("removed",
-		("A",1,STD),("B",2,STD),("C",3,STD),("D",4,STD))
+		(u"α",1,STD),("B",2,STD),("C",3,STD),("D",4,STD))
 
     # Duplicate a key
 	yield gen_map("duped",
@@ -62,7 +62,7 @@
 	
 	# Totally different keys
 	yield gen_map("diff_keys",
-		("a",1,STD),("b",2,STD),("c",3,STD),("d",4,STD),("e",5,STD))
+		("aa",1,STD),("bb",2,STD),("cc",3,STD),("dd",4,STD),("ee",5,STD))
 
 	# Totally different codes
 	yield gen_map("diff_codes",
--- keymapper-0.5.3.orig/keymapper/keymap.py
+++ keymapper-0.5.3/keymapper/keymap.py
@@ -14,7 +14,9 @@
 keyboard mapping.
 """
 
-from sets import ImmutableSet
+from sets import Set,ImmutableSet
+from keymapper.equiv import looks_like,get_sym,chartype
+from unicodedata import normalize
 
 # This code implements a bitmask and associated bit values.
 modlist=("shift","altgr","control","alt","shiftl","shiftr","controll","controlr","capsshift")
@@ -50,7 +52,7 @@
 	
 		pri=0
 		mods=self.mods
-		for mod,val in (("altgr",500),("alt",1000),("control",1500)):
+		for mod,val in (("altgr",800),("alt",1000),("control",1500)):
 			if mod in self.mods:
 				pri -= val
 				mods = mods-ImmutableSet(mod)
@@ -111,15 +113,26 @@
 #	"""Trying to add a code+modifier entry to a keymap that's already known"""
 #	pass
 
+class SymSet(Set):
+	"""Add and compare with NFC"""
+	def __contains__(self,sym):
+		return Set.__contains__(self,normalize("NFC",sym.lower()))
+	def add(self,sym):
+		return Set.add(self,normalize("NFC",sym.lower()))
+
 class Keymap(object):
 	"""encapsulates a named symbol <=> keycode+modifiers mapping"""
 	
-	def __init__(self,name):
+	def __init__(self,name, with_alt=True):
 		self.name = name
 		self.sym2code = {} # sym => (code,modifier) list
 		self.sym2cod = {} # sym => code list
-#		self.code2sym = {} # <=
+		self.sym2cod_no_alt = {} # sym => code list
+		self.code2sym = {} # <=
 		self.submap_cache = {}
+		self.seen = SymSet() # symbols actually seen
+		self.stdseen = SymSet() # symbols reachable without modifier keys
+		self.with_alt = with_alt
 	
 	def __str__(self):
 		return "Map<%s>" % (self.name,)
@@ -129,39 +142,86 @@
 
 	def add(self,sym,code,mod=STD):
 		"""add a single key mapping to this keymap"""
-		if sym == "":
+		if sym == "" or sym is None:
 			return
+		if len(sym) == 1:
+			cat = chartype(sym)
+			if cat == "Z" or cat == "C" or cat == "U":
+				return # zero-width, control, unassigned
+		if not self.with_alt:
+			if mod != STD and mod != SHIFT:
+				return
+		self.seen.add(sym)
+		if mod == STD:
+			self.stdseen.add(sym)
+		sym = looks_like(sym)
 		if sym in self.sym2cod:
 			if code not in self.sym2cod[sym]:
 				self.sym2cod[sym].append(code)
 		else:
 			self.sym2cod[sym] = [code]
 
+		if mod in (STD,SHIFT):
+			if sym in self.sym2cod_no_alt:
+				if code not in self.sym2cod_no_alt[sym]:
+					self.sym2cod_no_alt[sym].append(code)
+			else:
+				self.sym2cod_no_alt[sym] = [code]
+
+		if mod == STD:
+			if code not in self.code2sym:
+				self.code2sym[code] = []
+			self.code2sym[code].append(sym)
+
 		code = (code,mod)
 		if sym in self.sym2code:
 			if code not in self.sym2code[sym]:
 				self.sym2code[sym].append(code)
 			return
-#		if code in self.code2sym:
-#			raise CodeKnown(self.name,code)
 		self.sym2code[sym] = [code]
-#		self.code2sym[code] = sym
 
 	def symbols(self):
 		"""Return a list of known symbols"""
 		return self.sym2code.iterkeys()
 
+	def symbols_no_alt(self):
+		"""Return a list of known symbols on non-alt keys"""
+		#for k,(c,m) in self.sym2code.iteritems():
+		for s in self.sym2code.iteritems():
+			(k,l) = s
+			for c,m in l:
+				if m == STD or m == SHIFT:
+					yield k
+					break
+
 	def priority(self,sym):
 		"""Return how likely it is that this symbol is actually shown
 		   on the physical keyboard"""
 		if not self.sym2code[sym]:
 			pass
-		return reduce(max, [ k[1].pri for k in self.sym2code[sym] ])
-
+		# Disambiguate. The 500 is here to make the values non-negative.
+		return 500-sym + reduce(max, [ k[1].pri for k in self.sym2code[sym] ])
 
 	def dump(self):
-		"""Show my mapping"""
-		return self.name+": "+",".join([ "%s:%s" % (self.vis(s), "+".join([str(x) for x in c])) for s,c in self.sym2cod.items()])
+		"""Show my mapping (sym => code)"""
+		return self.name+": "+",".join([ "%s:%s" % ("".join([self.vis(sy) for sy in get_sym(s) if sy in self.seen]), "+".join([str(x) for x in c])) for s,c in self.sym2cod.items()])
+	
+	def rdump1(self,syms):
+		"""Helper for rdump"""
+		seen={}
+		res=[]
+		for sym in syms:
+			if sym in seen: continue
+			seen[sym]=1
+			for s in get_sym(sym):
+				if s not in self.stdseen: continue
+				res.append(self.vis(s))
+		return res
+
+
+	def rdump(self):
+		"""Show my reverse mapping (code => sym)"""
+		return self.name+": "+" ".join([ "%s:%s" % (c,",".join(self.rdump1(s))) for c,s in self.code2sym.items()])
 
 	def vis(self,s):
 		if len(s) == 1 and ord(s) < 128:
@@ -171,6 +231,8 @@
 
 	def is_submap(self,m):
 		"""Check if self is a submap of m."""
+		if self is m:
+			return False
 		try:
 			return self.submap_cache[m]
 		except KeyError:
--- keymapper-0.5.3.orig/keymapper/parse/linux.g
+++ keymapper-0.5.3/keymapper/parse/linux.g
@@ -3,22 +3,16 @@
 """
 
 from keymapper.parse.linuxsyms import lookup_symbol,SymbolNotFound
-from os.path import exists,join
+from os.path import exists,join,curdir
 from gzip import GzipFile
 from keymapper.keymap import Keymap,Modifier
 import os
 
 dirs = [
-#	".",
-	"/usr/share/keymaps/i386/azerty",
-	"/usr/share/keymaps/i386/dvorak",
-	"/usr/share/keymaps/i386/fgGIod",
-	"/usr/share/keymaps/i386/qwerty",
-	"/usr/share/keymaps/i386/qwertz",
-
-	"/usr/share/keymaps/i386/include",
-	"/usr/share/keymaps/include"
 ]
+def add_dir(d):
+	"""Helper to add a directory to the search path"""
+	dirs.append(d)
 
 class NoFileFound(Exception):
 	pass
@@ -29,6 +23,9 @@
 
 def get_file(name):
 	"""Find a keymap file"""
+	global dirs
+	if not dirs:
+		dirs=(curdir,)
 	for end in ("",".kmap",".kmap.gz",".inc",".inc.gz", ".gz"):
 		for dir in dirs:
 			n = os.path.join(dir,name+end)
@@ -73,9 +70,9 @@
 			self.add(rvalue, code, keys)
 
 
-def parse_file(name):
+def parse_file(name, with_alt=True):
 	f = get_file(name)
-	keymap = ConsoleKeymap(name)
+	keymap = ConsoleKeymap(name, with_alt=with_alt)
 	parser = linuxmap(linuxmapScanner("",file=f,filename=name))
 
 	try:
--- keymapper-0.5.3.orig/keymapper/parse/maps.py
+++ keymapper-0.5.3/keymapper/parse/maps.py
@@ -36,9 +36,9 @@
 names={"plain":STD, "shift":SHIFT, "altgr":ALT, "shift_altgr":ALTSHIFT,
 	"shift_alt":ALTSHIFT,"altgr_alt":ALT,"alt":ALT,"shift_altgr_alt":ALTSHIFT}
 
-def parse_map(name,f):
+def parse_map(name,f,with_alt=True):
 	"""read a Keymap"""
-	map=Keymap(name)
+	map=Keymap(name,with_alt)
 	l = f.read()
 	if not l:
 		raise EmptyMapError(name)
--- keymapper-0.5.3.orig/keymapper/parse/x11.g
+++ keymapper-0.5.3/keymapper/parse/x11.g
@@ -0,0 +1,262 @@
+"""
+This code implements a parser for Linux keyboard maps.
+"""
+
+from keymapper.parse.linuxsyms import lookup_symbol,SymbolNotFound
+from os.path import exists,join,curdir
+from gzip import GzipFile
+from keymapper.keymap import Keymap,Modifier, STD,SHIFT,ALT,ALTSHIFT
+import os, re
+
+symfile = "/usr/share/misc/keymap.xkeys";
+if exists("data/xkeys") and exists("gen_keymap"):
+	symfile = "data/xkeys";
+
+xsyms = {}
+def read_map():
+	f = open(symfile)
+	for l in f:
+		l = l.strip()
+		comment = l.find('#')
+		if comment > -1: l = l[:comment]
+		l = l.strip()
+		if l == "": continue
+		s,d = l.split()
+		xsyms[s] = eval("0x"+d, {},{})
+read_map()
+del read_map
+
+defmap="us"
+defkey="pc101"
+
+dirs = [
+]
+def add_dir(d):
+	"""Helper to add a directory to the search path"""
+	dirs.append(d)
+
+class BadStep(Exception):
+	pass
+class NoFileFound(Exception):
+	pass
+class FileProblem(Exception):
+	pass
+class TooManySyms(Exception):
+	pass
+
+class Restart: # Marker
+	pass
+class UseOld:
+	pass
+class UseNew:
+	pass
+
+def get_file(name):
+	"""Find a keymap file"""
+	global dirs
+	if not dirs:
+		dirs=("/usr/lib/X11/xkb/symbols",)
+	for end in ("",".gz"):
+		for dir in dirs:
+			n = os.path.join(dir,name+end)
+			if exists(n):
+				if n.endswith(".gz"):
+					f = GzipFile(n,"rb")
+				else:
+					f = open(n,"r")
+				return f
+
+	raise NoFileFound(name)
+
+m_incl2 = re.compile("^(.+)\\((.+)\\)$")
+next_mod = {STD:SHIFT, SHIFT:ALT, ALT:ALTSHIFT, ALTSHIFT:ALT}
+
+class X11Keymap(Keymap):
+	"""submap with interesting features for generating X11 maps"""
+	def __init__(self,name,sub=None):
+		Keymap.__init__(self,name+"("+sub+")")
+		self.map_vector = []
+		self.steps = []
+		self.build_done = False
+
+	def append(self,what):
+		self.steps.append(what)
+
+	def build_map(self,to_map=None,keymap=None):
+		if to_map is None:
+			if self.build_done:
+				return
+			to_map = self
+
+		if keymap is None:
+			keymap={}
+		for s in self.steps:
+			if isinstance(s,list) or isinstance(s,tuple):
+				rep = s[0]
+				code = s[1]
+				try:
+					code = xsyms[code]
+				except KeyError:
+					continue
+				s = s[2:]
+				if rep == UseOld and code in keymap:
+					continue
+				keymap[code] = s
+
+			elif isinstance(s,basestring):
+				# include file. Can be "name(sub)".
+				m = m_incl2.match(s)
+				if m:
+					s = (m.group(1),m.group(2))
+					if not known.has_key(s):
+						parse_file(s[0],s[1])
+				else:
+					if not known.has_key(s):
+						parse_file(s)
+
+				known[s].build_map(to_map,keymap)
+			else:
+				raise BadStep
+
+		if to_map == self and not self.build_done:
+			self.build_done = True
+			s = (defmap,defkey)
+			if not known.has_key(s):
+				parse_file(defmap,defkey)
+			known[s].build_map(to_map,keymap)
+
+		for code,keys in keymap.iteritems():
+			mod=STD
+			for k in keys:
+				if k == Restart:
+					# mod=STD # heuristic
+					continue
+				to_map.add(k,code,mod)
+				mod=next_mod[mod]
+		
+known = {}
+
+def parse_file(name, sub=None):
+	if sub:
+		k = (name,sub)
+	else:
+		m = m_incl2.match(name)
+		if m:
+			(name,sub) = (m.group(1),m.group(2))
+			k = (name,sub)
+		else:
+			k = name
+
+	if not known.has_key(k):
+		f = get_file(name)
+		parser = x11map(x11mapScanner("",file=f,filename=name))
+
+		try:
+			parser.map(name)
+		except SymbolNotFound,e:
+			print >>sys.stderr, "Keysym '%s' not found" % e.args
+			print >>sys.stderr, parser._scanner
+			raise FileProblem(name)
+		except runtime.SyntaxError, e:
+			runtime.print_error(e, parser._scanner, max_ctx=1)
+			raise FileProblem(name)
+		except runtime.NoMoreTokens:
+			print >>sys.stderr, 'Could not complete parsing; stopped around here:'
+			print >>sys.stderr, parser._scanner
+			raise FileProblem(name)
+
+	try:
+		map = known[k]
+	except KeyError:
+		return None
+	map.build_map()
+	return map
+
+%%
+
+parser x11map:
+    ignore:	"[ \n\r\t]+"
+	ignore:	"(#|!).*"
+	ignore:	"\/\/.*"
+
+	token EOF:	"$"
+	token INCLUDE:	"include"
+	token SETMODWHAT:	"SetMods\\.[a-zA-Z0-9_]+"
+	token KEYWHAT:	"key\\.[a-zA-Z0-9_]+"
+	token HEX:	"0x[a-zA-Z0-9]+"
+	token UNI:	"U[0-9A-Fa-f]{4}"
+	token UNI3:	"U[0-9A-Fa-f]{3}"
+	token SYM:	"[a-zA-Z0-9_]+"
+	token NUM:	"[-+]?[0-9_]+"
+	#token _CHAR1: "'([0-7]){1,3}'"
+	#token _CHAR2: "'\\\\.'"
+	#token _CHAR3: "'.'"
+	#token PLUS:	"\\+"
+	token _STRLITERAL: '\'([^\\n\'\\\\]|\\\\.)*\'|"([^\\n"\\\\]|\\\\.)*"'
+	token _KEYLITERAL: '<[A-Za-z0-9]+>'
+
+	rule STRLITERAL: _STRLITERAL {{ return eval(_STRLITERAL,{},{}) }}
+	rule KEYLITERAL: _KEYLITERAL {{ return _KEYLITERAL[1:-1] }}
+
+	rule map<<name>>: one_map<<name>>* EOF
+	
+	rule one_map<<name>>: {{ default = False }} {{ hidden = False }}
+			( "partial"
+			| "default" {{ default=True }} 
+			| "hidden" {{ hidden=True }} 
+			)*
+			mods*
+			"xkb_symbols" STRLITERAL {{ sub=STRLITERAL }}
+			{{ data = X11Keymap(name,sub) }}
+			"{"
+				( incl<<data>> | entry<<data>>
+				  | setmod | vmod | naming | modmap | keyset ) *
+			"}"
+			{{ known[(name,sub)] =  data }}
+			{{ if default: known[name] = data }}
+			";"
+
+	rule naming: "[Nn]ame" "\\[" SYM "\\]" "=" STRLITERAL ";" 
+
+	rule modmap: "modifier_map" SYM "{" symkey ( "," ? symkey ) * "}" ";"
+	#rule modmap: "modifier_map" SYM "{" SYM ( "," SYM ) * "}" ";"
+	rule symkey: SYM | _KEYLITERAL
+	rule vmod: "virtual_modifiers" SYM ";"
+	rule setmod:  SETMODWHAT "=" SYM ";"
+
+
+	rule keyset: KEYWHAT ( "\\[" SYM "\\]" ) ? "=" STRLITERAL ";"
+
+
+	rule mods: "keypad_keys" | "function_keys"
+			| "alphanumeric_keys" | "modifier_keys" | "alternate_group"
+	rule incl<<data>>: "include" STRLITERAL {{ data.append(STRLITERAL) }}
+
+	rule entry<<data>>: {{ rep=UseOld }}
+		( ( "replace" | "override" ) {{ rep=UseNew }} ) ?
+		"key" KEYLITERAL {{ k=[rep,KEYLITERAL] }}
+		"{" stuffgroup<<k>>
+		    ( "," {{ k.append(Restart) }} stuffgroup<<k>> ) *
+		"}" ";" {{ data.append(k) }}
+
+	rule stuffgroup<<k>>: stuff | group<<k>>
+	rule stuff: stuffsym | stuffvirt | stufftype | stuffover
+	rule stuffsym: "symbols" "\\[" SYM "\\]" "="
+		"\\[" ( SYM ( "," SYM ) * ) ? "\\]"
+	rule stuffvirt: "virtualMods" "=" SYM
+	rule stufftype: "type" ( "\\[" SYM "\\]" ) ? "=" STRLITERAL
+	rule stuffover: "overlay[12]" "=" KEYLITERAL
+
+	rule group<<k>>: "\\[" ( sym {{ if sym: k.append(sym) }}
+			( "," ? sym {{ if sym: k.append(sym) }} ) * ) ? 
+			"\\]"
+
+	rule sym: "NoSymbol" {{ return None }}
+			| "SetMods" "\\(" SYM "=" SYM "\\)" {{ return None }}
+			| "LockGroup" "\\(" SYM "=" NUM "\\)" {{ return None }}
+			| UNI {{ return eval('u"\\u%s"' % (UNI[1:]),{},{}) }}
+			| UNI3 {{ return eval('u"\\u0%s"' % (UNI3[1:]),{},{}) }}
+			| HEX {{ return eval('u"\\U%08x"' % (eval(HEX)-0x1000000,),{},{}) }}
+			| SYM {{ return lookup_symbol(SYM) }}
+ 	
+%%
--- keymapper-0.5.3.orig/keymapper/parse/Makefile
+++ keymapper-0.5.3/keymapper/parse/Makefile
@@ -1,8 +1,12 @@
 # Makefile for keymapper stuff
 #
 
-all: ${addsuffix .py, ${basename ${wildcard *.g}, .g}}
+GENPY := ${addsuffix .py, ${basename ${wildcard *.g}, .g}}
+
+all: $(GENPY)
 
 %.py: %.g
 	yapps $<
 
+clean:
+	rm -f $(GENPY)
--- keymapper-0.5.3.orig/keymapper/parse/linuxsyms.py
+++ keymapper-0.5.3/keymapper/parse/linuxsyms.py
@@ -13,7 +13,12 @@
 translate symbols to unicode (and back).
 """
 
-symfile = "data/symbols"
+from os.path import exists
+
+symfile = "/usr/share/misc/keymap.syms";
+if exists("data/symbols") and exists("gen_keymap"):
+	symfile = "data/symbols";
+
 map = {}
 alias = {}
 
@@ -57,9 +62,9 @@
 		read_table()
 	# print name,
 
-	# XXX TODO: return that stuff somehow?
-	if name.startswith("Meta_"):
-		name = name[5:]
+	if name.startswith("Meta_") or name.startswith("Alt_") \
+		or name.startswith("Hyper_"):
+		return None
 
 	while name in alias:
 		name = alias[name]
--- keymapper-0.5.3.orig/data/symbols
+++ keymapper-0.5.3/data/symbols
@@ -31,14 +31,14 @@
 001e Control_asciicircum
 001f Control_underscore
 0020 space
-0021 exclam
+0021 exclam excalem
 0022 quotedbl
 0023 numbersign
 0024 dollar
 0025 percent
 0026 ampersand
 0027 apostrophe
-0028 parenleft
+0028 parenleft parenlef
 0029 parenright
 002a asterisk
 002b plus
@@ -46,21 +46,23 @@
 002d minus
 002e period
 002f slash
-0030 zero
-0031 one
-0032 two
-0033 three
-0034 four
-0035 five
-0036 six
-0037 seven
-0038 eight
-0039 nine
+0030 0 zero
+0031 1 one
+0032 2 two
+0033 3 three
+0034 4 four
+0035 5 five
+0036 6 six
+0037 7 seven
+0038 8 eight
+0039 9 nine
 003a colon
 003b semicolon
+003c leftcaret
 003c less
 003d equal
 003e greater
+003e rightcaret
 003f question
 0040 at
 0041 A
@@ -92,9 +94,10 @@
 005b bracketleft
 005c backslash
 005d bracketright
-005e asciicircum dead_circumflex
+005e asciicircum dead_circumflex SunFA_Circum
+005f underbar
 005f underscore
-0060 grave dead_grave
+0060 grave dead_grave SunFA_Grave
 0061 a
 0062 b
 0063 c
@@ -124,7 +127,7 @@
 007b braceleft
 007c bar
 007d braceright
-007e asciitilde dead_tilde
+007e asciitilde dead_tilde SunFA_Tilde
 007f Delete
 00a0 nobreakspace
 00a0 no-break_space
@@ -136,7 +139,7 @@
 00a6 brokenbar
 00a7 paragraph_sign
 00a7 section
-00a8 diaeresis dead_diaeresis
+00a8 diaeresis dead_diaeresis SunFA_Diaeresis
 00a9 copyright
 00aa ordfeminine
 00ab guillemotleft
@@ -144,16 +147,17 @@
 00ad hyphen
 00ad soft_hyphen
 00ae registered
-00af macron
+00af macron dead_macron
+00af overbar
 00b0 degree
 00b1 plusminus
 00b2 twosuperior
 00b3 threesuperior
-00b4 acute dead_acute
+00b4 acute dead_acute SunFA_Acute
 00b5 mu
 00b6 paragraph
 00b7 periodcentered
-00b8 cedilla dead_cedilla
+00b8 cedilla dead_cedilla SunFA_Cedilla
 00b9 onesuperior
 00ba masculine
 00bb guillemotright
@@ -178,7 +182,7 @@
 00cd Iacute
 00ce Icircumflex
 00cf Idiaeresis
-00d0 ETH
+00d0 ETH Eth
 00d1 Ntilde
 00d2 Ograve
 00d3 Oacute
@@ -193,7 +197,7 @@
 00db Ucircumflex
 00dc Udiaeresis
 00dd Yacute
-00de THORN
+00de THORN Thorn
 00df ssharp
 00e0 agrave
 00e1 aacute
@@ -314,8 +318,8 @@
 015f scedilla
 0160 Scaron
 0161 scaron
-0162 Tcedilla
-0163 tcedilla
+0162 Tcedilla Tcediila
+0163 tcedilla tcediila
 0164 Tcaron
 0165 tcaron
 0166 Tslash
@@ -339,306 +343,852 @@
 017c zabovedot
 017d Zcaron
 017e zcaron
-02bc rightquote
-02bd leftquote
+0192 function
+01e6 Gcaron
+01e7 gcaron
+01a0 Ohorn
+01a1 ohorn
+01af Uhorn
+01b0 uhorn
+02bc rightquote quoteright
+02bd leftquote quoteleft
 02c7 caron
 02d8 breve
-02d9 abovedot
+02d9 abovedot dead_abovedot
+02da abovering dead_abovering
 02db ogonek
 02dd doubleacute
+0309 dead_hook
+031b dead_horn
+0323 dead_belowdot
 0384 accent
-0385 diaeresisaccent
-0386 Alphaaccent
-0388 Epsilonaccent
-0389 Etaaccent
-038a Iotaaccent
-038c Omicronaccent
-038e Upsilonaccent
-038f Omegaaccent
+0385 Greek_accentdieresis diaeresisaccent
+0386 Greek_ALPHAaccent Alphaaccent
+0388 Greek_EPSILONaccent Epsilonaccent
+0389 Greek_ETAaccent Etaaccent
+038a Greek_IOTAaccent Iotaaccent
+038c Greek_OMICRONaccent Omicronaccent
+038e Greek_UPSILONaccent Upsilonaccent
+038f Greek_OMEGAaccent Omegaaccent
+0390 Greek_iotaaccentdieresis
 0390 iotadiaeresisaccent
-0391 Alpha
-0392 Beta
-0393 Gamma
-0394 Delta
-0395 Epsilon
-0396 Zeta
-0397 Eta
-0398 Theta
-0399 Iota
-039a Kappa
-039b Lamda
-039c Mu
-039d Nu
-039e Ksi
-039f Omicron
-03a0 Pi
-03a1 Rho
-03a3 Sigma
-03a4 Tau
-03a5 Upsilon
-03a6 Phi
-03a7 Khi
-03a8 Psi
-03a9 Omega
-03aa Iotadiaeresis
-03ab Upsilondiaeresis
-03ac alphaaccent
-03ad epsilonaccent
-03ae etaaccent
-03af iotaaccent
-03b0 upsilondiaeresisaccent
-03b1 alpha
-03b2 beta
-03b3 gamma
-03b4 delta
-03b5 epsilon
-03b6 zeta
-03b7 eta
-03b8 theta
-03b9 iota
-03ba kappa
-03bb lamda
-03bc mu
-03bd nu
-03be ksi
-03bf omicron
-03c0 pi
-03c1 rho
-03c2 terminalsigma
-03c3 sigma
-03c4 tau
-03c5 upsilon
-03c6 phi
-03c7 khi
-03c8 psi
-03c9 omega
-03ca iotadiaeresis
-03cb upsilondiaeresis
-03cc omicronaccent
-03cd upsilonaccent
-03ce omegaaccent
-0401 cyrillic_capital_letter_io
-0402 serbocroatian_cyrillic_capital_letter_dje
-0403 macedonian_cyrillic_capital_letter_gje
-0404 ukrainian_cyrillic_capital_letter_ie
-0405 macedonian_cyrillic_capital_letter_dze
-0406 ukrainian_cyrillic_capital_letter_i
-0407 ukrainian_cyrillic_capital_letter_yi
-0408 cyrillic_capital_letter_je
-0409 cyrillic_capital_letter_lje
-040a cyrillic_capital_letter_nje
-040b serbocroatian_cyrillic_capital_letter_chje
-040c macedonian_cyrillic_capital_letter_kje
-040e bielorussian_cyrillic_capital_letter_short_u
-040f cyrillic_capital_letter_dze
-0410 cyrillic_capital_letter_a
-0411 cyrillic_capital_letter_be
-0412 cyrillic_capital_letter_ve
-0413 cyrillic_capital_letter_ghe
-0414 cyrillic_capital_letter_de
-0415 cyrillic_capital_letter_ie
-0416 cyrillic_capital_letter_zhe
-0417 cyrillic_capital_letter_ze
-0418 cyrillic_capital_letter_i
-0419 cyrillic_capital_letter_short_i
-041a cyrillic_capital_letter_ka
-041b cyrillic_capital_letter_el
-041c cyrillic_capital_letter_em
-041d cyrillic_capital_letter_en
-041e cyrillic_capital_letter_o
-041f cyrillic_capital_letter_pe
-0420 cyrillic_capital_letter_er
-0421 cyrillic_capital_letter_es
-0422 cyrillic_capital_letter_te
-0423 cyrillic_capital_letter_u
-0424 cyrillic_capital_letter_ef
-0425 cyrillic_capital_letter_ha
-0426 cyrillic_capital_letter_tse
-0427 cyrillic_capital_letter_che
-0428 cyrillic_capital_letter_sha
-0429 cyrillic_capital_letter_shcha
-042a cyrillic_capital_hard_sign
-042b cyrillic_capital_letter_yeru
-042c cyrillic_capital_soft_sign
-042d cyrillic_capital_letter_e
-042e cyrillic_capital_letter_yu
-042f cyrillic_capital_letter_ya
-0430 cyrillic_small_letter_a
-0431 cyrillic_small_letter_be
-0432 cyrillic_small_letter_ve
-0433 cyrillic_small_letter_ghe
-0434 cyrillic_small_letter_de
-0435 cyrillic_small_letter_ie
-0436 cyrillic_small_letter_zhe
-0437 cyrillic_small_letter_ze
-0438 cyrillic_small_letter_i
-0439 cyrillic_small_letter_short_i
-043a cyrillic_small_letter_ka
-043b cyrillic_small_letter_el
-043c cyrillic_small_letter_em
-043d cyrillic_small_letter_en
-043e cyrillic_small_letter_o
-043f cyrillic_small_letter_pe
-0440 cyrillic_small_letter_er
-0441 cyrillic_small_letter_es
-0442 cyrillic_small_letter_te
-0443 cyrillic_small_letter_u
-0444 cyrillic_small_letter_ef
-0445 cyrillic_small_letter_ha
-0446 cyrillic_small_letter_tse
-0447 cyrillic_small_letter_che
-0448 cyrillic_small_letter_sha
-0449 cyrillic_small_letter_shcha
-044a cyrillic_small_hard_sign
-044b cyrillic_small_letter_yeru
-044c cyrillic_small_soft_sign
-044d cyrillic_small_letter_e
-044e cyrillic_small_letter_yu
-044f cyrillic_small_letter_ya
-0451 cyrillic_small_letter_io
-0452 serbocroatian_cyrillic_small_letter_dje
-0453 macedonian_cyrillic_small_letter_gje
-0454 ukrainian_cyrillic_small_letter_ie
-0455 macedonian_cyrillic_small_letter_dze
-0456 ukrainian_cyrillic_small_letter_i
-0457 ukrainian_cyrillic_small_letter_yi
-0458 cyrillic_small_letter_je
-0459 cyrillic_small_letter_lje
-045a cyrillic_small_letter_nje
-045b serbocroatian_cyrillic_small_letter_chje
-045c macedonian_cyrillic_small_letter_kje
-045e bielorussian_cyrillic_small_letter_short_u
-045f cyrillic_small_letter_dze
-05d0 alef
-05d1 bet
-05d2 gimel
-05d3 dalet
-05d4 he
-05d5 vav
-05d6 zayin
-05d7 het
-05d8 tet
-05d9 yod
-05da finalkaf
-05db kaf
-05dc lamed
-05dd finalmem
-05de mem
-05df finalnun
-05e0 nun
-05e1 samekh
-05e2 ayin
-05e3 finalpe
-05e4 pe
-05e5 finaltsadi
-05e6 tsadi
-05e7 qof
-05e8 resh
-05e9 shin
-05ea tav
-2017 doubleunderscore
-201e quotedblbase
-203e overscore
-20ac euro
-2116 number_acronym
-- F1 F2 F3 F4 F5
-- F6 F7 F8 F9 F10
-- F11 F12 F13 F14 F15
-- F16 F17 F18 F19 F20
-- Find
-- Insert
-- Remove
-- Select
-- Prior
-- Next
-- Macro
-- Help
-- Do
-- Pause
-- F21 F22 F23 F24 F25
-- F26 F27 F28 F29 F30
-- F31 F32 F33 F34 F35
-- F36 F37 F38 F39 F40
-- F41 F42 F43 F44 F45
-- F46 F47 F48 F49 F50
-- F51 F52 F53 F54 F55
-- F56 F57 F58 F59 F60
-- F61 F62 F63 F64 F65
-- F66 F67 F68 F69 F70
-- F71 F72 F73 F74 F75
-- F76 F77 F78 F79 F80
-- F81 F82 F83 F84 F85
-- F86 F87 F88 F89 F90
-- F91 F92 F93 F94 F95
-- F96 F97 F98 F99 F100
-- F101 F102 F103 F104 F105
-- F106 F107 F108 F109 F110
-- F111 F112 F113 F114 F115
-- F116 F117 F118 F119 F120
-- F121 F122 F123 F124 F125
-- F126 F127 F128 F129 F130
-- F131 F132 F133 F134 F135
-- F136 F137 F138 F139 F140
-- F141 F142 F143 F144 F145
-- F146 F147 F148 F149 F150
-- F151 F152 F153 F154 F155
-- F156 F157 F158 F159 F160
-- F161 F162 F163 F164 F165
-- F166 F167 F168 F169 F170
-- F171 F172 F173 F174 F175
-- F176 F177 F178 F179 F180
-- F181 F182 F183 F184 F185
-- F186 F187 F188 F189 F190
-- F191 F192 F193 F194 F195
-- F196 F197 F198 F199 F200
-- F201 F202 F203 F204 F205
-- F206 F207 F208 F209 F210
-- F211 F212 F213 F214 F215
-- F216 F217 F218 F219 F220
-- F221 F222 F223 F224 F225
-- F226 F227 F228 F229 F230
-- F231 F232 F233 F234 F235
-- F236 F237 F238 F239 F240
-- F241 F242 F243 F244 F245
-- F246
-- VoidSymbol
-- Return
-- Show_Registers
-- Show_Memory
-- Show_State
+0391 Greek_ALPHA Alpha
+0392 Greek_BETA Beta
+0393 Greek_GAMMA Gamma
+0394 Greek_DELTA Delta
+0395 Greek_EPSILON Epsilon
+0396 Greek_ZETA Zeta
+0397 Greek_ETA Eta
+0398 Greek_THETA Theta
+0399 Greek_IOTA Iota
+039a Greek_KAPPA Kappa
+039b Greek_LAMBDA Lamda Greek_LAMDA
+039c Greek_MU Mu
+039d Greek_NU Nu
+039e Greek_XI Ksi
+039f Greek_OMICRON Omicron
+03a0 Greek_PI Pi
+03a1 Greek_RHO Rho
+03a3 Greek_SIGMA Sigma
+03a4 Greek_TAU Tau
+03a5 Greek_UPSILON Upsilon
+03a6 Greek_PHI Phi
+03a7 Greek_CHI Khi
+03a8 Greek_PSI Psi
+03a9 Greek_OMEGA Omega
+03aa Greek_IOTAdiaeresis Iotadiaeresis
+03ab Greek_UPSILONdieresis Upsilondiaeresis
+03ac Greek_alphaaccent alphaaccent
+03ad Greek_epsilonaccent epsilonaccent
+03ae Greek_etaaccent etaaccent
+03af Greek_iotaaccent iotaaccent
+03b0 Greek_upsilonaccentdieresis upsilondiaeresisaccent
+03b1 Greek_alpha alpha
+03b2 Greek_beta beta
+03b3 Greek_gamma gamma
+03b4 Greek_delta delta
+03b5 Greek_epsilon epsilon
+03b6 Greek_zeta zeta
+03b7 Greek_eta eta
+03b8 Greek_theta theta
+03b9 Greek_iota iota dead_iota
+# What the hell is a dead iota supposed to accomplish ??
+03ba Greek_kappa kappa
+03bb Greek_lambda lamda Greek_lamda
+03bc Greek_mu mu
+03bd Greek_nu nu
+03be Greek_xi ksi
+03bf Greek_omicron omicron
+03c0 Greek_pi pi
+03c1 Greek_rho rho
+03c2 Greek_finalsmallsigma terminalsigma
+03c3 Greek_sigma sigma
+03c4 Greek_tau tau
+03c5 Greek_upsilon upsilon
+03c6 Greek_phi phi
+03c7 Greek_chi khi
+03c8 Greek_psi psi
+03c9 Greek_omega omega
+03ca Greek_iotadieresis iotadiaeresis
+03cb Greek_upsilondieresis upsilondiaeresis
+03cc Greek_omicronaccent omicronaccent
+03cd Greek_upsilonaccent upsilonaccent
+03ce Greek_omegaaccent omegaaccent
+0401 cyrillic_capital_letter_io Cyrillic_IO
+0402 Serbian_DJE serbocroatian_cyrillic_capital_letter_dje
+0403 Macedonia_GJE macedonian_cyrillic_capital_letter_gje
+0404 Ukrainian_IE ukrainian_cyrillic_capital_letter_ie
+0405 Macedonia_DSE macedonian_cyrillic_capital_letter_dze
+0406 ukrainian_cyrillic_capital_letter_i Ukrainian_I
+0407 ukrainian_cyrillic_capital_letter_yi Ukrainian_YI
+0408 cyrillic_capital_letter_je Cyrillic_JE
+0409 cyrillic_capital_letter_lje Cyrillic_LJE
+040a cyrillic_capital_letter_nje Cyrillic_NJE
+040b Serbian_TSHE serbocroatian_cyrillic_capital_letter_chje
+040c Macedonia_KJE macedonian_cyrillic_capital_letter_kje
+040e bielorussian_cyrillic_capital_letter_short_u Byelorussian_SHORTU
+040f cyrillic_capital_letter_dze Cyrillic_DZHE
+0410 Cyrillic_A cyrillic_capital_letter_a
+0411 Cyrillic_BE cyrillic_capital_letter_be
+0412 cyrillic_capital_letter_ve Cyrillic_VE
+0413 cyrillic_capital_letter_ghe Cyrillic_GHE
+0414 cyrillic_capital_letter_de Cyrillic_DE
+0415 cyrillic_capital_letter_ie Cyrillic_IE
+0416 cyrillic_capital_letter_zhe Cyrillic_ZHE
+0417 cyrillic_capital_letter_ze Cyrillic_ZE
+0418 cyrillic_capital_letter_i Cyrillic_I
+0419 cyrillic_capital_letter_short_i Cyrillic_SHORTI
+041a cyrillic_capital_letter_ka Cyrillic_KA
+041b cyrillic_capital_letter_el Cyrillic_EL
+041c cyrillic_capital_letter_em Cyrillic_EM
+041d cyrillic_capital_letter_en Cyrillic_EN
+041e cyrillic_capital_letter_o Cyrillic_O
+041f cyrillic_capital_letter_pe Cyrillic_PE
+0420 cyrillic_capital_letter_er Cyrillic_ER
+0421 cyrillic_capital_letter_es Cyrillic_ES
+0422 cyrillic_capital_letter_te Cyrillic_TE
+0423 cyrillic_capital_letter_u Cyrillic_U
+0424 cyrillic_capital_letter_ef Cyrillic_EF
+0425 cyrillic_capital_letter_ha Cyrillic_HA
+0426 cyrillic_capital_letter_tse Cyrillic_TSE
+0427 cyrillic_capital_letter_che Cyrillic_CHE
+0428 cyrillic_capital_letter_sha Cyrillic_SHA
+0429 cyrillic_capital_letter_shcha Cyrillic_SHCHA
+042a cyrillic_capital_hard_sign Cyrillic_HARDSIGN
+042b cyrillic_capital_letter_yeru Cyrillic_YERU
+042c cyrillic_capital_soft_sign Cyrillic_SOFTSIGN
+042d cyrillic_capital_letter_e Cyrillic_E
+042e cyrillic_capital_letter_yu Cyrillic_YU
+042f cyrillic_capital_letter_ya Cyrillic_YA
+0430 Cyrillic_a cyrillic_small_letter_a
+0431 Cyrillic_be cyrillic_small_letter_be
+0432 cyrillic_small_letter_ve Cyrillic_ve
+0433 Cyrillic_ghe cyrillic_small_letter_ghe
+0434 Cyrillic_de cyrillic_small_letter_de
+0435 Cyrillic_ie cyrillic_small_letter_ie
+0436 cyrillic_small_letter_zhe Cyrillic_zhe
+0437 cyrillic_small_letter_ze Cyrillic_ze
+0438 Cyrillic_i cyrillic_small_letter_i
+0439 Cyrillic_shorti cyrillic_small_letter_short_i
+043a Cyrillic_ka cyrillic_small_letter_ka
+043b Cyrillic_el cyrillic_small_letter_el
+043c Cyrillic_em cyrillic_small_letter_em
+043d Cyrillic_en cyrillic_small_letter_en
+043e Cyrillic_o cyrillic_small_letter_o
+043f Cyrillic_pe cyrillic_small_letter_pe
+0440 Cyrillic_er cyrillic_small_letter_er
+0441 Cyrillic_es cyrillic_small_letter_es
+0442 cyrillic_small_letter_te Cyrillic_te
+0443 cyrillic_small_letter_u Cyrillic_u
+0444 Cyrillic_ef cyrillic_small_letter_ef
+0445 Cyrillic_ha cyrillic_small_letter_ha
+0446 cyrillic_small_letter_tse Cyrillic_tse
+0447 Cyrillic_che cyrillic_small_letter_che
+0448 Cyrillic_sha cyrillic_small_letter_sha
+0449 Cyrillic_shcha cyrillic_small_letter_shcha
+044a Cyrillic_hardsign cyrillic_small_hard_sign
+044b cyrillic_small_letter_yeru Cyrillic_yeru
+044c cyrillic_small_soft_sign Cyrillic_softsign
+044d Cyrillic_e cyrillic_small_letter_e
+044e cyrillic_small_letter_yu Cyrillic_yu
+044f cyrillic_small_letter_ya Cyrillic_ya
+0451 Cyrillic_io cyrillic_small_letter_io
+0452 Serbian_dje serbocroatian_cyrillic_small_letter_dje
+0453 Macedonia_gje macedonian_cyrillic_small_letter_gje
+0454 ukrainian_cyrillic_small_letter_ie Ukrainian_ie
+0455 Macedonia_dse macedonian_cyrillic_small_letter_dze
+0456 ukrainian_cyrillic_small_letter_i Ukrainian_i
+0457 ukrainian_cyrillic_small_letter_yi Ukrainian_yi
+0458 Cyrillic_je cyrillic_small_letter_je
+0459 Cyrillic_lje cyrillic_small_letter_lje
+045a Cyrillic_nje cyrillic_small_letter_nje
+045b Serbian_tshe serbocroatian_cyrillic_small_letter_chje
+045c Macedonia_kje macedonian_cyrillic_small_letter_kje
+045e bielorussian_cyrillic_small_letter_short_u Byelorussian_shortu
+045f Cyrillic_dzhe cyrillic_small_letter_dze
+0490 Ukrainian_GHE_WITH_UPTURN
+0491 Ukrainian_ghe_with_upturn
+04ae Cyrillic_U_straight
+04af Cyrillic_u_straight
+04e8 Cyrillic_O_bar
+04e9 Cyrillic_o_bar
+05d0 alef hebrew_aleph
+05d1 bet hebrew_bet
+05d2 gimel hebrew_gimel
+05d3 dalet hebrew_dalet
+05d4 he hebrew_he
+05d5 hebrew_waw vav
+05d6 hebrew_zain zayin
+05d7 hebrew_chet het
+05d8 hebrew_tet tet
+05d9 hebrew_yod yod
+05da finalkaf hebrew_finalkaph
+05db hebrew_kaph kaf
+05dc hebrew_lamed lamed
+05dd finalmem hebrew_finalmem
+05de hebrew_mem mem
+05df finalnun hebrew_finalnun
+05e0 hebrew_nun nun
+05e1 hebrew_samech samekh
+05e2 ayin hebrew_ayin
+05e3 finalpe hebrew_finalpe
+05e4 hebrew_pe pe
+05e5 finaltsadi hebrew_finalzade
+05e6 hebrew_zade tsadi
+05e7 hebrew_qoph qof
+05e8 hebrew_resh resh
+05e9 hebrew_shin shin
+05ea hebrew_taw tav
+060c Arabic_comma
+061b Arabic_semicolon
+061f Arabic_question_mark
+0621 Arabic_hamza
+0622 Arabic_maddaonalef
+0623 Arabic_hamzaonalef
+0624 Arabic_hamzaonwaw
+0625 Arabic_hamzaunderalef
+0626 Arabic_hamzaonyeh
+0627 Arabic_alef
+0628 Arabic_beh
+0629 Arabic_tehmarbuta
+062a Arabic_teh
+062b Arabic_theh
+062c Arabic_jeem
+062d Arabic_hah
+062e Arabic_khah
+062f Arabic_dal
+0630 Arabic_thal
+0631 Arabic_ra
+0632 Arabic_zain
+0633 Arabic_seen
+0634 Arabic_sheen
+0635 Arabic_sad
+0636 Arabic_dad
+0637 Arabic_tah
+0638 Arabic_zah
+0639 Arabic_ain
+063a Arabic_ghain
+0640 Arabic_tatweel
+0641 Arabic_feh
+0642 Arabic_qaf
+0643 Arabic_kaf
+0644 Arabic_lam
+0645 Arabic_meem
+0646 Arabic_noon
+0647 Arabic_ha Arabic_heh
+0648 Arabic_waw
+0649 Arabic_alefmaksura
+064a Arabic_yeh
+064b Arabic_fathatan
+064c Arabic_dammatan
+064d Arabic_kasratan
+064e Arabic_fatha
+064f Arabic_damma
+0650 Arabic_kasra
+0651 Arabic_shadda
+0652 Arabic_sukun
+0653 Arabic_madda_above
+0654 Arabic_hamza_above
+0655 Arabic_hamza_below
+0670 Arabic_superscript_alef
+- gur_v_r gur_v_r_s
+0A02 gur_bindi
+0A03 gur_visarga
+0A05 gur_a
+0A06 gur_aa
+0A07 gur_i
+0A08 gur_ii
+0A09 gur_u
+0A0A gur_uu
+0A0F gur_ee
+0A10 gur_ai
+0A13 gur_oo
+0A14 gur_au
+0A15 gur_ka
+0A16 gur_kha
+0A17 gur_ga
+0A18 gur_gha
+0A19 gur_nga
+0A1A gur_ca
+0A1B gur_cha
+0A1C gur_ja
+0A1D gur_jha
+0A1E gur_nya
+0A1F gur_tta
+0A20 gur_ttha
+0A21 gur_dda
+0A22 gur_ddha
+0A23 gur_nna
+0A24 gur_ta
+0A25 gur_tha
+0A26 gur_da
+0A27 gur_dha
+0A28 gur_na
+0A2A gur_pa
+0A2B gur_pha
+0A2C gur_ba
+0A2D gur_bha
+0A2E gur_ma
+0A2F gur_ya
+0A30 gur_ra
+0A32 gur_la
+0A35 gur_va
+0A36 gur_sha
+0A38 gur_sa
+0A39 gur_ha
+0A3C gur_nukta
+0A3E gur_aamatra
+0A3F gur_imatra
+0A40 gur_iimatra
+0A41 gur_umatra
+0A42 gur_uumatra
+0A47 gur_eematra
+0A48 gur_aimatra
+0A4B gur_oomatra
+0A4C gur_aumatra
+0A4D gur_halant
+0A59 gur_khha
+0A5A gur_ghha
+0A5B gur_za
+0A5C gur_rra
+0A5E gur_fa
+0A66 gur_zero
+0A67 gur_one
+0A68 gur_two
+0A69 gur_three
+0A6A gur_four
+0A6B gur_five
+0A6C gur_six
+0A6D gur_seven
+0A6E gur_eight
+0A6F gur_nine
+0A70 gur_tippi
+0A71 gur_addak
+0A72 gur_iri
+0A73 gur_ura
+0A74 gur_ekonkar
+0A81 guj_candrabindu
+0A82 guj_anusvara
+0A83 guj_visarga
+0A85 guj_a
+0A86 guj_aa
+0A87 guj_i
+0A88 guj_ii
+0A89 guj_u
+0A8A guj_uu
+0A8B guj_rvocalic
+0A8D guj_ecandra
+0A8F guj_e
+0A90 guj_ai
+0A91 guj_ocandra
+0A93 guj_o
+0A94 guj_au
+0A95 guj_ka
+0A96 guj_kha
+0A97 guj_ga
+0A98 guj_gha
+0A99 guj_nga
+0A9A guj_ca
+0A9B guj_cha
+0A9C guj_ja
+0A9D guj_jha
+0A9E guj_nya
+0A9F guj_tta
+0AA0 guj_ttha
+0AA1 guj_dda
+0AA2 guj_ddha
+0AA3 guj_nna
+0AA4 guj_nnna
+0AA4 guj_ta
+0AA5 guj_tha
+0AA6 guj_da
+0AA7 guj_dha
+0AA8 guj_na
+0AAA guj_pa
+0AAB guj_pha
+0AAC guj_ba
+0AAD guj_bha
+0AAE guj_ma
+0AAF guj_ya
+0AB0 guj_ra
+0AB1 guj_rra
+0AB2 guj_la
+0AB3 guj_lla
+0AB4 guj_llla
+0AB5 guj_va
+0AB6 guj_sha
+0AB7 guj_ssa
+0AB8 guj_sa
+0AB9 guj_ha
+0ABC guj_nukta
+0ABE guj_aavowelsign
+0ABF guj_ivowelsign
+0AC0 guj_iivowelsign
+0AC1 guj_uvowelsign
+0AC2 guj_uuvowelsign
+0AC3 guj_rvocalicvowelsign
+0AC4 guj_rrvocalicvowelsign
+0AC5 guj_ecandravowelsign
+0AC7 guj_evowelsign
+0AC8 guj_aivowelsign
+0AC9 guj_ocandravowelsign
+0ACB guj_ovowelsign
+0ACC guj_auvowelsign
+0ACD guj_virama
+0AD0 guj_om
+0AE0 guj_rrvocalic
+0AE6 guj_zero
+0AE7 guj_one
+0AE8 guj_two
+0AE9 guj_three
+0AEA guj_four
+0AEB guj_five
+0AEC guj_six
+0AED guj_seven
+0AEE guj_eight
+0AEF guj_nine
+0e01 thai_kokai
+0e02 thai_khokhai
+0e03 thai_khokhuat
+0e04 thai_khokhwai
+0e05 thai_khokhon
+0e06 thai_khorakhang
+0e07 thai_ngongu
+0e08 thai_chochan
+0e09 thai_choching
+0e0a thai_chochang
+0e0b thai_soso
+0e0c thai_chochoe
+0e0d thai_yoying
+0e0e thai_dochada
+0e0f thai_topatak
+0e10 thai_thothan
+0e11 thai_thonangmontho
+0e12 thai_thophuthao
+0e13 thai_nonen
+0e14 thai_dodek
+0e15 thai_totao
+0e16 thai_thothung
+0e17 thai_thothahan
+0e18 thai_thothong
+0e19 thai_nonu
+0e1a thai_bobaimai
+0e1b thai_popla
+0e1c thai_phophung
+0e1d thai_fofa
+0e1e thai_phophan
+0e1f thai_fofan
+0e20 thai_phosamphao
+0e21 thai_moma
+0e22 thai_yoyak
+0e23 thai_rorua
+0e24 thai_ru
+0e25 thai_loling
+0e26 thai_lu
+0e27 thai_wowaen
+0e28 thai_sosala
+0e29 thai_sorusi
+0e2a thai_sosua
+0e2b thai_hohip
+0e2c thai_lochula
+0e2d thai_oang
+0e2e thai_honokhuk
+0e2f thai_paiyannoi
+0e30 thai_saraa
+0e31 thai_maihanakat
+0e32 thai_saraaa
+0e33 thai_saraam
+0e34 thai_sarai
+0e35 thai_saraii
+0e36 thai_saraue
+0e37 thai_sarauee
+0e38 thai_sarau
+0e39 thai_sarauu
+0e3a thai_phinthu
+0e3f thai_baht
+0e40 thai_sarae
+0e41 thai_saraae
+0e42 thai_sarao
+0e43 thai_saraaimaimuan
+0e44 thai_saraaimaimalai
+0e45 thai_lakkhangyao
+0e46 thai_maiyamok
+0e47 thai_maitaikhu
+0e48 thai_maiek
+0e49 thai_maitho
+0e4a thai_maitri
+0e4b thai_maichattawa
+0e4c thai_thanthakhat
+0e4d thai_nikhahit
+0e4e thai_yamakkan
+0e4f thai_fongman
+0e50 thai_leksun
+0e51 thai_leknung
+0e52 thai_leksong
+0e53 thai_leksam
+0e54 thai_leksi
+0e55 thai_lekha
+0e56 thai_lekhok
+0e57 thai_lekchet
+0e58 thai_lekpaet
+0e59 thai_lekkao
+0e5a thai_angkhankhu
+0e5b thai_khomut
+11a8 Hangul_J_Kiyeog
+11a9 Hangul_J_SsangKiyeog
+11aa Hangul_J_KiyeogSios
+11ab Hangul_J_Nieun
+11ac Hangul_J_NieunJieuj
+11ad Hangul_J_NieunHieuh
+11ae Hangul_J_Dikeud
+11af Hangul_J_Rieul
+11b0 Hangul_J_RieulKiyeog
+11b1 Hangul_J_RieulMieum
+11b2 Hangul_J_RieulPieub
+11b3 Hangul_J_RieulSios
+11b4 Hangul_J_RieulTieut
+11b5 Hangul_J_RieulPhieuf
+11b6 Hangul_J_RieulHieuh
+11b7 Hangul_J_Mieum
+11b8 Hangul_J_Pieub
+11b9 Hangul_J_PieubSios
+11ba Hangul_J_Sios
+11bb Hangul_J_SsangSios
+11bc Hangul_J_Ieung
+11bd Hangul_J_Jieuj
+11be Hangul_J_Cieuc
+11bf Hangul_J_Khieuq
+11c0 Hangul_J_Tieut
+11c1 Hangul_J_Phieuf
+11c2 Hangul_J_Hieuh
+11eb Hangul_J_PanSios
+11f0 Hangul_J_KkogjiDalrinIeung
+11f9 Hangul_J_YeorinHieuh
+1e02 Babovedot
+1e03 babovedot
+1e0a Dabovedot
+1e0b dabovedot
+1e1e Fabovedot
+1e1f fabovedot
+1e40 Mabovedot
+1e41 mabovedot
+1e56 Pabovedot
+1e57 pabovedot
+1e60 Sabovedot
+1e61 sabovedot
+1e6a Tabovedot
+1e6b tabovedot
+2002 enspace
+2003 emspace
+2004 em3space
+2005 em4space
+2007 digitspace
+2008 punctspace
+2009 thinspace
+200a hairspace
+2012 figdash
+2013 endash
+2014 emdash
+2015 Greek_horizbar
+2017 doubleunderscore hebrew_doublelowline
+2018 leftsinglequotemark
+2019 rightsinglequotemark
+201a singlelowquotemark
+201c leftdoublequotemark
+201d rightdoublequotemark
+201e doublelowquotemark quotedblbase
+2020 dagger
+2021 doubledagger
+2022 enfilledcircbullet
+2025 doubbaselinedot
+2026 ellipsis
+2032 minutes
+2033 seconds
+2038 caret
+203e overline overscore
+20a9 Korean_Won
+20ab DongSign
+20ac euro Euro EuroSign
+2105 careof
+2116 number_acronym numerosign
+2117 phonographcopyright
+211e prescription
+2122 trademark
+2153 onethird
+2154 twothirds
+2155 onefifth
+2156 twofifths
+2157 threefifths
+2158 fourfifths
+2159 onesixth
+215a fivesixths
+215b oneeighth
+215c threeeighths
+215d fiveeighths
+215e seveneighths
+2190 leftarrow
+2191 uparrow
+2192 rightarrow
+2193 downarrow
+21d2 implies
+21d4 ifonlyif
+2202 partialderivative
+2207 nabla
+2218 jot
+221a radical
+221d variation
+221e infinity
+2227 logicaland
+2227 upcaret
+2228 downcaret logicalor
+2229 intersection upshoe
+222a downshoe union
+222b integral
+2234 therefore
+223c approximate
+2243 similarequal
+2260 notequal
+2261 identical
+2264 lessthanequal
+2265 greaterthanequal
+2282 includedin leftshoe
+2283 includes rightshoe
+22a2 lefttack
+22a3 righttack
+22a4 uptack
+22a5 downtack
+2308 upstile
+230a downstile
+2315 telephonerecorder
+2320 topintegral
+2321 botintegral
+2329 leftanglebracket
+232a rightanglebracket
+2395 quad
+239b topleftparens
+239d botleftparens
+239e toprightparens
+23a0 botrightparens
+23a1 topleftsqbracket
+23a3 botleftsqbracket
+23a4 toprightsqbracket
+23a6 botrightsqbracket
+23a8 leftmiddlecurlybrace
+23ac rightmiddlecurlybrace
+23b7 leftradical
+23ba horizlinescan1
+23bb horizlinescan3
+23bc horizlinescan7
+23bd horizlinescan9
+2409 ht
+240a lf
+240b vt
+240c ff
+240d cr
+2424 nl
+2500 horizconnector horizlinescan5
+2502 vertbar vertconnector
+250c topleftradical upleftcorner
+2510 uprightcorner
+2514 lowleftcorner
+2518 lowrightcorner
+251c leftt
+2524 rightt
+252c topt
+2534 bott
+253c crossinglines
+2592 checkerboard
+25aa enfilledsqbullet
+25ab enopensquarebullet
+25ac filledrectbullet
+25ad openrectbullet
+25ae emfilledrect
+25af emopenrectangle
+25b2 filledtribulletup
+25b3 opentribulletup
+25b6 filledrighttribullet
+25b7 rightopentriangle
+25bc filledtribulletdown
+25bd opentribulletdown
+25c0 filledlefttribullet
+25c1 leftopentriangle
+25c6 soliddiamond
+25cb circle
+25cb emopencircle
+25cf emfilledcircle
+25e6 enopencircbullet
+2606 openstar
+260e telephone
+2613 signaturemark
+261c leftpointer
+261e rightpointer
+2640 femalesymbol
+2642 malesymbol
+2663 club
+2665 heart
+2666 diamond
+266d musicalflat
+266f musicalsharp
+2713 checkmark
+2717 ballotcross
+271d latincross
+2720 maltesecross
+3001 kana_comma
+3002 kana_fullstop
+300c kana_openingbracket
+300d kana_closingbracket
+309b voicedsound
+309c semivoicedsound
+30a1 kana_a
+30a2 kana_A
+30a3 kana_i
+30a4 kana_I
+30a5 kana_u
+30a6 kana_U
+30a7 kana_e
+30a8 kana_E
+30a9 kana_o
+30aa kana_O
+30ab kana_KA
+30ad kana_KI
+30af kana_KU
+30b1 kana_KE
+30b3 kana_KO
+30b5 kana_SA
+30b7 kana_SHI
+30b9 kana_SU
+30bb kana_SE
+30bd kana_SO
+30bf kana_TA
+30c1 kana_CHI
+30c3 kana_tsu
+30c4 kana_TSU
+30c6 kana_TE
+30c8 kana_TO
+30ca kana_NA
+30cb kana_NI
+30cc kana_NU
+30cd kana_NE
+30ce kana_NO
+30cf kana_HA
+30d2 kana_HI
+30d5 kana_FU
+30d8 kana_HE
+30db kana_HO
+30de kana_MA
+30df kana_MI
+30e0 kana_MU
+30e1 kana_ME
+30e2 kana_MO
+30e3 kana_ya
+30e4 kana_YA
+30e5 kana_yu
+30e6 kana_YU
+30e7 kana_yo
+30e8 kana_YO
+30e9 kana_RA
+30ea kana_RI
+30eb kana_RU
+30ec kana_RE
+30ed kana_RO
+30ef kana_WA
+30f2 kana_WO
+30f3 kana_N
+30fb kana_conjunctive kana_middledot
+30fc prolongedsound
+- Muhenkan
+3131 Hangul_Kiyeog
+3132 Hangul_SsangKiyeog
+3133 Hangul_KiyeogSios
+3134 Hangul_Nieun
+3135 Hangul_NieunJieuj
+3136 Hangul_NieunHieuh
+3137 Hangul_Dikeud
+3138 Hangul_SsangDikeud
+3139 Hangul_Rieul
+313a Hangul_RieulKiyeog
+313b Hangul_RieulMieum
+313c Hangul_RieulPieub
+313d Hangul_RieulSios
+313e Hangul_RieulTieut
+313f Hangul_RieulPhieuf
+3140 Hangul_RieulHieuh
+3141 Hangul_Mieum
+3142 Hangul_Pieub
+3143 Hangul_SsangPieub
+3144 Hangul_PieubSios
+3145 Hangul_Sios
+3146 Hangul_SsangSios
+3147 Hangul_Ieung
+3148 Hangul_Jieuj
+3149 Hangul_SsangJieuj
+314a Hangul_Cieuc
+314b Hangul_Khieuq
+314c Hangul_Tieut
+314d Hangul_Phieuf
+314e Hangul_Hieuh
+314f Hangul_A
+3150 Hangul_AE
+3151 Hangul_YA
+3152 Hangul_YAE
+3153 Hangul_EO
+3154 Hangul_E
+3155 Hangul_YEO
+3156 Hangul_YE
+3157 Hangul_O
+3158 Hangul_WA
+3159 Hangul_WAE
+315a Hangul_OE
+315b Hangul_YO
+315c Hangul_U
+315d Hangul_WEO
+315e Hangul_WE
+315f Hangul_WI
+3160 Hangul_YU
+3161 Hangul_EU
+3162 Hangul_YI
+3163 Hangul_I
+316d Hangul_RieulYeorinHieuh
+3171 Hangul_SunkyeongeumMieum
+3178 Hangul_SunkyeongeumPieub
+317f Hangul_PanSios
+3181 Hangul_KkogjiDalrinIeung
+3184 Hangul_SunkyeongeumPhieuf
+3186 Hangul_YeorinHieuh
+318d Hangul_AraeA
+318e Hangul_AraeAE
+- Alt Alt_Lock
+- AltGr AltGr_Lock
+- Ascii_0 Ascii_1 Ascii_2 Ascii_3 Ascii_4
+- Ascii_5 Ascii_6 Ascii_7 Ascii_8 Ascii_9
+- Bare_Num_Lock
+- Boot
 - Break
-- Last_Console
 - Caps_Lock
-- Num_Lock
-- Scroll_Lock
-- Scroll_Forward
-- Scroll_Backward
-- Boot
 - Caps_On
+- CapsShift
+- Clear
 - Compose
-- SAK
-- Decr_Console
-- Incr_Console
-- KeyboardSignal
-- Bare_Num_Lock
-- KP_0
-- KP_1
-- KP_2
-- KP_3
-- KP_4
-- KP_5
-- KP_6
-- KP_7
-- KP_8
-- KP_9
-- KP_Add
-- KP_Subtract
-- KP_Multiply
-- KP_Divide
-- KP_Enter
-- KP_Comma
-- KP_Period
-- KP_MinPlus
 - Console_1
 - Console_2
 - Console_3
@@ -702,61 +1252,263 @@
 - Console_61
 - Console_62
 - Console_63
+- Control
+- Control_Lock
+- CtrlL
+- CtrlL_Lock
+- CtrlR
+- CtrlR_Lock
+- Decr_Console
+- Do
 - Down
+- Eisu_toggle
+- Execute
+- F1 F2 F3 F4 F5
+- F6 F7 F8 F9 F10
+- F11 F12 F13 F14 F15
+- F16 F17 F18 F19 F20
+- F21 F22 F23 F24 F25
+- F26 F27 F28 F29 F30
+- F31 F32 F33 F34 F35
+- F36 F37 F38 F39 F40
+- F41 F42 F43 F44 F45
+- F46 F47 F48 F49 F50
+- F51 F52 F53 F54 F55
+- F56 F57 F58 F59 F60
+- F61 F62 F63 F64 F65
+- F66 F67 F68 F69 F70
+- F71 F72 F73 F74 F75
+- F76 F77 F78 F79 F80
+- F81 F82 F83 F84 F85
+- F86 F87 F88 F89 F90
+- F91 F92 F93 F94 F95
+- F96 F97 F98 F99 F100
+- F101 F102 F103 F104 F105
+- F106 F107 F108 F109 F110
+- F111 F112 F113 F114 F115
+- F116 F117 F118 F119 F120
+- F121 F122 F123 F124 F125
+- F126 F127 F128 F129 F130
+- F131 F132 F133 F134 F135
+- F136 F137 F138 F139 F140
+- F141 F142 F143 F144 F145
+- F146 F147 F148 F149 F150
+- F151 F152 F153 F154 F155
+- F156 F157 F158 F159 F160
+- F161 F162 F163 F164 F165
+- F166 F167 F168 F169 F170
+- F171 F172 F173 F174 F175
+- F176 F177 F178 F179 F180
+- F181 F182 F183 F184 F185
+- F186 F187 F188 F189 F190
+- F191 F192 F193 F194 F195
+- F196 F197 F198 F199 F200
+- F201 F202 F203 F204 F205
+- F206 F207 F208 F209 F210
+- F211 F212 F213 F214 F215
+- F216 F217 F218 F219 F220
+- F221 F222 F223 F224 F225
+- F226 F227 F228 F229 F230
+- F231 F232 F233 F234 F235
+- F236 F237 F238 F239 F240
+- F241 F242 F243 F244 F245
+- F246
+- Find
+- Help
+- Hex_0 Hex_1 Hex_2 Hex_3 Hex_4 Hex_5 Hex_6 Hex_7
+- Hex_8 Hex_9 Hex_A Hex_B Hex_C Hex_D Hex_E Hex_F
+- Incr_Console
+- Insert
+- ISO_First_Group
+- ISO_Last_Group
+- ISO_Left_Tab
+- ISO_Level3_Lock
+- ISO_Level3_Shift
+- ISO_Lock
+- ISO_Next_Group
+- ISO_Prev_Group
+- KeyboardSignal
+- KP_0 KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9
+- KP_Add
+- KP_Begin
+- KP_Comma
+- KP_Decimal
+- KP_Delete
+- KP_Divide
+- KP_Down
+- KP_End
+- KP_Enter
+- KP_Equal
+- KP_Home
+- KP_Insert
+- KP_Left
+- KP_MinPlus
+- KP_Multiply
+- KP_Next
+- KP_Period
+- KP_Prior
+- KP_Right
+- KP_Separator
+- KP_Seprator
+- KP_Subtract
+- KP_Up
+- Last_Console
 - Left
+- Macro
+- Menu
+- Mode_switch
+- Multi_key
+- Next
+- Nosymbol
+- Num_Lock
+- Pause
+- Pointer_EnableKeys
+- Print
+- Prior
+- Redo
+- Remove
+- Return
 - Right
-- Up
+- SAK
+- SAlt
+- SAltGr
+- SControl
+- Scroll_Backward
+- Scroll_Forward
+- Scroll_Lock
+- SCtrlL
+- SCtrlR
+- Select
 - Shift
-- AltGr
-- Control
-- Alt
 - ShiftL
-- ShiftR
-- CtrlL
-- CtrlR
-- CapsShift
-- Ascii_0
-- Ascii_1
-- Ascii_2
-- Ascii_3
-- Ascii_4
-- Ascii_5
-- Ascii_6
-- Ascii_7
-- Ascii_8
-- Ascii_9
-- Hex_0
-- Hex_1
-- Hex_2
-- Hex_3
-- Hex_4
-- Hex_5
-- Hex_6
-- Hex_7
-- Hex_8
-- Hex_9
-- Hex_A
-- Hex_B
-- Hex_C
-- Hex_D
-- Hex_E
-- Hex_F
-- Shift_Lock
-- AltGr_Lock
-- Control_Lock
-- Alt_Lock
 - ShiftL_Lock
+- Shift_Lock
+- ShiftR
 - ShiftR_Lock
-- CtrlL_Lock
-- CtrlR_Lock
+- Show_Memory
+- Show_Registers
+- Show_State
 - SShift
-- SAltGr
-- SControl
-- SAlt
 - SShiftL
 - SShiftR
-- SCtrlL
-- SCtrlR
+- Super_L
+- Super_R
+- Sys_Req
+- Undo
+- Up
+- VoidSymbol
+- XF86AddFavorite
+- XF86ApplicationLeft
+- XF86ApplicationRight
+- XF86AudioLowerVolume
+- XF86AudioMedia
+- XF86AudioMute
+- XF86AudioNext
+- XF86AudioPause
+- XF86AudioPlay
+- XF86AudioPrev
+- XF86AudioRaiseVolume
+- XF86AudioRecord
+- XF86AudioRewind
+- XF86AudioStop
+- XF86Away
+- XF86Back
+- XF86BackForward
+- XF86Book
+- XF86BrightnessAdjust
+- XF86Calculator
+- XF86Calendar
+- XF86CD
+- XF86Clear
+- XF86Close
+- XF86Community
+- XF86ContrastAdjust
+- XF86Copy
+- XF86Cut
+- XF86Display
+- XF86Documents
+- XF86DOS
+- XF86Eject
+- XF86Excel
+- XF86Explorer
+- XF86Favorites
+- XF86Finance
+- XF86Forward
+- XF86Game
+- XF86Go
+- XF86History
+- XF86HomePage
+- XF86HotLinks
+- XF86Launch0
+- XF86Launch1
+- XF86Launch2
+- XF86Launch3
+- XF86Launch4
+- XF86Launch5
+- XF86LaunchA
+- XF86LaunchB
+- XF86LaunchC
+- XF86LightBulb
+- XF86LogOff
+- XF86Mail
+- XF86MailForward
+- XF86Market
+- XF86Meeting
+- XF86MenuKB
+- XF86MenuPB
+- XF86Messenger
+- XF86Music
+- XF86MyComputer
+- XF86MySites
+- XF86New
+- XF86News
+- XF86OfficeHome
+- XF86Open
+- XF86OpenURL
+- XF86Option
+- XF86Paste
+- XF86Phone
+- XF86Pictures
+- XF86PowerOff
+- XF86Q
+- XF86Refresh
+- XF86Reload
+- XF86Reply
+- XF86RotateWindows
+- XF86RotationKB
+- XF86RotationPB
+- XF86Save
+- XF86ScreenSaver
+- XF86ScrollClick
+- XF86ScrollDown
+- XF86ScrollUp
+- XF86Search
+- XF86Send
+- XF86Shop
+- XF86Sleep
+- XF86Spell
+- XF86SplitScreen
+- XF86Standby
+- XF86Start
+- XF86Stop
+- XF86Support
+- XF86TaskPane
+- XF86Terminal
+- XF86Tools
+- XF86Travel
+- XF86User1KB
+- XF86User2KB
+- XF86UserPB
+- XF86VendorHome
+- XF86Video
+- XF86WakeUp
+- XF86WebCam
+- XF86Word
+- XF86WWW
+- XF86Xfer
+- XF86ZoomIn
+- XF86ZoomOut
+- any
 = Control_h BackSpace
 = Control_i Tab
 = Control_j Linefeed
--- keymapper-0.5.3.orig/data/xkeys
+++ keymapper-0.5.3/data/xkeys
@@ -0,0 +1,58 @@
+# Map: X11 key name => Linux keycode (hex)
+AB01 2c
+AB02 2d
+AB03 2e
+AB04 2f
+AB05 30
+AB06 31
+AB07 32
+AB08 33
+AB09 34
+AC01 1e
+AC02 1f
+AC03 20
+AC04 21
+AC05 22
+AC06 23
+AC07 24
+AC08 25
+AC09 26
+AC10 27
+AC11 28
+AD01 10
+AD02 11
+AD03 12
+AD04 13
+AD05 14
+AD06 15
+AD07 16
+AD08 17
+AD09 18
+AD10 19
+AD11 1a
+AD12 1b
+AE02 03
+AE03 04
+AE04 05
+AE05 06
+AE06 07
+AE07 08
+AE08 09
+AE09 0a
+AE10 0b
+AE11 0c
+AE12 0d
+BKSL 2b
+BKSP 0e
+CAPS 3a
+ESC 01
+LALT 38
+LCTL 1d
+LFSH 2a
+LSGT 56
+RALT 64
+RCTL 61
+RTRN 1c
+RTSH 36
+TAB 0f
+TLDE 29
--- keymapper-0.5.3.orig/data/equivs
+++ keymapper-0.5.3/data/equivs
@@ -0,0 +1,153 @@
+£₤
+aаAαАΑаαɑą
+bвBΒ♭ьƅВЬвьℬʙ
+чƨᠽᠴ
+cℂCСсʗ∁¢
+dD
+eE∈ℰεЕℇеєƐΕ℮Ɛɛeɛ∊∈∊ƹع
+fFϜϝℱ
+gGɡɢℊցɡ
+hнHНнһℋℍℌℎΗʜʰհ
+jJℐјℑϳʲ
+kкKКкҚқҠҡΚκKK
+l∟ΙL1iӀІİIℓℒ¡ІіΙιɪʟⅠˡւԼℭıi讠⻈ɩι℩Ɩɩɪ℩⍳וןוּיּיاﭐﺃﺄﺍﺎ
+mМℳMмΜмᠮ
+nNΝɴറℕոⁿה
+oOѺoѻОоΟο0ഠܘՕօ०∅⌀Ø
+pPРрΡℙρϱр
+qQℚ
+rRʀʳℛℝℜ
+sSѕЅˢടՏ
+șş
+tтTТтΤττէ⊤ʈƮ
+uUυՍսՄԱ
+wWωΩѠѡʷΩΩ
+xхXχΧХхˣﬡאאּ
+yУYүУуҮүΥγʸɣγƔvVѴѵν
+zZΖℤℨƶ
+äÄ
+ÏïϊÏïİı
+öÖ
+üÜϋŰű
+´`'
+ßβϐ阝ƀ
+θϑ
+ϕφΦՓ
+ѰѱΨψ
+Ϟϟ
+Ϡϡ
+зэ∃∋∍ӡʒȝ∍϶
+Ϛϛςσ
+гΓГгΓ୮
+пЛПΠπлᴫᠯ ᠳдΠ∏
+∂ĐƉÐđðђδɖ
+əӘǝәƏ
+ӨƟөθѳɵ
+υ℧ʋʊƲ
+1¹
+2Չշ²२Ձ
+3Յ३³ӠȜƷ
+5ƽ
+8ȣ
+-‒–—―─━﹣-⁻₋−᠆−­-‑‐–‒ー—
++⁺₊∔﹢
+.·˙ׁׂ̇ׄ۰۔ܼ݀݁․⋅⠁⠂⠄⠈⠐⠠⡀⢀〮៙๏
+Ɓɓ
+⁠     
+⋀⌃̂˄∧ˆ⊍ʌ⨃⟑⩀‸Λ⍝^
+ǀ∣⧸⁄ʇ׀/∕❘̸|¦
+։ː׃:∶
+₠€
+́΄҆̍̓̒̕’‘❛ء'′´ʹʻʼʾˈˊ՛՚❜٬ʹ
+!ǃ❢יִ
+؟ˁ҅‽ʕ̔?ˀʔՙ
+‛ʽʿ
+;؛;
+٪%
+͇ˍ̱̳̲‗_
+בℶ
+∼̃⌇⫭˜〰⫬~⦚〜~
+ǁ∥⃦ʖ‖⫽
+☀⨀☉◉⊙ʘ☼⦿
+⋃∪
+⦁•⋅‧·⁰̊․●❌ˑ°·◘∙∘・˚◦
+ɪƗ
+ɔƆ
+〈〈<⟨‹≺⧼«≪⋘《⟪⋘⫷
+╳✕×
+★⋆✨*٭⁎✱∗¤
+℡℻
+ϛς
+⊚◎
+◆♦
+。۔.
+Ɗɗ
+〚⟦
+␣⌴
+▪◾
+ଓବ@
+±∓
+△⃤⧍Δ∆
+※྿
+ᠣо
+见⻅
+隸隷
+ىيی
+ℸד
+〃"❝̋”̎〞〝″‶ʺ˝“❞
+♥❤
+♢⋄◇◊⃟
+⌋⟓」⏌⨼
+ɲƝ
+◺◿⊿
+、‚،,¸
+■❎◼█
+民⺠
+ÅÅ
+疋⺪
+❡⁋¶
+µμ
+⁁⋌
+∩⋂⩍
+љlj
+⟩〉❭❯⊱〉≻›⧽>»≫≫》⟫⋙
+□☐◻⟤⃞
+œɶ
+ӕæ
+∐⨿
+Ƞƞ
+ ̄‾
+łƚ
+⊲◅
+՝`ˋ‵̀
+⧹⧵⃥\∖
+≠ǂ
+○⃝〇◯
+☓✗
+țţ
+⊠☒
+✩☆
+ʃ∫
+ƩΣ∑
+ɸϕφ
+⊥┴⟘
+刂
+ᚹƿ
+ֿﬞ
+ğǧ
+⋁∨˅
+Ћћℏħ
+✓√
+©℗
+☙❧
+Ɯɯ
+גℷ
+͵ˏ
+ˉ̅̄¯
+Бƃб
+肉⺼
+ɠƓ
+Ÿÿ
+Ѳϴ
+þᚦ
+Ṫṫ