Merge remote branch 'whot/for-keith'
This commit is contained in:
commit
07a093add0
|
@ -193,16 +193,12 @@ void
|
|||
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
|
||||
{
|
||||
KeyClassPtr mk = master->key;
|
||||
KeyClassPtr dk = device->key;
|
||||
int i;
|
||||
|
||||
if (device == master)
|
||||
return;
|
||||
|
||||
mk->sourceid = device->id;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
|
||||
|
||||
if (!XkbCopyDeviceKeymap(master, device))
|
||||
FatalError("Couldn't pivot keymap from device to core!\n");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#define DBUS_API_SUBJECT_TO_CHANGE
|
||||
#include <dbus/dbus.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
202
config/fdi2iclass.py
Executable file
202
config/fdi2iclass.py
Executable file
|
@ -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@gmail.com>
|
||||
# Author: Martin Pitt <martin.pitt@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))
|
32
config/hal.c
32
config/hal.c
|
@ -129,6 +129,7 @@ static void
|
|||
device_added(LibHalContext *hal_ctx, const char *udi)
|
||||
{
|
||||
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
|
||||
char *hal_tags, *parent;
|
||||
InputOption *options = NULL, *tmpo = NULL;
|
||||
InputAttributes attrs = {0};
|
||||
DeviceIntPtr dev = NULL;
|
||||
|
@ -164,7 +165,9 @@ device_added(LibHalContext *hal_ctx, const char *udi)
|
|||
attrs.product = xstrdup(name);
|
||||
|
||||
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
|
||||
attrs.tags = xstrtokenize(get_prop_string(hal_ctx, udi, "input.tags"), ",");
|
||||
hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
|
||||
attrs.tags = xstrtokenize(hal_tags, ",");
|
||||
free(hal_tags);
|
||||
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
|
||||
attrs.flags |= ATTR_KEYBOARD;
|
||||
|
@ -179,6 +182,29 @@ device_added(LibHalContext *hal_ctx, const char *udi)
|
|||
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
|
||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
||||
|
||||
parent = get_prop_string(hal_ctx, udi, "info.parent");
|
||||
if (parent) {
|
||||
int usb_vendor, usb_product;
|
||||
|
||||
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
|
||||
|
||||
/* construct USB ID in lowercase - "0000:ffff" */
|
||||
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.vendor_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.vendor_id on %s "
|
||||
"returned %04x\n", parent, usb_vendor);
|
||||
usb_product = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.product_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.product_id on %s "
|
||||
"returned %04x\n", parent, usb_product);
|
||||
if (usb_vendor && usb_product)
|
||||
attrs.usb_id = Xprintf("%04x:%04x", usb_vendor, usb_product);
|
||||
|
||||
free(parent);
|
||||
}
|
||||
|
||||
options = calloc(sizeof(*options), 1);
|
||||
if (!options){
|
||||
LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n");
|
||||
|
@ -381,6 +407,8 @@ unwind:
|
|||
free(attrs.product);
|
||||
free(attrs.vendor);
|
||||
free(attrs.device);
|
||||
free(attrs.pnp_id);
|
||||
free(attrs.usb_id);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
while (*tag) {
|
||||
|
@ -619,7 +647,7 @@ config_hal_init(void)
|
|||
}
|
||||
|
||||
/* verbose message */
|
||||
LogMessageVerb(X_INFO,7,"config/hal: initialized");
|
||||
LogMessageVerb(X_INFO,7,"config/hal: initialized\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#endif
|
||||
|
||||
#include <libudev.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
|
@ -37,6 +38,17 @@
|
|||
|
||||
#define UDEV_XKB_PROP_KEY "xkb"
|
||||
|
||||
#define LOG_PROPERTY(path, prop, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting property %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(prop), (path), (val) ? (val) : "(null)")
|
||||
#define LOG_SYSATTR(path, attr, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting attribute %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(attr), (path), (val) ? (val) : "(null)")
|
||||
|
||||
static struct udev_monitor *udev_monitor;
|
||||
|
||||
static void
|
||||
|
@ -45,6 +57,8 @@ device_added(struct udev_device *udev_device)
|
|||
const char *path, *name = NULL;
|
||||
char *config_info = NULL;
|
||||
const char *syspath;
|
||||
const char *tags_prop;
|
||||
const char *usb_vendor = NULL, *usb_model = NULL;
|
||||
const char *key, *value, *tmp;
|
||||
InputOption *options = NULL, *tmpo;
|
||||
InputAttributes attrs = {};
|
||||
|
@ -60,8 +74,13 @@ device_added(struct udev_device *udev_device)
|
|||
if (!path || !syspath)
|
||||
return;
|
||||
|
||||
if (!udev_device_get_property_value(udev_device, "ID_INPUT"))
|
||||
if (!udev_device_get_property_value(udev_device, "ID_INPUT")) {
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/udev: ignoring device %s without "
|
||||
"property ID_INPUT set\n",
|
||||
path);
|
||||
return;
|
||||
}
|
||||
|
||||
options = calloc(sizeof(*options), 1);
|
||||
if (!options)
|
||||
|
@ -74,9 +93,17 @@ device_added(struct udev_device *udev_device)
|
|||
|
||||
parent = udev_device_get_parent(udev_device);
|
||||
if (parent) {
|
||||
const char *ppath = udev_device_get_devnode(parent);
|
||||
|
||||
name = udev_device_get_sysattr_value(parent, "name");
|
||||
if (!name)
|
||||
LOG_SYSATTR(ppath, "name", name);
|
||||
if (!name) {
|
||||
name = udev_device_get_property_value(parent, "NAME");
|
||||
LOG_PROPERTY(ppath, "NAME", name);
|
||||
}
|
||||
|
||||
attrs.pnp_id = udev_device_get_sysattr_value(parent, "id");
|
||||
LOG_SYSATTR(ppath, "id", attrs.pnp_id);
|
||||
}
|
||||
if (!name)
|
||||
name = "(unnamed)";
|
||||
|
@ -87,7 +114,10 @@ device_added(struct udev_device *udev_device)
|
|||
add_option(&options, "path", path);
|
||||
add_option(&options, "device", path);
|
||||
attrs.device = path;
|
||||
attrs.tags = xstrtokenize(udev_device_get_property_value(udev_device, "ID_INPUT.tags"), ",");
|
||||
|
||||
tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
|
||||
LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
|
||||
attrs.tags = xstrtokenize(tags_prop, ",");
|
||||
|
||||
config_info = Xprintf("udev:%s", syspath);
|
||||
if (!config_info)
|
||||
|
@ -107,6 +137,7 @@ device_added(struct udev_device *udev_device)
|
|||
value = udev_list_entry_get_value(entry);
|
||||
if (!strncasecmp(key, UDEV_XKB_PROP_KEY,
|
||||
sizeof(UDEV_XKB_PROP_KEY) - 1)) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
|
||||
if (!strcasecmp(tmp, "rules"))
|
||||
add_option(&options, "xkb_rules", value);
|
||||
|
@ -119,21 +150,45 @@ device_added(struct udev_device *udev_device)
|
|||
else if (!strcasecmp(tmp, "options"))
|
||||
add_option(&options, "xkb_options", value);
|
||||
} else if (!strcmp(key, "ID_VENDOR")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.vendor = value;
|
||||
} else if (!strcmp(key, "ID_VENDOR_ID")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
usb_vendor = value;
|
||||
} else if (!strcmp(key, "ID_VENDOR_MODEL")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
usb_model = value;
|
||||
} else if (!strcmp(key, "ID_INPUT_KEY")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_KEYBOARD;
|
||||
} else if (!strcmp(key, "ID_INPUT_MOUSE")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_POINTER;
|
||||
} else if (!strcmp(key, "ID_INPUT_JOYSTICK")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_JOYSTICK;
|
||||
} else if (!strcmp(key, "ID_INPUT_TABLET")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_TABLET;
|
||||
} else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_TOUCHPAD;
|
||||
} else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct USB ID in lowercase hex - "0000:ffff" */
|
||||
if (usb_vendor && usb_model) {
|
||||
attrs.usb_id = Xprintf("%s:%s", usb_vendor, usb_model);
|
||||
if (attrs.usb_id) {
|
||||
char *cur;
|
||||
for (cur = attrs.usb_id; *cur; cur++)
|
||||
*cur = tolower(*cur);
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
|
||||
name, path);
|
||||
rc = NewInputDeviceRequest(options, &attrs, &dev);
|
||||
|
@ -154,6 +209,7 @@ device_added(struct udev_device *udev_device)
|
|||
free(tmpo);
|
||||
}
|
||||
|
||||
free(attrs.usb_id);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
while (*tag) {
|
||||
|
|
|
@ -123,7 +123,7 @@ AM_CONDITIONAL(SPECIAL_DTRACE_OBJECTS, [test "x$SPECIAL_DTRACE_OBJECTS" = "xyes"
|
|||
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.h])
|
||||
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.h sys/utsname.h])
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
|
@ -809,6 +809,7 @@ LIBPCIACCESS="pciaccess >= 0.8.0"
|
|||
LIBGLIB="glib-2.0 >= 2.16"
|
||||
LIBUDEV="libudev >= 143"
|
||||
LIBSELINUX="libselinux >= 2.0.86"
|
||||
LIBDBUS="dbus-1 >= 1.0"
|
||||
|
||||
if test "x$CONFIG_UDEV" = xyes &&
|
||||
{ test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then
|
||||
|
@ -832,7 +833,7 @@ fi
|
|||
dnl HAVE_DBUS is true if we actually have the D-Bus library, whereas
|
||||
dnl CONFIG_DBUS_API is true if we want to enable the D-Bus config
|
||||
dnl API.
|
||||
PKG_CHECK_MODULES(DBUS, dbus-1, [HAVE_DBUS=yes], [HAVE_DBUS=no])
|
||||
PKG_CHECK_MODULES(DBUS, $LIBDBUS, [HAVE_DBUS=yes], [HAVE_DBUS=no])
|
||||
if test "x$HAVE_DBUS" = xyes; then
|
||||
AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support])
|
||||
fi
|
||||
|
|
|
@ -357,6 +357,10 @@ DuplicateInputAttributes(InputAttributes *attrs)
|
|||
goto unwind;
|
||||
if (attrs->device && !(new_attr->device = strdup(attrs->device)))
|
||||
goto unwind;
|
||||
if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
|
||||
goto unwind;
|
||||
if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
|
||||
goto unwind;
|
||||
|
||||
new_attr->flags = attrs->flags;
|
||||
|
||||
|
@ -401,6 +405,8 @@ FreeInputAttributes(InputAttributes *attrs)
|
|||
free(attrs->product);
|
||||
free(attrs->vendor);
|
||||
free(attrs->device);
|
||||
free(attrs->pnp_id);
|
||||
free(attrs->usb_id);
|
||||
|
||||
if ((tags = attrs->tags))
|
||||
while(*tags)
|
||||
|
|
|
@ -80,6 +80,9 @@
|
|||
#ifdef HAVE_FNMATCH_H
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UTSNAME_H
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include "extnsionst.h"
|
||||
|
||||
|
@ -496,74 +499,153 @@ AddOtherInputDevices(void)
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the operating system name from uname and store it statically to avoid
|
||||
* repeating the system call each time MatchOS is checked.
|
||||
*/
|
||||
static const char *
|
||||
HostOS(void)
|
||||
{
|
||||
#ifdef HAVE_SYS_UTSNAME_H
|
||||
struct utsname name;
|
||||
static char host_os[sizeof(name.sysname)] = "";
|
||||
|
||||
if (*host_os == '\0') {
|
||||
if (uname(&name) >= 0)
|
||||
strcpy(host_os, name.sysname);
|
||||
else {
|
||||
strncpy(host_os, "unknown", sizeof(host_os));
|
||||
host_os[sizeof(host_os)-1] = '\0';
|
||||
}
|
||||
}
|
||||
return host_os;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
match_substring(const char *attr, const char *pattern)
|
||||
{
|
||||
return (strstr(attr, pattern)) ? 0 : -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FNMATCH_H
|
||||
static int
|
||||
match_pattern(const char *attr, const char *pattern)
|
||||
{
|
||||
return fnmatch(pattern, attr, 0);
|
||||
}
|
||||
#else
|
||||
#define match_pattern match_substring
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FNMATCH_H
|
||||
static int
|
||||
match_path_pattern(const char *attr, const char *pattern)
|
||||
{
|
||||
return fnmatch(pattern, attr, FNM_PATHNAME);
|
||||
}
|
||||
#else
|
||||
#define match_path_pattern match_substring
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Match an attribute against a list of NULL terminated arrays of patterns.
|
||||
* If a pattern in each list entry is matched, return TRUE.
|
||||
*/
|
||||
static Bool
|
||||
MatchAttrToken(const char *attr, struct list *patterns,
|
||||
int (*compare)(const char *attr, const char *pattern))
|
||||
{
|
||||
const xf86MatchGroup *group;
|
||||
|
||||
/* If there are no patterns, accept the match */
|
||||
if (list_is_empty(patterns))
|
||||
return TRUE;
|
||||
|
||||
/* If there are patterns but no attribute, reject the match */
|
||||
if (!attr)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* Otherwise, iterate the list of patterns ensuring each entry has a
|
||||
* match. Each list entry is a separate Match line of the same type.
|
||||
*/
|
||||
list_for_each_entry(group, patterns, entry) {
|
||||
char * const *cur;
|
||||
Bool match = FALSE;
|
||||
|
||||
for (cur = group->values; *cur; cur++)
|
||||
if ((*compare)(attr, *cur) == 0) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!match)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* All the entries in the list matched the attribute */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Classes without any Match statements match all devices. Otherwise, all
|
||||
* statements must match.
|
||||
*/
|
||||
static Bool
|
||||
InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
||||
InputClassMatches(const XF86ConfInputClassPtr iclass, const IDevPtr idev,
|
||||
const InputAttributes *attrs)
|
||||
{
|
||||
char **cur;
|
||||
Bool match;
|
||||
/* MatchProduct substring */
|
||||
if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
|
||||
return FALSE;
|
||||
|
||||
/* MatchVendor substring */
|
||||
if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
|
||||
return FALSE;
|
||||
|
||||
/* MatchDevicePath pattern */
|
||||
if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
|
||||
return FALSE;
|
||||
|
||||
/* MatchOS case-insensitive string */
|
||||
if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
|
||||
return FALSE;
|
||||
|
||||
/* MatchPnPID pattern */
|
||||
if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
|
||||
return FALSE;
|
||||
|
||||
/* MatchUSBID pattern */
|
||||
if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
|
||||
return FALSE;
|
||||
|
||||
/* MatchDriver string */
|
||||
if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* MatchTag string
|
||||
* See if any of the device's tags match any of the MatchTag tokens.
|
||||
*/
|
||||
if (!list_is_empty(&iclass->match_tag)) {
|
||||
char * const *tag;
|
||||
Bool match;
|
||||
|
||||
if (iclass->match_product) {
|
||||
if (!attrs->product)
|
||||
return FALSE;
|
||||
/* see if any of the values match */
|
||||
for (cur = iclass->match_product, match = FALSE; *cur; cur++)
|
||||
if (strstr(attrs->product, *cur)) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!match)
|
||||
return FALSE;
|
||||
}
|
||||
if (iclass->match_vendor) {
|
||||
if (!attrs->vendor)
|
||||
return FALSE;
|
||||
/* see if any of the values match */
|
||||
for (cur = iclass->match_vendor, match = FALSE; *cur; cur++)
|
||||
if (strstr(attrs->vendor, *cur)) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!match)
|
||||
return FALSE;
|
||||
}
|
||||
if (iclass->match_device) {
|
||||
if (!attrs->device)
|
||||
return FALSE;
|
||||
/* see if any of the values match */
|
||||
for (cur = iclass->match_device, match = FALSE; *cur; cur++)
|
||||
#ifdef HAVE_FNMATCH_H
|
||||
if (fnmatch(*cur, attrs->device, FNM_PATHNAME) == 0) {
|
||||
#else
|
||||
if (strstr(attrs->device, *cur)) {
|
||||
#endif
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
if (!match)
|
||||
return FALSE;
|
||||
}
|
||||
if (iclass->match_tag) {
|
||||
if (!attrs->tags)
|
||||
return FALSE;
|
||||
|
||||
for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) {
|
||||
char * const *tag;
|
||||
for(tag = attrs->tags; *tag; tag++) {
|
||||
if (!strcmp(*tag, *cur)) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
for (tag = attrs->tags, match = FALSE; *tag; tag++) {
|
||||
if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* MatchIs* booleans */
|
||||
if (iclass->is_keyboard.set &&
|
||||
iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
|
||||
return FALSE;
|
||||
|
@ -582,6 +664,7 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
|||
if (iclass->is_touchscreen.set &&
|
||||
iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -591,37 +674,36 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
|||
* well as any previous InputClass sections.
|
||||
*/
|
||||
static int
|
||||
MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
|
||||
MergeInputClasses(const IDevPtr idev, const InputAttributes *attrs)
|
||||
{
|
||||
XF86ConfInputClassPtr cl;
|
||||
XF86OptionPtr classopts, mergedopts = NULL;
|
||||
char *classdriver = NULL;
|
||||
XF86OptionPtr classopts;
|
||||
|
||||
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
||||
if (!InputClassMatches(cl, attrs))
|
||||
if (!InputClassMatches(cl, idev, attrs))
|
||||
continue;
|
||||
|
||||
/* Collect class options and merge over previous classes */
|
||||
/* Collect class options and driver settings */
|
||||
classopts = xf86optionListDup(cl->option_lst);
|
||||
if (cl->driver) {
|
||||
free(idev->driver);
|
||||
idev->driver = xstrdup(cl->driver);
|
||||
if (!idev->driver) {
|
||||
xf86Msg(X_ERROR, "Failed to allocate memory while merging "
|
||||
"InputClass configuration");
|
||||
return BadAlloc;
|
||||
}
|
||||
classopts = xf86ReplaceStrOption(classopts, "driver",
|
||||
idev->driver);
|
||||
}
|
||||
|
||||
/* Apply options to device with InputClass settings preferred. */
|
||||
xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
|
||||
idev->identifier, cl->identifier);
|
||||
if (cl->driver)
|
||||
classdriver = cl->driver;
|
||||
classopts = xf86optionListDup(cl->option_lst);
|
||||
mergedopts = xf86optionListMerge(mergedopts, classopts);
|
||||
idev->commonOptions = xf86optionListMerge(idev->commonOptions,
|
||||
classopts);
|
||||
}
|
||||
|
||||
/* Apply options to device with InputClass settings preferred. */
|
||||
if (classdriver) {
|
||||
free(idev->driver);
|
||||
idev->driver = xstrdup(classdriver);
|
||||
if (!idev->driver) {
|
||||
xf86Msg(X_ERROR, "Failed to allocate memory while merging "
|
||||
"InputClass configuration");
|
||||
return BadAlloc;
|
||||
}
|
||||
mergedopts = xf86ReplaceStrOption(mergedopts, "driver", idev->driver);
|
||||
}
|
||||
idev->commonOptions = xf86optionListMerge(idev->commonOptions, mergedopts);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
@ -630,14 +712,14 @@ MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
|
|||
* value of the last matching class and holler when returning TRUE.
|
||||
*/
|
||||
static Bool
|
||||
IgnoreInputClass(IDevPtr idev, InputAttributes *attrs)
|
||||
IgnoreInputClass(const IDevPtr idev, const InputAttributes *attrs)
|
||||
{
|
||||
XF86ConfInputClassPtr cl;
|
||||
Bool ignore = FALSE;
|
||||
const char *ignore_class;
|
||||
|
||||
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
||||
if (!InputClassMatches(cl, attrs))
|
||||
if (!InputClassMatches(cl, idev, attrs))
|
||||
continue;
|
||||
if (xf86findOption(cl->option_lst, "Ignore")) {
|
||||
ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
|
||||
|
|
|
@ -1065,35 +1065,85 @@ of the class. If none of the optional entries appear, the
|
|||
.B InputClass
|
||||
section is generic and will match any input device. If more than one of
|
||||
these entries appear, they all must match for the configuration to apply.
|
||||
The allowed matching entries are shown below.
|
||||
.PP
|
||||
There are two types of match entries used in
|
||||
.B InputClass
|
||||
sections. The first allows various tokens to be matched against attributes
|
||||
of the device. An entry can be constructed to match attributes from different
|
||||
devices by separating arguments with a '|' character. Multiple entries of the
|
||||
same type may be supplied to add multiple matching conditions on the same
|
||||
attribute. For example:
|
||||
.PP
|
||||
.RS 4
|
||||
.nf
|
||||
.B "Section \*qInputClass\*q"
|
||||
.B " Identifier \*qMy Class\*q"
|
||||
.B " # product string must contain example and
|
||||
.B " # either gizmo or gadget
|
||||
.B " MatchProduct \*qexample\*q
|
||||
.B " MatchProduct \*qgizmo|gadget\*q
|
||||
.I " ..."
|
||||
.B "EndSection"
|
||||
.fi
|
||||
.RE
|
||||
.TP 7
|
||||
.BI "MatchProduct \*q" matchproduct \*q
|
||||
This entry can be used to check if the substring
|
||||
.RI \*q matchproduct \*q
|
||||
occurs in the device's product name. Multiple substrings can be matched by
|
||||
separating arguments with a '|' character.
|
||||
occurs in the device's product name.
|
||||
.TP 7
|
||||
.BI "MatchVendor \*q" matchvendor \*q
|
||||
This entry can be used to check if the substring
|
||||
.RI \*q matchvendor \*q
|
||||
occurs in the device's vendor name. Multiple substrings can be matched by
|
||||
separating arguments with a '|' character.
|
||||
occurs in the device's vendor name.
|
||||
.TP 7
|
||||
.BI "MatchDevicePath \*q" matchdevice \*q
|
||||
This entry can be used to check if the device file matches the
|
||||
.RI \*q matchdevice \*q
|
||||
pathname pattern. Multiple patterns can be matched by separating arguments
|
||||
with a '|' character.
|
||||
pathname pattern.
|
||||
.TP 7
|
||||
.BI "MatchOS \*q" matchos \*q
|
||||
This entry can be used to check if the operating system matches the
|
||||
case-insensitive
|
||||
.RI \*q matchos \*q
|
||||
string. This entry is only supported on platforms providing the
|
||||
.BR uname (2)
|
||||
system call.
|
||||
.TP 7
|
||||
.BI "MatchPnPID \*q" matchpnp \*q
|
||||
The device's Plug and Play (PnP) ID can be checked against the
|
||||
.RI \*q matchpnp \*q
|
||||
shell wildcard pattern.
|
||||
.TP 7
|
||||
.BI "MatchUSBID \*q" matchusb \*q
|
||||
The device's USB ID can be checked against the
|
||||
.RI \*q matchusb \*q
|
||||
shell wildcard pattern. The ID is constructed as lowercase hexadecimal numbers
|
||||
separated by a ':'. This is the same format as the
|
||||
.BR lsusb (8)
|
||||
program.
|
||||
.TP 7
|
||||
.BI "MatchDriver \*q" matchdriver \*q
|
||||
Check the case-sensitive string
|
||||
.RI \*q matchdriver \*q
|
||||
against the currently configured driver of the device. Ordering of sections
|
||||
using this entry is important since it will not match unless the driver has
|
||||
been set by the config backend or a previous
|
||||
.B InputClass
|
||||
section.
|
||||
.TP 7
|
||||
.BI "MatchTag \*q" matchtag \*q
|
||||
This entry can be used to check if tags assigned by the config backend
|
||||
matches the
|
||||
.RI \*q matchtag \*q
|
||||
pattern. Multiple patterns can be matched by separating arguments
|
||||
with a '|' character. A match is found if at least one of the tags given in
|
||||
pattern. A match is found if at least one of the tags given in
|
||||
.RI \*q matchtag \*q
|
||||
matches at least one of the tags assigned by the backend.
|
||||
.PP
|
||||
The second type of entry is used to match device types. These entries take a
|
||||
boolean argument similar to
|
||||
.B Option
|
||||
entries.
|
||||
.TP 7
|
||||
.BI "MatchIsKeyboard \*q" bool \*q
|
||||
.TP 7
|
||||
|
@ -1106,9 +1156,6 @@ matches at least one of the tags assigned by the backend.
|
|||
.BI "MatchIsTouchpad \*q" bool \*q
|
||||
.TP 7
|
||||
.BI "MatchIsTouchscreen \*q" bool \*q
|
||||
Match device types. These entries take a boolean argument similar to
|
||||
.B Option
|
||||
entries.
|
||||
.PP
|
||||
When an input device has been matched to the
|
||||
.B InputClass
|
||||
|
|
|
@ -47,6 +47,10 @@ xf86ConfigSymTabRec InputClassTab[] =
|
|||
{MATCH_PRODUCT, "matchproduct"},
|
||||
{MATCH_VENDOR, "matchvendor"},
|
||||
{MATCH_DEVICE_PATH, "matchdevicepath"},
|
||||
{MATCH_OS, "matchos"},
|
||||
{MATCH_PNPID, "matchpnpid"},
|
||||
{MATCH_USBID, "matchusbid"},
|
||||
{MATCH_DRIVER, "matchdriver"},
|
||||
{MATCH_TAG, "matchtag"},
|
||||
{MATCH_IS_KEYBOARD, "matchiskeyboard"},
|
||||
{MATCH_IS_POINTER, "matchispointer"},
|
||||
|
@ -61,6 +65,18 @@ xf86ConfigSymTabRec InputClassTab[] =
|
|||
|
||||
#define TOKEN_SEP "|"
|
||||
|
||||
static void
|
||||
add_group_entry(struct list *head, char **values)
|
||||
{
|
||||
xf86MatchGroup *group;
|
||||
|
||||
group = malloc(sizeof(*group));
|
||||
if (group) {
|
||||
group->values = values;
|
||||
list_add(&group->entry, head);
|
||||
}
|
||||
}
|
||||
|
||||
XF86ConfInputClassPtr
|
||||
xf86parseInputClassSection(void)
|
||||
{
|
||||
|
@ -69,6 +85,16 @@ xf86parseInputClassSection(void)
|
|||
|
||||
parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
|
||||
|
||||
/* Initialize MatchGroup lists */
|
||||
list_init(&ptr->match_product);
|
||||
list_init(&ptr->match_vendor);
|
||||
list_init(&ptr->match_device);
|
||||
list_init(&ptr->match_os);
|
||||
list_init(&ptr->match_pnpid);
|
||||
list_init(&ptr->match_usbid);
|
||||
list_init(&ptr->match_driver);
|
||||
list_init(&ptr->match_tag);
|
||||
|
||||
while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
|
||||
switch (token) {
|
||||
case COMMENT:
|
||||
|
@ -96,22 +122,50 @@ xf86parseInputClassSection(void)
|
|||
case MATCH_PRODUCT:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchProduct");
|
||||
ptr->match_product = xstrtokenize(val.str, TOKEN_SEP);
|
||||
add_group_entry(&ptr->match_product,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_VENDOR:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchVendor");
|
||||
ptr->match_vendor = xstrtokenize(val.str, TOKEN_SEP);
|
||||
add_group_entry(&ptr->match_vendor,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_DEVICE_PATH:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchDevicePath");
|
||||
ptr->match_device = xstrtokenize(val.str, TOKEN_SEP);
|
||||
add_group_entry(&ptr->match_device,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_OS:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchOS");
|
||||
add_group_entry(&ptr->match_os,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_PNPID:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchPnPID");
|
||||
add_group_entry(&ptr->match_pnpid,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_USBID:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchUSBID");
|
||||
add_group_entry(&ptr->match_usbid,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_DRIVER:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchDriver");
|
||||
add_group_entry(&ptr->match_driver,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_TAG:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
Error(QUOTE_MSG, "MatchTag");
|
||||
ptr->match_tag = xstrtokenize(val.str, TOKEN_SEP);
|
||||
add_group_entry(&ptr->match_tag,
|
||||
xstrtokenize(val.str, TOKEN_SEP));
|
||||
break;
|
||||
case MATCH_IS_KEYBOARD:
|
||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||
|
@ -183,7 +237,8 @@ xf86parseInputClassSection(void)
|
|||
void
|
||||
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
|
||||
{
|
||||
char **list;
|
||||
const xf86MatchGroup *group;
|
||||
char * const *cur;
|
||||
|
||||
while (ptr) {
|
||||
fprintf(cf, "Section \"InputClass\"\n");
|
||||
|
@ -193,38 +248,64 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
|
|||
fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier);
|
||||
if (ptr->driver)
|
||||
fprintf(cf, "\tDriver \"%s\"\n", ptr->driver);
|
||||
if (ptr->match_product) {
|
||||
|
||||
list_for_each_entry(group, &ptr->match_product, entry) {
|
||||
fprintf(cf, "\tMatchProduct \"");
|
||||
for (list = ptr->match_product; *list; list++)
|
||||
fprintf(cf, "%s%s",
|
||||
list == ptr->match_product ? "" : TOKEN_SEP,
|
||||
*list);
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
if (ptr->match_vendor) {
|
||||
list_for_each_entry(group, &ptr->match_vendor, entry) {
|
||||
fprintf(cf, "\tMatchVendor \"");
|
||||
for (list = ptr->match_vendor; *list; list++)
|
||||
fprintf(cf, "%s%s",
|
||||
list == ptr->match_vendor ? "" : TOKEN_SEP,
|
||||
*list);
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
if (ptr->match_device) {
|
||||
list_for_each_entry(group, &ptr->match_device, entry) {
|
||||
fprintf(cf, "\tMatchDevicePath \"");
|
||||
for (list = ptr->match_device; *list; list++)
|
||||
fprintf(cf, "%s%s",
|
||||
list == ptr->match_device ? "" : TOKEN_SEP,
|
||||
*list);
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
if (ptr->match_tag) {
|
||||
fprintf(cf, "\tMatchTag \"");
|
||||
for (list = ptr->match_tag; *list; list++)
|
||||
fprintf(cf, "%s%s",
|
||||
list == ptr->match_tag ? "" : TOKEN_SEP,
|
||||
*list);
|
||||
list_for_each_entry(group, &ptr->match_os, entry) {
|
||||
fprintf(cf, "\tMatchOS \"");
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
list_for_each_entry(group, &ptr->match_pnpid, entry) {
|
||||
fprintf(cf, "\tMatchPnPID \"");
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
list_for_each_entry(group, &ptr->match_usbid, entry) {
|
||||
fprintf(cf, "\tMatchUSBID \"");
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
list_for_each_entry(group, &ptr->match_driver, entry) {
|
||||
fprintf(cf, "\tMatchDriver \"");
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
list_for_each_entry(group, &ptr->match_tag, entry) {
|
||||
fprintf(cf, "\tMatchTag \"");
|
||||
for (cur = group->values; *cur; cur++)
|
||||
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||
*cur);
|
||||
fprintf(cf, "\"\n");
|
||||
}
|
||||
|
||||
if (ptr->is_keyboard.set)
|
||||
fprintf(cf, "\tIsKeyboard \"%s\"\n",
|
||||
ptr->is_keyboard.val ? "yes" : "no");
|
||||
|
@ -253,31 +334,63 @@ void
|
|||
xf86freeInputClassList (XF86ConfInputClassPtr ptr)
|
||||
{
|
||||
XF86ConfInputClassPtr prev;
|
||||
char **list;
|
||||
|
||||
while (ptr) {
|
||||
xf86MatchGroup *group, *next;
|
||||
char **list;
|
||||
|
||||
TestFree(ptr->identifier);
|
||||
TestFree(ptr->driver);
|
||||
if (ptr->match_product) {
|
||||
for (list = ptr->match_product; *list; list++)
|
||||
|
||||
list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(ptr->match_product);
|
||||
free(group);
|
||||
}
|
||||
if (ptr->match_vendor) {
|
||||
for (list = ptr->match_vendor; *list; list++)
|
||||
list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(ptr->match_vendor);
|
||||
free(group);
|
||||
}
|
||||
if (ptr->match_device) {
|
||||
for (list = ptr->match_device; *list; list++)
|
||||
list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(ptr->match_device);
|
||||
free(group);
|
||||
}
|
||||
if (ptr->match_tag) {
|
||||
for (list = ptr->match_tag; *list; list++)
|
||||
list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(ptr->match_tag);
|
||||
free(group);
|
||||
}
|
||||
list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(group);
|
||||
}
|
||||
list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(group);
|
||||
}
|
||||
list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(group);
|
||||
}
|
||||
list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
|
||||
list_del(&group->entry);
|
||||
for (list = group->values; *list; list++)
|
||||
free(*list);
|
||||
free(group);
|
||||
}
|
||||
|
||||
TestFree(ptr->comment);
|
||||
xf86optionListFree(ptr->option_lst);
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
|
||||
#include <X11/Xdefs.h>
|
||||
#include "xf86Optrec.h"
|
||||
#include "list.h"
|
||||
|
||||
#define HAVE_PARSER_DECLS
|
||||
|
||||
|
@ -338,15 +339,26 @@ typedef struct
|
|||
}
|
||||
xf86TriState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list entry;
|
||||
char **values;
|
||||
}
|
||||
xf86MatchGroup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GenericListRec list;
|
||||
char *identifier;
|
||||
char *driver;
|
||||
char **match_product;
|
||||
char **match_vendor;
|
||||
char **match_device;
|
||||
char **match_tag;
|
||||
struct list match_product;
|
||||
struct list match_vendor;
|
||||
struct list match_device;
|
||||
struct list match_os;
|
||||
struct list match_pnpid;
|
||||
struct list match_usbid;
|
||||
struct list match_driver;
|
||||
struct list match_tag;
|
||||
xf86TriState is_keyboard;
|
||||
xf86TriState is_pointer;
|
||||
xf86TriState is_joystick;
|
||||
|
|
|
@ -279,6 +279,10 @@ typedef enum {
|
|||
MATCH_PRODUCT,
|
||||
MATCH_VENDOR,
|
||||
MATCH_DEVICE_PATH,
|
||||
MATCH_OS,
|
||||
MATCH_PNPID,
|
||||
MATCH_USBID,
|
||||
MATCH_DRIVER,
|
||||
MATCH_TAG,
|
||||
MATCH_IS_KEYBOARD,
|
||||
MATCH_IS_POINTER,
|
||||
|
|
|
@ -222,6 +222,9 @@
|
|||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#undef HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/vm86.h> header file. */
|
||||
#undef HAVE_SYS_VM86_H
|
||||
|
||||
|
|
|
@ -215,6 +215,8 @@ typedef struct _InputAttributes {
|
|||
char *product;
|
||||
char *vendor;
|
||||
char *device;
|
||||
char *pnp_id;
|
||||
char *usb_id;
|
||||
char **tags; /* null-terminated */
|
||||
uint32_t flags;
|
||||
} InputAttributes;
|
||||
|
|
24
test/input.c
24
test/input.c
|
@ -801,6 +801,20 @@ static void cmp_attr_fields(InputAttributes *attr1,
|
|||
} else
|
||||
g_assert(attr2->device == NULL);
|
||||
|
||||
if (attr1->pnp_id != NULL)
|
||||
{
|
||||
g_assert(attr1->pnp_id != attr2->pnp_id);
|
||||
g_assert(strcmp(attr1->pnp_id, attr2->pnp_id) == 0);
|
||||
} else
|
||||
g_assert(attr2->pnp_id == NULL);
|
||||
|
||||
if (attr1->usb_id != NULL)
|
||||
{
|
||||
g_assert(attr1->usb_id != attr2->usb_id);
|
||||
g_assert(strcmp(attr1->usb_id, attr2->usb_id) == 0);
|
||||
} else
|
||||
g_assert(attr2->usb_id == NULL);
|
||||
|
||||
tags1 = attr1->tags;
|
||||
tags2 = attr2->tags;
|
||||
|
||||
|
@ -866,6 +880,16 @@ static void dix_input_attributes(void)
|
|||
cmp_attr_fields(&orig, new);
|
||||
FreeInputAttributes(new);
|
||||
|
||||
orig.pnp_id = "PnPID";
|
||||
new = DuplicateInputAttributes(&orig);
|
||||
cmp_attr_fields(&orig, new);
|
||||
FreeInputAttributes(new);
|
||||
|
||||
orig.usb_id = "USBID";
|
||||
new = DuplicateInputAttributes(&orig);
|
||||
cmp_attr_fields(&orig, new);
|
||||
FreeInputAttributes(new);
|
||||
|
||||
orig.flags = 0xF0;
|
||||
new = DuplicateInputAttributes(&orig);
|
||||
cmp_attr_fields(&orig, new);
|
||||
|
|
Loading…
Reference in New Issue
Block a user