Replace pointer acceleration with a much simpler linear one
[platform/upstream/libinput.git] / src / evdev.c
index 45020ba..de7ee16 100644 (file)
@@ -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,
@@ -560,6 +607,14 @@ evdev_tag_external_mouse(struct evdev_device *device,
 }
 
 static void
+evdev_tag_trackpoint(struct evdev_device *device,
+                    struct udev_device *udev_device)
+{
+       if (libevdev_has_property(device->evdev, INPUT_PROP_POINTING_STICK))
+               device->tags |= EVDEV_TAG_TRACKPOINT;
+}
+
+static void
 fallback_process(struct evdev_dispatch *dispatch,
                 struct evdev_device *device,
                 struct input_event *event,
@@ -597,6 +652,7 @@ fallback_tag_device(struct evdev_device *device,
                    struct udev_device *udev_device)
 {
        evdev_tag_external_mouse(device, udev_device);
+       evdev_tag_trackpoint(device, udev_device);
 }
 
 static int
@@ -645,6 +701,8 @@ struct evdev_dispatch_interface fallback_interface = {
        fallback_destroy,
        NULL, /* device_added */
        NULL, /* device_removed */
+       NULL, /* device_suspended */
+       NULL, /* device_resumed */
        fallback_tag_device,
 };
 
@@ -807,7 +865,7 @@ configure_pointer_acceleration(struct evdev_device *device)
 {
        device->pointer.filter =
                create_pointer_accelator_filter(
-                       pointer_accel_profile_smooth_simple);
+                       pointer_accel_profile_linear);
        if (!device->pointer.filter)
                return -1;
 
@@ -946,6 +1004,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;
@@ -1022,11 +1089,17 @@ evdev_notify_added_device(struct evdev_device *device)
                if (dev == &device->base)
                        continue;
 
+               /* Notify existing device d about addition of device device */
                if (d->dispatch->interface->device_added)
                        d->dispatch->interface->device_added(d, device);
 
+               /* Notify new device device about existing device d */
                if (device->dispatch->interface->device_added)
                        device->dispatch->interface->device_added(device, d);
+
+               /* Notify new device device if existing device d is suspended */
+               if (d->suspended && device->dispatch->interface->device_suspended)
+                       device->dispatch->interface->device_suspended(device, d);
        }
 
        notify_added_device(&device->base);
@@ -1357,9 +1430,51 @@ release_pressed_keys(struct evdev_device *device)
        }
 }
 
+void
+evdev_notify_suspended_device(struct evdev_device *device)
+{
+       struct libinput_device *it;
+
+       if (device->suspended)
+               return;
+
+       list_for_each(it, &device->base.seat->devices_list, link) {
+               struct evdev_device *d = (struct evdev_device*)it;
+               if (it == &device->base)
+                       continue;
+
+               if (d->dispatch->interface->device_suspended)
+                       d->dispatch->interface->device_suspended(d, device);
+       }
+
+       device->suspended = 1;
+}
+
+void
+evdev_notify_resumed_device(struct evdev_device *device)
+{
+       struct libinput_device *it;
+
+       if (!device->suspended)
+               return;
+
+       list_for_each(it, &device->base.seat->devices_list, link) {
+               struct evdev_device *d = (struct evdev_device*)it;
+               if (it == &device->base)
+                       continue;
+
+               if (d->dispatch->interface->device_resumed)
+                       d->dispatch->interface->device_resumed(d, device);
+       }
+
+       device->suspended = 0;
+}
+
 int
 evdev_device_suspend(struct evdev_device *device)
 {
+       evdev_notify_suspended_device(device);
+
        if (device->source) {
                libinput_remove_source(device->base.seat->libinput,
                                       device->source);
@@ -1450,6 +1565,8 @@ evdev_device_resume(struct evdev_device *device)
 
        memset(device->hw_key_mask, 0, sizeof(device->hw_key_mask));
 
+       evdev_notify_resumed_device(device);
+
        return 0;
 }