Skip to content

Commit 46a0a2c

Browse files
m-khvoinitskyJiri Kosina
authored andcommitted
HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround
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 3cb5ff0 ("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] Signed-off-by: Mikhail Khvainitski <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 29aa98d commit 46a0a2c

File tree

1 file changed

+45
-23
lines changed

1 file changed

+45
-23
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ struct lenovo_drvdata {
5151
int select_right;
5252
int sensitivity;
5353
int press_speed;
54-
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
54+
/* 0: Up
55+
* 1: Down (undecided)
56+
* 2: Scrolling
57+
* 3: Patched firmware, disable workaround
58+
*/
59+
u8 middlebutton_state;
5560
bool fn_lock;
5661
};
5762

@@ -668,31 +673,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
668673
{
669674
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
670675

671-
/* "wheel" scroll events */
672-
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
673-
usage->code == REL_HWHEEL)) {
674-
/* Scroll events disable middle-click event */
675-
cptkbd_data->middlebutton_state = 2;
676-
return 0;
677-
}
676+
if (cptkbd_data->middlebutton_state != 3) {
677+
/* REL_X and REL_Y events during middle button pressed
678+
* are only possible on patched, bug-free firmware
679+
* so set middlebutton_state to 3
680+
* to never apply workaround anymore
681+
*/
682+
if (cptkbd_data->middlebutton_state == 1 &&
683+
usage->type == EV_REL &&
684+
(usage->code == REL_X || usage->code == REL_Y)) {
685+
cptkbd_data->middlebutton_state = 3;
686+
/* send middle button press which was hold before */
687+
input_event(field->hidinput->input,
688+
EV_KEY, BTN_MIDDLE, 1);
689+
input_sync(field->hidinput->input);
690+
}
678691

679-
/* Middle click events */
680-
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
681-
if (value == 1) {
682-
cptkbd_data->middlebutton_state = 1;
683-
} else if (value == 0) {
684-
if (cptkbd_data->middlebutton_state == 1) {
685-
/* No scrolling inbetween, send middle-click */
686-
input_event(field->hidinput->input,
687-
EV_KEY, BTN_MIDDLE, 1);
688-
input_sync(field->hidinput->input);
689-
input_event(field->hidinput->input,
690-
EV_KEY, BTN_MIDDLE, 0);
691-
input_sync(field->hidinput->input);
692+
/* "wheel" scroll events */
693+
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
694+
usage->code == REL_HWHEEL)) {
695+
/* Scroll events disable middle-click event */
696+
cptkbd_data->middlebutton_state = 2;
697+
return 0;
698+
}
699+
700+
/* Middle click events */
701+
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
702+
if (value == 1) {
703+
cptkbd_data->middlebutton_state = 1;
704+
} else if (value == 0) {
705+
if (cptkbd_data->middlebutton_state == 1) {
706+
/* No scrolling inbetween, send middle-click */
707+
input_event(field->hidinput->input,
708+
EV_KEY, BTN_MIDDLE, 1);
709+
input_sync(field->hidinput->input);
710+
input_event(field->hidinput->input,
711+
EV_KEY, BTN_MIDDLE, 0);
712+
input_sync(field->hidinput->input);
713+
}
714+
cptkbd_data->middlebutton_state = 0;
692715
}
693-
cptkbd_data->middlebutton_state = 0;
716+
return 1;
694717
}
695-
return 1;
696718
}
697719

698720
if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {

0 commit comments

Comments
 (0)