diff --git a/Makefile b/Makefile index 73d20dc..3ed066b 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ all: sed -e 's#@PREFIX@#$(PREFIX)#' src/vkbd/usb-gadget.service.in > src/vkbd/usb-gadget.service $(CC) $(CFLAGS) -O3 $(COMPAT_FILES) src/*.c src/vkbd/$(VKBD).c -lpthread -o bin/keyd $(LDFLAGS) debug: - CFLAGS="-g -Wunused" $(MAKE) + CFLAGS="-g -fsanitize=address -Wunused" $(MAKE) compose: -mkdir data ./scripts/generate_xcompose diff --git a/data/keyd-application-mapper.1.gz b/data/keyd-application-mapper.1.gz index 30c69d3..af4a6a8 100644 Binary files a/data/keyd-application-mapper.1.gz and b/data/keyd-application-mapper.1.gz differ diff --git a/data/keyd.1.gz b/data/keyd.1.gz index 4a67f0c..27d5fb9 100644 Binary files a/data/keyd.1.gz and b/data/keyd.1.gz differ diff --git a/docs/keyd.scdoc b/docs/keyd.scdoc index 56e09da..aa2c41d 100644 --- a/docs/keyd.scdoc +++ b/docs/keyd.scdoc @@ -75,8 +75,8 @@ section that has one of the following forms: ``` [ids] - : - : + + ... ``` @@ -86,8 +86,8 @@ or [ids] * - -: - -: + - + - ... ``` @@ -107,12 +107,12 @@ Will match all devices which *do not*(2) have the id _0123:4567_, while: ``` [ids] + 0123:4567 ``` -will exclusively match any devices which do. Note that you can obtain -the ':' specifiers from the monitor command (see -_COMMANDS_). +will exclusively match any devices which do. Device ids can be obtained from +the monitor command (see _COMMANDS_). Each subsequent section of the file corresponds to a _layer_ (with the exception of _[global]_ (see _GLOBALS_). @@ -120,7 +120,7 @@ of _[global]_ (see _GLOBALS_). Config errors will appear in the log output and can be accessed in the usual way using your system's service manager (e.g sudo journalctl -eu keyd). -If a vendor/product pair matches more than one device type, the prefix k: may +If an id matches more than one device type, the prefix k: may be used to exclusively match keyboards and the prefix m: may be used to exclusively match mice. (E.g m:046d:b01d) diff --git a/src/config.c b/src/config.c index 5b65566..d3b301c 100644 --- a/src/config.c +++ b/src/config.c @@ -773,39 +773,28 @@ static void parse_id_section(struct config *config, struct ini_section *section) if (!strcmp(s, "*")) { config->wildcard = 1; + } else if (strstr(s, "m:") == s) { + assert(config->nr_ids < ARRAY_SIZE(config->ids)); + config->ids[config->nr_ids].flags = ID_MOUSE; + + snprintf(config->ids[config->nr_ids++].id, sizeof(config->ids[0].id), "%s", s+2); + } else if (strstr(s, "k:") == s) { + assert(config->nr_ids < ARRAY_SIZE(config->ids)); + config->ids[config->nr_ids].flags = ID_KEYBOARD; + + snprintf(config->ids[config->nr_ids++].id, sizeof(config->ids[0].id), "%s", s+2); + } else if (strstr(s, "-") == s) { + assert(config->nr_ids < ARRAY_SIZE(config->ids)); + config->ids[config->nr_ids].flags = ID_EXCLUDED; + + snprintf(config->ids[config->nr_ids++].id, sizeof(config->ids[0].id), "%s", s+1); + } else if (strlen(s) < sizeof(config->ids[config->nr_ids].id)-1) { + assert(config->nr_ids < ARRAY_SIZE(config->ids)); + config->ids[config->nr_ids].flags = ID_KEYBOARD | ID_MOUSE; + + snprintf(config->ids[config->nr_ids++].id, sizeof(config->ids[0].id), "%s", s); } else { - if (sscanf(s, "m:%hx:%hx", &vendor, &product) == 2) { - assert(config->nr_ids < ARRAY_SIZE(config->ids)); - config->ids[config->nr_ids].product = product; - config->ids[config->nr_ids].vendor = vendor; - config->ids[config->nr_ids].flags = ID_MOUSE; - - config->nr_ids++; - } else if (sscanf(s, "k:%hx:%hx", &vendor, &product) == 2) { - assert(config->nr_ids < ARRAY_SIZE(config->ids)); - config->ids[config->nr_ids].product = product; - config->ids[config->nr_ids].vendor = vendor; - config->ids[config->nr_ids].flags = ID_KEYBOARD; - - config->nr_ids++; - } else if (sscanf(s, "-%hx:%hx", &vendor, &product) == 2) { - assert(config->nr_ids < ARRAY_SIZE(config->ids)); - config->ids[config->nr_ids].product = product; - config->ids[config->nr_ids].vendor = vendor; - config->ids[config->nr_ids].flags = ID_EXCLUDED; - - config->nr_ids++; - } else if (sscanf(s, "%hx:%hx", &vendor, &product) == 2) { - assert(config->nr_ids < ARRAY_SIZE(config->ids)); - config->ids[config->nr_ids].product = product; - config->ids[config->nr_ids].vendor = vendor; - config->ids[config->nr_ids].flags = ID_KEYBOARD | ID_MOUSE; - - config->nr_ids++; - } - else { - warn("%s is not a valid device id", s); - } + warn("%s is not a valid device id", s); } } } @@ -958,12 +947,13 @@ int config_parse(struct config *config, const char *path) return config_parse_string(config, content); } -int config_check_match(struct config *config, uint16_t vendor, uint16_t product, uint8_t flags) +int config_check_match(struct config *config, const char *id, uint8_t flags) { size_t i; for (i = 0; i < config->nr_ids; i++) { - if (config->ids[i].product == product && config->ids[i].vendor == vendor) { + //Prefix match to allow matching : for backward compatibility. + if (strstr(id, config->ids[i].id) == id) { if (config->ids[i].flags & ID_EXCLUDED) { return 0; } else if (config->ids[i].flags & flags) { diff --git a/src/config.h b/src/config.h index 3fc402c..953e2c9 100644 --- a/src/config.h +++ b/src/config.h @@ -120,8 +120,7 @@ struct config { uint8_t wildcard; struct { - uint16_t product; - uint16_t vendor; + char id[64]; uint8_t flags; } ids[64]; @@ -152,6 +151,6 @@ int config_parse(struct config *config, const char *path); int config_add_entry(struct config *config, const char *exp); int config_get_layer_index(const struct config *config, const char *name); -int config_check_match(struct config *config, uint16_t vendor, uint16_t product, uint8_t flags); +int config_check_match(struct config *config, const char *id, uint8_t flags); #endif diff --git a/src/daemon.c b/src/daemon.c index 1ef17c8..9033372 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -182,16 +182,14 @@ static void load_configs() closedir(dh); } -static struct config_ent *lookup_config_ent(uint16_t vendor, - uint16_t product, - uint8_t flags) +static struct config_ent *lookup_config_ent(const char *id, uint8_t flags) { struct config_ent *ent = configs; struct config_ent *match = NULL; int rank = 0; while (ent) { - int r = config_check_match(&ent->config, vendor, product, flags); + int r = config_check_match(&ent->config, id, flags); if (r > rank) { match = ent; @@ -221,24 +219,21 @@ static void manage_device(struct device *dev) if (dev->capabilities & (CAP_MOUSE|CAP_MOUSE_ABS)) flags |= ID_MOUSE; - if ((ent = lookup_config_ent(dev->vendor_id, dev->product_id, flags))) { + if ((ent = lookup_config_ent(dev->id, flags))) { if (device_grab(dev)) { keyd_log("DEVICE: y{WARNING} Failed to grab %s\n", dev->path); dev->data = NULL; return; } - keyd_log("DEVICE: g{match} %04hx:%04hx %s\t(%s)\n", - dev->vendor_id, dev->product_id, - ent->config.path, - dev->name); + keyd_log("DEVICE: g{match} %s %s\t(%s)\n", + dev->id, ent->config.path, dev->name); dev->data = ent->kbd; } else { dev->data = NULL; device_ungrab(dev); - keyd_log("DEVICE: r{ignoring} %04hx:%04hx (%s)\n", - dev->vendor_id, dev->product_id, dev->name); + keyd_log("DEVICE: r{ignoring} %s (%s)\n", dev->id, dev->name); } } @@ -523,10 +518,7 @@ static int event_handler(struct event *ev) manage_device(ev->dev); break; case EV_DEV_REMOVE: - keyd_log("DEVICE: r{removed}\t%04hx:%04hx %s\n", - ev->dev->vendor_id, - ev->dev->product_id, - ev->dev->name); + keyd_log("DEVICE: r{removed}\t%s %s\n", ev->dev->id, ev->dev->name); break; case EV_FD_ACTIVITY: diff --git a/src/device.c b/src/device.c index 39724ca..56adbaf 100644 --- a/src/device.c +++ b/src/device.c @@ -41,7 +41,7 @@ * corresponding device should be considered invalid by the caller. */ -static uint8_t resolve_device_capabilities(int fd) +static uint8_t resolve_device_capabilities(int fd, int *num_keys, uint8_t *relmask, uint8_t *absmask) { const uint32_t keyboard_mask = 1<name)), dev->name) == -1) { keyd_log("ERROR: could not fetch device name of %s\n", dev->path); @@ -144,10 +150,18 @@ static int device_init(const char *path, struct device *dev) strncpy(dev->path, path, sizeof(dev->path)-1); dev->path[sizeof(dev->path)-1] = 0; + /* + * Attempt to generate a reproducible unique identifier for each device. + * The product and vendor ids are insufficient to identify some devices since + * they can create multiple device nodes with different capabilities. Thus + * we factor in the capabilities of the resultant evdev node to + * further distinguish between input devices. These should be + * regarded as opaque identifiers by the user. + */ + snprintf(dev->id, sizeof dev->id, "%04x:%04x:%04x%02x%02x", info.vendor, info.product, num_keys, absmask, relmask); + dev->fd = fd; dev->capabilities = capabilities; - dev->vendor_id = info.vendor; - dev->product_id = info.product; dev->data = NULL; dev->grabbed = 0; diff --git a/src/device.h b/src/device.h index 6a8718b..bf306c6 100644 --- a/src/device.h +++ b/src/device.h @@ -23,10 +23,9 @@ struct device { uint8_t grabbed; uint8_t capabilities; - uint16_t product_id; - uint16_t vendor_id; uint8_t is_virtual; + char id[64]; char name[64]; char path[256]; diff --git a/src/monitor.c b/src/monitor.c index aed5bb0..86142e5 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -38,14 +38,12 @@ int event_handler(struct event *ev) const char *name; case EV_DEV_ADD: - keyd_log("device added: %04x:%04x %s (%s)\n", - ev->dev->vendor_id, ev->dev->product_id, - ev->dev->name, ev->dev->path); + keyd_log("device added: %s %s (%s)\n", + ev->dev->id, ev->dev->name, ev->dev->path); break; case EV_DEV_REMOVE: - keyd_log("device removed: %04x:%04x %s (%s)\n", - ev->dev->vendor_id, ev->dev->product_id, - ev->dev->name, ev->dev->path); + keyd_log("device removed: %s %s (%s)\n", + ev->dev->id, ev->dev->name, ev->dev->path); break; case EV_DEV_EVENT: switch (ev->devev->type) { @@ -55,11 +53,9 @@ int event_handler(struct event *ev) if (time_flag) keyd_log("r{+%ld} ms\t", ev->timestamp - last_time); - keyd_log("%s\t%04x:%04x\t%s %s\n", - ev->dev->name, - ev->dev->vendor_id, - ev->dev->product_id, name, - ev->devev->pressed ? "down" : "up"); + keyd_log("%s\t%s\t%s %s\n", + ev->dev->name, ev->dev->id, + name, ev->devev->pressed ? "down" : "up"); break; default: