16747b715Smrg#!/usr/bin/python 26747b715Smrg# 36747b715Smrg# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections. 46747b715Smrg# Modified from Martin Pitt's original fdi2mpi.py script: 56747b715Smrg# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py 66747b715Smrg# 76747b715Smrg# (C) 2010 Dan Nicholson 86747b715Smrg# (C) 2009 Canonical Ltd. 96747b715Smrg# Author: Dan Nicholson <dbn.lists@gmail.com> 106747b715Smrg# Author: Martin Pitt <martin.pitt@ubuntu.com> 116747b715Smrg# 126747b715Smrg# Permission is hereby granted, free of charge, to any person obtaining a copy 136747b715Smrg# of this software and associated documentation files (the "Software"), to 146747b715Smrg# deal in the Software without restriction, including without limitation the 156747b715Smrg# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 166747b715Smrg# sell copies of the Software, and to permit persons to whom the Software is 176747b715Smrg# fur- nished to do so, subject to the following conditions: 186747b715Smrg# 196747b715Smrg# The above copyright notice and this permission notice shall be included in 206747b715Smrg# all copies or substantial portions of the Software. 216747b715Smrg# 226747b715Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 236747b715Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 246747b715Smrg# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 256747b715Smrg# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 266747b715Smrg# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- 276747b715Smrg# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 286747b715Smrg 296747b715Smrgimport sys, xml.dom.minidom 306747b715Smrg 316747b715Smrg# dict converting <match> tags to Match* entries 326747b715Smrgmatch_table = { 336747b715Smrg 'info.product': 'MatchProduct', 346747b715Smrg 'input.product': 'MatchProduct', 356747b715Smrg 'info.vendor': 'MatchVendor', 366747b715Smrg 'input.vendor': 'MatchVendor', 376747b715Smrg 'info.device': 'MatchDevicePath', 386747b715Smrg 'linux.device_file': 'MatchDevicePath', 396747b715Smrg '/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS', 406747b715Smrg '@info.parent:pnp.id': 'MatchPnPID', 416747b715Smrg} 426747b715Smrg 436747b715Smrg# dict converting info.capabilities list to Match* entries 446747b715Smrgcap_match_table = { 456747b715Smrg 'input.keys': 'MatchIsKeyboard', 466747b715Smrg 'input.keyboard': 'MatchIsKeyboard', 476747b715Smrg 'input.keypad': 'MatchIsKeyboard', 486747b715Smrg 'input.mouse': 'MatchIsPointer', 496747b715Smrg 'input.joystick': 'MatchIsJoystick', 506747b715Smrg 'input.tablet': 'MatchIsTablet', 516747b715Smrg 'input.touchpad': 'MatchIsTouchpad', 526747b715Smrg 'input.touchscreen': 'MatchIsTouchscreen', 536747b715Smrg} 546747b715Smrg 556747b715Smrgdef device_glob(path): 566747b715Smrg '''Convert a contains device path to a glob entry''' 576747b715Smrg if path[0] != '/': 586747b715Smrg path = '*' + path 596747b715Smrg return path + '*' 606747b715Smrg 616747b715Smrgdef parse_match(node): 626747b715Smrg '''Parse a <match> tag to a tuple with InputClass values''' 636747b715Smrg match = None 646747b715Smrg value = None 656747b715Smrg booltype = False 666747b715Smrg 676747b715Smrg # see what type of key we have 686747b715Smrg if node.attributes.has_key('key'): 696747b715Smrg key = node.attributes['key'].nodeValue 706747b715Smrg if key in match_table: 716747b715Smrg match = match_table[key] 726747b715Smrg elif key == 'info.capabilities': 736747b715Smrg booltype = True 746747b715Smrg 756747b715Smrg # bail out now if it's unrecognized 766747b715Smrg if not match and not booltype: 776747b715Smrg return (match, value) 786747b715Smrg 796747b715Smrg if node.attributes.has_key('string'): 806747b715Smrg value = node.attributes['string'].nodeValue 816747b715Smrg elif node.attributes.has_key('contains'): 826747b715Smrg value = node.attributes['contains'].nodeValue 836747b715Smrg if match == 'MatchDevicePath': 846747b715Smrg value = device_glob(value) 856747b715Smrg elif booltype and value in cap_match_table: 866747b715Smrg match = cap_match_table[value] 876747b715Smrg value = 'yes' 886747b715Smrg elif node.attributes.has_key('string_outof'): 896747b715Smrg value = node.attributes['string_outof'].nodeValue.replace(';','|') 906747b715Smrg elif node.attributes.has_key('contains_outof'): 916747b715Smrg all_values = node.attributes['contains_outof'].nodeValue.split(';') 926747b715Smrg for v in all_values: 936747b715Smrg if match == 'MatchDevicePath': 946747b715Smrg v = device_glob(v) 956747b715Smrg elif match == 'MatchPnPID' and len(v) < 7: 966747b715Smrg v += '*' 976747b715Smrg if value: 986747b715Smrg value += '|' + v 996747b715Smrg else: 1006747b715Smrg value = v 1016747b715Smrg 1026747b715Smrg return (match, value) 1036747b715Smrg 1046747b715Smrgdef parse_options(node): 1056747b715Smrg '''Parse the x11_* options and return InputClass entries''' 1066747b715Smrg driver = '' 1076747b715Smrg ignore = False 1086747b715Smrg options = [] 1096747b715Smrg for n in node.childNodes: 1106747b715Smrg if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE: 1116747b715Smrg continue 1126747b715Smrg 1136747b715Smrg tag = n.tagName 1146747b715Smrg key = n.attributes['key'].nodeValue 1156747b715Smrg value = '' 1166747b715Smrg 1176747b715Smrg if n.hasChildNodes(): 1186747b715Smrg content_node = n.childNodes[0] 1196747b715Smrg assert content_node.nodeType == xml.dom.Node.TEXT_NODE 1206747b715Smrg value = content_node.nodeValue 1216747b715Smrg 1226747b715Smrg if tag == 'match': 1236747b715Smrg continue 1246747b715Smrg assert tag in ('addset', 'merge', 'append', 'remove') 1256747b715Smrg 1266747b715Smrg if tag == 'remove' and key == 'input.x11_driver': 1276747b715Smrg ignore = True 1286747b715Smrg elif key == 'input.x11_driver': 1296747b715Smrg driver = value 1306747b715Smrg elif key.startswith('input.x11_options.'): 1316747b715Smrg option = key.split('.', 2)[2] 1326747b715Smrg options.append((option, value)) 1336747b715Smrg 1346747b715Smrg return (driver, ignore, options) 1356747b715Smrg 1366747b715Smrgdef is_match_node(node): 1376747b715Smrg '''Check if a node is a <match> element''' 1386747b715Smrg return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \ 1396747b715Smrg node.tagName == 'match' 1406747b715Smrg 1416747b715Smrgdef parse_all_matches(node): 1426747b715Smrg '''Parse a x11 match tag and any parents that don't supply their 1436747b715Smrg own options''' 1446747b715Smrg matches = [] 1456747b715Smrg 1466747b715Smrg while True: 1476747b715Smrg (key, value) = parse_match(node) 1486747b715Smrg if key and value: 1496747b715Smrg matches.append((key, value)) 1506747b715Smrg 1516747b715Smrg # walk up to a parent match node 1526747b715Smrg node = node.parentNode 1536747b715Smrg if node == None or not is_match_node(node): 1546747b715Smrg break 1556747b715Smrg 1566747b715Smrg # leave if there other options at this level 1576747b715Smrg children = set([n.tagName for n in node.childNodes 1586747b715Smrg if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE]) 1596747b715Smrg if children & set(['addset', 'merge', 'append']): 1606747b715Smrg break 1616747b715Smrg 1626747b715Smrg return matches 1636747b715Smrg 1646747b715Smrg# stupid counter to give "unique" rule names 1656747b715Smrgnum_sections = 1 1666747b715Smrgdef print_section(matches, driver, ignore, options): 1676747b715Smrg '''Print a valid InputClass section to stdout''' 1686747b715Smrg global num_sections 1696747b715Smrg print 'Section "InputClass"' 1706747b715Smrg print '\tIdentifier "Converted Class %d"' % num_sections 1716747b715Smrg num_sections += 1 1726747b715Smrg for m, v in matches: 1736747b715Smrg print '\t%s "%s"' % (m, v) 1746747b715Smrg if driver: 1756747b715Smrg print '\tDriver "%s"' % driver 1766747b715Smrg if ignore: 1776747b715Smrg print '\tOption "Ignore" "yes"' 1786747b715Smrg for o, v in options: 1796747b715Smrg print '\tOption "%s" "%s"' % (o, v) 1806747b715Smrg print 'EndSection' 1816747b715Smrg 1826747b715Smrgdef parse_fdi(fdi): 1836747b715Smrg '''Parse x11 matches from fdi''' 1846747b715Smrg # find all <match> leaf nodes 1856747b715Smrg num = 0 1866747b715Smrg for match_node in fdi.getElementsByTagName('match'): 1876747b715Smrg children = set([n.tagName for n in match_node.childNodes 1886747b715Smrg if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE]) 1896747b715Smrg 1906747b715Smrg # see if there are any options at this level 1916747b715Smrg (driver, ignore, options) = parse_options(match_node) 1926747b715Smrg if not driver and not ignore and not options: 1936747b715Smrg continue 1946747b715Smrg 1956747b715Smrg matches = parse_all_matches(match_node) 1966747b715Smrg if num > 0: 1976747b715Smrg print 1986747b715Smrg print_section(matches, driver, ignore, options) 1996747b715Smrg num += 1 2006747b715Smrg 2016747b715Smrgfor f in sys.argv[1:]: 2026747b715Smrg parse_fdi(xml.dom.minidom.parse(f)) 203