quirks: allow overriding of AttrEventCode and AttrInputProp
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 15 Nov 2022 03:53:43 +0000 (13:53 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Sun, 27 Nov 2022 22:25:41 +0000 (08:25 +1000)
This switches the quirk from AttrEventCodeEnable/Disable to just
AttrEventCode with a +/- prefix for each entry.
This switches the quirk from AttrInputPropEnable/Disable to just
AttrInputProp with a +/- prefix for each entry.

Previously, both event codes and input props would only apply the
last-matching section entry for a device. Furthermore, an earlier Disable entry
would take precedence over a later Enable entry. For example, a set of
sections with these lines *should* enable left, right and middle:

  [first]
  AttrEventCodeEnable=BTN_LEFT;BTN_RIGHT;BTN_MIDDLE

  [second]
  AttrEventCodeDisable=BTN_RIGHT

  [third]
  AttrEventCodeEnable=BTN_LEFT;BTN_RIGHT;

Alas: the first line was effectively ignored (quirks only returned the
last-matching one, i.e. the one from "third"). And due to implementation
details in evdev.c, the Disable attribute was processed after Enable,
i.e. the device was enabled for left + right and then disabled for
right. As a result, the device only had BTN_LEFT enabled.

Fix this by changing the attribute to carry both enable/disable
information and merging the commands together.

Internally, all quirks matching a device are simply ref'd into an array
in the struct quirks. The applied value is simply the last entry in the
array corresponding to our quirk.

For AttrEventCode and AttrInputProp instead do this:
- switch them to a tuple with the code as first entry and a boolean
  enable/disable as second entry
- if the struct quirk already has an entry for either, append the more
  recent one to the existing entry (instead of creating a new entry in
  the array). This way we have all entries that match and in-order of
  precedence - i.e. we can process them left-to-right to end up
  with the right state.

Fixes: https://gitlab.freedesktop.org/libinput/libinput/-/issues/821
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
29 files changed:
doc/user/clickpad-with-right-button.rst
doc/user/device-quirks.rst
doc/user/incorrectly-enabled-hires.rst
quirks/30-vendor-aiptek.quirks
quirks/30-vendor-kensington.quirks
quirks/30-vendor-logitech.quirks
quirks/30-vendor-madcatz.quirks
quirks/30-vendor-synaptics.quirks
quirks/30-vendor-wacom.quirks
quirks/50-framework.quirks
quirks/50-system-apple.quirks
quirks/50-system-asus.quirks
quirks/50-system-chuwi.quirks
quirks/50-system-cyborg.quirks
quirks/50-system-dell.quirks
quirks/50-system-gpd.quirks
quirks/50-system-hp.quirks
quirks/50-system-huawei.quirks
quirks/50-system-lenovo.quirks
quirks/50-system-starlabs.quirks
src/evdev.c
src/quirks.c
src/quirks.h
src/util-prop-parsers.c
src/util-prop-parsers.h
test/litest-device-keyboard-quirked.c
test/test-device.c
test/test-utils.c
tools/shared.c

index b874b2ed77c70c577c9722e969b8fea41cc585f3..76c1ca5420d84eebb5f80cff27d657b137171850 100644 (file)
@@ -30,7 +30,7 @@ MyVendor OEM::
     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``.
index 7c2202828dba906d419ca462ffa455b95eee61ff..d7461b0872b9c642d3e1aca03956ac78358dc594 100644 (file)
@@ -174,19 +174,14 @@ AttrTPKComboLayout=below
     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.
index 7dffca7904ef3e9335cee6163d0b0f488191dfa0..4273db211020b065753ed9d0c65e5baf10688204 100644 (file)
@@ -57,6 +57,6 @@ events are sent: ::
 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.
index 3efddb639eed3090c0b36c2e1035dff8851e2ab6..70bed02301aafc5a97bb33043d9a19f95a1a6ef9 100644 (file)
@@ -4,7 +4,7 @@
 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
index f4d83a091300052deb128f1aee82736ff81f99b6..e77204b6add975740400ab097004b26e4b2fdbc8 100644 (file)
@@ -4,4 +4,4 @@ MatchBus=usb
 MatchVendor=0x047D
 MatchProduct=0x2048
 ModelTrackball=1
-AttrEventCodeDisable=BTN_MIDDLE
+AttrEventCode=-BTN_MIDDLE
index c2b327d4c490ef948444ccca39c5aaacaed50035..4a4fe859d9d1f60fd2746144cac8ab04677ad9cb 100644 (file)
@@ -10,7 +10,7 @@ MatchUdevType=mouse
 MatchBus=usb
 MatchVendor=0x46D
 MatchProduct=0xC408
-AttrEventCodeDisable=BTN_MIDDLE
+AttrEventCode=-BTN_MIDDLE
 
 [Logitech K400]
 MatchUdevType=mouse
index 57934c0390713fa06a6a7fe8a87895021aad4f9e..3cfb27ce59fe6648b99617c1e4048cf42f00d1ce 100644 (file)
@@ -21,7 +21,7 @@ MatchBus=usb
 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
@@ -37,4 +37,4 @@ MatchBus=usb
 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
index 26f4373a12d7325d344de0c5fa9b84c248b17836..315ab41e7745746c6e47398077c048b313d7c47d 100644 (file)
@@ -16,4 +16,4 @@ ModelSynapticsSerialTouchpad=1
 [Synaptics 0911:5288 Touchpad]
 MatchUdevType=touchpad
 MatchName=* 0911:5288 Touchpad
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
index 685c007dda1a9ed52008d184808be7458c9e1e92..d9733aeaed74751292fcfa809ae298bcb82f73c9 100644 (file)
@@ -18,11 +18,11 @@ MatchUdevType=tablet
 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;
index aa9523f8a16b7d14f5f913ee4e514a7e51a1665c..d42fe370ef46414d4287b6101fb3ad67d5f5457d 100644 (file)
@@ -2,4 +2,4 @@
 MatchName=PIXA3854:00 093A:0274 Touchpad
 MatchUdevType=touchpad
 MatchDMIModalias=dmi:*svnFramework:pnLaptop*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
index a6d6eea91d5aa6940a676e081a8b1831e10eff88..a9a094231b7cc29237fb9bdb35d4a3bfad1399a1 100644 (file)
@@ -41,7 +41,7 @@ MatchUdevType=mouse
 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
index 623fc72495109c166bb272364dc14a3dafc9cdc4..d5b79754ee857c261d19f7cf562b62c3e5bf16a8 100644 (file)
@@ -16,7 +16,7 @@ AttrPressureRange=24:10
 [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
index f93a53d594dfda9d73df1b1af1b1d4189a75c200..ac90037aef8c39586be4120bf45fa491b5f72f30 100644 (file)
@@ -1,9 +1,9 @@
 [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
index 6a21f6468f97d650ba40e23a4c0a277dd498b5ff..7dec23525f0d42a6020c18cf3d6cb599d17d3b96 100644 (file)
@@ -28,4 +28,4 @@ MatchBus=usb
 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
index 9bc3e357bd938529c6a6bab600110425016fa784..7abb6ce9072e508d1a732e9df5ffce79b82d65b4 100644 (file)
@@ -98,7 +98,7 @@ AttrTrackpointMultiplier=0.3
 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
index 6f8b2c761db163af3fa7762e1a9f56b4df23fec0..bdfeae95410fb2f6caa6d12eddb85d013a22e0b7 100644 (file)
@@ -2,4 +2,4 @@
 MatchName=HTIX5288:00 093A:0255 Touchpad
 MatchUdevType=touchpad
 MatchDMIModalias=dmi:*svnGPD:*pnG1619-*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
index 9ab0a22fe84c38509fe888558d4c04e5573bb727..03901d850117fc6ef1c186cb46ed2d84eae3b34d 100644 (file)
@@ -5,14 +5,14 @@
 [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
@@ -24,7 +24,7 @@ ModelHPPavilionDM4Touchpad=1
 [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
index 43ccb075605ed2486379c2e6759fe12dc192d419..c25379a683de92b12198795a3c08a896a8c32257 100644 (file)
@@ -4,4 +4,4 @@
 MatchName=ELAN2604:00 04F3:3114 Touchpad
 MatchUdevType=touchpad
 MatchDMIModalias=dmi:*svnHUAWEI:*pvrM1010*
-AttrEventCodeDisable=BTN_RIGHT
+AttrEventCode=-BTN_RIGHT
index 3526e6c4a4e681ec7ab21e93d17204fd281441c5..ade458832f0a89ac5917734a2b34afcd56140b34 100644 (file)
@@ -41,14 +41,14 @@ AttrTrackpointMultiplier=0.4
 [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
@@ -60,7 +60,7 @@ AttrTrackpointMultiplier=0.4
 [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
@@ -147,7 +147,7 @@ AttrTrackpointMultiplier=1.25
 MatchBus=i2c
 MatchVendor=0x06CB
 MatchProduct=0xCE37
-AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
+AttrEventCode=-ABS_MT_PRESSURE;-ABS_PRESSURE;
 
 [Lenovo Yoga C930 Tablet]
 MatchBus=i2c
@@ -160,7 +160,7 @@ AttrTabletSmoothing=1
 [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]
@@ -272,7 +272,7 @@ AttrKeyboardIntegration=internal
 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'.
index 9864d85bf1773597d503013796b07a3aea9efb46..794f4173026badde246c772aaff3b9980af8336b 100644 (file)
@@ -2,5 +2,5 @@
 MatchName=*Touchpad
 MatchUdevType=touchpad
 MatchDMIModalias=dmi:*svnStarLabs:*
-AttrEventCodeDisable=BTN_RIGHT
-AttrInputPropEnable=INPUT_PROP_BUTTONPAD
+AttrEventCode=-BTN_RIGHT
+AttrInputProp=+INPUT_PROP_BUTTONPAD
index 2c4d4726267d9b64aab2cf9831be84ffbbbfce56..c20d2749d9c0dbc78c806df48e323d4a0e733e54 100644 (file)
@@ -2231,8 +2231,6 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
        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
@@ -2251,7 +2249,7 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
                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,
@@ -2260,37 +2258,27 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
 
                        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,
@@ -2298,37 +2286,28 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
                }
        }
 
-       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);
index 932706f38cfb0833e0a625a4f6cd0bbce162f7b8..0e3006b5cd387bc7acf64a469f2f23ab5e8c018f 100644 (file)
@@ -175,6 +175,10 @@ struct quirks {
        /* 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;
 };
 
 /**
@@ -282,10 +286,8 @@ quirk_get_name(enum quirk q)
        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();
        }
@@ -817,14 +819,11 @@ parse_attr(struct quirks_context *ctx,
                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)
@@ -833,27 +832,29 @@ parse_attr(struct quirks_context *ctx,
                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 {
@@ -1201,6 +1202,7 @@ quirks_new(void)
        q->refcount = 1;
        q->nproperties = 0;
        list_init(&q->link);
+       list_init(&q->floating_properties);
 
        return q;
 }
@@ -1219,6 +1221,13 @@ quirks_unref(struct quirks *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);
@@ -1378,6 +1387,41 @@ match_free(struct match *m)
        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,
@@ -1401,7 +1445,26 @@ quirk_apply_section(struct quirks_context *ctx,
                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);
        }
 }
 
index 8f1aae918ee8917cd00b8ec4b5ceece7e457d6f5..bd96c3af4b4c179123ac488e8947e71c2de87e1e 100644 (file)
@@ -54,6 +54,7 @@ struct quirk_tuples {
        struct {
                int first;
                int second;
+               int third;
        } tuples[32];
        size_t ntuples;
 };
@@ -104,10 +105,8 @@ enum quirk {
        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 */
 };
index a03fbdd549b3c93707c6804f10129a7b910ac795..47ba3b51544f751852e807534de78e7d1040345a 100644 (file)
@@ -347,10 +347,10 @@ parse_evcode_string(const char *s, int *type_out, int *code_out)
 }
 
 /**
- * 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
@@ -361,7 +361,8 @@ parse_evcode_string(const char *s, int *type_out, int *code_out)
  * 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)
@@ -380,6 +381,16 @@ parse_evcode_property(const char *prop, struct input_event *events, size_t *neve
        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;
 
@@ -399,6 +410,7 @@ parse_evcode_property(const char *prop, struct input_event *events, size_t *neve
 
                evs[idx].type = type;
                evs[idx].code = code;
+               evs[idx].value = enable;
        }
 
        memcpy(events, evs, ncodes * sizeof *events);
@@ -411,9 +423,9 @@ out:
 }
 
 /**
- * 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
@@ -423,10 +435,10 @@ out:
  * 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);
@@ -437,6 +449,16 @@ parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *npr
        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)
@@ -447,7 +469,8 @@ parse_input_prop_property(const char *prop, unsigned int *props_out, size_t *npr
                                goto out;
                        prop = (unsigned int)val;
                }
-               props[idx] = prop;
+               props[idx].prop = prop;
+               props[idx].enabled = enable;
        }
 
        memcpy(props_out, props, count * sizeof *props);
index 71789141da9cb71922edbfd3a57d563184816f0b..81b2049000befbe3afc69f0ac4a266f292170ece 100644 (file)
 #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);
@@ -39,7 +44,7 @@ bool parse_range_property(const char *prop, int *hi, int *lo);
 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,
index 53161fa42600addaa0d91e49eb3465e164008d2d..914238a961259d4470bb0dec46f88940446065c6 100644 (file)
@@ -199,22 +199,46 @@ static int events[] = {
 };
 
 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
 ;
 
index 3b153436d959fa8a79147abe503f0b0e0a47b38b..f7895b28d788677fcb7aca24397df8d44ab7cf73 100644 (file)
@@ -1477,7 +1477,11 @@ START_TEST(device_quirks)
             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();
@@ -1490,6 +1494,8 @@ START_TEST(device_quirks)
                                                     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,
@@ -1510,6 +1516,22 @@ START_TEST(device_quirks)
                        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++;
@@ -1520,6 +1542,10 @@ START_TEST(device_quirks)
 #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);
index ab3158a9493830a23043ba21d2657570ac053e1c..a5248147c6154ce1a2dc30f4b83adc572faadc22 100644 (file)
@@ -560,47 +560,50 @@ START_TEST(evcode_prop_parser)
        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 },
        };
@@ -617,14 +620,14 @@ START_TEST(evcode_prop_parser)
                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);
                }
        }
 }
@@ -636,16 +639,16 @@ START_TEST(input_prop_parser)
                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 },
@@ -659,7 +662,7 @@ START_TEST(input_prop_parser)
 
        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];
@@ -670,7 +673,8 @@ START_TEST(input_prop_parser)
 
                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);
                }
        }
 }
index 8dc3b607e43313cd58536f1ff8b763e6dffefc28..d779183878dd36ff3982a799cd5ffe6bb2f4905c 100644 (file)
@@ -632,11 +632,13 @@ sprintf_event_codes(char *buf, size_t sz, struct quirks *quirks, enum quirk q)
        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;
        }
@@ -645,21 +647,24 @@ sprintf_event_codes(char *buf, size_t sz, struct quirks *quirks, enum quirk q)
 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;
        }
@@ -747,13 +752,11 @@ tools_list_device_quirks(struct quirks_context *ctx,
                                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;