Keep the default behavior of middle button scrolling on trackpoints, this
allows turning off middle button scrolling on trackpoints, as well as turning
on button scrolling on trackballs.

Signed-off-by: Hans de Goede <hdego...@redhat.com>
---
 src/evdev.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 src/evdev.h |  13 ++++-
 2 files changed, 153 insertions(+), 25 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 2821cc6..765f3e5 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -123,6 +123,10 @@ evdev_pointer_notify_button(struct evdev_device *device,
                if (state == LIBINPUT_BUTTON_STATE_RELEASED &&
                    device->buttons.change_to_left_handed)
                        device->buttons.change_to_left_handed(device);
+
+               if (state == LIBINPUT_BUTTON_STATE_RELEASED &&
+                   device->scroll.change_scroll_mode)
+                       device->scroll.change_scroll_mode(device);
        }
 
 }
@@ -213,9 +217,9 @@ evdev_flush_pending_event(struct evdev_device *device, 
uint64_t time)
                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)
+               if (device->scroll.mode == 
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN &&
+                   hw_is_key_down(device, device->scroll.button)) {
+                       if (device->scroll.button_scroll_active)
                                evdev_post_scroll(device, time,
                                                  motion.dx, motion.dy);
                        break;
@@ -364,31 +368,33 @@ get_key_type(uint16_t code)
 }
 
 static void
-evdev_middle_button_scroll_timeout(uint64_t time, void *data)
+evdev_button_scroll_timeout(uint64_t time, void *data)
 {
        struct evdev_device *device = data;
 
-       device->scroll.middle_button_scroll_active = true;
+       device->scroll.button_scroll_active = true;
 }
 
 static void
-evdev_middle_button_scroll_button(struct evdev_device *device,
-                                uint64_t time, int is_press)
+evdev_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) {
+               if (device->scroll.button_scroll_active) {
                        evdev_stop_scroll(device, time);
-                       device->scroll.middle_button_scroll_active = false;
+                       device->scroll.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,
+                       evdev_pointer_notify_button(device, time,
+                                       device->scroll.button,
                                        LIBINPUT_BUTTON_STATE_PRESSED);
-                       evdev_pointer_notify_button(device, time, BTN_MIDDLE,
+                       evdev_pointer_notify_button(device, time,
+                                       device->scroll.button,
                                        LIBINPUT_BUTTON_STATE_RELEASED);
                }
        }
@@ -454,10 +460,9 @@ 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);
+               if (device->scroll.mode == 
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN &&
+                   e->code == device->scroll.button) {
+                       evdev_button_scroll_button(device, time, e->value);
                        break;
                }
                evdev_pointer_notify_button(
@@ -839,6 +844,115 @@ evdev_init_left_handed(struct evdev_device *device,
        return 0;
 }
 
+static uint32_t
+evdev_scroll_get_modes(struct libinput_device *device)
+{
+       return LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
+}
+
+static void
+evdev_change_scroll_mode(struct evdev_device *device)
+{
+       if (device->scroll.want_mode == device->scroll.mode &&
+           device->scroll.want_button == device->scroll.button)
+               return;
+
+       if (evdev_any_button_down(device))
+               return;
+
+       device->scroll.mode = device->scroll.want_mode;
+       device->scroll.button = device->scroll.want_button;
+}
+
+static enum libinput_config_status
+evdev_scroll_set_mode(struct libinput_device *device,
+                     enum libinput_config_scroll_mode mode)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+
+       evdev->scroll.want_mode = mode;
+       evdev->scroll.change_scroll_mode(evdev);
+
+       return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static enum libinput_config_scroll_mode
+evdev_scroll_get_mode(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device *)device;
+
+       /* return the wanted configuration, even if it hasn't taken
+        * effect yet! */
+       return evdev->scroll.want_mode;
+}
+
+static enum libinput_config_scroll_mode
+evdev_scroll_get_default_mode(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device *)device;
+
+       if (libevdev_has_property(evdev->evdev, INPUT_PROP_POINTING_STICK))
+               return LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
+       else
+               return LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
+}
+
+static enum libinput_config_status
+evdev_scroll_set_button(struct libinput_device *device,
+                       uint32_t button)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+
+       evdev->scroll.want_button = button;
+       evdev->scroll.change_scroll_mode(evdev);
+
+       return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static uint32_t
+evdev_scroll_get_button(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device *)device;
+
+       /* return the wanted configuration, even if it hasn't taken
+        * effect yet! */
+       return evdev->scroll.want_button;
+}
+
+static uint32_t
+evdev_scroll_get_default_button(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device *)device;
+
+       if (libevdev_has_property(evdev->evdev, INPUT_PROP_POINTING_STICK))
+               return BTN_MIDDLE;
+       else
+               return 0;
+}
+
+static int
+evdev_init_button_scroll(struct evdev_device *device,
+                        void (*change_scroll_mode)(struct evdev_device *))
+{
+       libinput_timer_init(&device->scroll.timer, device->base.seat->libinput,
+                           evdev_button_scroll_timeout, device);
+       device->scroll.config.get_modes = evdev_scroll_get_modes;
+       device->scroll.config.set_mode = evdev_scroll_set_mode;
+       device->scroll.config.get_mode = evdev_scroll_get_mode;
+       device->scroll.config.get_default_mode = evdev_scroll_get_default_mode;
+       device->scroll.config.set_button = evdev_scroll_set_button;
+       device->scroll.config.get_button = evdev_scroll_get_button;
+       device->scroll.config.get_default_button = 
evdev_scroll_get_default_button;
+       device->base.config.scroll_mode = &device->scroll.config;
+       device->scroll.mode = evdev_scroll_get_default_mode((struct 
libinput_device *)device);
+       device->scroll.want_mode = device->scroll.mode;
+       device->scroll.button = evdev_scroll_get_default_button((struct 
libinput_device *)device);
+       device->scroll.want_button = device->scroll.button;
+       device->scroll.change_scroll_mode = change_scroll_mode;
+
+       return 0;
+}
+
 static struct evdev_dispatch *
 fallback_dispatch_create(struct libinput_device *device)
 {
@@ -857,6 +971,13 @@ fallback_dispatch_create(struct libinput_device *device)
                return NULL;
        }
 
+       if (evdev_device->scroll.want_button &&
+           evdev_init_button_scroll(evdev_device,
+                                    evdev_change_scroll_mode) == -1) {
+               free(dispatch);
+               return NULL;
+       }
+
        device->config.calibration = &dispatch->calibration;
 
        dispatch->calibration.has_matrix = evdev_calibration_has_matrix;
@@ -1149,14 +1270,6 @@ evdev_configure_device(struct evdev_device *device)
                }
        }
 
-       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;
@@ -1210,6 +1323,12 @@ evdev_configure_device(struct evdev_device *device)
                /* want left-handed config option */
                device->buttons.want_left_handed = true;
        }
+
+       if (has_rel && has_button) {
+               /* want button scrolling config option */
+               device->scroll.want_button = 1;
+       }
+
        if (has_keyboard) {
                device->seat_caps |= EVDEV_DEVICE_KEYBOARD;
                log_info(libinput,
diff --git a/src/evdev.h b/src/evdev.h
index 6867db6..c99fc25 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -100,8 +100,17 @@ struct evdev_device {
 
        struct {
                struct libinput_timer timer;
-               bool has_middle_button_scroll;
-               bool middle_button_scroll_active;
+               struct libinput_device_config_scroll_mode config;
+               /* Currently enabled mode, button */
+               enum libinput_config_scroll_mode mode;
+               uint32_t button;
+               /* set during device init, used at runtime to delay changes
+                * until all buttons are up */
+               enum libinput_config_scroll_mode want_mode;
+               uint32_t want_button;
+               /* Checks if buttons are down and commits the setting */
+               void (*change_scroll_mode)(struct evdev_device *device);
+               bool button_scroll_active;
                double threshold;
                uint32_t direction;
        } scroll;
-- 
2.1.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to