MatchName=Foo Bar Touchpad
MatchUdevtype=touchpad
MatchDMIModAlias=dmi:*svnMyVendor:pnMyModel:*
- AttrEventCodeDisable=BTN_RIGHT
+ AttrEventCode=-BTN_RIGHT
The name of the device can be obtained using :ref:`libinput record <libinput-record>`,
the modalias match is a shell-style glob against the value of ``/sys/class/dmi/id/modalias``.
Indicates the position of the touchpad on an external touchpad+keyboard
combination device. This is a string enum. Don't specify it unless the
touchpad is below.
-AttrEventCodeDisable=EV_ABS;BTN_STYLUS;EV_KEY:0x123;
- Disables the evdev event type/code tuples on the device. Entries may be
+AttrEventCode=+EV_ABS;-BTN_STYLUS;+EV_KEY:0x123;
+ Enables or disables the evdev event type/code tuples on the device. The prefix
+ for each entry is either '+' (enable) or '-' (disable). Entries may be
a named event type, or a named event code, or a named event type with a
hexadecimal event code, separated by a single colon.
-AttrEventCodeEnable=EV_ABS;BTN_STYLUS;EV_KEY:0x123;
- Enables the evdev event type/code tuples on the device. Entries may be
- a named event type, or a named event code, or a named event type with a
- hexadecimal event code, separated by a single colon.
-AttrInputPropDisable=INPUT_PROP_BUTTONPAD;INPUT_PROP_POINTER;
- Disables the evdev input property on the device. Entries may be
- a named input property or the hexadecimal value of that property.
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD;INPUT_PROP_POINTER;
- Enables the evdev input property on the device. Entries may be
+AttrInputProp=+INPUT_PROP_BUTTONPAD;-INPUT_PROP_POINTER;
+ Enables or disables the evdev input property on the device. The prefix
+ for each entry is either '+' (enable) or '-' (disable). Entries may be
a named input property or the hexadecimal value of that property.
AttrPointingStickIntegration=internal|external
Indicates the integration of the pointing stick. This is a string enum.
The issue can be fixed by adding a quirk to unset the ``REL_WHEEL_HI_RES`` and
``REL_HWHEEL_HI_RES`` event codes: ::
- AttrEventCodeDisable=REL_WHEEL_HI_RES;REL_HWHEEL_HI_RES;
+ AttrEventCode=-REL_WHEEL_HI_RES;-REL_HWHEEL_HI_RES;
Please see :ref:`device-quirks` for details.
MatchUdevType=tablet
MatchBus=usb
MatchVendor=0x08CA
-AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y;
+AttrEventCode=-ABS_TILT_X;-ABS_TILT_Y;
[Aiptek 8000U pressure threshold]
MatchUdevType=tablet
MatchVendor=0x047D
MatchProduct=0x2048
ModelTrackball=1
-AttrEventCodeDisable=BTN_MIDDLE
+AttrEventCode=-BTN_MIDDLE
MatchBus=usb
MatchVendor=0x46D
MatchProduct=0xC408
-AttrEventCodeDisable=BTN_MIDDLE
+AttrEventCode=-BTN_MIDDLE
[Logitech K400]
MatchUdevType=mouse
MatchVendor=0x0738
MatchProduct=0x1703
# EV_KEY 0x115, 0x116, 0x117
-AttrEventCodeDisable=EV_KEY:0x115;EV_KEY:0x116;EV_KEY:0x117
+AttrEventCode=-EV_KEY:0x115;-EV_KEY:0x116;-EV_KEY:0x117
# Like the Madcatz RAT3, but with different codes:
# event8 POINTER_BUTTON +0.488s ??? (280) pressed, seat count: 1
MatchVendor=0x0738
MatchProduct=0x1708
# EV_KEY 0x118, 0x119, 0x11A
-AttrEventCodeDisable=EV_KEY:0x118;EV_KEY:0x119;EV_KEY:0x11A
+AttrEventCode=-EV_KEY:0x118;-EV_KEY:0x119;-EV_KEY:0x11A
[Synaptics 0911:5288 Touchpad]
MatchUdevType=touchpad
MatchName=* 0911:5288 Touchpad
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
MatchBus=usb
MatchVendor=0x56A
MatchProduct=0x4200
-AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y;
+AttrEventCode=-ABS_TILT_X;-ABS_TILT_Y;
[Wacom ISDV4 524c Pen]
MatchUdevType=tablet
MatchBus=usb
MatchVendor=0x2D1F
MatchProduct=0x524C
-AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y;
+AttrEventCode=-ABS_TILT_X;-ABS_TILT_Y;
MatchName=PIXA3854:00 093A:0274 Touchpad
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnFramework:pnLaptop*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
MatchBus=bluetooth
MatchVendor=0x05AC
MatchProduct=0x030D
-AttrEventCodeDisable=EV_ABS
+AttrEventCode=-EV_ABS
# The External Apple "Magic" trackpads, both the 1st and 2nd generations, have
# pretty good built-in spurious touch filtering in the device firmware. Using
[Asus UX302LA]
MatchName=*ETPS/2 Elantech Touchpad*
MatchDMIModalias=dmi:*svnASUSTeKCOMPUTERINC.:pnUX302LA:*
-AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
+AttrEventCode=-ABS_MT_PRESSURE;-ABS_PRESSURE;
# Asus VivoBook Flip 14 TP412UA tablet switch seems misbehaving, always
# indicating tablet position
[Chuwi Gemibook]
MatchName=HTIX5288:00 093A:1336 Touchpad
MatchUdevType=touchpad
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
[Chuwi AeroBook Plus]
MatchName=SYNA3602:01 093A:1336 Touchpad
MatchUdevType=touchpad
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
MatchVendor=0x06A3
MatchProduct=0x0CD5
# EV_KEY 0x118, 0x119, 0x11a
-AttrEventCodeDisable=EV_KEY:0x118;EV_KEY:0x119;EV_KEY:0x11a
+AttrEventCode=-EV_KEY:0x118;-EV_KEY:0x119;-EV_KEY:0x11a
MatchBus=i2c
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnDellInc.:pnPrecision7?50*
-AttrInputPropDisable=INPUT_PROP_BUTTONPAD
+AttrInputProp=-INPUT_PROP_BUTTONPAD
# The touch device has the same vid/pid as the totem, the MatchName
# directive is required here
MatchName=HTIX5288:00 093A:0255 Touchpad
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnGPD:*pnG1619-*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
[HP Compaq 6910p]
MatchName=*SynPS/2 Synaptics TouchPad
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq6910p*
-AttrEventCodeDisable=BTN_TOOL_DOUBLETAP;BTN_TOOL_TRIPLETAP;
+AttrEventCode=-BTN_TOOL_DOUBLETAP;-BTN_TOOL_TRIPLETAP;
# Claims to have double/tripletap but doesn't actually send it
# https://bugzilla.redhat.com/show_bug.cgi?id=1351285 and
[HP Compaq 8510w]
MatchName=*SynPS/2 Synaptics TouchPad
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq8510w*
-AttrEventCodeDisable=BTN_TOOL_DOUBLETAP;BTN_TOOL_TRIPLETAP;
+AttrEventCode=-BTN_TOOL_DOUBLETAP;-BTN_TOOL_TRIPLETAP;
[HP Pavilion dmi4]
MatchName=*SynPS/2 Synaptics TouchPad
[HP Stream 11]
MatchName=SYN1EDE:00 06CB:7442*
MatchDMIModalias=dmi:*svnHewlett-Packard:pnHPStreamNotebookPC11*
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrInputProp=+INPUT_PROP_BUTTONPAD
# The HP stream x360's embedded-controller filters out events form its builtin
# keyboard when in tablet-mode itself; and it has a capacitive home-button
MatchName=ELAN2604:00 04F3:3114 Touchpad
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnHUAWEI:*pvrM1010*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
[Lenovo T480s Touchpad]
MatchName=Elan Touchpad
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT480s*
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrInputProp=+INPUT_PROP_BUTTONPAD
# Touchpad is a clickpad but INPUT_PROP_BUTTONPAD is not set, see
# https://gitlab.freedesktop.org/libinput/libinput/issues/177
[Lenovo T490s Touchpad]
MatchName=Elan Touchpad
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT490s*
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrInputProp=+INPUT_PROP_BUTTONPAD
[Lenovo T490s Trackpoint]
MatchName=*TPPS/2 IBM TrackPoint
[Lenovo L380 Touchpad]
MatchName=Elan Touchpad
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadL380*
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrInputProp=+INPUT_PROP_BUTTONPAD
[Lenovo X200 Trackpoint]
MatchName=*TPPS/2 IBM TrackPoint
MatchBus=i2c
MatchVendor=0x06CB
MatchProduct=0xCE37
-AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
+AttrEventCode=-ABS_MT_PRESSURE;-ABS_PRESSURE;
[Lenovo Yoga C930 Tablet]
MatchBus=i2c
[Lenovo Carbon X1 6th gen]
MatchName=Synaptics TM3288-011
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX1Carbon6th:*
-AttrEventCodeDisable=ABS_MT_TOOL_TYPE
+AttrEventCode=-ABS_MT_TOOL_TYPE
ModelLenovoX1Gen6Touchpad=1
[Lenovo X41 Tablet]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x01E8
-AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
+AttrEventCode=-ABS_MT_PRESSURE;-ABS_PRESSURE;
# Duet 7i tablet switch activated by folding keyboard cover, or removing it.
# We must not disable volume rocker 'keyboard'.
MatchName=*Touchpad
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnStarLabs:*
-AttrEventCodeDisable=BTN_RIGHT
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrEventCode=-BTN_RIGHT
+AttrInputProp=+INPUT_PROP_BUTTONPAD
struct quirks_context *quirks;
struct quirks *q;
const struct quirk_tuples *t;
- const uint32_t *props = NULL;
- size_t nprops = 0;
char *prop;
/* Touchpad claims to have 4 slots but only ever sends 2
libevdev_disable_event_code(device->evdev, EV_MSC, MSC_TIMESTAMP);
}
- if (quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE_ENABLE, &t)) {
+ if (quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE, &t)) {
for (size_t i = 0; i < t->ntuples; i++) {
const struct input_absinfo absinfo = {
.minimum = 0,
int type = t->tuples[i].first;
int code = t->tuples[i].second;
+ bool enable = t->tuples[i].third;
- if (code == EVENT_CODE_UNDEFINED)
- libevdev_enable_event_type(device->evdev, type);
- else
- libevdev_enable_event_code(device->evdev,
- type,
- code,
- type == EV_ABS ? &absinfo : NULL);
- evdev_log_debug(device,
- "quirks: enabling %s %s (%#x %#x)\n",
- libevdev_event_type_get_name(type),
- libevdev_event_code_get_name(type, code),
- type,
- code);
- }
- }
-
- if (quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE_DISABLE, &t)) {
- for (size_t i = 0; i < t->ntuples; i++) {
- int type = t->tuples[i].first;
- int code = t->tuples[i].second;
-
- if (code == EVENT_CODE_UNDEFINED)
- libevdev_disable_event_type(device->evdev,
- type);
- else
- libevdev_disable_event_code(device->evdev,
- type,
- code);
+ if (code == EVENT_CODE_UNDEFINED) {
+ if (enable)
+ libevdev_enable_event_type(device->evdev, type);
+ else
+ libevdev_disable_event_type(device->evdev, type);
+ } else {
+ if (enable)
+ libevdev_enable_event_code(device->evdev,
+ type,
+ code,
+ type == EV_ABS ? &absinfo : NULL);
+ else
+ libevdev_disable_event_code(device->evdev,
+ type,
+ code);
+ }
evdev_log_debug(device,
- "quirks: disabling %s %s (%#x %#x)\n",
+ "quirks: %s %s %s (%#x %#x)\n",
+ enable ? "enabling" : "disabling",
libevdev_event_type_get_name(type),
libevdev_event_code_get_name(type, code),
type,
}
}
- if (quirks_get_uint32_array(q,
- QUIRK_ATTR_INPUT_PROP_ENABLE,
- &props,
- &nprops)) {
- for (size_t idx = 0; idx < nprops; idx++) {
- unsigned int p = props[idx];
- libevdev_enable_property(device->evdev, p);
- evdev_log_debug(device,
- "quirks: enabling %s (%#x)\n",
- libevdev_property_get_name(p),
- p);
- }
- }
+ if (quirks_get_tuples(q, QUIRK_ATTR_INPUT_PROP, &t)) {
+ for (size_t idx = 0; idx < t->ntuples; idx++) {
+ unsigned int p = t->tuples[idx].first;
+ bool enable = t->tuples[idx].second;
- if (quirks_get_uint32_array(q,
- QUIRK_ATTR_INPUT_PROP_DISABLE,
- &props,
- &nprops)) {
+ if (enable) {
+ libevdev_enable_property(device->evdev, p);
+ }
+ else {
#if HAVE_LIBEVDEV_DISABLE_PROPERTY
- for (size_t idx = 0; idx < nprops; idx++) {
- unsigned int p = props[idx];
- libevdev_disable_property(device->evdev, p);
+ libevdev_disable_property(device->evdev, p);
+#else
+ evdev_log_error(device,
+ "quirks: a quirk for this device requires newer libevdev than installed\n");
+#endif
+ }
evdev_log_debug(device,
- "quirks: disabling %s (%#x)\n",
+ "quirks: %s %s (%#x)\n",
+ enable ? "enabling" : "disabling",
libevdev_property_get_name(p),
p);
}
-#else
- evdev_log_error(device,
- "quirks: a quirk for this device requires newer libevdev than installed\n");
-#endif
}
quirks_unref(q);
/* These are not ref'd, just a collection of pointers */
struct property **properties;
size_t nproperties;
+
+ /* Special properties for AttrEventCode and AttrInputCode, these are
+ * owned by us, not the section */
+ struct list floating_properties;
};
/**
case QUIRK_ATTR_TABLET_SMOOTHING: return "AttrTabletSmoothing";
case QUIRK_ATTR_THUMB_SIZE_THRESHOLD: return "AttrThumbSizeThreshold";
case QUIRK_ATTR_MSC_TIMESTAMP: return "AttrMscTimestamp";
- case QUIRK_ATTR_EVENT_CODE_DISABLE: return "AttrEventCodeDisable";
- case QUIRK_ATTR_EVENT_CODE_ENABLE: return "AttrEventCodeEnable";
- case QUIRK_ATTR_INPUT_PROP_DISABLE: return "AttrInputPropDisable";
- case QUIRK_ATTR_INPUT_PROP_ENABLE: return "AttrInputPropEnable";
+ case QUIRK_ATTR_EVENT_CODE: return "AttrEventCode";
+ case QUIRK_ATTR_INPUT_PROP: return "AttrInputProp";
default:
abort();
}
p->type = PT_STRING;
p->value.s = safe_strdup(value);
rc = true;
- } else if (streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE_DISABLE)) ||
- streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE_ENABLE))) {
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE))) {
struct input_event events[32];
size_t nevents = ARRAY_LENGTH(events);
- if (streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE_DISABLE)))
- p->id = QUIRK_ATTR_EVENT_CODE_DISABLE;
- else
- p->id = QUIRK_ATTR_EVENT_CODE_ENABLE;
+
+ p->id = QUIRK_ATTR_EVENT_CODE;
if (!parse_evcode_property(value, events, &nevents) ||
nevents == 0)
for (size_t i = 0; i < nevents; i++) {
p->value.tuples.tuples[i].first = events[i].type;
p->value.tuples.tuples[i].second = events[i].code;
+ p->value.tuples.tuples[i].third = events[i].value;
}
p->value.tuples.ntuples = nevents;
p->type = PT_TUPLES;
rc = true;
- } else if (streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP_DISABLE)) ||
- streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP_ENABLE))) {
- unsigned int props[INPUT_PROP_CNT];
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP))) {
+ struct input_prop props[INPUT_PROP_CNT];
size_t nprops = ARRAY_LENGTH(props);
- if (streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP_DISABLE)))
- p->id = QUIRK_ATTR_INPUT_PROP_DISABLE;
- else
- p->id = QUIRK_ATTR_INPUT_PROP_ENABLE;
+
+ p->id = QUIRK_ATTR_INPUT_PROP;
if (!parse_input_prop_property(value, props, &nprops) ||
nprops == 0)
goto out;
- memcpy(p->value.array.data.u, props, nprops * sizeof(unsigned int));
- p->value.array.nelements = nprops;
- p->type = PT_UINT_ARRAY;
+ for (size_t i = 0; i < nprops; i++) {
+ p->value.tuples.tuples[i].first = props[i].prop;
+ p->value.tuples.tuples[i].second = props[i].enabled;
+ }
+
+ p->value.tuples.ntuples = nprops;
+ p->type = PT_TUPLES;
rc = true;
} else {
q->refcount = 1;
q->nproperties = 0;
list_init(&q->link);
+ list_init(&q->floating_properties);
return q;
}
property_unref(q->properties[i]);
}
+ /* Floating properties are owned by our quirks context, need to be
+ * cleaned up here */
+ struct property *p;
+ list_for_each_safe(p, &q->floating_properties, link) {
+ property_cleanup(p);
+ }
+
list_remove(&q->link);
free(q->properties);
free(q);
free(m);
}
+static void
+quirk_merge_event_codes(struct quirks_context *ctx,
+ struct quirks *q,
+ const struct property *property)
+{
+ for (size_t i = 0; i < q->nproperties; i++) {
+ struct property *p = q->properties[i];
+
+ if (p->id != property->id)
+ continue;
+
+ /* We have a duplicated property, merge in with ours */
+ size_t offset = p->value.tuples.ntuples;
+ size_t max = ARRAY_LENGTH(p->value.tuples.tuples);
+ for (size_t j = 0; j < property->value.tuples.ntuples; j++) {
+ if (offset + j >= max)
+ break;
+ p->value.tuples.tuples[offset + j] = property->value.tuples.tuples[j];
+ p->value.tuples.ntuples++;
+ }
+ return;
+ }
+
+ /* First time we add AttrEventCode: create a new property.
+ * Unlike the other properties, this one isn't part of a section, it belongs
+ * to the quirks */
+ struct property *newprop = property_new();
+ newprop->id = property->id;
+ newprop->type = property->type;
+ newprop->value.tuples = property->value.tuples;
+ /* Caller responsible for pre-allocating space */
+ q->properties[q->nproperties++] = property_ref(newprop);
+ list_append(&q->floating_properties, &newprop->link);
+}
+
static void
quirk_apply_section(struct quirks_context *ctx,
struct quirks *q,
qlog_debug(ctx, "property added: %s from %s\n",
quirk_get_name(p->id), s->name);
- q->properties[q->nproperties++] = property_ref(p);
+ /* All quirks but AttrEventCode and AttrInputProp
+ * simply overwrite each other, so we can just append the
+ * matching property and, later when checking the quirk, pick
+ * the last one in the array.
+ *
+ * The event codes/input props are special because they're lists
+ * that may *partially* override each other, e.g. a section may
+ * enable BTN_LEFT and BTN_RIGHT but a later section may disable
+ * only BTN_RIGHT. This should result in BTN_LEFT force-enabled
+ * and BTN_RIGHT force-disabled.
+ *
+ * To hack around this, those are the only ones where only ever
+ * have one struct property in the list (not owned by a section)
+ * and we simply merge any extra sections onto that.
+ */
+ if (p->id == QUIRK_ATTR_EVENT_CODE ||
+ p->id == QUIRK_ATTR_INPUT_PROP)
+ quirk_merge_event_codes(ctx, q, p);
+ else
+ q->properties[q->nproperties++] = property_ref(p);
}
}
struct {
int first;
int second;
+ int third;
} tuples[32];
size_t ntuples;
};
QUIRK_ATTR_TABLET_SMOOTHING,
QUIRK_ATTR_THUMB_SIZE_THRESHOLD,
QUIRK_ATTR_MSC_TIMESTAMP,
- QUIRK_ATTR_EVENT_CODE_DISABLE,
- QUIRK_ATTR_EVENT_CODE_ENABLE,
- QUIRK_ATTR_INPUT_PROP_DISABLE,
- QUIRK_ATTR_INPUT_PROP_ENABLE,
+ QUIRK_ATTR_EVENT_CODE,
+ QUIRK_ATTR_INPUT_PROP,
_QUIRK_LAST_ATTR_QUIRK_, /* Guard: do not modify */
};
}
/**
- * Parses a string of the format "EV_ABS;KEY_A;BTN_TOOL_DOUBLETAP;ABS_X;"
- * where each element must be a named event type OR a named event code OR a
- * tuple in the form of EV_KEY:0x123, i.e. a named event type followed by a
- * hex event code.
+ * Parses a string of the format "+EV_ABS;+KEY_A;-BTN_TOOL_DOUBLETAP;-ABS_X;"
+ * where each element must be + or - (enable/disable) followed by a named event
+ * type OR a named event code OR a tuple in the form of EV_KEY:0x123, i.e. a
+ * named event type followed by a hex event code.
*
* events must point to an existing array of size nevents.
* nevents specifies the size of the array in events and returns the number
* other fields undefined. Where only the event type is specified, the code
* is set to EVENT_CODE_UNDEFINED.
*
- * On success, events contains nevents events.
+ * On success, events contains nevents events with each event's value set to 1
+ * or 0 depending on the + or - prefix.
*/
bool
parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
ncodes = min(*nevents, ncodes);
for (size_t idx = 0; strv[idx]; idx++) {
char *s = strv[idx];
+ bool enable;
+
+ switch (*s) {
+ case '+': enable = true; break;
+ case '-': enable = false; break;
+ default:
+ goto out;
+ }
+
+ s++;
int type, code;
evs[idx].type = type;
evs[idx].code = code;
+ evs[idx].value = enable;
}
memcpy(events, evs, ncodes * sizeof *events);
}
/**
- * Parses a string of the format "INPUT_PROP_BUTTONPAD;INPUT_PROP_POINTER;0x123;"
+ * Parses a string of the format "+INPUT_PROP_BUTTONPAD;-INPUT_PROP_POINTER;+0x123;"
* where each element must be a named input prop OR a hexcode in the form
- * 0x1234
+ * 0x1234. The prefix for each element must be either '+' (enable) or '-' (disable).
*
* props must point to an existing array of size nprops.
* nprops specifies the size of the array in props and returns the number
* On success, props contains nprops elements.
*/
bool
-parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *nprops)
+parse_input_prop_property(const char *prop, struct input_prop *props_out, size_t *nprops)
{
bool rc = false;
- unsigned int props[INPUT_PROP_CNT]; /* doubling up on quirks is a bug */
+ struct input_prop props[INPUT_PROP_CNT]; /* doubling up on quirks is a bug */
size_t count;
char **strv = strv_from_string(prop, ";", &count);
for (size_t idx = 0; strv[idx]; idx++) {
char *s = strv[idx];
unsigned int prop;
+ bool enable;
+
+ switch (*s) {
+ case '+': enable = true; break;
+ case '-': enable = false; break;
+ default:
+ goto out;
+ }
+
+ s++;
if (safe_atou_base(s, &prop, 16)) {
if (prop > INPUT_PROP_MAX)
goto out;
prop = (unsigned int)val;
}
- props[idx] = prop;
+ props[idx].prop = prop;
+ props[idx].enabled = enable;
}
memcpy(props_out, props, count * sizeof *props);
#include <stddef.h>
#include <stdint.h>
+struct input_prop {
+ unsigned int prop;
+ bool enabled;
+};
+
int parse_mouse_dpi_property(const char *prop);
int parse_mouse_wheel_click_angle_property(const char *prop);
int parse_mouse_wheel_click_count_property(const char *prop);
bool parse_boolean_property(const char *prop, bool *b);
#define EVENT_CODE_UNDEFINED 0xffff
bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
-bool parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *nprops);
+bool parse_input_prop_property(const char *prop, struct input_prop *props_out, size_t *nprops);
enum tpkbcombo_layout {
TPKBCOMBO_LAYOUT_UNKNOWN,
};
static const char quirk_file[] =
-"[litest Quirked Keyboard enable rel]\n"
+"[litest Quirked Keyboard enable buttons]\n"
"MatchName=litest Quirked Keyboard\n"
-"AttrEventCodeEnable=BTN_RIGHT;EV_KEY:0x110\n" /* BTN_LEFT */
+"AttrEventCode=+BTN_RIGHT;+BTN_MIDDLE;+EV_KEY:0x110\n" /* BTN_LEFT */
+"\n"
+"[litest Quirked Keyboard disable buttons]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrEventCode=-BTN_MIDDLE;-BTN_RIGHT\n"
+"\n"
+"[litest Quirked Keyboard re-enable buttons]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrEventCode=+BTN_RIGHT\n"
"\n"
"[litest Quirked keyboard disable F1-F3]\n"
"MatchName=litest Quirked Keyboard\n"
-"AttrEventCodeDisable=KEY_F1;EV_KEY:0x3c;KEY_F3\n"
+"AttrEventCode=-KEY_F1;-EV_KEY:0x3c;-KEY_F3\n"
#if HAVE_LIBEVDEV_DISABLE_PROPERTY
"\n"
"[litest Quirked keyboard enable buttonpad]\n"
"MatchName=litest Quirked Keyboard\n"
-"AttrInputPropEnable=INPUT_PROP_BUTTONPAD\n"
+"AttrInputProp=+INPUT_PROP_BUTTONPAD\n"
"\n"
"[litest Quirked keyboard disable pointingstick]\n"
"MatchName=litest Quirked Keyboard\n"
-"AttrInputPropDisable=INPUT_PROP_POINTING_STICK\n"
+"AttrInputProp=-INPUT_PROP_POINTING_STICK\n"
+"\n"
+"[litest Quirked keyboard enable direct]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrInputProp=+INPUT_PROP_DIRECT\n"
+"\n"
+"[litest Quirked keyboard disable direct]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrInputProp=-INPUT_PROP_DIRECT\n"
+"\n"
+"[litest Quirked keyboard disable semi-mt]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrInputProp=-INPUT_PROP_SEMI_MT\n"
+"\n"
+"[litest Quirked keyboard enable semi-mt]\n"
+"MatchName=litest Quirked Keyboard\n"
+"AttrInputProp=+INPUT_PROP_SEMI_MT\n"
#endif
;
enable_btn_left = false;
#if HAVE_LIBEVDEV_DISABLE_PROPERTY
bool disable_pointingstick = false,
- enable_buttonpad = false;
+ enable_buttonpad = false,
+ enable_direct = false,
+ disable_direct = false,
+ enable_semi_mt = false,
+ disable_semi_mt = false;
#endif
li = litest_create_context();
BTN_LEFT));
ck_assert(libinput_device_pointer_has_button(dev->libinput_device,
BTN_RIGHT));
+ ck_assert(!libinput_device_pointer_has_button(device,
+ BTN_MIDDLE));
ck_assert(!libinput_device_keyboard_has_key(dev->libinput_device,
KEY_F1));
ck_assert(!libinput_device_keyboard_has_key(dev->libinput_device,
enable_buttonpad = true;
if (strstr(*message, "disabling INPUT_PROP_POINTING_STICK"))
disable_pointingstick = true;
+ if (strstr(*message, "enabling INPUT_PROP_DIRECT")) {
+ ck_assert(!disable_direct);
+ enable_direct = true;
+ }
+ if (strstr(*message, "disabling INPUT_PROP_DIRECT")) {
+ ck_assert(enable_direct);
+ disable_direct = true;
+ }
+ if (strstr(*message, "enabling INPUT_PROP_SEMI_MT")) {
+ ck_assert(disable_semi_mt);
+ enable_semi_mt = true;
+ }
+ if (strstr(*message, "disabling INPUT_PROP_SEMI_MT")) {
+ ck_assert(!enable_semi_mt);
+ disable_semi_mt = true;
+ }
#endif
free(*message);
message++;
#if HAVE_LIBEVDEV_DISABLE_PROPERTY
ck_assert(enable_buttonpad);
ck_assert(disable_pointingstick);
+ ck_assert(enable_direct);
+ ck_assert(disable_direct);
+ ck_assert(enable_semi_mt);
+ ck_assert(disable_semi_mt);
#endif
litest_disable_log_handler(li);
struct parser_test_tuple {
const char *prop;
bool success;
- size_t ntuples;
- int tuples[20];
+ size_t nevents;
+ struct input_event events[20];
} tests[] = {
- { "EV_KEY", true, 1, {EV_KEY, 0xffff} },
- { "EV_ABS;", true, 1, {EV_ABS, 0xffff} },
- { "ABS_X;", true, 1, {EV_ABS, ABS_X} },
- { "SW_TABLET_MODE;", true, 1, {EV_SW, SW_TABLET_MODE} },
- { "EV_SW", true, 1, {EV_SW, 0xffff} },
- { "ABS_Y", true, 1, {EV_ABS, ABS_Y} },
- { "EV_ABS:0x00", true, 1, {EV_ABS, ABS_X} },
- { "EV_ABS:01", true, 1, {EV_ABS, ABS_Y} },
- { "ABS_TILT_X;ABS_TILT_Y;", true, 2,
- { EV_ABS, ABS_TILT_X,
- EV_ABS, ABS_TILT_Y} },
- { "BTN_TOOL_DOUBLETAP;EV_KEY;KEY_A", true, 3,
- { EV_KEY, BTN_TOOL_DOUBLETAP,
- EV_KEY, 0xffff,
- EV_KEY, KEY_A } },
- { "REL_Y;ABS_Z;BTN_STYLUS", true, 3,
- { EV_REL, REL_Y,
- EV_ABS, ABS_Z,
- EV_KEY, BTN_STYLUS } },
- { "REL_Y;EV_KEY:0x123;BTN_STYLUS", true, 3,
- { EV_REL, REL_Y,
- EV_KEY, 0x123,
- EV_KEY, BTN_STYLUS } },
+ { "+EV_KEY", true, 1, {{ .type = EV_KEY, .code = 0xffff, .value = 1 }} },
+ { "-EV_ABS;", true, 1, {{ .type = EV_ABS, .code = 0xffff, .value = 0 }} },
+ { "+ABS_X;", true, 1, {{ .type = EV_ABS, .code = ABS_X, .value = 1 }} },
+ { "-SW_TABLET_MODE;", true, 1, {{ .type = EV_SW, .code = SW_TABLET_MODE, .value = 0 }} },
+ { "+EV_SW", true, 1, {{ .type = EV_SW, .code = 0xffff, .value = 1 }} },
+ { "-ABS_Y", true, 1, {{ .type = EV_ABS, .code = ABS_Y, .value = 0 }} },
+ { "+EV_ABS:0x00", true, 1, {{ .type = EV_ABS, .code = ABS_X, .value = 1 }} },
+ { "-EV_ABS:01", true, 1, {{ .type = EV_ABS, .code = ABS_Y, .value = 0 }} },
+ { "+ABS_TILT_X;-ABS_TILT_Y;", true, 2,
+ {{ .type = EV_ABS, .code = ABS_TILT_X, .value = 1 },
+ { .type = EV_ABS, .code = ABS_TILT_Y, .value = 0}} },
+ { "+BTN_TOOL_DOUBLETAP;+EV_KEY;-KEY_A", true, 3,
+ {{ .type = EV_KEY, .code = BTN_TOOL_DOUBLETAP, .value = 1 } ,
+ { .type = EV_KEY, .code = 0xffff, .value = 1 },
+ { .type = EV_KEY, .code = KEY_A, .value = 0 }} },
+ { "+REL_Y;-ABS_Z;+BTN_STYLUS", true, 3,
+ {{ .type = EV_REL, .code = REL_Y, .value = 1},
+ { .type = EV_ABS, .code = ABS_Z, .value = 0},
+ { .type = EV_KEY, .code = BTN_STYLUS, .value = 1 }} },
+ { "-REL_Y;+EV_KEY:0x123;-BTN_STYLUS", true, 3,
+ {{ .type = EV_REL, .code = REL_Y, .value = 0 },
+ { .type = EV_KEY, .code = 0x123, .value = 1 },
+ { .type = EV_KEY, .code = BTN_STYLUS, .value = 0 }} },
{ .prop = "", .success = false },
- { .prop = "EV_FOO", .success = false },
- { .prop = "EV_KEY;EV_FOO", .success = false },
- { .prop = "BTN_STYLUS;EV_FOO", .success = false },
- { .prop = "BTN_UNKNOWN", .success = false },
- { .prop = "BTN_UNKNOWN;EV_KEY", .success = false },
- { .prop = "PR_UNKNOWN", .success = false },
- { .prop = "BTN_STYLUS;PR_UNKNOWN;ABS_X", .success = false },
- { .prop = "EV_REL:0xffff", .success = false },
- { .prop = "EV_REL:0x123.", .success = false },
- { .prop = "EV_REL:ffff", .success = false },
- { .prop = "EV_REL:blah", .success = false },
- { .prop = "KEY_A:0x11", .success = false },
- { .prop = "EV_KEY:0x11 ", .success = false },
- { .prop = "EV_KEY:0x11not", .success = false },
+ { .prop = "+", .success = false },
+ { .prop = "-", .success = false },
+ { .prop = "!", .success = false },
+ { .prop = "+EV_FOO", .success = false },
+ { .prop = "+EV_KEY;-EV_FOO", .success = false },
+ { .prop = "+BTN_STYLUS;-EV_FOO", .success = false },
+ { .prop = "-BTN_UNKNOWN", .success = false },
+ { .prop = "+BTN_UNKNOWN;+EV_KEY", .success = false },
+ { .prop = "-PR_UNKNOWN", .success = false },
+ { .prop = "-BTN_STYLUS;+PR_UNKNOWN;-ABS_X", .success = false },
+ { .prop = "-EV_REL:0xffff", .success = false },
+ { .prop = "-EV_REL:0x123.", .success = false },
+ { .prop = "-EV_REL:ffff", .success = false },
+ { .prop = "-EV_REL:blah", .success = false },
+ { .prop = "+KEY_A:0x11", .success = false },
+ { .prop = "+EV_KEY:0x11 ", .success = false },
+ { .prop = "+EV_KEY:0x11not", .success = false },
{ .prop = "none", .success = false },
{ .prop = NULL },
};
if (!success)
continue;
- ck_assert_int_eq(nevents, t->ntuples);
+ ck_assert_int_eq(nevents, t->nevents);
for (size_t j = 0; j < nevents; j++) {
- int type, code;
-
- type = events[j].type;
- code = events[j].code;
- ck_assert_int_eq(t->tuples[j * 2], type);
- ck_assert_int_eq(t->tuples[j * 2 + 1], code);
+ unsigned int type = events[j].type;
+ unsigned int code = events[j].code;
+ int value = events[j].value;
+ ck_assert_int_eq(t->events[j].type, type);
+ ck_assert_int_eq(t->events[j].code, code);
+ ck_assert_int_eq(t->events[j].value, value);
}
}
}
const char *prop;
bool success;
size_t nvals;
- uint32_t values[20];
+ struct input_prop values[20];
} tests[] = {
- { "INPUT_PROP_BUTTONPAD", true, 1, {INPUT_PROP_BUTTONPAD}},
- { "INPUT_PROP_BUTTONPAD;INPUT_PROP_POINTER", true, 2,
- { INPUT_PROP_BUTTONPAD,
- INPUT_PROP_POINTER }},
- { "INPUT_PROP_BUTTONPAD;0x00;0x03", true, 3,
- { INPUT_PROP_BUTTONPAD,
- INPUT_PROP_POINTER,
- INPUT_PROP_SEMI_MT }},
+ { "+INPUT_PROP_BUTTONPAD", true, 1, {{ INPUT_PROP_BUTTONPAD, true }}},
+ { "+INPUT_PROP_BUTTONPAD;-INPUT_PROP_POINTER", true, 2,
+ { { INPUT_PROP_BUTTONPAD, true },
+ { INPUT_PROP_POINTER, false }}},
+ { "+INPUT_PROP_BUTTONPAD;-0x00;+0x03", true, 3,
+ { { INPUT_PROP_BUTTONPAD, true },
+ { INPUT_PROP_POINTER, false },
+ { INPUT_PROP_SEMI_MT, true }}},
{ .prop = "", .success = false },
{ .prop = "0xff", .success = false },
{ .prop = "INPUT_PROP", .success = false },
for (int i = 0; tests[i].prop; i++) {
bool success;
- uint32_t props[32];
+ struct input_prop props[32];
size_t nprops = ARRAY_LENGTH(props);
t = &tests[i];
ck_assert_int_eq(nprops, t->nvals);
for (size_t j = 0; j < t->nvals; j++) {
- ck_assert_int_eq(t->values[j], props[j]);
+ ck_assert_int_eq(t->values[j].prop, props[j].prop);
+ ck_assert_int_eq(t->values[j].enabled, props[j].enabled);
}
}
}
off += printed;
for (size_t i = 0; off < sz && i < t->ntuples; i++) {
- const char *name = libevdev_event_code_get_name(
- t->tuples[i].first,
- t->tuples[i].second);
+ unsigned int type = t->tuples[i].first;
+ unsigned int code = t->tuples[i].second;
+ bool enable = t->tuples[i].third;
- printed = snprintf(buf + off, sz - off, "%s;", name);
+ const char *name = libevdev_event_code_get_name(type, code);
+
+ printed = snprintf(buf + off, sz - off, "%c%s;", enable ? '+' : '-', name);
assert(printed != -1);
off += printed;
}
static void
sprintf_input_props(char *buf, size_t sz, struct quirks *quirks, enum quirk q)
{
- const uint32_t *properties;
- size_t nprops = 0;
+ const struct quirk_tuples *t;
size_t off = 0;
int printed;
const char *name;
- quirks_get_uint32_array(quirks, q, &properties, &nprops);
+ quirks_get_tuples(quirks, q, &t);
name = quirk_get_name(q);
printed = snprintf(buf, sz, "%s=", name);
assert(printed != -1);
off += printed;
- for (size_t i = 0; off < sz && i < nprops; i++) {
- const char *name = libevdev_property_get_name(properties[i]);
- printed = snprintf(buf + off, sz - off, "%s;", name);
+ for (size_t i = 0; off < sz && i < t->ntuples; i++) {
+ unsigned int prop = t->tuples[i].first;
+ bool enable = t->tuples[i].second;
+
+ const char *name = libevdev_property_get_name(prop);
+
+ printed = snprintf(buf + off, sz - off, "%c%s;", enable ? '+' : '-', name);
assert(printed != -1);
off += printed;
}
snprintf(buf, sizeof(buf), "%s=%d", name, b);
callback(userdata, buf);
break;
- case QUIRK_ATTR_EVENT_CODE_DISABLE:
- case QUIRK_ATTR_EVENT_CODE_ENABLE:
+ case QUIRK_ATTR_EVENT_CODE:
sprintf_event_codes(buf, sizeof(buf), quirks, q);
callback(userdata, buf);
break;
- case QUIRK_ATTR_INPUT_PROP_DISABLE:
- case QUIRK_ATTR_INPUT_PROP_ENABLE:
+ case QUIRK_ATTR_INPUT_PROP:
sprintf_input_props(buf, sizeof(buf), quirks, q);
callback(userdata, buf);
break;