From 6e60f8fb19cad03747b877dfcf587d9684dfc6f7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 28 May 2019 09:54:27 +1000 Subject: [PATCH] quirks: add trackpoint integration attribute Some versions [1] of the Lenovo ThinkPad Compact USB Keyboard with TrackPoint USB have the pointing stick on an event node that has keys but is not a regular keyboard. Thus the stick falls through the cracks and gets disabled on tablet mode switch. Instead of adding more hacks let's do this properly: tag the pointing stick as external and have the code in place to deal with that. [1] This may be caused by recent kernel changes Fixes #291 Signed-off-by: Peter Hutterer (cherry picked from commit 8dfe8c68eb9bde9eecc7de5665903d258df42272) --- doc/user/device-quirks.rst | 3 +++ quirks/50-system-lenovo.quirks | 9 ++++++++- src/evdev-fallback.c | 14 +++++++++----- src/evdev.c | 32 ++++++++++++++++++++++++++++---- src/quirks.c | 8 ++++++++ src/quirks.h | 1 + test/test-quirks.c | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 91 insertions(+), 10 deletions(-) diff --git a/doc/user/device-quirks.rst b/doc/user/device-quirks.rst index 2a449433..8b19ae81 100644 --- a/doc/user/device-quirks.rst +++ b/doc/user/device-quirks.rst @@ -183,3 +183,6 @@ AttrEventCodeDisable=EV_ABS;BTN_STYLUS;EV_KEY:0x123; Disables 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. +AttrPointingStickIntegration=internal|external + Indicates the integration of the pointing stick. This is a string enum. + Only needed for external pointing sticks. These are rare. diff --git a/quirks/50-system-lenovo.quirks b/quirks/50-system-lenovo.quirks index d2acefd4..ea4a0636 100644 --- a/quirks/50-system-lenovo.quirks +++ b/quirks/50-system-lenovo.quirks @@ -76,13 +76,20 @@ MatchName=*TPPS/2 Elan TrackPoint* MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX1Carbon6th* AttrTrackpointMultiplier=0.4 -[Lenovo ThinkPad Compact USB Keyboard with TrackPoint] +[Lenovo ThinkPad Compact USB Keyboard with TrackPoint (keyboard)] MatchUdevType=keyboard MatchBus=usb MatchVendor=0x17EF MatchProduct=0x6047 AttrKeyboardIntegration=external +[Lenovo ThinkPad Compact USB Keyboard with TrackPoint (trackpoint)] +MatchUdevType=pointingstick +MatchBus=usb +MatchVendor=0x17EF +MatchProduct=0x6047 +AttrPointingStickIntegration=external + # Lenovo Thinkpad Yoga (not the consumer versions) disables the keyboard # mechanically. We must not disable the keyboard because some keys are # still accessible on the screen and volume rocker. diff --git a/src/evdev-fallback.c b/src/evdev-fallback.c index e5169c48..18af9445 100644 --- a/src/evdev-fallback.c +++ b/src/evdev-fallback.c @@ -1382,8 +1382,8 @@ fallback_tablet_mode_switch_event(uint64_t time, } static void -fallback_keyboard_pair_tablet_mode(struct evdev_device *keyboard, - struct evdev_device *tablet_mode_switch) +fallback_pair_tablet_mode(struct evdev_device *keyboard, + struct evdev_device *tablet_mode_switch) { struct fallback_dispatch *dispatch = fallback_dispatch(keyboard->dispatch); @@ -1391,8 +1391,12 @@ fallback_keyboard_pair_tablet_mode(struct evdev_device *keyboard, if ((keyboard->tags & EVDEV_TAG_EXTERNAL_KEYBOARD)) return; - if ((keyboard->tags & - (EVDEV_TAG_TRACKPOINT|EVDEV_TAG_INTERNAL_KEYBOARD)) == 0) + if ((keyboard->tags & EVDEV_TAG_TRACKPOINT)) { + if (keyboard->tags & EVDEV_TAG_EXTERNAL_MOUSE) + return; + /* This filters out all internal keyboard-like devices (Video + * Switch) */ + } else if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0) return; if (evdev_device_has_model_quirk(keyboard, @@ -1429,7 +1433,7 @@ fallback_interface_device_added(struct evdev_device *device, struct evdev_device *added_device) { fallback_lid_pair_keyboard(device, added_device); - fallback_keyboard_pair_tablet_mode(device, added_device); + fallback_pair_tablet_mode(device, added_device); } static void diff --git a/src/evdev.c b/src/evdev.c index a077a87d..1c9980e0 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -387,10 +387,34 @@ static void evdev_tag_trackpoint(struct evdev_device *device, struct udev_device *udev_device) { - if (libevdev_has_property(device->evdev, - INPUT_PROP_POINTING_STICK) || - parse_udev_flag(device, udev_device, "ID_INPUT_POINTINGSTICK")) - device->tags |= EVDEV_TAG_TRACKPOINT; + struct quirks_context *quirks; + struct quirks *q; + char *prop; + + if (!libevdev_has_property(device->evdev, + INPUT_PROP_POINTING_STICK) && + !parse_udev_flag(device, udev_device, "ID_INPUT_POINTINGSTICK")) + return; + + device->tags |= EVDEV_TAG_TRACKPOINT; + + quirks = evdev_libinput_context(device)->quirks; + q = quirks_fetch_for_device(quirks, device->udev_device); + if (q && quirks_get_string(q, QUIRK_ATTR_TRACKPOINT_INTEGRATION, &prop)) { + if (streq(prop, "internal")) { + /* noop, this is the default anyway */ + } else if (streq(prop, "external")) { + device->tags |= EVDEV_TAG_EXTERNAL_MOUSE; + evdev_log_info(device, + "is an external pointing stick\n"); + } else { + evdev_log_info(device, + "tagged with unknown value %s\n", + prop); + } + } + + quirks_unref(q); } static inline void diff --git a/src/quirks.c b/src/quirks.c index c1edcd38..90bb4cbd 100644 --- a/src/quirks.c +++ b/src/quirks.c @@ -261,6 +261,7 @@ quirk_get_name(enum quirk q) case QUIRK_ATTR_PALM_SIZE_THRESHOLD: return "AttrPalmSizeThreshold"; case QUIRK_ATTR_LID_SWITCH_RELIABILITY: return "AttrLidSwitchReliability"; case QUIRK_ATTR_KEYBOARD_INTEGRATION: return "AttrKeyboardIntegration"; + case QUIRK_ATTR_TRACKPOINT_INTEGRATION: return "AttrPointingStickIntegration"; case QUIRK_ATTR_TPKBCOMBO_LAYOUT: return "AttrTPKComboLayout"; case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange"; case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold"; @@ -661,6 +662,13 @@ 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_TRACKPOINT_INTEGRATION))) { + p->id = QUIRK_ATTR_TRACKPOINT_INTEGRATION; + if (!streq(value, "internal") && !streq(value, "external")) + goto out; + p->type = PT_STRING; + p->value.s = safe_strdup(value); + rc = true; } else if (streq(key, quirk_get_name(QUIRK_ATTR_TPKBCOMBO_LAYOUT))) { p->id = QUIRK_ATTR_TPKBCOMBO_LAYOUT; if (!streq(value, "below")) diff --git a/src/quirks.h b/src/quirks.h index e269e999..4928ac1e 100644 --- a/src/quirks.h +++ b/src/quirks.h @@ -96,6 +96,7 @@ enum quirk { QUIRK_ATTR_PALM_SIZE_THRESHOLD, QUIRK_ATTR_LID_SWITCH_RELIABILITY, QUIRK_ATTR_KEYBOARD_INTEGRATION, + QUIRK_ATTR_TRACKPOINT_INTEGRATION, QUIRK_ATTR_TPKBCOMBO_LAYOUT, QUIRK_ATTR_PRESSURE_RANGE, QUIRK_ATTR_PALM_PRESSURE_THRESHOLD, diff --git a/test/test-quirks.c b/test/test-quirks.c index 1193c0f9..e4d48829 100644 --- a/test/test-quirks.c +++ b/test/test-quirks.c @@ -1204,6 +1204,39 @@ START_TEST(quirks_parse_string_attr) } END_TEST +START_TEST(quirks_parse_integration_attr) +{ + struct litest_device *dev = litest_current_device(); + char *do_not_use; /* freed before we can use it */ + bool + + rc = test_attr_parse(dev, + QUIRK_ATTR_KEYBOARD_INTEGRATION, + "internal", + (qparsefunc)quirks_get_string, + &do_not_use); + ck_assert(rc); + rc = test_attr_parse(dev, + QUIRK_ATTR_KEYBOARD_INTEGRATION, + "external", + (qparsefunc)quirks_get_string, + &do_not_use); + ck_assert(rc); + rc = test_attr_parse(dev, + QUIRK_ATTR_TRACKPOINT_INTEGRATION, + "internal", + (qparsefunc)quirks_get_string, + &do_not_use); + ck_assert(rc); + rc = test_attr_parse(dev, + QUIRK_ATTR_TRACKPOINT_INTEGRATION, + "external", + (qparsefunc)quirks_get_string, + &do_not_use); + ck_assert(rc); +} +END_TEST + START_TEST(quirks_model_one) { struct litest_device *dev = litest_current_device(); @@ -1432,6 +1465,7 @@ TEST_COLLECTION(quirks) litest_add_for_device("quirks:parsing", quirks_parse_uint_attr, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_double_attr, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_string_attr, LITEST_MOUSE); + litest_add_for_device("quirks:parsing", quirks_parse_integration_attr, LITEST_MOUSE); litest_add_for_device("quirks:model", quirks_model_one, LITEST_MOUSE); litest_add_for_device("quirks:model", quirks_model_zero, LITEST_MOUSE);