Add Comedi and NI triggering post.
[blog.git] / posts / Xmodmap / gen_sampler.py
1 #!/usr/bin/env python
2 # Generate a unicode sampler from an Xmodmap file
3
4 ENCODING = 'utf-8'
5 XKEYSIMDEF_H = "/usr/include/X11/keysymdef.h"
6
7
8 def sample(lines, keysyms):
9     """Conver lines from an Xmodmap file to sampler lines."""
10     for line in lines:
11         # parse line
12         line = line.strip()
13         if not line.startswith('keycode '):
14             continue
15         fields = line.split()
16         # keycode  10 = 1 exclam U2081 onehalf
17         fields = fields + [None] * (7-len(fields))
18         k,keycode,eq,a,b,c,d = fields
19         assert k == 'keycode', k
20         assert eq == '=', eq
21         keycode = int(keycode)
22         if keycode > 100:
23             continue  # control code, not very interesting
24
25         # convert keys to unicode
26         keys = [a,b,c,d]
27         for i,key in enumerate(keys):
28             if key == None:
29                 continue
30             if key in keysyms:
31                 keys[i] = keysyms[key]
32                 continue
33             assert key.startswith('U'), key
34             key = r'\u'+key[len('U'):]
35             keys[i] = unicode(key, 'unicode escape')
36
37         line = (' '.join([key or ' ' for key in keys])).rstrip()
38         if len(line) > 0:
39             yield line
40
41 def read_keysyms(file=None):
42     """Read keysymdef.h and extract keysym -> unicode mappings."""
43     if file == None:
44         file = XKEYSIMDEF_H
45     keysyms = {}
46     for line in open(file, 'r').readlines():
47         if not line.startswith('#define XK_'):
48             continue
49         # #define XK_space                         0x0020  /* U+0020 SPACE */
50         fields = line.split()
51         assert len(fields) >= 3, fields
52         keysym = fields[1]
53         code = fields[2]
54         assert keysym.startswith('XK_'), keysym
55         assert code.startswith('0x'), code
56         keysym = keysym[len('XK_'):]
57         if len(fields) >= 5:
58             codepoint = fields[4]
59             if not codepoint.startswith('U+'):
60                 codepoint = None
61             else:
62                 codepoint = r'\u'+codepoint[len('U+'):]
63                 codepoint = unicode(codepoint, 'unicode escape')
64         else:
65             codepoint = None  # keysym to unicode mapping not well defined
66         keysyms[keysym] = codepoint
67     return keysyms
68
69
70 if __name__ == '__main__':
71     import sys
72     import time
73
74     xmodmap_filename = sys.argv[1]
75
76     keysyms = read_keysyms()
77     lines = open(xmodmap_filename, 'r').readlines()
78     #lines = sample(lines, keysyms)
79     lines = sorted(sample(lines, keysyms))
80     print 'These characters are bound in my current .Xmodmap'
81     print '(%s)' % time.asctime()
82     print ''
83     for line in lines:
84         print line.encode(ENCODING)