[PATCH v2 09/11] config: Script to convert HAL fdi settings to InputClass sections

Dan Nicholson dbn.lists at gmail.com
Mon Jun 7 20:39:56 PDT 2010


In the new world of udev and InputClass, x11_* settings from HAL fdi
files will not be honored. This script converts those settings into
valid InputClass sections that can be dropped into xorg.conf.d.

Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
---
 config/Makefile.am   |    2 +-
 config/fdi2iclass.py |  202 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 203 insertions(+), 1 deletions(-)
 create mode 100755 config/fdi2iclass.py

diff --git a/config/Makefile.am b/config/Makefile.am
index 675a3b2..e1f1c4e 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -36,4 +36,4 @@ endif # CONFIG_NEED_DBUS
 
 endif # !CONFIG_UDEV
 
-EXTRA_DIST = xorg-server.conf x11-input.fdi 10-evdev.conf
+EXTRA_DIST = xorg-server.conf x11-input.fdi 10-evdev.conf fdi2iclass.py
diff --git a/config/fdi2iclass.py b/config/fdi2iclass.py
new file mode 100755
index 0000000..8974440
--- /dev/null
+++ b/config/fdi2iclass.py
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+#
+# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
+# Modified from Martin Pitt's original fdi2mpi.py script:
+# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
+#
+# (C) 2010 Dan Nicholson
+# (C) 2009 Canonical Ltd.
+# Author: Dan Nicholson <dbn.lists at gmail.com>
+# Author: Martin Pitt <martin.pitt at ubuntu.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# fur- nished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+#  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+#  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+#  NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import sys, xml.dom.minidom
+
+# dict converting <match> tags to Match* entries
+match_table = {
+    'info.product': 'MatchProduct',
+    'input.product': 'MatchProduct',
+    'info.vendor': 'MatchVendor',
+    'input.vendor': 'MatchVendor',
+    'info.device': 'MatchDevicePath',
+    'linux.device_file': 'MatchDevicePath',
+    '/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
+    '@info.parent:pnp.id': 'MatchPnPID',
+}
+
+# dict converting info.capabilities list to Match* entries
+cap_match_table = {
+    'input.keys': 'MatchIsKeyboard',
+    'input.keyboard': 'MatchIsKeyboard',
+    'input.keypad': 'MatchIsKeyboard',
+    'input.mouse': 'MatchIsPointer',
+    'input.joystick': 'MatchIsJoystick',
+    'input.tablet': 'MatchIsTablet',
+    'input.touchpad': 'MatchIsTouchpad',
+    'input.touchscreen': 'MatchIsTouchscreen',
+}
+
+def device_glob(path):
+    '''Convert a contains device path to a glob entry'''
+    if path[0] != '/':
+        path = '*' + path
+    return path + '*'
+
+def parse_match(node):
+    '''Parse a <match> tag to a tuple with InputClass values'''
+    match = None
+    value = None
+    booltype = False
+
+    # see what type of key we have
+    if node.attributes.has_key('key'):
+        key = node.attributes['key'].nodeValue
+        if key in match_table:
+            match = match_table[key]
+        elif key == 'info.capabilities':
+            booltype = True
+
+    # bail out now if it's unrecognized
+    if not match and not booltype:
+        return (match, value)
+
+    if node.attributes.has_key('string'):
+        value = node.attributes['string'].nodeValue
+    elif node.attributes.has_key('contains'):
+        value = node.attributes['contains'].nodeValue
+        if match == 'MatchDevicePath':
+            value = device_glob(value)
+        elif booltype and value in cap_match_table:
+            match = cap_match_table[value]
+            value = 'yes'
+    elif node.attributes.has_key('string_outof'):
+        value = node.attributes['string_outof'].nodeValue.replace(';','|')
+    elif node.attributes.has_key('contains_outof'):
+        all_values = node.attributes['contains_outof'].nodeValue.split(';')
+        for v in all_values:
+            if match == 'MatchDevicePath':
+                v = device_glob(v)
+            elif match == 'MatchPnPID' and len(v) < 7:
+                v += '*'
+            if value:
+                value += '|' + v
+            else:
+                value = v
+
+    return (match, value)
+
+def parse_options(node):
+    '''Parse the x11_* options and return InputClass entries'''
+    driver = ''
+    ignore = False
+    options = []
+    for n in node.childNodes:
+        if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
+            continue
+
+        tag = n.tagName
+        key = n.attributes['key'].nodeValue
+        value = ''
+
+        if n.hasChildNodes():
+            content_node = n.childNodes[0]
+            assert content_node.nodeType == xml.dom.Node.TEXT_NODE
+            value = content_node.nodeValue
+
+        if tag == 'match':
+            continue
+        assert tag in ('addset', 'merge', 'append', 'remove')
+
+        if tag == 'remove' and key == 'input.x11_driver':
+            ignore = True
+        elif key == 'input.x11_driver':
+            driver = value
+        elif key.startswith('input.x11_options.'):
+            option = key.split('.', 2)[2]
+            options.append((option, value))
+
+    return (driver, ignore, options)
+
+def is_match_node(node):
+    '''Check if a node is a <match> element'''
+    return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
+        node.tagName == 'match'
+
+def parse_all_matches(node):
+    '''Parse a x11 match tag and any parents that don't supply their
+    own options'''
+    matches = []
+
+    while True:
+        (key, value) = parse_match(node)
+        if key and value:
+            matches.append((key, value))
+
+        # walk up to a parent match node
+        node = node.parentNode
+        if node == None or not is_match_node(node):
+            break
+
+        # leave if there other options at this level
+        children = set([n.tagName for n in node.childNodes
+                        if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
+        if children & set(['addset', 'merge', 'append']):
+            break
+
+    return matches
+
+# stupid counter to give "unique" rule names
+num_sections = 1
+def print_section(matches, driver, ignore, options):
+    '''Print a valid InputClass section to stdout'''
+    global num_sections
+    print 'Section "InputClass"'
+    print '\tIdentifier "Converted Class %d"' % num_sections
+    num_sections += 1
+    for m, v in matches:
+        print '\t%s "%s"' % (m, v)
+    if driver:
+        print '\tDriver "%s"' % driver
+    if ignore:
+        print '\tOption "Ignore" "yes"'
+    for o, v in options:
+        print '\tOption "%s" "%s"' % (o, v)
+    print 'EndSection'
+
+def parse_fdi(fdi):
+    '''Parse x11 matches from fdi'''
+    # find all <match> leaf nodes
+    num = 0
+    for match_node in fdi.getElementsByTagName('match'):
+        children = set([n.tagName for n in match_node.childNodes
+                if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
+
+        # see if there are any options at this level
+        (driver, ignore, options) = parse_options(match_node)
+        if not driver and not ignore and not options:
+            continue
+
+        matches = parse_all_matches(match_node)
+        if num > 0:
+            print
+        print_section(matches, driver, ignore, options)
+        num += 1
+
+for f in sys.argv[1:]:
+    parse_fdi(xml.dom.minidom.parse(f))
-- 
1.6.6.1



More information about the xorg-devel mailing list