summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/scrolling.dox7
-rw-r--r--src/evdev-mt-touchpad.c36
-rw-r--r--src/evdev.c1
-rw-r--r--src/evdev.h1
-rw-r--r--test/litest-device-synaptics-hover.c10
-rw-r--r--test/touchpad.c21
-rw-r--r--udev/libinput-model-quirks.c26
7 files changed, 92 insertions, 10 deletions
diff --git a/doc/scrolling.dox b/doc/scrolling.dox
index 658fe4b6..0c03c98d 100644
--- a/doc/scrolling.dox
+++ b/doc/scrolling.dox
@@ -44,6 +44,13 @@ movements will translate into tiny scroll movements.
Scrolling in both directions at once is possible by meeting the required
distance thresholds to enable each direction separately.
+Two-finger scrolling requires the touchpad to track both touch points with
+reasonable precision. Unfortunately, some so-called "semi-mt" touchpads can
+only track the bounding box of the two fingers rather than the actual
+position of each finger. In addition, that bounding box usually suffers from
+a low resolution, causing jumpy movement during two-finger scrolling.
+libinput does not provide two-finger scrolling on those touchpads.
+
@section edge_scrolling Edge scrolling
On some touchpads, edge scrolling is available, triggered by moving a single
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 6718b616..257af999 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1521,18 +1521,29 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
}
static uint32_t
-tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
+tp_scroll_get_methods(struct tp_dispatch *tp)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
- struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint32_t methods = LIBINPUT_CONFIG_SCROLL_EDGE;
- if (tp->ntouches >= 2)
+ /* some Synaptics semi-mt touchpads have a terrible 2fg resolution,
+ * causing scroll jumps. For all other 2fg touchpads, we enable 2fg
+ * scrolling */
+ if (tp->ntouches >= 2 &&
+ (tp->device->model_flags & EVDEV_MODEL_JUMPING_SEMI_MT) == 0)
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
return methods;
}
+static uint32_t
+tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
+{
+ struct evdev_device *evdev = (struct evdev_device*)device;
+ struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+ return tp_scroll_get_methods(tp);
+}
+
static enum libinput_config_status
tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
enum libinput_config_scroll_method method)
@@ -1564,10 +1575,21 @@ tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
static enum libinput_config_scroll_method
tp_scroll_get_default_method(struct tp_dispatch *tp)
{
- if (tp->ntouches >= 2)
- return LIBINPUT_CONFIG_SCROLL_2FG;
+ uint32_t methods;
+ enum libinput_config_scroll_method method;
+
+ methods = tp_scroll_get_methods(tp);
+
+ if (methods & LIBINPUT_CONFIG_SCROLL_2FG)
+ method = LIBINPUT_CONFIG_SCROLL_2FG;
else
- return LIBINPUT_CONFIG_SCROLL_EDGE;
+ method = LIBINPUT_CONFIG_SCROLL_EDGE;
+
+ if ((methods & method) == 0)
+ log_bug_libinput(tp_libinput_context(tp),
+ "Invalid default scroll method %d\n",
+ method);
+ return method;
}
static enum libinput_config_scroll_method
diff --git a/src/evdev.c b/src/evdev.c
index 78d1f5df..0fc5a649 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1542,6 +1542,7 @@ evdev_read_model_flags(struct evdev_device *device)
{ "LIBINPUT_MODEL_WACOM_TOUCHPAD", EVDEV_MODEL_WACOM_TOUCHPAD },
{ "LIBINPUT_MODEL_ALPS_TOUCHPAD", EVDEV_MODEL_ALPS_TOUCHPAD },
{ "LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD", EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD },
+ { "LIBINPUT_MODEL_JUMPING_SEMI_MT", EVDEV_MODEL_JUMPING_SEMI_MT },
{ NULL, EVDEV_MODEL_DEFAULT },
};
const struct model_map *m = model_map;
diff --git a/src/evdev.h b/src/evdev.h
index 36eac217..cc61c5fb 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -105,6 +105,7 @@ enum evdev_device_model {
EVDEV_MODEL_WACOM_TOUCHPAD = (1 << 7),
EVDEV_MODEL_ALPS_TOUCHPAD = (1 << 8),
EVDEV_MODEL_SYNAPTICS_SERIAL_TOUCHPAD = (1 << 9),
+ EVDEV_MODEL_JUMPING_SEMI_MT = (1 << 10),
};
struct mt_slot {
diff --git a/test/litest-device-synaptics-hover.c b/test/litest-device-synaptics-hover.c
index 2cc9b725..3c36affa 100644
--- a/test/litest-device-synaptics-hover.c
+++ b/test/litest-device-synaptics-hover.c
@@ -102,6 +102,15 @@ static struct input_absinfo absinfo[] = {
{ .value = -1 }
};
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"synaptics_semi_mt_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"synaptics_semi_mt_end\"\n"
+"\n"
+"ATTRS{name}==\"SynPS/2 Synaptics TouchPad\",\n"
+" ENV{LIBINPUT_MODEL_JUMPING_SEMI_MT}=\"1\"\n"
+"\n"
+"LABEL=\"synaptics_semi_mt_end\"";
+
struct litest_test_device litest_synaptics_hover_device = {
.type = LITEST_SYNAPTICS_HOVER_SEMI_MT,
.features = LITEST_TOUCHPAD | LITEST_SEMI_MT | LITEST_BUTTON,
@@ -114,6 +123,7 @@ struct litest_test_device litest_synaptics_hover_device = {
.id = &input_id,
.events = events,
.absinfo = absinfo,
+ .udev_rule = udev_rule,
};
static void
diff --git a/test/touchpad.c b/test/touchpad.c
index 7fc8fdc5..5db79f8a 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -91,6 +91,16 @@ enable_buttonareas(struct litest_device *dev)
litest_assert_int_eq(status, expected);
}
+static inline int
+is_synaptics_semi_mt(struct litest_device *dev)
+{
+ struct libevdev *evdev = dev->evdev;
+
+ return libevdev_has_property(evdev, INPUT_PROP_SEMI_MT) &&
+ libevdev_get_id_vendor(evdev) == 0x2 &&
+ libevdev_get_id_product(evdev) == 0x7;
+}
+
START_TEST(touchpad_1fg_motion)
{
struct litest_device *dev = litest_current_device();
@@ -461,10 +471,14 @@ START_TEST(touchpad_scroll_defaults)
method = libinput_device_config_scroll_get_methods(device);
ck_assert(method & LIBINPUT_CONFIG_SCROLL_EDGE);
- if (libevdev_get_num_slots(evdev) > 1)
+ if (libevdev_get_num_slots(evdev) > 1 &&
+ !is_synaptics_semi_mt(dev))
ck_assert(method & LIBINPUT_CONFIG_SCROLL_2FG);
+ else
+ ck_assert((method & LIBINPUT_CONFIG_SCROLL_2FG) == 0);
- if (libevdev_get_num_slots(evdev) > 1)
+ if (libevdev_get_num_slots(evdev) > 1 &&
+ !is_synaptics_semi_mt(dev))
expected = LIBINPUT_CONFIG_SCROLL_2FG;
else
expected = LIBINPUT_CONFIG_SCROLL_EDGE;
@@ -480,7 +494,8 @@ START_TEST(touchpad_scroll_defaults)
status = libinput_device_config_scroll_set_method(device,
LIBINPUT_CONFIG_SCROLL_2FG);
- if (libevdev_get_num_slots(evdev) > 1)
+ if (libevdev_get_num_slots(evdev) > 1 &&
+ !is_synaptics_semi_mt(dev))
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
else
ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
diff --git a/udev/libinput-model-quirks.c b/udev/libinput-model-quirks.c
index fc3dbe85..0e737a4b 100644
--- a/udev/libinput-model-quirks.c
+++ b/udev/libinput-model-quirks.c
@@ -69,6 +69,30 @@ handle_touchpad_alps(struct udev_device *device)
}
static void
+handle_touchpad_synaptics(struct udev_device *device)
+{
+ const char *product, *props;
+ int bus, vid, pid, version;
+ int prop;
+
+ product = prop_value(device, "PRODUCT");
+ if (!product)
+ return;
+
+ if (sscanf(product, "%x/%x/%x/%x", &bus, &vid, &pid, &version) != 4)
+ return;
+
+ if (bus != BUS_I8042 || vid != 0x2 || pid != 0x7)
+ return;
+
+ props = prop_value(device, "PROP");
+ if (sscanf(props, "%x", &prop) != 1)
+ return;
+ if (prop & (1 << INPUT_PROP_SEMI_MT))
+ printf("LIBINPUT_MODEL_JUMPING_SEMI_MT=1\n");
+}
+
+static void
handle_touchpad(struct udev_device *device)
{
const char *name = NULL;
@@ -79,6 +103,8 @@ handle_touchpad(struct udev_device *device)
if (strstr(name, "AlpsPS/2 ALPS") != NULL)
handle_touchpad_alps(device);
+ if (strstr(name, "Synaptics ") != NULL)
+ handle_touchpad_synaptics(device);
}
int main(int argc, char **argv)