diff mbox series

HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd

Message ID 20230918145042.37368-1-me@khvoinitsky.org
State Superseded
Headers show
Series HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd | expand

Commit Message

Mikhail Khvoinitsky Sept. 18, 2023, 2:50 p.m. UTC
Built-in firmware of cptkbd handles scrolling by itself (when middle
button is pressed) but with issues: it does not support horizontal and
hi-res scrolling and upon middle button release it sends middle button
click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID:
lenovo: Hide middle-button press until release") workarounds last
issue but it's impossible to workaround scrolling-related issues
without firmware modification.

Likely, Dennis Schneider has reverse engineered the firmware and
provided an instruction on how to patch it [1]. However,
aforementioned workaround prevents userspace (libinput) from knowing
exact moment when middle button has been pressed down and performing
"On-Button scrolling". This commit makes it possible to disable this
workaround by sysfs knob.

Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]

Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>
---
 drivers/hid/hid-lenovo.c | 84 +++++++++++++++++++++++++++++-----------
 1 file changed, 62 insertions(+), 22 deletions(-)

Comments

Mikhail Khvoinitsky Sept. 23, 2023, 10:58 p.m. UTC | #1
So, while I was waiting for the review of the patch, I've come up with
much better idea: we can just autodetect if stock and buggy or
patched and bug-free firmware is used and have no need to introduce
additional sysfs knob. So the patch which implements this follows in
the next message.

While the patch is ready to be merged as is (of course, if there are
no comments from reviewers), I thought about the following: may be we
should add a message to dmesg upon detecting stock and buggy firmware
that user should consider patching the firmware? If so, what is the
best place to put an instruction to? Post a link to dmesg? Can the
link point directly to Dennis' blog or its better to put it somewhere
else (with credits, of course)?

Thanks.
Yauhen Kharuzhy Dec. 9, 2023, 12:50 p.m. UTC | #2
On Sun, Sep 24, 2023 at 01:58:30AM +0300, Mikhail Khvainitski wrote:
> Built-in firmware of cptkbd handles scrolling by itself (when middle
> button is pressed) but with issues: it does not support horizontal and
> hi-res scrolling and upon middle button release it sends middle button
> click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID:
> lenovo: Hide middle-button press until release") workarounds last
> issue but it's impossible to workaround scrolling-related issues
> without firmware modification.
> 
> Likely, Dennis Schneider has reverse engineered the firmware and
> provided an instruction on how to patch it [1]. However,
> aforementioned workaround prevents userspace (libinput) from knowing
> exact moment when middle button has been pressed down and performing
> "On-Button scrolling". This commit detects correctly-behaving patched
> firmware if cursor movement events has been received during middle
> button being pressed and stops applying workaround for this device.
> 
> Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]

This patch breaks a scrolling at my ThinkPad TrackPoint Keyboard II: it
starts to report middle-button push/release events with scrolling events
between. A support for this keyboard was added in
24401f291dcc4f2c18b9e2f65763cbaadc7a1528 "HID: lenovo: Add support for
ThinkPad TrackPoint Keyboard II" commit.

There is an evtest output below:

Without of commit:

Middle-button click:
Event: time 1702122290.593300, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1702122290.593300, -------------- SYN_REPORT ------------
Event: time 1702122290.593312, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1702122290.593312, -------------- SYN_REPORT ------------

Vertical scrolling:
Event: time 1702122300.441627, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702122300.441627, -------------- SYN_REPORT ------------
Event: time 1702122300.565663, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702122300.565663, -------------- SYN_REPORT ------------

Horizontal scrolling:
Event: time 1702122307.845969, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
Event: time 1702122307.845969, -------------- SYN_REPORT ------------
Event: time 1702122307.981954, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
Event: time 1702122307.981954, -------------- SYN_REPORT ------------



After commit:

Middle-button click:
Event: time 1702125091.290045, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125091.290045, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1702125091.290045, -------------- SYN_REPORT ------------
Event: time 1702125092.626118, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125092.626118, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1702125092.626118, -------------- SYN_REPORT ------------


Vscroll:
Event: time 1702125286.653639, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125286.653639, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1702125286.653639, -------------- SYN_REPORT ------------
Event: time 1702125287.929689, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702125287.929689, -------------- SYN_REPORT ------------
Event: time 1702125288.037688, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702125288.037688, -------------- SYN_REPORT ------------
Event: time 1702125290.481787, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125290.481787, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1702125290.481787, -------------- SYN_REPORT ------------

Hscroll:
Event: time 1702125293.841920, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125293.841920, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1702125293.841920, -------------- SYN_REPORT ------------
Event: time 1702125294.761952, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
Event: time 1702125294.761952, -------------- SYN_REPORT ------------
Event: time 1702125294.893967, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
Event: time 1702125294.893967, -------------- SYN_REPORT ------------
Event: time 1702125296.134006, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702125296.134006, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1702125296.134006, -------------- SYN_REPORT ------------
Yauhen Kharuzhy Dec. 9, 2023, 4:56 p.m. UTC | #3
On Sat, Dec 09, 2023 at 02:50:16PM +0200, Yauhen Kharuzhy wrote:
> On Sun, Sep 24, 2023 at 01:58:30AM +0300, Mikhail Khvainitski wrote:
> > Built-in firmware of cptkbd handles scrolling by itself (when middle
> > button is pressed) but with issues: it does not support horizontal and
> > hi-res scrolling and upon middle button release it sends middle button
> > click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID:
> > lenovo: Hide middle-button press until release") workarounds last
> > issue but it's impossible to workaround scrolling-related issues
> > without firmware modification.
> > 
> > Likely, Dennis Schneider has reverse engineered the firmware and
> > provided an instruction on how to patch it [1]. However,
> > aforementioned workaround prevents userspace (libinput) from knowing
> > exact moment when middle button has been pressed down and performing
> > "On-Button scrolling". This commit detects correctly-behaving patched
> > firmware if cursor movement events has been received during middle
> > button being pressed and stops applying workaround for this device.
> > 
> > Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]
> 
> This patch breaks a scrolling at my ThinkPad TrackPoint Keyboard II: it
> starts to report middle-button push/release events with scrolling events
> between. A support for this keyboard was added in
> 24401f291dcc4f2c18b9e2f65763cbaadc7a1528 "HID: lenovo: Add support for
> ThinkPad TrackPoint Keyboard II" commit.

I figured this out.

This keyboard can emit REL_Y/REL_X events between of middle-button
events (if user was moving a cursor and press middle button without of
stopping this), so this algorithm does a false-positive detection and switches
the workaround off like for patched firmware:

Event: time 1702140625.854777, type 2 (EV_REL), code 1 (REL_Y), value 2
Event: time 1702140625.854777, -------------- SYN_REPORT ------------
Event: time 1702140625.870769, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
Event: time 1702140625.870769, -------------- SYN_REPORT ------------
Event: time 1702140625.870771, type 2 (EV_REL), code 1 (REL_Y), value 2
Event: time 1702140625.870771, -------------- SYN_REPORT ------------
Event: time 1702140625.970780, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702140625.970780, -------------- SYN_REPORT ------------
Event: time 1702140626.058800, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
Event: time 1702140626.058800, -------------- SYN_REPORT ------------
Event: time 1702140630.462974, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
Event: time 1702140630.462974, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
Event: time 1702140630.462974, -------------- SYN_REPORT ------------


> 
> There is an evtest output below:
> 
> Without of commit:
> 
> Middle-button click:
> Event: time 1702122290.593300, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> Event: time 1702122290.593300, -------------- SYN_REPORT ------------
> Event: time 1702122290.593312, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> Event: time 1702122290.593312, -------------- SYN_REPORT ------------
> 
> Vertical scrolling:
> Event: time 1702122300.441627, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702122300.441627, -------------- SYN_REPORT ------------
> Event: time 1702122300.565663, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702122300.565663, -------------- SYN_REPORT ------------
> 
> Horizontal scrolling:
> Event: time 1702122307.845969, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> Event: time 1702122307.845969, -------------- SYN_REPORT ------------
> Event: time 1702122307.981954, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> Event: time 1702122307.981954, -------------- SYN_REPORT ------------
> 
> 
> 
> After commit:
> 
> Middle-button click:
> Event: time 1702125091.290045, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125091.290045, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> Event: time 1702125091.290045, -------------- SYN_REPORT ------------
> Event: time 1702125092.626118, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125092.626118, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> Event: time 1702125092.626118, -------------- SYN_REPORT ------------
> 
> 
> Vscroll:
> Event: time 1702125286.653639, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125286.653639, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> Event: time 1702125286.653639, -------------- SYN_REPORT ------------
> Event: time 1702125287.929689, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702125287.929689, -------------- SYN_REPORT ------------
> Event: time 1702125288.037688, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702125288.037688, -------------- SYN_REPORT ------------
> Event: time 1702125290.481787, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125290.481787, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> Event: time 1702125290.481787, -------------- SYN_REPORT ------------
> 
> Hscroll:
> Event: time 1702125293.841920, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125293.841920, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> Event: time 1702125293.841920, -------------- SYN_REPORT ------------
> Event: time 1702125294.761952, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> Event: time 1702125294.761952, -------------- SYN_REPORT ------------
> Event: time 1702125294.893967, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> Event: time 1702125294.893967, -------------- SYN_REPORT ------------
> Event: time 1702125296.134006, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702125296.134006, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> Event: time 1702125296.134006, -------------- SYN_REPORT ------------
Yauhen Kharuzhy Dec. 9, 2023, 6:21 p.m. UTC | #4
On Sat, Dec 09, 2023 at 06:56:48PM +0200, Yauhen Kharuzhy wrote:
> On Sat, Dec 09, 2023 at 02:50:16PM +0200, Yauhen Kharuzhy wrote:
> > On Sun, Sep 24, 2023 at 01:58:30AM +0300, Mikhail Khvainitski wrote:
> > > Built-in firmware of cptkbd handles scrolling by itself (when middle
> > > button is pressed) but with issues: it does not support horizontal and
> > > hi-res scrolling and upon middle button release it sends middle button
> > > click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID:
> > > lenovo: Hide middle-button press until release") workarounds last
> > > issue but it's impossible to workaround scrolling-related issues
> > > without firmware modification.
> > > 
> > > Likely, Dennis Schneider has reverse engineered the firmware and
> > > provided an instruction on how to patch it [1]. However,
> > > aforementioned workaround prevents userspace (libinput) from knowing
> > > exact moment when middle button has been pressed down and performing
> > > "On-Button scrolling". This commit detects correctly-behaving patched
> > > firmware if cursor movement events has been received during middle
> > > button being pressed and stops applying workaround for this device.
> > > 
> > > Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]
> > 
> > This patch breaks a scrolling at my ThinkPad TrackPoint Keyboard II: it
> > starts to report middle-button push/release events with scrolling events
> > between. A support for this keyboard was added in
> > 24401f291dcc4f2c18b9e2f65763cbaadc7a1528 "HID: lenovo: Add support for
> > ThinkPad TrackPoint Keyboard II" commit.
> 
> I figured this out.
> 
> This keyboard can emit REL_Y/REL_X events between of middle-button
> events (if user was moving a cursor and press middle button without of
> stopping this), so this algorithm does a false-positive detection and switches
> the workaround off like for patched firmware:
> 
> Event: time 1702140625.854777, type 2 (EV_REL), code 1 (REL_Y), value 2
> Event: time 1702140625.854777, -------------- SYN_REPORT ------------
> Event: time 1702140625.870769, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> Event: time 1702140625.870769, -------------- SYN_REPORT ------------
> Event: time 1702140625.870771, type 2 (EV_REL), code 1 (REL_Y), value 2
> Event: time 1702140625.870771, -------------- SYN_REPORT ------------
> Event: time 1702140625.970780, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702140625.970780, -------------- SYN_REPORT ------------
> Event: time 1702140626.058800, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> Event: time 1702140626.058800, -------------- SYN_REPORT ------------
> Event: time 1702140630.462974, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> Event: time 1702140630.462974, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> Event: time 1702140630.462974, -------------- SYN_REPORT ------------

Maybe we should map the wheel HID reports to REL_Y/REL_X in
lenovo_input_mapping_tpIIkbd() to allow libinput to do its wheel emulation job?
I tried this but I am not familiar with HID drivers and had no success.


> 
> 
> > 
> > There is an evtest output below:
> > 
> > Without of commit:
> > 
> > Middle-button click:
> > Event: time 1702122290.593300, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > Event: time 1702122290.593300, -------------- SYN_REPORT ------------
> > Event: time 1702122290.593312, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > Event: time 1702122290.593312, -------------- SYN_REPORT ------------
> > 
> > Vertical scrolling:
> > Event: time 1702122300.441627, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702122300.441627, -------------- SYN_REPORT ------------
> > Event: time 1702122300.565663, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702122300.565663, -------------- SYN_REPORT ------------
> > 
> > Horizontal scrolling:
> > Event: time 1702122307.845969, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > Event: time 1702122307.845969, -------------- SYN_REPORT ------------
> > Event: time 1702122307.981954, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > Event: time 1702122307.981954, -------------- SYN_REPORT ------------
> > 
> > 
> > 
> > After commit:
> > 
> > Middle-button click:
> > Event: time 1702125091.290045, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125091.290045, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > Event: time 1702125091.290045, -------------- SYN_REPORT ------------
> > Event: time 1702125092.626118, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125092.626118, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > Event: time 1702125092.626118, -------------- SYN_REPORT ------------
> > 
> > 
> > Vscroll:
> > Event: time 1702125286.653639, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125286.653639, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > Event: time 1702125286.653639, -------------- SYN_REPORT ------------
> > Event: time 1702125287.929689, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702125287.929689, -------------- SYN_REPORT ------------
> > Event: time 1702125288.037688, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702125288.037688, -------------- SYN_REPORT ------------
> > Event: time 1702125290.481787, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125290.481787, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > Event: time 1702125290.481787, -------------- SYN_REPORT ------------
> > 
> > Hscroll:
> > Event: time 1702125293.841920, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125293.841920, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > Event: time 1702125293.841920, -------------- SYN_REPORT ------------
> > Event: time 1702125294.761952, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > Event: time 1702125294.761952, -------------- SYN_REPORT ------------
> > Event: time 1702125294.893967, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > Event: time 1702125294.893967, -------------- SYN_REPORT ------------
> > Event: time 1702125296.134006, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702125296.134006, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > Event: time 1702125296.134006, -------------- SYN_REPORT ------------
> 
> -- 
> Yauhen Kharuzhy
Mikhail Khvoinitsky Dec. 11, 2023, 4:17 p.m. UTC | #5
Hello.

Well, that's unfortunate. As far as I can see, yes, TrackPoint
Keyboard II behaves similarly to 1st gen Trackpoint Keyboard (a.k.a.
Compact) but not quite. The best way would be to make the keyboard not
emulate scrolling at all but not sure if its possible. For cptkbd it
required patching firmware, it might be also the case for 2nd gen.

> Maybe we should map the wheel HID reports to REL_Y/REL_X in
> lenovo_input_mapping_tpIIkbd() to allow libinput to do its wheel emulation job?

It might work but since emulated wheel events aren't continuous (at
least this is the case with cptkbd), it doesn't make much sense in
comparison with the original implementation — just ignore the middle
button if scrolling.

I'll try to get the keyboard and check, but at the moment it seems
that the best thing to do is before stopping applying a workaround,
check that it's a Trackpoint Compact keyboard, not anything else. If I
won't be able to find a better solution shortly, I'll make a patch
which makes sure that it's only cptkbd before disabling the
workaround.

On Sat, 9 Dec 2023 at 20:21, Yauhen Kharuzhy <jekhor@gmail.com> wrote:
>
> On Sat, Dec 09, 2023 at 06:56:48PM +0200, Yauhen Kharuzhy wrote:
> > On Sat, Dec 09, 2023 at 02:50:16PM +0200, Yauhen Kharuzhy wrote:
> > > On Sun, Sep 24, 2023 at 01:58:30AM +0300, Mikhail Khvainitski wrote:
> > > > Built-in firmware of cptkbd handles scrolling by itself (when middle
> > > > button is pressed) but with issues: it does not support horizontal and
> > > > hi-res scrolling and upon middle button release it sends middle button
> > > > click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID:
> > > > lenovo: Hide middle-button press until release") workarounds last
> > > > issue but it's impossible to workaround scrolling-related issues
> > > > without firmware modification.
> > > >
> > > > Likely, Dennis Schneider has reverse engineered the firmware and
> > > > provided an instruction on how to patch it [1]. However,
> > > > aforementioned workaround prevents userspace (libinput) from knowing
> > > > exact moment when middle button has been pressed down and performing
> > > > "On-Button scrolling". This commit detects correctly-behaving patched
> > > > firmware if cursor movement events has been received during middle
> > > > button being pressed and stops applying workaround for this device.
> > > >
> > > > Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]
> > >
> > > This patch breaks a scrolling at my ThinkPad TrackPoint Keyboard II: it
> > > starts to report middle-button push/release events with scrolling events
> > > between. A support for this keyboard was added in
> > > 24401f291dcc4f2c18b9e2f65763cbaadc7a1528 "HID: lenovo: Add support for
> > > ThinkPad TrackPoint Keyboard II" commit.
> >
> > I figured this out.
> >
> > This keyboard can emit REL_Y/REL_X events between of middle-button
> > events (if user was moving a cursor and press middle button without of
> > stopping this), so this algorithm does a false-positive detection and switches
> > the workaround off like for patched firmware:
> >
> > Event: time 1702140625.854777, type 2 (EV_REL), code 1 (REL_Y), value 2
> > Event: time 1702140625.854777, -------------- SYN_REPORT ------------
> > Event: time 1702140625.870769, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > Event: time 1702140625.870769, -------------- SYN_REPORT ------------
> > Event: time 1702140625.870771, type 2 (EV_REL), code 1 (REL_Y), value 2
> > Event: time 1702140625.870771, -------------- SYN_REPORT ------------
> > Event: time 1702140625.970780, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702140625.970780, -------------- SYN_REPORT ------------
> > Event: time 1702140626.058800, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > Event: time 1702140626.058800, -------------- SYN_REPORT ------------
> > Event: time 1702140630.462974, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > Event: time 1702140630.462974, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > Event: time 1702140630.462974, -------------- SYN_REPORT ------------
>
> Maybe we should map the wheel HID reports to REL_Y/REL_X in
> lenovo_input_mapping_tpIIkbd() to allow libinput to do its wheel emulation job?
> I tried this but I am not familiar with HID drivers and had no success.
>
>
> >
> >
> > >
> > > There is an evtest output below:
> > >
> > > Without of commit:
> > >
> > > Middle-button click:
> > > Event: time 1702122290.593300, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > > Event: time 1702122290.593300, -------------- SYN_REPORT ------------
> > > Event: time 1702122290.593312, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > > Event: time 1702122290.593312, -------------- SYN_REPORT ------------
> > >
> > > Vertical scrolling:
> > > Event: time 1702122300.441627, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > > Event: time 1702122300.441627, -------------- SYN_REPORT ------------
> > > Event: time 1702122300.565663, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > > Event: time 1702122300.565663, -------------- SYN_REPORT ------------
> > >
> > > Horizontal scrolling:
> > > Event: time 1702122307.845969, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > > Event: time 1702122307.845969, -------------- SYN_REPORT ------------
> > > Event: time 1702122307.981954, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > > Event: time 1702122307.981954, -------------- SYN_REPORT ------------
> > >
> > >
> > >
> > > After commit:
> > >
> > > Middle-button click:
> > > Event: time 1702125091.290045, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125091.290045, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > > Event: time 1702125091.290045, -------------- SYN_REPORT ------------
> > > Event: time 1702125092.626118, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125092.626118, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > > Event: time 1702125092.626118, -------------- SYN_REPORT ------------
> > >
> > >
> > > Vscroll:
> > > Event: time 1702125286.653639, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125286.653639, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > > Event: time 1702125286.653639, -------------- SYN_REPORT ------------
> > > Event: time 1702125287.929689, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > > Event: time 1702125287.929689, -------------- SYN_REPORT ------------
> > > Event: time 1702125288.037688, type 2 (EV_REL), code 8 (REL_WHEEL), value -1
> > > Event: time 1702125288.037688, -------------- SYN_REPORT ------------
> > > Event: time 1702125290.481787, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125290.481787, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > > Event: time 1702125290.481787, -------------- SYN_REPORT ------------
> > >
> > > Hscroll:
> > > Event: time 1702125293.841920, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125293.841920, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 1
> > > Event: time 1702125293.841920, -------------- SYN_REPORT ------------
> > > Event: time 1702125294.761952, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > > Event: time 1702125294.761952, -------------- SYN_REPORT ------------
> > > Event: time 1702125294.893967, type 2 (EV_REL), code 6 (REL_HWHEEL), value -1
> > > Event: time 1702125294.893967, -------------- SYN_REPORT ------------
> > > Event: time 1702125296.134006, type 4 (EV_MSC), code 4 (MSC_SCAN), value ffa000fb
> > > Event: time 1702125296.134006, type 1 (EV_KEY), code 274 (BTN_MIDDLE), value 0
> > > Event: time 1702125296.134006, -------------- SYN_REPORT ------------
> >
> > --
> > Yauhen Kharuzhy
>
> --
> Yauhen Kharuzhy
diff mbox series

Patch

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 44763c0da444..8993fa1ce66a 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -53,6 +53,7 @@  struct lenovo_drvdata {
 	int press_speed;
 	u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
 	bool fn_lock;
+	bool middleclick_workaround_cptkbd;
 };
 
 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
@@ -603,6 +604,36 @@  static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
 	return count;
 }
 
+static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		cptkbd_data->middleclick_workaround_cptkbd);
+}
+
+static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
+	int value;
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	cptkbd_data->middleclick_workaround_cptkbd = !!value;
+
+	return count;
+}
+
 
 static struct device_attribute dev_attr_fn_lock =
 	__ATTR(fn_lock, S_IWUSR | S_IRUGO,
@@ -614,10 +645,16 @@  static struct device_attribute dev_attr_sensitivity_cptkbd =
 			attr_sensitivity_show_cptkbd,
 			attr_sensitivity_store_cptkbd);
 
+static struct device_attribute dev_attr_middleclick_workaround_cptkbd =
+	__ATTR(middleclick_workaround, S_IWUSR | S_IRUGO,
+			attr_middleclick_workaround_show_cptkbd,
+			attr_middleclick_workaround_store_cptkbd);
+
 
 static struct attribute *lenovo_attributes_cptkbd[] = {
 	&dev_attr_fn_lock.attr,
 	&dev_attr_sensitivity_cptkbd.attr,
+	&dev_attr_middleclick_workaround_cptkbd.attr,
 	NULL
 };
 
@@ -668,31 +705,33 @@  static int lenovo_event_cptkbd(struct hid_device *hdev,
 {
 	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
 
-	/* "wheel" scroll events */
-	if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
-			usage->code == REL_HWHEEL)) {
-		/* Scroll events disable middle-click event */
-		cptkbd_data->middlebutton_state = 2;
-		return 0;
-	}
+	if (cptkbd_data->middleclick_workaround_cptkbd) {
+		/* "wheel" scroll events */
+		if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
+				usage->code == REL_HWHEEL)) {
+			/* Scroll events disable middle-click event */
+			cptkbd_data->middlebutton_state = 2;
+			return 0;
+		}
 
-	/* Middle click events */
-	if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
-		if (value == 1) {
-			cptkbd_data->middlebutton_state = 1;
-		} else if (value == 0) {
-			if (cptkbd_data->middlebutton_state == 1) {
-				/* No scrolling inbetween, send middle-click */
-				input_event(field->hidinput->input,
-					EV_KEY, BTN_MIDDLE, 1);
-				input_sync(field->hidinput->input);
-				input_event(field->hidinput->input,
-					EV_KEY, BTN_MIDDLE, 0);
-				input_sync(field->hidinput->input);
+		/* Middle click events */
+		if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
+			if (value == 1) {
+				cptkbd_data->middlebutton_state = 1;
+			} else if (value == 0) {
+				if (cptkbd_data->middlebutton_state == 1) {
+					/* No scrolling inbetween, send middle-click */
+					input_event(field->hidinput->input,
+						EV_KEY, BTN_MIDDLE, 1);
+					input_sync(field->hidinput->input);
+					input_event(field->hidinput->input,
+						EV_KEY, BTN_MIDDLE, 0);
+					input_sync(field->hidinput->input);
+				}
+				cptkbd_data->middlebutton_state = 0;
 			}
-			cptkbd_data->middlebutton_state = 0;
+			return 1;
 		}
-		return 1;
 	}
 
 	if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
@@ -1146,6 +1185,7 @@  static int lenovo_probe_cptkbd(struct hid_device *hdev)
 	cptkbd_data->middlebutton_state = 0;
 	cptkbd_data->fn_lock = true;
 	cptkbd_data->sensitivity = 0x05;
+	cptkbd_data->middleclick_workaround_cptkbd = true;
 	lenovo_features_set_cptkbd(hdev);
 
 	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);