Skip to content

Commit 3cb5ff0

Browse files
lentinjJiri Kosina
authored andcommitted
HID: lenovo: Hide middle-button press until release
Don't relay a middle button press to userspace until release, and then only if there was no scroll events inbetween. This is closer to what Xorg's wheel emulation does, and avoids spurious middle-click pastes. Signed-off-by: Jamie Lentin <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent dbfebb4 commit 3cb5ff0

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd {
3737
};
3838

3939
struct lenovo_drvdata_cptkbd {
40+
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
4041
bool fn_lock;
4142
int sensitivity;
4243
};
@@ -316,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev,
316317
return 0;
317318
}
318319

320+
static int lenovo_event_cptkbd(struct hid_device *hdev,
321+
struct hid_field *field, struct hid_usage *usage, __s32 value)
322+
{
323+
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
324+
325+
/* "wheel" scroll events */
326+
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
327+
usage->code == REL_HWHEEL)) {
328+
/* Scroll events disable middle-click event */
329+
cptkbd_data->middlebutton_state = 2;
330+
return 0;
331+
}
332+
333+
/* Middle click events */
334+
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
335+
if (value == 1) {
336+
cptkbd_data->middlebutton_state = 1;
337+
} else if (value == 0) {
338+
if (cptkbd_data->middlebutton_state == 1) {
339+
/* No scrolling inbetween, send middle-click */
340+
input_event(field->hidinput->input,
341+
EV_KEY, BTN_MIDDLE, 1);
342+
input_sync(field->hidinput->input);
343+
input_event(field->hidinput->input,
344+
EV_KEY, BTN_MIDDLE, 0);
345+
input_sync(field->hidinput->input);
346+
}
347+
cptkbd_data->middlebutton_state = 0;
348+
}
349+
return 1;
350+
}
351+
352+
return 0;
353+
}
354+
355+
static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
356+
struct hid_usage *usage, __s32 value)
357+
{
358+
switch (hdev->product) {
359+
case USB_DEVICE_ID_LENOVO_CUSBKBD:
360+
case USB_DEVICE_ID_LENOVO_CBTKBD:
361+
return lenovo_event_cptkbd(hdev, field, usage, value);
362+
default:
363+
return 0;
364+
}
365+
}
366+
319367
static int lenovo_features_set_tpkbd(struct hid_device *hdev)
320368
{
321369
struct hid_report *report;
@@ -708,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
708756
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
709757

710758
/* Set keyboard settings to known state */
759+
cptkbd_data->middlebutton_state = 0;
711760
cptkbd_data->fn_lock = true;
712761
cptkbd_data->sensitivity = 0x05;
713762
lenovo_features_set_cptkbd(hdev);
@@ -835,6 +884,7 @@ static struct hid_driver lenovo_driver = {
835884
.probe = lenovo_probe,
836885
.remove = lenovo_remove,
837886
.raw_event = lenovo_raw_event,
887+
.event = lenovo_event,
838888
.report_fixup = lenovo_report_fixup,
839889
};
840890
module_hid_driver(lenovo_driver);

0 commit comments

Comments
 (0)