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