Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+50 −0
Original line number Original line Diff line number Diff line
@@ -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,
	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)
		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 = {
	.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);