2015-08-11 22:19:56

by Jamie Lentin

[permalink] [raw]
Subject: [PATCH 0/3] HID: lenovo: Improve wheel emulation

A collection of unrelated patches to improve support for the Thinkpad
compact keyboards. The first 2 are just cleanup patches.

The final patch alters the behaviour of the middle button so userspace
either gets wheel events or a button click, not both. This stops
browsers opening a link in a new tab as well as scrolling, for example.

This means you can no longer long-middle-click, but I don't think this
is likely to upset users as much as the current behaviour.

Tested against 4.1.2 with both Bluetooth and USB compact keyboards.

Cheers,

Jamie Lentin (3):
HID: lenovo: Use constants for axes names
HID: lenovo: Add missing return-value check
HID: lenovo: Hide middle-button press until release

drivers/hid/hid-lenovo.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 56 insertions(+), 3 deletions(-)

--
2.1.4


2015-08-11 22:19:59

by Jamie Lentin

[permalink] [raw]
Subject: [PATCH 1/3] HID: lenovo: Use constants for axes names

Signed-off-by: Jamie Lentin <[email protected]>
---
drivers/hid/hid-lenovo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index c4c3f09..65df414 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -117,10 +117,10 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,

switch (usage->hid & HID_USAGE) {
case 0x0000:
- hid_map_usage(hi, usage, bit, max, EV_REL, 0x06);
+ hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
return 1;
case 0x0001:
- hid_map_usage(hi, usage, bit, max, EV_REL, 0x08);
+ hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL);
return 1;
default:
return -1;
--
2.1.4

2015-08-11 22:20:35

by Jamie Lentin

[permalink] [raw]
Subject: [PATCH 2/3] HID: lenovo: Add missing return-value check

Signed-off-by: Jamie Lentin <[email protected]>
---
drivers/hid/hid-lenovo.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 65df414..265bfe2 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -178,9 +178,12 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);

ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
- ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
if (ret)
hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
+
+ ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
+ if (ret)
+ hid_err(hdev, "Sensitivity setting failed: %d\n", ret);
}

static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
--
2.1.4

2015-08-11 22:19:52

by Jamie Lentin

[permalink] [raw]
Subject: [PATCH 3/3] 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]>
---
drivers/hid/hid-lenovo.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 265bfe2..629d988 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd {
};

struct lenovo_drvdata_cptkbd {
+ u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
bool fn_lock;
int sensitivity;
};
@@ -287,6 +288,53 @@ static int lenovo_raw_event(struct hid_device *hdev,
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)
{
struct hid_report *report;
@@ -674,6 +722,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);

/* Set keyboard settings to known state */
+ cptkbd_data->middlebutton_state = 0;
cptkbd_data->fn_lock = true;
cptkbd_data->sensitivity = 0x05;
lenovo_features_set_cptkbd(hdev);
@@ -781,6 +830,7 @@ static struct hid_driver lenovo_driver = {
.probe = lenovo_probe,
.remove = lenovo_remove,
.raw_event = lenovo_raw_event,
+ .event = lenovo_event,
};
module_hid_driver(lenovo_driver);

--
2.1.4

2015-08-12 12:36:09

by Jiri Kosina

[permalink] [raw]
Subject: Re: [PATCH 0/3] HID: lenovo: Improve wheel emulation

On Tue, 11 Aug 2015, Jamie Lentin wrote:

> A collection of unrelated patches to improve support for the Thinkpad
> compact keyboards. The first 2 are just cleanup patches.
>
> The final patch alters the behaviour of the middle button so userspace
> either gets wheel events or a button click, not both. This stops
> browsers opening a link in a new tab as well as scrolling, for example.
>
> This means you can no longer long-middle-click, but I don't think this
> is likely to upset users as much as the current behaviour.

Makes sense. Let's see whether we receive any complaints about it (I don't
expect that).

Applied to for-4.3/lenovo.

--
Jiri Kosina
SUSE Labs