diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index cccf033d..d5ce8803 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -998,6 +998,7 @@ static int tp_init_accel(struct tp_dispatch *tp, double diagonal) { int res_x, res_y; + accel_profile_func_t profile; res_x = tp->device->abs.absinfo_x->resolution; res_y = tp->device->abs.absinfo_y->resolution; @@ -1021,9 +1022,16 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal) tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal; } - if (evdev_device_init_pointer_acceleration( - tp->device, - touchpad_accel_profile_linear) == -1) + switch (tp->device->model) { + case EVDEV_MODEL_LENOVO_X230: + profile = touchpad_lenovo_x230_accel_profile; + break; + default: + profile = touchpad_accel_profile_linear; + break; + } + + if (evdev_device_init_pointer_acceleration(tp->device, profile) == -1) return -1; return 0; diff --git a/src/evdev.c b/src/evdev.c index e3bba93e..6a9df499 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1429,6 +1429,7 @@ evdev_read_model(struct evdev_device *device) const char *property; enum evdev_device_model model; } model_map[] = { + { "LIBINPUT_MODEL_LENOVO_X230", EVDEV_MODEL_LENOVO_X230 }, { NULL, EVDEV_MODEL_DEFAULT }, }; const struct model_map *m = model_map; diff --git a/src/evdev.h b/src/evdev.h index edd40119..151d1031 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -95,6 +95,7 @@ enum evdev_middlebutton_event { enum evdev_device_model { EVDEV_MODEL_DEFAULT, + EVDEV_MODEL_LENOVO_X230, }; struct mt_slot { diff --git a/src/filter.c b/src/filter.c index 962d74de..b953bee8 100644 --- a/src/filter.c +++ b/src/filter.c @@ -345,3 +345,40 @@ touchpad_accel_profile_linear(struct motion_filter *filter, return speed_out * TP_MAGIC_SLOWDOWN; } + +double +touchpad_lenovo_x230_accel_profile(struct motion_filter *filter, + void *data, + double speed_in, + uint64_t time) +{ + /* Keep the magic factor from touchpad_accel_profile_linear. */ + const double TP_MAGIC_SLOWDOWN = 0.4; + + /* Those touchpads presents an actual lower resolution that what is + * advertised. We see some jumps from the cursor due to the big steps + * in X and Y when we are receiving data. + * Apply a factor to minimize those jumps at low speed, and try + * keeping the same feeling as regular touchpads at high speed. + * It still feels slower but it is usable at least */ + const double TP_MAGIC_LOW_RES_FACTOR = 4.0; + double speed_out; + struct pointer_accelerator *accel_filter = + (struct pointer_accelerator *)filter; + + double s1, s2; + const double max_accel = accel_filter->accel * + TP_MAGIC_LOW_RES_FACTOR; /* unitless factor */ + const double threshold = accel_filter->threshold / + TP_MAGIC_LOW_RES_FACTOR; /* units/ms */ + const double incline = accel_filter->incline * TP_MAGIC_LOW_RES_FACTOR; + + speed_in *= TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR; + + s1 = min(1, speed_in * 5); + s2 = 1 + (speed_in - threshold) * incline; + + speed_out = min(max_accel, s2 > 1 ? s2 : s1); + + return speed_out * TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR; +} diff --git a/src/filter.h b/src/filter.h index 70363a62..a0538601 100644 --- a/src/filter.h +++ b/src/filter.h @@ -67,4 +67,9 @@ touchpad_accel_profile_linear(struct motion_filter *filter, void *data, double speed_in, uint64_t time); +double +touchpad_lenovo_x230_accel_profile(struct motion_filter *filter, + void *data, + double speed_in, + uint64_t time); #endif /* FILTER_H */ diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb index 02bb8f97..959be0ff 100644 --- a/udev/90-libinput-model-quirks.hwdb +++ b/udev/90-libinput-model-quirks.hwdb @@ -14,3 +14,11 @@ # # Sort by brand, model + +########################################## +# LENOVO +########################################## + +# X230 (Tablet) +libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX230* + LIBINPUT_MODEL_LENOVO_X230=1