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
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>
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:
19 # The above copyright notice and this permission notice shall be included in
20 # all copies or substantial portions of the Software.
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.
29 import sys
, xml
.dom
.minidom
31 # dict converting <match> tags to Match* entries
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',
43 # dict converting info.capabilities list to Match* entries
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',
55 def device_glob(path
):
56 '''Convert a contains device path to a glob entry'''
61 def parse_match(node
):
62 '''Parse a <match> tag to a tuple with InputClass values'''
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':
75 # bail out now if it's unrecognized
76 if not match
and not booltype
:
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
]
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(';')
93 if match
== 'MatchDevicePath':
95 elif match
== 'MatchPnPID' and len(v
) < 7:
102 return (match
, value
)
104 def parse_options(node
):
105 '''Parse the x11_* options and return InputClass entries'''
109 for n
in node
.childNodes
:
110 if n
.nodeType
!= xml
.dom
.minidom
.Node
.ELEMENT_NODE
:
114 key
= n
.attributes
['key'].nodeValue
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
124 assert tag
in ('addset', 'merge', 'append', 'remove')
126 if tag
== 'remove' and key
== 'input.x11_driver':
128 elif key
== 'input.x11_driver':
130 elif key
.startswith('input.x11_options.'):
131 option
= key
.split('.', 2)[2]
132 options
.append((option
, value
))
134 return (driver
, ignore
, options
)
136 def 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'
141 def parse_all_matches(node
):
142 '''Parse a x11 match tag and any parents that don't supply their
147 (key
, value
) = parse_match(node
)
149 matches
.append((key
, value
))
151 # walk up to a parent match node
152 node
= node
.parentNode
153 if node
== None or not is_match_node(node
):
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']):
164 # stupid counter to give "unique" rule names
166 def print_section(matches
, driver
, ignore
, options
):
167 '''Print a valid InputClass section to stdout'''
169 print 'Section "InputClass"'
170 print '\tIdentifier "Converted Class %d"' % num_sections
173 print '\t%s "%s"' % (m
, v
)
175 print '\tDriver "%s"' % driver
177 print '\tOption "Ignore" "yes"'
179 print '\tOption "%s" "%s"' % (o
, v
)
183 '''Parse x11 matches from fdi'''
184 # find all <match> leaf nodes
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
])
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
:
195 matches
= parse_all_matches(match_node
)
198 print_section(matches
, driver
, ignore
, options
)
201 for f
in sys
.argv
[1:]:
202 parse_fdi(xml
.dom
.minidom
.parse(f
))