Imported Upstream version 1.15.1
[deb_xorg-server.git] / config / fdi2iclass.py
CommitLineData
a09e091a
JB
1#!/usr/bin/python
2#
3# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
4# Modified from Martin Pitt's original fdi2mpi.py script:
5# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
6#
7# (C) 2010 Dan Nicholson
8# (C) 2009 Canonical Ltd.
9# Author: Dan Nicholson <dbn.lists@gmail.com>
10# Author: Martin Pitt <martin.pitt@ubuntu.com>
11#
12# Permission is hereby granted, free of charge, to any person obtaining a copy
13# of this software and associated documentation files (the "Software"), to
14# deal in the Software without restriction, including without limitation the
15# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
16# sell copies of the Software, and to permit persons to whom the Software is
17# fur- nished to do so, subject to the following conditions:
18#
19# The above copyright notice and this permission notice shall be included in
20# all copies or substantial portions of the Software.
21#
22# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
27# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29import sys, xml.dom.minidom
30
31# dict converting <match> tags to Match* entries
32match_table = {
33 'info.product': 'MatchProduct',
34 'input.product': 'MatchProduct',
35 'info.vendor': 'MatchVendor',
36 'input.vendor': 'MatchVendor',
37 'info.device': 'MatchDevicePath',
38 'linux.device_file': 'MatchDevicePath',
39 '/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
40 '@info.parent:pnp.id': 'MatchPnPID',
41}
42
43# dict converting info.capabilities list to Match* entries
44cap_match_table = {
45 'input.keys': 'MatchIsKeyboard',
46 'input.keyboard': 'MatchIsKeyboard',
47 'input.keypad': 'MatchIsKeyboard',
48 'input.mouse': 'MatchIsPointer',
49 'input.joystick': 'MatchIsJoystick',
50 'input.tablet': 'MatchIsTablet',
51 'input.touchpad': 'MatchIsTouchpad',
52 'input.touchscreen': 'MatchIsTouchscreen',
53}
54
55def device_glob(path):
56 '''Convert a contains device path to a glob entry'''
57 if path[0] != '/':
58 path = '*' + path
59 return path + '*'
60
61def parse_match(node):
62 '''Parse a <match> tag to a tuple with InputClass values'''
63 match = None
64 value = None
65 booltype = False
66
67 # see what type of key we have
68 if node.attributes.has_key('key'):
69 key = node.attributes['key'].nodeValue
70 if key in match_table:
71 match = match_table[key]
72 elif key == 'info.capabilities':
73 booltype = True
74
75 # bail out now if it's unrecognized
76 if not match and not booltype:
77 return (match, value)
78
79 if node.attributes.has_key('string'):
80 value = node.attributes['string'].nodeValue
81 elif node.attributes.has_key('contains'):
82 value = node.attributes['contains'].nodeValue
83 if match == 'MatchDevicePath':
84 value = device_glob(value)
85 elif booltype and value in cap_match_table:
86 match = cap_match_table[value]
87 value = 'yes'
88 elif node.attributes.has_key('string_outof'):
89 value = node.attributes['string_outof'].nodeValue.replace(';','|')
90 elif node.attributes.has_key('contains_outof'):
91 all_values = node.attributes['contains_outof'].nodeValue.split(';')
92 for v in all_values:
93 if match == 'MatchDevicePath':
94 v = device_glob(v)
95 elif match == 'MatchPnPID' and len(v) < 7:
96 v += '*'
97 if value:
98 value += '|' + v
99 else:
100 value = v
101
102 return (match, value)
103
104def parse_options(node):
105 '''Parse the x11_* options and return InputClass entries'''
106 driver = ''
107 ignore = False
108 options = []
109 for n in node.childNodes:
110 if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
111 continue
112
113 tag = n.tagName
114 key = n.attributes['key'].nodeValue
115 value = ''
116
117 if n.hasChildNodes():
118 content_node = n.childNodes[0]
119 assert content_node.nodeType == xml.dom.Node.TEXT_NODE
120 value = content_node.nodeValue
121
122 if tag == 'match':
123 continue
124 assert tag in ('addset', 'merge', 'append', 'remove')
125
126 if tag == 'remove' and key == 'input.x11_driver':
127 ignore = True
128 elif key == 'input.x11_driver':
129 driver = value
130 elif key.startswith('input.x11_options.'):
131 option = key.split('.', 2)[2]
132 options.append((option, value))
133
134 return (driver, ignore, options)
135
136def is_match_node(node):
137 '''Check if a node is a <match> element'''
138 return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
139 node.tagName == 'match'
140
141def parse_all_matches(node):
142 '''Parse a x11 match tag and any parents that don't supply their
143 own options'''
144 matches = []
145
146 while True:
147 (key, value) = parse_match(node)
148 if key and value:
149 matches.append((key, value))
150
151 # walk up to a parent match node
152 node = node.parentNode
153 if node == None or not is_match_node(node):
154 break
155
156 # leave if there other options at this level
157 children = set([n.tagName for n in node.childNodes
158 if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
159 if children & set(['addset', 'merge', 'append']):
160 break
161
162 return matches
163
164# stupid counter to give "unique" rule names
165num_sections = 1
166def print_section(matches, driver, ignore, options):
167 '''Print a valid InputClass section to stdout'''
168 global num_sections
169 print 'Section "InputClass"'
170 print '\tIdentifier "Converted Class %d"' % num_sections
171 num_sections += 1
172 for m, v in matches:
173 print '\t%s "%s"' % (m, v)
174 if driver:
175 print '\tDriver "%s"' % driver
176 if ignore:
177 print '\tOption "Ignore" "yes"'
178 for o, v in options:
179 print '\tOption "%s" "%s"' % (o, v)
180 print 'EndSection'
181
182def parse_fdi(fdi):
183 '''Parse x11 matches from fdi'''
184 # find all <match> leaf nodes
185 num = 0
186 for match_node in fdi.getElementsByTagName('match'):
187 children = set([n.tagName for n in match_node.childNodes
188 if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
189
190 # see if there are any options at this level
191 (driver, ignore, options) = parse_options(match_node)
192 if not driver and not ignore and not options:
193 continue
194
195 matches = parse_all_matches(match_node)
196 if num > 0:
197 print
198 print_section(matches, driver, ignore, options)
199 num += 1
200
201for f in sys.argv[1:]:
202 parse_fdi(xml.dom.minidom.parse(f))