summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/input.h1
-rw-r--r--src/evdev.c56
-rw-r--r--src/evdev.h5
-rw-r--r--test/litest-trackpoint.c2
-rw-r--r--test/pointer.c4
5 files changed, 67 insertions, 1 deletions
diff --git a/include/linux/input.h b/include/linux/input.h
index aa98ce7..39b550b 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -163,6 +163,7 @@ struct input_keymap_entry {
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
+#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
diff --git a/src/evdev.c b/src/evdev.c
index 45020ba..85e4d71 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -41,6 +41,7 @@
#include "libinput-private.h"
#define DEFAULT_AXIS_STEP_DISTANCE 10
+#define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT 200
enum evdev_key_type {
EVDEV_KEY_TYPE_NONE,
@@ -203,6 +204,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
device->rel.dx = 0;
device->rel.dy = 0;
+ /* Use unaccelerated deltas for pointing stick scroll */
+ if (device->scroll.has_middle_button_scroll &&
+ hw_is_key_down(device, BTN_MIDDLE)) {
+ if (device->scroll.middle_button_scroll_active)
+ evdev_post_scroll(device, time,
+ motion.dx, motion.dy);
+ break;
+ }
+
/* Apply pointer acceleration. */
filter_dispatch(device->pointer.filter, &motion, device, time);
@@ -346,6 +356,37 @@ get_key_type(uint16_t code)
}
static void
+evdev_middle_button_scroll_timeout(uint64_t time, void *data)
+{
+ struct evdev_device *device = data;
+
+ device->scroll.middle_button_scroll_active = true;
+}
+
+static void
+evdev_middle_button_scroll_button(struct evdev_device *device,
+ uint64_t time, int is_press)
+{
+ if (is_press) {
+ libinput_timer_set(&device->scroll.timer,
+ time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT);
+ } else {
+ libinput_timer_cancel(&device->scroll.timer);
+ if (device->scroll.middle_button_scroll_active) {
+ evdev_stop_scroll(device, time);
+ device->scroll.middle_button_scroll_active = false;
+ } else {
+ /* If the button is released quickly enough emit the
+ * button press/release events. */
+ evdev_pointer_notify_button(device, time, BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ evdev_pointer_notify_button(device, time, BTN_MIDDLE,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+ }
+ }
+}
+
+static void
evdev_process_touch_button(struct evdev_device *device,
uint64_t time, int value)
{
@@ -405,6 +446,12 @@ evdev_process_key(struct evdev_device *device,
LIBINPUT_KEY_STATE_RELEASED);
break;
case EVDEV_KEY_TYPE_BUTTON:
+ if (device->scroll.has_middle_button_scroll &&
+ e->code == BTN_MIDDLE) {
+ evdev_middle_button_scroll_button(device, time,
+ e->value);
+ break;
+ }
evdev_pointer_notify_button(
device,
time,
@@ -946,6 +993,15 @@ evdev_configure_device(struct evdev_device *device)
device->mt.slot = active_slot;
}
}
+
+ if (libevdev_has_property(evdev, INPUT_PROP_POINTING_STICK)) {
+ libinput_timer_init(&device->scroll.timer,
+ device->base.seat->libinput,
+ evdev_middle_button_scroll_timeout,
+ device);
+ device->scroll.has_middle_button_scroll = true;
+ }
+
if (libevdev_has_event_code(evdev, EV_REL, REL_X) ||
libevdev_has_event_code(evdev, EV_REL, REL_Y))
has_rel = 1;
diff --git a/src/evdev.h b/src/evdev.h
index 311dddc..e1506d2 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -26,10 +26,12 @@
#include "config.h"
+#include <stdbool.h>
#include "linux/input.h"
#include <libevdev/libevdev.h>
#include "libinput-private.h"
+#include "timer.h"
enum evdev_event_type {
EVDEV_NONE,
@@ -96,6 +98,9 @@ struct evdev_device {
} rel;
struct {
+ struct libinput_timer timer;
+ bool has_middle_button_scroll;
+ bool middle_button_scroll_active;
double threshold;
uint32_t direction;
} scroll;
diff --git a/test/litest-trackpoint.c b/test/litest-trackpoint.c
index 25a377c..40b9ed0 100644
--- a/test/litest-trackpoint.c
+++ b/test/litest-trackpoint.c
@@ -49,6 +49,8 @@ static int events[] = {
EV_KEY, BTN_MIDDLE,
EV_REL, REL_X,
EV_REL, REL_Y,
+ INPUT_PROP_MAX, INPUT_PROP_POINTER,
+ INPUT_PROP_MAX, INPUT_PROP_POINTING_STICK,
-1, -1,
};
diff --git a/test/pointer.c b/test/pointer.c
index 82c5245..f704372 100644
--- a/test/pointer.c
+++ b/test/pointer.c
@@ -132,7 +132,9 @@ START_TEST(pointer_button)
test_button_event(dev, BTN_RIGHT, 0);
}
- if (libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE)) {
+ /* Skip middle button test on trackpoints (used for scrolling) */
+ if (!libevdev_has_property(dev->evdev, INPUT_PROP_POINTING_STICK) &&
+ libevdev_has_event_code(dev->evdev, EV_KEY, BTN_MIDDLE)) {
test_button_event(dev, BTN_MIDDLE, 1);
test_button_event(dev, BTN_MIDDLE, 0);
}