Merge remote branch 'whot/for-keith'
This commit is contained in:
commit
07a093add0
|
@ -193,16 +193,12 @@ void
|
||||||
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
|
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
|
||||||
{
|
{
|
||||||
KeyClassPtr mk = master->key;
|
KeyClassPtr mk = master->key;
|
||||||
KeyClassPtr dk = device->key;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (device == master)
|
if (device == master)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mk->sourceid = device->id;
|
mk->sourceid = device->id;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
|
||||||
mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
|
|
||||||
|
|
||||||
if (!XkbCopyDeviceKeymap(master, device))
|
if (!XkbCopyDeviceKeymap(master, device))
|
||||||
FatalError("Couldn't pivot keymap from device to core!\n");
|
FatalError("Couldn't pivot keymap from device to core!\n");
|
||||||
|
|
|
@ -36,4 +36,4 @@ endif # CONFIG_NEED_DBUS
|
||||||
|
|
||||||
endif # !CONFIG_UDEV
|
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>
|
#include <dix-config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DBUS_API_SUBJECT_TO_CHANGE
|
|
||||||
#include <dbus/dbus.h>
|
#include <dbus/dbus.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
|
@ -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)
|
device_added(LibHalContext *hal_ctx, const char *udi)
|
||||||
{
|
{
|
||||||
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
|
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
|
||||||
|
char *hal_tags, *parent;
|
||||||
InputOption *options = NULL, *tmpo = NULL;
|
InputOption *options = NULL, *tmpo = NULL;
|
||||||
InputAttributes attrs = {0};
|
InputAttributes attrs = {0};
|
||||||
DeviceIntPtr dev = NULL;
|
DeviceIntPtr dev = NULL;
|
||||||
|
@ -164,7 +165,9 @@ device_added(LibHalContext *hal_ctx, const char *udi)
|
||||||
attrs.product = xstrdup(name);
|
attrs.product = xstrdup(name);
|
||||||
|
|
||||||
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
|
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))
|
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
|
||||||
attrs.flags |= ATTR_KEYBOARD;
|
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))
|
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
|
||||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
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);
|
options = calloc(sizeof(*options), 1);
|
||||||
if (!options){
|
if (!options){
|
||||||
LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n");
|
LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n");
|
||||||
|
@ -381,6 +407,8 @@ unwind:
|
||||||
free(attrs.product);
|
free(attrs.product);
|
||||||
free(attrs.vendor);
|
free(attrs.vendor);
|
||||||
free(attrs.device);
|
free(attrs.device);
|
||||||
|
free(attrs.pnp_id);
|
||||||
|
free(attrs.usb_id);
|
||||||
if (attrs.tags) {
|
if (attrs.tags) {
|
||||||
char **tag = attrs.tags;
|
char **tag = attrs.tags;
|
||||||
while (*tag) {
|
while (*tag) {
|
||||||
|
@ -619,7 +647,7 @@ config_hal_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verbose message */
|
/* verbose message */
|
||||||
LogMessageVerb(X_INFO,7,"config/hal: initialized");
|
LogMessageVerb(X_INFO,7,"config/hal: initialized\n");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "inputstr.h"
|
#include "inputstr.h"
|
||||||
|
@ -37,6 +38,17 @@
|
||||||
|
|
||||||
#define UDEV_XKB_PROP_KEY "xkb"
|
#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 struct udev_monitor *udev_monitor;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -45,6 +57,8 @@ device_added(struct udev_device *udev_device)
|
||||||
const char *path, *name = NULL;
|
const char *path, *name = NULL;
|
||||||
char *config_info = NULL;
|
char *config_info = NULL;
|
||||||
const char *syspath;
|
const char *syspath;
|
||||||
|
const char *tags_prop;
|
||||||
|
const char *usb_vendor = NULL, *usb_model = NULL;
|
||||||
const char *key, *value, *tmp;
|
const char *key, *value, *tmp;
|
||||||
InputOption *options = NULL, *tmpo;
|
InputOption *options = NULL, *tmpo;
|
||||||
InputAttributes attrs = {};
|
InputAttributes attrs = {};
|
||||||
|
@ -60,8 +74,13 @@ device_added(struct udev_device *udev_device)
|
||||||
if (!path || !syspath)
|
if (!path || !syspath)
|
||||||
return;
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
options = calloc(sizeof(*options), 1);
|
options = calloc(sizeof(*options), 1);
|
||||||
if (!options)
|
if (!options)
|
||||||
|
@ -74,9 +93,17 @@ device_added(struct udev_device *udev_device)
|
||||||
|
|
||||||
parent = udev_device_get_parent(udev_device);
|
parent = udev_device_get_parent(udev_device);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
const char *ppath = udev_device_get_devnode(parent);
|
||||||
|
|
||||||
name = udev_device_get_sysattr_value(parent, "name");
|
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");
|
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)
|
if (!name)
|
||||||
name = "(unnamed)";
|
name = "(unnamed)";
|
||||||
|
@ -87,7 +114,10 @@ device_added(struct udev_device *udev_device)
|
||||||
add_option(&options, "path", path);
|
add_option(&options, "path", path);
|
||||||
add_option(&options, "device", path);
|
add_option(&options, "device", path);
|
||||||
attrs.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);
|
config_info = Xprintf("udev:%s", syspath);
|
||||||
if (!config_info)
|
if (!config_info)
|
||||||
|
@ -107,6 +137,7 @@ device_added(struct udev_device *udev_device)
|
||||||
value = udev_list_entry_get_value(entry);
|
value = udev_list_entry_get_value(entry);
|
||||||
if (!strncasecmp(key, UDEV_XKB_PROP_KEY,
|
if (!strncasecmp(key, UDEV_XKB_PROP_KEY,
|
||||||
sizeof(UDEV_XKB_PROP_KEY) - 1)) {
|
sizeof(UDEV_XKB_PROP_KEY) - 1)) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
|
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
|
||||||
if (!strcasecmp(tmp, "rules"))
|
if (!strcasecmp(tmp, "rules"))
|
||||||
add_option(&options, "xkb_rules", value);
|
add_option(&options, "xkb_rules", value);
|
||||||
|
@ -119,21 +150,45 @@ device_added(struct udev_device *udev_device)
|
||||||
else if (!strcasecmp(tmp, "options"))
|
else if (!strcasecmp(tmp, "options"))
|
||||||
add_option(&options, "xkb_options", value);
|
add_option(&options, "xkb_options", value);
|
||||||
} else if (!strcmp(key, "ID_VENDOR")) {
|
} else if (!strcmp(key, "ID_VENDOR")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.vendor = 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")) {
|
} else if (!strcmp(key, "ID_INPUT_KEY")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_KEYBOARD;
|
attrs.flags |= ATTR_KEYBOARD;
|
||||||
} else if (!strcmp(key, "ID_INPUT_MOUSE")) {
|
} else if (!strcmp(key, "ID_INPUT_MOUSE")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_POINTER;
|
attrs.flags |= ATTR_POINTER;
|
||||||
} else if (!strcmp(key, "ID_INPUT_JOYSTICK")) {
|
} else if (!strcmp(key, "ID_INPUT_JOYSTICK")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_JOYSTICK;
|
attrs.flags |= ATTR_JOYSTICK;
|
||||||
} else if (!strcmp(key, "ID_INPUT_TABLET")) {
|
} else if (!strcmp(key, "ID_INPUT_TABLET")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_TABLET;
|
attrs.flags |= ATTR_TABLET;
|
||||||
} else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) {
|
} else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_TOUCHPAD;
|
attrs.flags |= ATTR_TOUCHPAD;
|
||||||
} else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
|
} else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
|
||||||
|
LOG_PROPERTY(path, key, value);
|
||||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
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",
|
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
|
||||||
name, path);
|
name, path);
|
||||||
rc = NewInputDeviceRequest(options, &attrs, &dev);
|
rc = NewInputDeviceRequest(options, &attrs, &dev);
|
||||||
|
@ -154,6 +209,7 @@ device_added(struct udev_device *udev_device)
|
||||||
free(tmpo);
|
free(tmpo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(attrs.usb_id);
|
||||||
if (attrs.tags) {
|
if (attrs.tags) {
|
||||||
char **tag = attrs.tags;
|
char **tag = attrs.tags;
|
||||||
while (*tag) {
|
while (*tag) {
|
||||||
|
|
|
@ -123,7 +123,7 @@ AM_CONDITIONAL(SPECIAL_DTRACE_OBJECTS, [test "x$SPECIAL_DTRACE_OBJECTS" = "xyes"
|
||||||
|
|
||||||
AC_HEADER_DIRENT
|
AC_HEADER_DIRENT
|
||||||
AC_HEADER_STDC
|
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.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
|
@ -809,6 +809,7 @@ LIBPCIACCESS="pciaccess >= 0.8.0"
|
||||||
LIBGLIB="glib-2.0 >= 2.16"
|
LIBGLIB="glib-2.0 >= 2.16"
|
||||||
LIBUDEV="libudev >= 143"
|
LIBUDEV="libudev >= 143"
|
||||||
LIBSELINUX="libselinux >= 2.0.86"
|
LIBSELINUX="libselinux >= 2.0.86"
|
||||||
|
LIBDBUS="dbus-1 >= 1.0"
|
||||||
|
|
||||||
if test "x$CONFIG_UDEV" = xyes &&
|
if test "x$CONFIG_UDEV" = xyes &&
|
||||||
{ test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then
|
{ 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 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 CONFIG_DBUS_API is true if we want to enable the D-Bus config
|
||||||
dnl API.
|
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
|
if test "x$HAVE_DBUS" = xyes; then
|
||||||
AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support])
|
AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support])
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -357,6 +357,10 @@ DuplicateInputAttributes(InputAttributes *attrs)
|
||||||
goto unwind;
|
goto unwind;
|
||||||
if (attrs->device && !(new_attr->device = strdup(attrs->device)))
|
if (attrs->device && !(new_attr->device = strdup(attrs->device)))
|
||||||
goto unwind;
|
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;
|
new_attr->flags = attrs->flags;
|
||||||
|
|
||||||
|
@ -401,6 +405,8 @@ FreeInputAttributes(InputAttributes *attrs)
|
||||||
free(attrs->product);
|
free(attrs->product);
|
||||||
free(attrs->vendor);
|
free(attrs->vendor);
|
||||||
free(attrs->device);
|
free(attrs->device);
|
||||||
|
free(attrs->pnp_id);
|
||||||
|
free(attrs->usb_id);
|
||||||
|
|
||||||
if ((tags = attrs->tags))
|
if ((tags = attrs->tags))
|
||||||
while(*tags)
|
while(*tags)
|
||||||
|
|
|
@ -80,6 +80,9 @@
|
||||||
#ifdef HAVE_FNMATCH_H
|
#ifdef HAVE_FNMATCH_H
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYS_UTSNAME_H
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "extnsionst.h"
|
#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
|
* Classes without any Match statements match all devices. Otherwise, all
|
||||||
* statements must match.
|
* statements must match.
|
||||||
*/
|
*/
|
||||||
static Bool
|
static Bool
|
||||||
InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
InputClassMatches(const XF86ConfInputClassPtr iclass, const IDevPtr idev,
|
||||||
|
const InputAttributes *attrs)
|
||||||
{
|
{
|
||||||
char **cur;
|
/* MatchProduct substring */
|
||||||
Bool match;
|
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)
|
if (!attrs->tags)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
for (tag = attrs->tags, match = FALSE; *tag; tag++) {
|
||||||
for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) {
|
if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
|
||||||
char * const *tag;
|
match = TRUE;
|
||||||
for(tag = attrs->tags; *tag; tag++) {
|
break;
|
||||||
if (!strcmp(*tag, *cur)) {
|
|
||||||
match = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match)
|
if (!match)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MatchIs* booleans */
|
||||||
if (iclass->is_keyboard.set &&
|
if (iclass->is_keyboard.set &&
|
||||||
iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
|
iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -582,6 +664,7 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
||||||
if (iclass->is_touchscreen.set &&
|
if (iclass->is_touchscreen.set &&
|
||||||
iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
|
iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,37 +674,36 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
|
||||||
* well as any previous InputClass sections.
|
* well as any previous InputClass sections.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
|
MergeInputClasses(const IDevPtr idev, const InputAttributes *attrs)
|
||||||
{
|
{
|
||||||
XF86ConfInputClassPtr cl;
|
XF86ConfInputClassPtr cl;
|
||||||
XF86OptionPtr classopts, mergedopts = NULL;
|
XF86OptionPtr classopts;
|
||||||
char *classdriver = NULL;
|
|
||||||
|
|
||||||
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
||||||
if (!InputClassMatches(cl, attrs))
|
if (!InputClassMatches(cl, idev, attrs))
|
||||||
continue;
|
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",
|
xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
|
||||||
idev->identifier, cl->identifier);
|
idev->identifier, cl->identifier);
|
||||||
if (cl->driver)
|
idev->commonOptions = xf86optionListMerge(idev->commonOptions,
|
||||||
classdriver = cl->driver;
|
classopts);
|
||||||
classopts = xf86optionListDup(cl->option_lst);
|
|
||||||
mergedopts = xf86optionListMerge(mergedopts, 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;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,14 +712,14 @@ MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
|
||||||
* value of the last matching class and holler when returning TRUE.
|
* value of the last matching class and holler when returning TRUE.
|
||||||
*/
|
*/
|
||||||
static Bool
|
static Bool
|
||||||
IgnoreInputClass(IDevPtr idev, InputAttributes *attrs)
|
IgnoreInputClass(const IDevPtr idev, const InputAttributes *attrs)
|
||||||
{
|
{
|
||||||
XF86ConfInputClassPtr cl;
|
XF86ConfInputClassPtr cl;
|
||||||
Bool ignore = FALSE;
|
Bool ignore = FALSE;
|
||||||
const char *ignore_class;
|
const char *ignore_class;
|
||||||
|
|
||||||
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
|
||||||
if (!InputClassMatches(cl, attrs))
|
if (!InputClassMatches(cl, idev, attrs))
|
||||||
continue;
|
continue;
|
||||||
if (xf86findOption(cl->option_lst, "Ignore")) {
|
if (xf86findOption(cl->option_lst, "Ignore")) {
|
||||||
ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
|
ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
|
||||||
|
|
|
@ -1065,35 +1065,85 @@ of the class. If none of the optional entries appear, the
|
||||||
.B InputClass
|
.B InputClass
|
||||||
section is generic and will match any input device. If more than one of
|
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.
|
these entries appear, they all must match for the configuration to apply.
|
||||||
The allowed matching entries are shown below.
|
|
||||||
.PP
|
.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
|
.TP 7
|
||||||
.BI "MatchProduct \*q" matchproduct \*q
|
.BI "MatchProduct \*q" matchproduct \*q
|
||||||
This entry can be used to check if the substring
|
This entry can be used to check if the substring
|
||||||
.RI \*q matchproduct \*q
|
.RI \*q matchproduct \*q
|
||||||
occurs in the device's product name. Multiple substrings can be matched by
|
occurs in the device's product name.
|
||||||
separating arguments with a '|' character.
|
|
||||||
.TP 7
|
.TP 7
|
||||||
.BI "MatchVendor \*q" matchvendor \*q
|
.BI "MatchVendor \*q" matchvendor \*q
|
||||||
This entry can be used to check if the substring
|
This entry can be used to check if the substring
|
||||||
.RI \*q matchvendor \*q
|
.RI \*q matchvendor \*q
|
||||||
occurs in the device's vendor name. Multiple substrings can be matched by
|
occurs in the device's vendor name.
|
||||||
separating arguments with a '|' character.
|
|
||||||
.TP 7
|
.TP 7
|
||||||
.BI "MatchDevicePath \*q" matchdevice \*q
|
.BI "MatchDevicePath \*q" matchdevice \*q
|
||||||
This entry can be used to check if the device file matches the
|
This entry can be used to check if the device file matches the
|
||||||
.RI \*q matchdevice \*q
|
.RI \*q matchdevice \*q
|
||||||
pathname pattern. Multiple patterns can be matched by separating arguments
|
pathname pattern.
|
||||||
with a '|' character.
|
.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
|
.TP 7
|
||||||
.BI "MatchTag \*q" matchtag \*q
|
.BI "MatchTag \*q" matchtag \*q
|
||||||
This entry can be used to check if tags assigned by the config backend
|
This entry can be used to check if tags assigned by the config backend
|
||||||
matches the
|
matches the
|
||||||
.RI \*q matchtag \*q
|
.RI \*q matchtag \*q
|
||||||
pattern. Multiple patterns can be matched by separating arguments
|
pattern. A match is found if at least one of the tags given in
|
||||||
with a '|' character. A match is found if at least one of the tags given in
|
|
||||||
.RI \*q matchtag \*q
|
.RI \*q matchtag \*q
|
||||||
matches at least one of the tags assigned by the backend.
|
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
|
.TP 7
|
||||||
.BI "MatchIsKeyboard \*q" bool \*q
|
.BI "MatchIsKeyboard \*q" bool \*q
|
||||||
.TP 7
|
.TP 7
|
||||||
|
@ -1106,9 +1156,6 @@ matches at least one of the tags assigned by the backend.
|
||||||
.BI "MatchIsTouchpad \*q" bool \*q
|
.BI "MatchIsTouchpad \*q" bool \*q
|
||||||
.TP 7
|
.TP 7
|
||||||
.BI "MatchIsTouchscreen \*q" bool \*q
|
.BI "MatchIsTouchscreen \*q" bool \*q
|
||||||
Match device types. These entries take a boolean argument similar to
|
|
||||||
.B Option
|
|
||||||
entries.
|
|
||||||
.PP
|
.PP
|
||||||
When an input device has been matched to the
|
When an input device has been matched to the
|
||||||
.B InputClass
|
.B InputClass
|
||||||
|
|
|
@ -47,6 +47,10 @@ xf86ConfigSymTabRec InputClassTab[] =
|
||||||
{MATCH_PRODUCT, "matchproduct"},
|
{MATCH_PRODUCT, "matchproduct"},
|
||||||
{MATCH_VENDOR, "matchvendor"},
|
{MATCH_VENDOR, "matchvendor"},
|
||||||
{MATCH_DEVICE_PATH, "matchdevicepath"},
|
{MATCH_DEVICE_PATH, "matchdevicepath"},
|
||||||
|
{MATCH_OS, "matchos"},
|
||||||
|
{MATCH_PNPID, "matchpnpid"},
|
||||||
|
{MATCH_USBID, "matchusbid"},
|
||||||
|
{MATCH_DRIVER, "matchdriver"},
|
||||||
{MATCH_TAG, "matchtag"},
|
{MATCH_TAG, "matchtag"},
|
||||||
{MATCH_IS_KEYBOARD, "matchiskeyboard"},
|
{MATCH_IS_KEYBOARD, "matchiskeyboard"},
|
||||||
{MATCH_IS_POINTER, "matchispointer"},
|
{MATCH_IS_POINTER, "matchispointer"},
|
||||||
|
@ -61,6 +65,18 @@ xf86ConfigSymTabRec InputClassTab[] =
|
||||||
|
|
||||||
#define TOKEN_SEP "|"
|
#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
|
XF86ConfInputClassPtr
|
||||||
xf86parseInputClassSection(void)
|
xf86parseInputClassSection(void)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +85,16 @@ xf86parseInputClassSection(void)
|
||||||
|
|
||||||
parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
|
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) {
|
while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
|
@ -96,22 +122,50 @@ xf86parseInputClassSection(void)
|
||||||
case MATCH_PRODUCT:
|
case MATCH_PRODUCT:
|
||||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||||
Error(QUOTE_MSG, "MatchProduct");
|
Error(QUOTE_MSG, "MatchProduct");
|
||||||
ptr->match_product = xstrtokenize(val.str, TOKEN_SEP);
|
add_group_entry(&ptr->match_product,
|
||||||
|
xstrtokenize(val.str, TOKEN_SEP));
|
||||||
break;
|
break;
|
||||||
case MATCH_VENDOR:
|
case MATCH_VENDOR:
|
||||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||||
Error(QUOTE_MSG, "MatchVendor");
|
Error(QUOTE_MSG, "MatchVendor");
|
||||||
ptr->match_vendor = xstrtokenize(val.str, TOKEN_SEP);
|
add_group_entry(&ptr->match_vendor,
|
||||||
|
xstrtokenize(val.str, TOKEN_SEP));
|
||||||
break;
|
break;
|
||||||
case MATCH_DEVICE_PATH:
|
case MATCH_DEVICE_PATH:
|
||||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||||
Error(QUOTE_MSG, "MatchDevicePath");
|
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;
|
break;
|
||||||
case MATCH_TAG:
|
case MATCH_TAG:
|
||||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||||
Error(QUOTE_MSG, "MatchTag");
|
Error(QUOTE_MSG, "MatchTag");
|
||||||
ptr->match_tag = xstrtokenize(val.str, TOKEN_SEP);
|
add_group_entry(&ptr->match_tag,
|
||||||
|
xstrtokenize(val.str, TOKEN_SEP));
|
||||||
break;
|
break;
|
||||||
case MATCH_IS_KEYBOARD:
|
case MATCH_IS_KEYBOARD:
|
||||||
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
if (xf86getSubToken(&(ptr->comment)) != STRING)
|
||||||
|
@ -183,7 +237,8 @@ xf86parseInputClassSection(void)
|
||||||
void
|
void
|
||||||
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
|
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
|
||||||
{
|
{
|
||||||
char **list;
|
const xf86MatchGroup *group;
|
||||||
|
char * const *cur;
|
||||||
|
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
fprintf(cf, "Section \"InputClass\"\n");
|
fprintf(cf, "Section \"InputClass\"\n");
|
||||||
|
@ -193,38 +248,64 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
|
||||||
fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier);
|
fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier);
|
||||||
if (ptr->driver)
|
if (ptr->driver)
|
||||||
fprintf(cf, "\tDriver \"%s\"\n", 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 \"");
|
fprintf(cf, "\tMatchProduct \"");
|
||||||
for (list = ptr->match_product; *list; list++)
|
for (cur = group->values; *cur; cur++)
|
||||||
fprintf(cf, "%s%s",
|
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||||
list == ptr->match_product ? "" : TOKEN_SEP,
|
*cur);
|
||||||
*list);
|
|
||||||
fprintf(cf, "\"\n");
|
fprintf(cf, "\"\n");
|
||||||
}
|
}
|
||||||
if (ptr->match_vendor) {
|
list_for_each_entry(group, &ptr->match_vendor, entry) {
|
||||||
fprintf(cf, "\tMatchVendor \"");
|
fprintf(cf, "\tMatchVendor \"");
|
||||||
for (list = ptr->match_vendor; *list; list++)
|
for (cur = group->values; *cur; cur++)
|
||||||
fprintf(cf, "%s%s",
|
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||||
list == ptr->match_vendor ? "" : TOKEN_SEP,
|
*cur);
|
||||||
*list);
|
|
||||||
fprintf(cf, "\"\n");
|
fprintf(cf, "\"\n");
|
||||||
}
|
}
|
||||||
if (ptr->match_device) {
|
list_for_each_entry(group, &ptr->match_device, entry) {
|
||||||
fprintf(cf, "\tMatchDevicePath \"");
|
fprintf(cf, "\tMatchDevicePath \"");
|
||||||
for (list = ptr->match_device; *list; list++)
|
for (cur = group->values; *cur; cur++)
|
||||||
fprintf(cf, "%s%s",
|
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||||
list == ptr->match_device ? "" : TOKEN_SEP,
|
*cur);
|
||||||
*list);
|
|
||||||
fprintf(cf, "\"\n");
|
fprintf(cf, "\"\n");
|
||||||
}
|
}
|
||||||
if (ptr->match_tag) {
|
list_for_each_entry(group, &ptr->match_os, entry) {
|
||||||
fprintf(cf, "\tMatchTag \"");
|
fprintf(cf, "\tMatchOS \"");
|
||||||
for (list = ptr->match_tag; *list; list++)
|
for (cur = group->values; *cur; cur++)
|
||||||
fprintf(cf, "%s%s",
|
fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
|
||||||
list == ptr->match_tag ? "" : TOKEN_SEP,
|
*cur);
|
||||||
*list);
|
|
||||||
fprintf(cf, "\"\n");
|
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)
|
if (ptr->is_keyboard.set)
|
||||||
fprintf(cf, "\tIsKeyboard \"%s\"\n",
|
fprintf(cf, "\tIsKeyboard \"%s\"\n",
|
||||||
ptr->is_keyboard.val ? "yes" : "no");
|
ptr->is_keyboard.val ? "yes" : "no");
|
||||||
|
@ -253,31 +334,63 @@ void
|
||||||
xf86freeInputClassList (XF86ConfInputClassPtr ptr)
|
xf86freeInputClassList (XF86ConfInputClassPtr ptr)
|
||||||
{
|
{
|
||||||
XF86ConfInputClassPtr prev;
|
XF86ConfInputClassPtr prev;
|
||||||
char **list;
|
|
||||||
|
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
|
xf86MatchGroup *group, *next;
|
||||||
|
char **list;
|
||||||
|
|
||||||
TestFree(ptr->identifier);
|
TestFree(ptr->identifier);
|
||||||
TestFree(ptr->driver);
|
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(*list);
|
||||||
free(ptr->match_product);
|
free(group);
|
||||||
}
|
}
|
||||||
if (ptr->match_vendor) {
|
list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
|
||||||
for (list = ptr->match_vendor; *list; list++)
|
list_del(&group->entry);
|
||||||
|
for (list = group->values; *list; list++)
|
||||||
free(*list);
|
free(*list);
|
||||||
free(ptr->match_vendor);
|
free(group);
|
||||||
}
|
}
|
||||||
if (ptr->match_device) {
|
list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
|
||||||
for (list = ptr->match_device; *list; list++)
|
list_del(&group->entry);
|
||||||
|
for (list = group->values; *list; list++)
|
||||||
free(*list);
|
free(*list);
|
||||||
free(ptr->match_device);
|
free(group);
|
||||||
}
|
}
|
||||||
if (ptr->match_tag) {
|
list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
|
||||||
for (list = ptr->match_tag; *list; list++)
|
list_del(&group->entry);
|
||||||
|
for (list = group->values; *list; list++)
|
||||||
free(*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);
|
TestFree(ptr->comment);
|
||||||
xf86optionListFree(ptr->option_lst);
|
xf86optionListFree(ptr->option_lst);
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
|
|
||||||
#include <X11/Xdefs.h>
|
#include <X11/Xdefs.h>
|
||||||
#include "xf86Optrec.h"
|
#include "xf86Optrec.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
#define HAVE_PARSER_DECLS
|
#define HAVE_PARSER_DECLS
|
||||||
|
|
||||||
|
@ -338,15 +339,26 @@ typedef struct
|
||||||
}
|
}
|
||||||
xf86TriState;
|
xf86TriState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
char **values;
|
||||||
|
}
|
||||||
|
xf86MatchGroup;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GenericListRec list;
|
GenericListRec list;
|
||||||
char *identifier;
|
char *identifier;
|
||||||
char *driver;
|
char *driver;
|
||||||
char **match_product;
|
struct list match_product;
|
||||||
char **match_vendor;
|
struct list match_vendor;
|
||||||
char **match_device;
|
struct list match_device;
|
||||||
char **match_tag;
|
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_keyboard;
|
||||||
xf86TriState is_pointer;
|
xf86TriState is_pointer;
|
||||||
xf86TriState is_joystick;
|
xf86TriState is_joystick;
|
||||||
|
|
|
@ -279,6 +279,10 @@ typedef enum {
|
||||||
MATCH_PRODUCT,
|
MATCH_PRODUCT,
|
||||||
MATCH_VENDOR,
|
MATCH_VENDOR,
|
||||||
MATCH_DEVICE_PATH,
|
MATCH_DEVICE_PATH,
|
||||||
|
MATCH_OS,
|
||||||
|
MATCH_PNPID,
|
||||||
|
MATCH_USBID,
|
||||||
|
MATCH_DRIVER,
|
||||||
MATCH_TAG,
|
MATCH_TAG,
|
||||||
MATCH_IS_KEYBOARD,
|
MATCH_IS_KEYBOARD,
|
||||||
MATCH_IS_POINTER,
|
MATCH_IS_POINTER,
|
||||||
|
|
|
@ -222,6 +222,9 @@
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
#undef HAVE_SYS_TYPES_H
|
#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. */
|
/* Define to 1 if you have the <sys/vm86.h> header file. */
|
||||||
#undef HAVE_SYS_VM86_H
|
#undef HAVE_SYS_VM86_H
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,8 @@ typedef struct _InputAttributes {
|
||||||
char *product;
|
char *product;
|
||||||
char *vendor;
|
char *vendor;
|
||||||
char *device;
|
char *device;
|
||||||
|
char *pnp_id;
|
||||||
|
char *usb_id;
|
||||||
char **tags; /* null-terminated */
|
char **tags; /* null-terminated */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
} InputAttributes;
|
} InputAttributes;
|
||||||
|
|
24
test/input.c
24
test/input.c
|
@ -801,6 +801,20 @@ static void cmp_attr_fields(InputAttributes *attr1,
|
||||||
} else
|
} else
|
||||||
g_assert(attr2->device == NULL);
|
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;
|
tags1 = attr1->tags;
|
||||||
tags2 = attr2->tags;
|
tags2 = attr2->tags;
|
||||||
|
|
||||||
|
@ -866,6 +880,16 @@ static void dix_input_attributes(void)
|
||||||
cmp_attr_fields(&orig, new);
|
cmp_attr_fields(&orig, new);
|
||||||
FreeInputAttributes(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;
|
orig.flags = 0xF0;
|
||||||
new = DuplicateInputAttributes(&orig);
|
new = DuplicateInputAttributes(&orig);
|
||||||
cmp_attr_fields(&orig, new);
|
cmp_attr_fields(&orig, new);
|
||||||
|
|
Loading…
Reference in New Issue