Remap your keyboard in X! Ok, so not really a tool, but one of those
things you wish someone had told you about earlier. Excellent for
getting easy access to all those neat [unicode][unicode]
-[[symbols|unicode_sampler]].
+[[symbols|unicode_sampler]] (generated with [[gen_sampler.py]]).
-You're welcome to my `~/.Xmodmap` file, which I version with
-[[dotfiles]] so it stays up to date across several computers.
+You're welcome to my [[~/.Xmodmap|_Xmodmap]] file, which I version
+with [[dotfiles]] so it stays up to date across several computers.
[gucharmap][] is a nice tool for finding Unicode encodings for
whichever character you're looking for.
--- /dev/null
+#!/usr/bin/env python
+# Generate a unicode sampler from an Xmodmap file
+
+ENCODING = 'utf-8'
+XKEYSIMDEF_H = "/usr/include/X11/keysymdef.h"
+
+
+def sample(lines, keysyms):
+ """Conver lines from an Xmodmap file to sampler lines."""
+ for line in lines:
+ # parse line
+ line = line.strip()
+ if not line.startswith('keycode '):
+ continue
+ fields = line.split()
+ # keycode 10 = 1 exclam U2081 onehalf
+ fields = fields + [None] * (7-len(fields))
+ k,keycode,eq,a,b,c,d = fields
+ assert k == 'keycode', k
+ assert eq == '=', eq
+ keycode = int(keycode)
+ if keycode > 100:
+ continue # control code, not very interesting
+
+ # convert keys to unicode
+ keys = [a,b,c,d]
+ for i,key in enumerate(keys):
+ if key == None:
+ continue
+ if key in keysyms:
+ keys[i] = keysyms[key]
+ continue
+ assert key.startswith('U'), key
+ key = r'\u'+key[len('U'):]
+ keys[i] = unicode(key, 'unicode escape')
+
+ line = (' '.join([key or ' ' for key in keys])).rstrip()
+ if len(line) > 0:
+ yield line
+
+def read_keysyms(file=None):
+ """Read keysymdef.h and extract keysym -> unicode mappings."""
+ if file == None:
+ file = XKEYSIMDEF_H
+ keysyms = {}
+ for line in open(file, 'r').readlines():
+ if not line.startswith('#define XK_'):
+ continue
+ # #define XK_space 0x0020 /* U+0020 SPACE */
+ fields = line.split()
+ assert len(fields) >= 3, fields
+ keysym = fields[1]
+ code = fields[2]
+ assert keysym.startswith('XK_'), keysym
+ assert code.startswith('0x'), code
+ keysym = keysym[len('XK_'):]
+ if len(fields) >= 5:
+ codepoint = fields[4]
+ if not codepoint.startswith('U+'):
+ codepoint = None
+ else:
+ codepoint = r'\u'+codepoint[len('U+'):]
+ codepoint = unicode(codepoint, 'unicode escape')
+ else:
+ codepoint = None # keysym to unicode mapping not well defined
+ keysyms[keysym] = codepoint
+ return keysyms
+
+
+if __name__ == '__main__':
+ import sys
+ import time
+
+ xmodmap_filename = sys.argv[1]
+
+ keysyms = read_keysyms()
+ lines = open(xmodmap_filename, 'r').readlines()
+ #lines = sample(lines, keysyms)
+ lines = sorted(sample(lines, keysyms))
+ print 'These characters are bound in my current .Xmodmap'
+ print '(%s)' % time.asctime()
+ print ''
+ for line in lines:
+ print line.encode(ENCODING)