Commit 3cb5ff02 authored by Jamie Lentin's avatar Jamie Lentin Committed by Jiri Kosina

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: default avatarJamie Lentin <jm@lentin.co.uk>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent dbfebb44
...@@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd { ...@@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd {
}; };
struct lenovo_drvdata_cptkbd { struct lenovo_drvdata_cptkbd {
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
bool fn_lock; bool fn_lock;
int sensitivity; int sensitivity;
}; };
...@@ -316,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev, ...@@ -316,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev,
return 0; return 0;
} }
static int lenovo_event_cptkbd(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct lenovo_drvdata_cptkbd *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;
}
/* 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;
}
return 1;
}
return 0;
}
static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
switch (hdev->product) {
case USB_DEVICE_ID_LENOVO_CUSBKBD:
case USB_DEVICE_ID_LENOVO_CBTKBD:
return lenovo_event_cptkbd(hdev, field, usage, value);
default:
return 0;
}
}
static int lenovo_features_set_tpkbd(struct hid_device *hdev) static int lenovo_features_set_tpkbd(struct hid_device *hdev)
{ {
struct hid_report *report; struct hid_report *report;
...@@ -708,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) ...@@ -708,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret); hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
/* Set keyboard settings to known state */ /* Set keyboard settings to known state */
cptkbd_data->middlebutton_state = 0;
cptkbd_data->fn_lock = true; cptkbd_data->fn_lock = true;
cptkbd_data->sensitivity = 0x05; cptkbd_data->sensitivity = 0x05;
lenovo_features_set_cptkbd(hdev); lenovo_features_set_cptkbd(hdev);
...@@ -835,6 +884,7 @@ static struct hid_driver lenovo_driver = { ...@@ -835,6 +884,7 @@ static struct hid_driver lenovo_driver = {
.probe = lenovo_probe, .probe = lenovo_probe,
.remove = lenovo_remove, .remove = lenovo_remove,
.raw_event = lenovo_raw_event, .raw_event = lenovo_raw_event,
.event = lenovo_event,
.report_fixup = lenovo_report_fixup, .report_fixup = lenovo_report_fixup,
}; };
module_hid_driver(lenovo_driver); module_hid_driver(lenovo_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment