summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2017-02-22 07:56:07 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2017-02-22 07:56:07 +1000
commit4ce0fe4a2d2e54e401b1073dfc1c894d596a4a0f (patch)
tree8a8ee0fac17412f208e9759770c3386b847922da /src
parent765ef9a31dc3b8551f388858392bfa64ee013c66 (diff)
parentc225c0592c4b3b61a01b6227f293b7fb853d5dbf (diff)
Merge branch 'wip/logitech-marble-mouse-middleemulation'
Diffstat (limited to 'src')
-rw-r--r--src/evdev.c89
-rw-r--r--src/evdev.h11
-rw-r--r--src/timer.c22
-rw-r--r--src/timer.h10
4 files changed, 105 insertions, 27 deletions
diff --git a/src/evdev.c b/src/evdev.c
index b691333..6132d54 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -48,7 +48,7 @@
#endif
#define DEFAULT_WHEEL_CLICK_ANGLE 15
-#define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200)
+#define DEFAULT_BUTTON_SCROLL_TIMEOUT ms2us(200)
enum evdev_key_type {
EVDEV_KEY_TYPE_NONE,
@@ -221,27 +221,51 @@ evdev_button_scroll_timeout(uint64_t time, void *data)
{
struct evdev_device *device = data;
- device->scroll.button_scroll_active = true;
+ device->scroll.button_scroll_state = BUTTONSCROLL_READY;
}
static void
evdev_button_scroll_button(struct evdev_device *device,
uint64_t time, int is_press)
{
- device->scroll.button_scroll_btn_pressed = is_press;
-
if (is_press) {
- libinput_timer_set(&device->scroll.timer,
- time + DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT);
+ enum timer_flags flags = TIMER_FLAG_NONE;
+
+ device->scroll.button_scroll_state = BUTTONSCROLL_BUTTON_DOWN;
+
+ /* Special case: if middle button emulation is enabled and
+ * our scroll button is the left or right button, we only
+ * get here *after* the middle button timeout has expired
+ * for that button press. The time passed is the button-down
+ * time though (which is in the past), so we have to allow
+ * for a negative timer to be set.
+ */
+ if (device->middlebutton.enabled &&
+ (device->scroll.button == BTN_LEFT ||
+ device->scroll.button == BTN_RIGHT)) {
+ flags = TIMER_FLAG_ALLOW_NEGATIVE;
+ }
+
+ libinput_timer_set_flags(&device->scroll.timer,
+ time + DEFAULT_BUTTON_SCROLL_TIMEOUT,
+ flags);
device->scroll.button_down_time = time;
+ log_debug(evdev_libinput_context(device),
+ "btnscroll: down\n");
} else {
libinput_timer_cancel(&device->scroll.timer);
- if (device->scroll.button_scroll_active) {
- evdev_stop_scroll(device, time,
- LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
- device->scroll.button_scroll_active = false;
- } else {
- /* If the button is released quickly enough emit the
+ switch(device->scroll.button_scroll_state) {
+ case BUTTONSCROLL_IDLE:
+ log_bug_libinput(evdev_libinput_context(device),
+ "invalid state IDLE for button up\n");
+ break;
+ case BUTTONSCROLL_BUTTON_DOWN:
+ case BUTTONSCROLL_READY:
+ log_debug(evdev_libinput_context(device),
+ "btnscroll: cancel\n");
+
+ /* If the button is released quickly enough or
+ * without scroll events, emit the
* button press/release events. */
evdev_pointer_post_button(device,
device->scroll.button_down_time,
@@ -250,7 +274,16 @@ evdev_button_scroll_button(struct evdev_device *device,
evdev_pointer_post_button(device, time,
device->scroll.button,
LIBINPUT_BUTTON_STATE_RELEASED);
+ break;
+ case BUTTONSCROLL_SCROLLING:
+ log_debug(evdev_libinput_context(device),
+ "btnscroll: up\n");
+ evdev_stop_scroll(device, time,
+ LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
+ break;
}
+
+ device->scroll.button_scroll_state = BUTTONSCROLL_IDLE;
}
}
@@ -359,18 +392,29 @@ evdev_post_trackpoint_scroll(struct evdev_device *device,
struct normalized_coords unaccel,
uint64_t time)
{
- if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN ||
- !device->scroll.button_scroll_btn_pressed)
+ if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)
return false;
- if (device->scroll.button_scroll_active)
+ switch(device->scroll.button_scroll_state) {
+ case BUTTONSCROLL_IDLE:
+ return false;
+ case BUTTONSCROLL_BUTTON_DOWN:
+ /* if the button is down but scroll is not active, we're within the
+ timeout where swallow motion events but don't post scroll buttons */
+ log_debug(evdev_libinput_context(device),
+ "btnscroll: discarding\n");
+ return true;
+ case BUTTONSCROLL_READY:
+ device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING;
+ /* fallthrough */
+ case BUTTONSCROLL_SCROLLING:
evdev_post_scroll(device, time,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
&unaccel);
- /* if the button is down but scroll is not active, we're within the
- timeout where swallow motion events but don't post scroll buttons */
+ return true;
+ }
- return true;
+ assert(!"invalid scroll button state");
}
static inline bool
@@ -2245,6 +2289,7 @@ evdev_read_model_flags(struct evdev_device *device)
MODEL(HP_ZBOOK_STUDIO_G3),
MODEL(HP_PAVILION_DM4_TOUCHPAD),
MODEL(APPLE_TOUCHPAD_ONEBUTTON),
+ MODEL(LOGITECH_MARBLE_MOUSE),
#undef MODEL
{ "ID_INPUT_TRACKBALL", EVDEV_MODEL_TRACKBALL },
{ NULL, EVDEV_MODEL_DEFAULT },
@@ -2643,7 +2688,9 @@ evdev_configure_device(struct evdev_device *device)
/* want natural-scroll config option */
device->scroll.natural_scrolling_enabled = true;
/* want button scrolling config option */
- device->scroll.want_button = 1;
+ if (libevdev_has_event_code(evdev, EV_REL, REL_X) ||
+ libevdev_has_event_code(evdev, EV_REL, REL_Y))
+ device->scroll.want_button = 1;
}
if (udev_tags & EVDEV_UDEV_TAG_KEYBOARD) {
@@ -2842,6 +2889,10 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
* https://bugs.freedesktop.org/show_bug.cgi?id=98100 */
if (device->model_flags & EVDEV_MODEL_HP_ZBOOK_STUDIO_G3)
libevdev_set_abs_maximum(device->evdev, ABS_MT_SLOT, 1);
+
+ /* Logitech Marble Mouse claims to have a middle button */
+ if (device->model_flags & EVDEV_MODEL_LOGITECH_MARBLE_MOUSE)
+ libevdev_disable_event_code(device->evdev, EV_KEY, BTN_MIDDLE);
}
struct evdev_device *
diff --git a/src/evdev.h b/src/evdev.h
index 967feaf..392d71c 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -126,6 +126,14 @@ enum evdev_device_model {
EVDEV_MODEL_HP_ZBOOK_STUDIO_G3 = (1 << 23),
EVDEV_MODEL_HP_PAVILION_DM4_TOUCHPAD = (1 << 24),
EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON = (1 << 25),
+ EVDEV_MODEL_LOGITECH_MARBLE_MOUSE = (1 << 26),
+};
+
+enum evdev_button_scroll_state {
+ BUTTONSCROLL_IDLE,
+ BUTTONSCROLL_BUTTON_DOWN, /* button is down */
+ BUTTONSCROLL_READY, /* ready for scroll events */
+ BUTTONSCROLL_SCROLLING, /* have sent scroll events */
};
struct mt_slot {
@@ -187,8 +195,7 @@ struct evdev_device {
uint32_t want_button;
/* Checks if buttons are down and commits the setting */
void (*change_scroll_method)(struct evdev_device *device);
- bool button_scroll_active;
- bool button_scroll_btn_pressed;
+ enum evdev_button_scroll_state button_scroll_state;
double threshold;
double direction_lock_threshold;
uint32_t direction;
diff --git a/src/timer.c b/src/timer.c
index c924794..362d81d 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -67,19 +67,23 @@ libinput_timer_arm_timer_fd(struct libinput *libinput)
}
void
-libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
+libinput_timer_set_flags(struct libinput_timer *timer,
+ uint64_t expire,
+ uint32_t flags)
{
#ifndef NDEBUG
uint64_t now = libinput_now(timer->libinput);
- if (expire < now)
- log_bug_libinput(timer->libinput,
- "timer offset negative (-%" PRIu64 ")\n",
- now - expire);
- else if ((expire - now) > ms2us(5000))
+ if (expire < now) {
+ if ((flags & TIMER_FLAG_ALLOW_NEGATIVE) == 0)
+ log_bug_libinput(timer->libinput,
+ "timer offset negative (-%" PRIu64 ")\n",
+ now - expire);
+ } else if ((expire - now) > ms2us(5000)) {
log_bug_libinput(timer->libinput,
"timer offset more than 5s, now %"
PRIu64 " expire %" PRIu64 "\n",
now, expire);
+ }
#endif
assert(expire);
@@ -92,6 +96,12 @@ libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
}
void
+libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
+{
+ libinput_timer_set_flags(timer, expire, TIMER_FLAG_NONE);
+}
+
+void
libinput_timer_cancel(struct libinput_timer *timer)
{
if (!timer->expire)
diff --git a/src/timer.h b/src/timer.h
index f8315cf..93d684a 100644
--- a/src/timer.h
+++ b/src/timer.h
@@ -47,6 +47,16 @@ libinput_timer_init(struct libinput_timer *timer, struct libinput *libinput,
void
libinput_timer_set(struct libinput_timer *timer, uint64_t expire);
+enum timer_flags {
+ TIMER_FLAG_NONE = 0,
+ TIMER_FLAG_ALLOW_NEGATIVE = (1 << 0),
+};
+
+void
+libinput_timer_set_flags(struct libinput_timer *timer,
+ uint64_t expire,
+ uint32_t flags);
+
void
libinput_timer_cancel(struct libinput_timer *timer);