1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
|
#!/usr/bin/python
# Convert hal keymap FDIs into udev rules and key map files
# Please note that this is far from perfect, since the mapping between fdi and
# udev rules is not straightforward (and impossible in some cases).
#
# (C) 2009 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# keymap is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with keymap; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
import sys, os.path, xml.dom.minidom
def string_op2glob(node):
'''Convert FDI string match operator to a glob.
Return pair (glob, identifier) with the actual glob, and a string
containing no glob characters or spaces, which is suitable as a file
name.
'''
if node.attributes.has_key('string'):
v = node.attributes['string'].nodeValue
return (v, v.replace(' ', '_').replace('/', '_').lower())
if node.attributes.has_key('prefix'):
v = node.attributes['prefix'].nodeValue
return (v + '*', v.replace(' ', '_').replace('/', '_').lower())
if node.attributes.has_key('suffix'):
v = node.attributes['suffix'].nodeValue
return ('*' + v, v.replace(' ', '_').replace('/', '_').lower())
if node.attributes.has_key('contains'):
v = node.attributes['contains'].nodeValue
return ('*' + v + '*', v.replace(' ', '_').replace('/', '_').lower())
if node.attributes.has_key('contains_outof'):
alternatives = node.attributes['contains_outof'].nodeValue.split(';')
gl = '|'.join(['*%s*' % v for v in alternatives])
id = '_'.join([v.replace(' ', '_').replace('/', '_').lower() for v in alternatives])
return (gl, id)
if node.attributes.has_key('string_outof'):
alternatives = node.attributes['string_outof'].nodeValue.split(';')
gl = '|'.join(alternatives)
id = '_'.join([v.replace(' ', '_').lower() for v in alternatives])
return (gl, id)
if node.attributes.has_key('contains_ncase'):
v = node.attributes['contains_ncase'].nodeValue
nocase_glob = ''.join(['[%s%s]' % (c.lower(), c.upper()) for c in v])
return ('*' + nocase_glob + '*', v.replace(' ', '_').lower())
if node.attributes.has_key('prefix_ncase'):
v = node.attributes['prefix_ncase'].nodeValue
nocase_glob = ''.join(['[%s%s]' % (c.lower(), c.upper()) for c in v])
return (nocase_glob + '*', v.replace(' ', '_').lower())
raise NotImplementedError, 'unknown string operator ' + str(node.attributes.keys())
def get_node_comment(node):
'''Find the next comment node after node'''
while node:
node = node.nextSibling
if node and node.nodeType == xml.dom.Node.COMMENT_NODE:
return node.nodeValue.strip()
return None
def normalize_code(code):
code = int(code, 16)
if code >= 0xE000:
return code - 0xE000 + 128
return code
def create_keylist(node, filename):
'''Parse key code assignmends from <append> notes and create map file.'''
if not os.path.isdir('keymaps'):
os.mkdir('keymaps')
f = open(os.path.join('keymaps', filename), 'w')
#f = sys.stdout
#print '-------------- %s -------------' % filename
for c in node.childNodes:
if c.nodeName == 'append' and c.attributes.get('key').nodeValue == 'input.keymap.data':
content_node = c.childNodes[0]
assert content_node.nodeType == xml.dom.Node.TEXT_NODE
(code, name) = content_node.nodeValue.split(':')
comment = get_node_comment(c)
if comment:
print >> f, '0x%X %s # %s' % (normalize_code(code), name, comment)
else:
print >> f, '0x%X %s' % (normalize_code(code), name)
#print '---------------------------'
f.close()
def get_vendor_node(node):
'''Find the node's parent which matches the system vendor.'''
while True:
node = node.parentNode
if not node:
raise SystemError, 'no vendor parent node found'
if node.nodeName == 'match' and node.attributes['key'].nodeValue == \
'/org/freedesktop/Hal/devices/computer:system.hardware.vendor':
return node
def parse_fdi_vendor(node):
(vendor_glob, fname) = string_op2glob(node)
print 'ATTR{[dmi/id]sys_vendor}=="%s", RUN+="keymap $name %s"' % (vendor_glob, fname)
create_keylist(node, fname)
def parse_fdi_product(node):
(vendor_glob, vendor_fname) = string_op2glob(get_vendor_node(node))
(product_glob, product_fname) = string_op2glob(node)
fname = '%s-%s' % (vendor_fname, product_fname)
print 'ATTR{[dmi/id]sys_vendor}=="%s", ATTR{[dmi/id]product_name}=="%s", RUN+="keymap $name %s"' % (vendor_glob, product_glob, fname)
create_keylist(node, fname)
def parse_fdi_version(node):
(vendor_glob, vendor_fname) = string_op2glob(get_vendor_node(node))
(product_glob, product_fname) = string_op2glob(node)
fname = '%s-%s' % (vendor_fname, product_fname)
print 'ATTR{[dmi/id]sys_vendor}=="%s", ATTR{[dmi/id]product_version}=="%s", RUN+="keymap $name %s"' % (vendor_glob, product_glob, fname)
create_keylist(node, fname)
def parse_fdi(fdi):
'''Parse keymaps from a fdi node.'''
for match_node in fdi.getElementsByTagName('match'):
key = match_node.attributes['key'].nodeValue
if key == '/org/freedesktop/Hal/devices/computer:system.hardware.vendor':
# vendor list without model specific quirks
parse_fdi_vendor(match_node)
elif key == '/org/freedesktop/Hal/devices/computer:system.hardware.product':
# product specific list
parse_fdi_product(match_node)
elif key == '/org/freedesktop/Hal/devices/computer:system.hardware.version':
# product version specific list
parse_fdi_version(match_node)
elif key == '/org/freedesktop/Hal/devices/computer:system.formfactor':
# this assumes that a formfactor does not have product submatches
try:
(vendor_glob, fname) = string_op2glob(get_vendor_node(match_node))
create_keylist(match_node, fname)
except SystemError:
# formfactor match is at toplevel
pass
elif key == '@input.originating_device:info.linux.driver':
# already covered in udev rules header
pass
else:
print >> sys.stderr, 'WARNING: I do not understand key type', key
# udev rules header
print '''ACTION!="add", GOTO="keyboard_end"
SUBSYSTEM!="input", GOTO="keyboard_end"
DRIVERS=="atkbd", GOTO="keyboard_vendorcheck"
GOTO="keyboard_end"
LABEL="keyboard_vendorcheck"'''
# parse FDI files
for f in sys.argv[1:]:
parse_fdi(xml.dom.minidom.parse(f))
# udev rules footer
print '\nLABEL="keyboard_end"'
|