mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-04 19:00:14 +01:00
Merge branch 'master' into tablet-support
This commit is contained in:
commit
8fe7f08e85
42 changed files with 15962 additions and 378 deletions
25
configure.ac
25
configure.ac
|
|
@ -1,7 +1,7 @@
|
|||
AC_PREREQ([2.64])
|
||||
|
||||
m4_define([libinput_major_version], [0])
|
||||
m4_define([libinput_minor_version], [21])
|
||||
m4_define([libinput_major_version], [1])
|
||||
m4_define([libinput_minor_version], [0])
|
||||
m4_define([libinput_micro_version], [0])
|
||||
m4_define([libinput_version],
|
||||
[libinput_major_version.libinput_minor_version.libinput_micro_version])
|
||||
|
|
@ -31,7 +31,7 @@ AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
|||
# b) If interfaces have been changed or added, but binary compatibility has
|
||||
# been preserved, change to C+1:0:A+1
|
||||
# c) If the interface is the same as the previous version, change to C:R+1:A
|
||||
LIBINPUT_LT_VERSION=15:0:5
|
||||
LIBINPUT_LT_VERSION=15:2:5
|
||||
AC_SUBST(LIBINPUT_LT_VERSION)
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
|
|
@ -60,13 +60,22 @@ PKG_PROG_PKG_CONFIG()
|
|||
PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0])
|
||||
PKG_CHECK_MODULES(LIBUDEV, [libudev])
|
||||
PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4])
|
||||
PKG_CHECK_MODULES(LIBUNWIND,
|
||||
|
||||
AC_ARG_WITH(libunwind,
|
||||
AS_HELP_STRING([--without-libunwind],[Do not use libunwind]))
|
||||
|
||||
AS_IF([test "x$with_libunwind" != "xno"],
|
||||
[PKG_CHECK_MODULES(LIBUNWIND,
|
||||
[libunwind],
|
||||
[HAVE_LIBUNWIND=yes],
|
||||
[HAVE_LIBUNWIND=no])
|
||||
if test "x$HAVE_LIBUNWIND" = "xyes"; then
|
||||
AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
|
||||
fi
|
||||
[HAVE_LIBUNWIND=no])],
|
||||
[HAVE_LIBUNWIND=no])
|
||||
|
||||
AS_IF([test "x$HAVE_LIBUNWIND" = "xyes"],
|
||||
[AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])],
|
||||
[AS_IF([test "x$with_libunwind" = "xyes"],
|
||||
[AC_MSG_ERROR([libunwind requested but not found])])])
|
||||
|
||||
AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes])
|
||||
AC_PATH_PROG(ADDR2LINE, [addr2line])
|
||||
if test "x$ADDR2LINE" != "x"; then
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ header_files = \
|
|||
$(srcdir)/normalization-of-relative-motion.dox \
|
||||
$(srcdir)/palm-detection.dox \
|
||||
$(srcdir)/page-hierarchy.dox \
|
||||
$(srcdir)/pointer-acceleration.dox \
|
||||
$(srcdir)/reporting-bugs.dox \
|
||||
$(srcdir)/scrolling.dox \
|
||||
$(srcdir)/seats.dox \
|
||||
|
|
@ -34,12 +35,17 @@ diagram_files = \
|
|||
$(srcdir)/dot/libinput-stack-wayland.gv \
|
||||
$(srcdir)/dot/libinput-stack-xorg.gv \
|
||||
$(srcdir)/dot/libinput-stack-gnome.gv \
|
||||
$(srcdir)/dot/evemu.gv \
|
||||
$(srcdir)/svg/software-buttons.svg \
|
||||
$(srcdir)/svg/clickfinger.svg \
|
||||
$(srcdir)/svg/button-scrolling.svg \
|
||||
$(srcdir)/svg/edge-scrolling.svg \
|
||||
$(srcdir)/svg/palm-detection.svg \
|
||||
$(srcdir)/svg/pinch-gestures.svg \
|
||||
$(srcdir)/svg/ptraccel-linear.svg \
|
||||
$(srcdir)/svg/ptraccel-low-dpi.svg \
|
||||
$(srcdir)/svg/ptraccel-touchpad.svg \
|
||||
$(srcdir)/svg/ptraccel-trackpoint.svg \
|
||||
$(srcdir)/svg/swipe-gestures.svg \
|
||||
$(srcdir)/svg/tap-n-drag.svg \
|
||||
$(srcdir)/svg/thumb-detection.svg \
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ or height. Note that rotation applies to the device's origin, rotation
|
|||
usually requires an offset to move the coordinates back into the original
|
||||
range.
|
||||
|
||||
The most comon matrices are:
|
||||
The most common matrices are:
|
||||
|
||||
- 90 degree clockwise:
|
||||
@f$
|
||||
|
|
|
|||
19
doc/dot/evemu.gv
Normal file
19
doc/dot/evemu.gv
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
digraph stack
|
||||
{
|
||||
compound=true;
|
||||
rankdir="LR";
|
||||
node [
|
||||
shape="box";
|
||||
]
|
||||
|
||||
kernel [label="Kernel"];
|
||||
|
||||
libinput;
|
||||
xserver [label="X Server"];
|
||||
|
||||
kernel -> libinput
|
||||
libinput -> xserver
|
||||
|
||||
kernel -> evemu
|
||||
evemu -> stdout
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ scroll_sources.
|
|||
@section faq_gpl Is libinput GPL-licensed?
|
||||
|
||||
No, libinput is MIT licensed. The Linux kernel header file linux/input.h in
|
||||
libinput's tree is provded to ensure the same behavior regardless of which
|
||||
libinput's tree is provided to ensure the same behavior regardless of which
|
||||
kernel version libinput is built on. It does not make libinput GPL-licensed.
|
||||
|
||||
@section faq_config_options Where is the configuration stored?
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ screen as well as the context of those virtual objects:
|
|||
@image html touchscreen-gestures.svg "Context-sensitivity of touchscreen gestures"
|
||||
|
||||
In this example, the finger movements are identical but in the left case
|
||||
both fingers are located within the same window, thus suggesting an attemp
|
||||
both fingers are located within the same window, thus suggesting an attempt
|
||||
to zoom. In the right case both fingers are located on a window border,
|
||||
thus suggesting a window movement. libinput only has knowledge of the finger
|
||||
coordinates (and even then only in device coordinates, not in screen
|
||||
|
|
|
|||
|
|
@ -25,16 +25,16 @@ movement speed increases, acceleration is applied - at high speeds a low-dpi
|
|||
device will roughly feel the same as a higher-dpi mouse.
|
||||
|
||||
This normalization only applies to accelerated coordinates, unaccelerated
|
||||
coordiantes are left in device-units. It is up to the caller to interpret
|
||||
coordinates are left in device-units. It is up to the caller to interpret
|
||||
those coordinates correctly.
|
||||
|
||||
@section Normalization of touchpad coordinates
|
||||
|
||||
Touchpads may have a different resolution for the horizontal and vertical
|
||||
axis. Interpreting coordinates from the touchpad without taking resolutino
|
||||
axis. Interpreting coordinates from the touchpad without taking resolution
|
||||
into account results in uneven motion.
|
||||
|
||||
libinput scales unaccelerated touchpad motion do the resolution of the
|
||||
libinput scales unaccelerated touchpad motion to the resolution of the
|
||||
touchpad's x axis, i.e. the unaccelerated value for the y axis is:
|
||||
y = (x / resolution_x) * resolution_y
|
||||
|
||||
|
|
|
|||
|
|
@ -31,5 +31,6 @@
|
|||
|
||||
- @subpage test-suite
|
||||
- @subpage tools
|
||||
- @subpage pointer-acceleration
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ will generate a button event for this touch.
|
|||
|
||||
If a device provides a <a
|
||||
href="http://en.wikipedia.org/wiki/Pointing_stick">trackpoint</a>, it is
|
||||
usually located above the touchpad. This increases the likelyhood of
|
||||
usually located above the touchpad. This increases the likelihood of
|
||||
accidental touches whenever the trackpoint is used.
|
||||
|
||||
libinput disables the touchpad whenver it detects trackpoint activity for a
|
||||
libinput disables the touchpad whenever it detects trackpoint activity for a
|
||||
certain timeout until after trackpoint activity stops. Touches generated
|
||||
during this timeout will not move the pointer, and touches started during
|
||||
this timeout will likewise not move the pointer (allowing for a user to rest
|
||||
|
|
|
|||
110
doc/pointer-acceleration.dox
Normal file
110
doc/pointer-acceleration.dox
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
@page pointer-acceleration Pointer acceleration
|
||||
|
||||
libinput uses device-specific pointer acceleration methods, with the default
|
||||
being the @ref ptraccel-linear. The methods share common properties, such as
|
||||
@ref ptraccel-velocity.
|
||||
|
||||
This page explains the high-level concepts used in the code. It aims to
|
||||
provide an overview for developers and is not necessarily useful for
|
||||
users.
|
||||
|
||||
@section ptraccel-velocity Velocity calculation
|
||||
|
||||
The device's speed of movement is measured across multiple input events
|
||||
through so-called "trackers". Each event prepends a the tracker item, each
|
||||
subsequent tracker contains the delta of that item to the current position,
|
||||
the timestamp of the event that created it and the cardinal direction of the
|
||||
movement at the time. If a device moves into the same direction, the
|
||||
velocity is calculated across multiple trackers. For example, if a device
|
||||
moves steadily for 10 events to the left, the velocity is calculated across
|
||||
all 10 events.
|
||||
|
||||
Whenever the movement changes direction or significantly changes speed, the
|
||||
velocity is calculated from the direction/speed change only. For example, if
|
||||
a device moves steadily for 8 events to the left and then 2 events to the
|
||||
right, the velocity is only that of the last 2 events.
|
||||
|
||||
An extra time limit prevents events that are too old to factor into the
|
||||
velocity calculation. For example, if a device moves steadily for 5 events
|
||||
to the left, then pauses, then moves again for 5 events to the left, only
|
||||
the last 5 events are used for velocity calculation.
|
||||
|
||||
The velocity is then used to calculate the acceleration factor
|
||||
|
||||
@section ptraccel-factor Acceleration factor
|
||||
|
||||
The acceleration factor is the final outcome of the pointer acceleration
|
||||
calculations. It is a unitless factor that is applied to the current delta,
|
||||
a factor of 2 doubles the delta (i.e. speeds up the movement), a factor of
|
||||
less than 1 reduces the delta (i.e. slows the movement).
|
||||
|
||||
Any factor less than 1 requires the user to move the device further to move
|
||||
the visible pointer. This is called deceleration and enables high precision
|
||||
target selection through subpixel movements. libinput's current maximum
|
||||
deceleration factor is 0.3 (i.e. slow down to 30% of the pointer speed).
|
||||
|
||||
A factor higher than 1 moves the pointer further than the physical device
|
||||
moves. This is acceleration and allows a user to cross the screen quickly
|
||||
but effectively skips pixels. libinput's current maximum acceleration factor
|
||||
is 3.5.
|
||||
|
||||
@section ptraccel-linear Linear pointer acceleration
|
||||
|
||||
The linear pointer acceleration method is the default for most pointer
|
||||
devices. It provides deceleration at very slow movements, a 1:1 mapping for
|
||||
regular movements and a linear increase to the maximum acceleration factor
|
||||
for fast movements.
|
||||
|
||||
Linear pointer acceleration applies to devices with above 1000dpi resolution
|
||||
and after @ref motion_normalization is applied.
|
||||
|
||||
@image html ptraccel-linear.svg "Linear pointer acceleration"
|
||||
|
||||
The image above shows the linear pointer acceleration settings at various
|
||||
speeds. The line for 0.0 is the default acceleration curve, speed settings
|
||||
above 0.0 accelerate sooner, faster and to a higher maximum acceleration.
|
||||
Speed settings below 0 delay when acceleration kicks in, how soon the
|
||||
maximum acceleration is reached and the maximum acceleration factor.
|
||||
|
||||
Extremely low speed settings provide no acceleration and additionally
|
||||
decelerate all movement by a constant factor.
|
||||
|
||||
@section ptraccel-low-dpi Pointer acceleration for low-dpi devices
|
||||
|
||||
Low-dpi devices are those with a physical resolution of less than 1000 dots
|
||||
per inch (dpi). The pointer acceleration is adjusted to provide roughly the
|
||||
same feel for all devices at normal to high speeds. At slow speeds, the
|
||||
pointer acceleration works on device-units rather than normalized
|
||||
coordinates (see @ref motion_normalization).
|
||||
|
||||
@image html ptraccel-low-dpi.svg "Pointer acceleration for low-dpi devices"
|
||||
|
||||
The image above shows the default pointer acceleration curve for a speed of
|
||||
0.0 at different DPI settings. A device with low DPI has the acceleration
|
||||
applied sooner and with a stronger acceleration factor.
|
||||
|
||||
@section ptraccel-touchpad Pointer acceleration on touchpads
|
||||
|
||||
Touchpad pointer acceleration uses the @ref ptraccel-linear profile, with a
|
||||
constant deceleration factor applied. The user expectation of how much a
|
||||
pointer should move in response to finger movement is different to that of a
|
||||
mouse device, hence the constant deceleration factor.
|
||||
|
||||
@image html ptraccel-touchpad.svg "Pointer acceleration curve for touchpads"
|
||||
|
||||
The image above shows the touchpad acceleration profile in comparison to the
|
||||
@ref ptraccel-linear. The shape of the curve is identical but vertically squashed.
|
||||
|
||||
@section ptraccel-trackpoint Pointer acceleration on trackpoints
|
||||
|
||||
Trackpoint pointer acceleration uses the @ref ptraccel-low-dpi profile, with a
|
||||
constant deceleration factor taking the place of the DPI settings.
|
||||
|
||||
@image html ptraccel-trackpoint.svg "Pointer acceleration curves for trackpoints"
|
||||
|
||||
The image above shows the trackpoint acceleration profile in comparison to the
|
||||
@ref ptraccel-linear. The constant acceleration factor, usually applied by
|
||||
udev, shapes the acceleration profile.
|
||||
|
||||
*/
|
||||
|
|
@ -8,7 +8,7 @@ When reporting bugs against libinput, please follow the instructions below
|
|||
and provide the required data. This will speed up triage, resulting in a
|
||||
quicker bugfix.
|
||||
|
||||
First, try to identify the bugi by reproducing it reliably. The more
|
||||
First, try to identify the bug by reproducing it reliably. The more
|
||||
specific a bug description is, the easier it is to fix. The @ref
|
||||
libinput-debug-events helper tool can help identify whether the bug is in
|
||||
libinput at all. This tool is a direct hook to libinput without a desktop
|
||||
|
|
@ -85,4 +85,10 @@ $ sudo evemu-play /dev/input/event4 < scroll.evemu
|
|||
If the bug is triggered by replaying on your device, attach the recording to
|
||||
the bug report.
|
||||
|
||||
@note libinput does not affect the evemu recording. libinput and evemu talk
|
||||
directly to the kernel's device nodes. An evemu recording is not influenced
|
||||
by the libinput version or whether a libinput context is currently active.
|
||||
|
||||
@dotfile evemu.gv
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Each device in libinput is assigned to one seat.
|
|||
A seat has two identifiers, the physical name and the logical name. The
|
||||
physical name is summarized as the list of devices a process on the same
|
||||
physical seat has access to. The logical seat name is the seat name for a
|
||||
logical group of devices. A compositor may use that to create additonal
|
||||
logical group of devices. A compositor may use that to create additional
|
||||
seats as independent device sets. Alternatively, a compositor may limit
|
||||
itself to a single logical seat, leaving a second compositor to manage
|
||||
devices on the other logical seats.
|
||||
|
|
@ -32,7 +32,7 @@ libinput_seat, all other devices reference their own respective seats.
|
|||
|
||||
@section seats_and_features The effect of seat assignment
|
||||
|
||||
A logical set is interprested as a group of devices that usually belong to a
|
||||
A logical set is interpreted as a group of devices that usually belong to a
|
||||
single user that interacts with a computer. Thus, the devices are
|
||||
semantically related. This means for devices within the same logical seat:
|
||||
|
||||
|
|
|
|||
5486
doc/svg/ptraccel-linear.svg
Normal file
5486
doc/svg/ptraccel-linear.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 550 KiB |
3748
doc/svg/ptraccel-low-dpi.svg
Normal file
3748
doc/svg/ptraccel-low-dpi.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 377 KiB |
1723
doc/svg/ptraccel-touchpad.svg
Normal file
1723
doc/svg/ptraccel-touchpad.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 171 KiB |
3689
doc/svg/ptraccel-trackpoint.svg
Normal file
3689
doc/svg/ptraccel-trackpoint.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 371 KiB |
|
|
@ -40,7 +40,7 @@ disabled with libinput_device_config_tap_set_drag_lock_enabled().
|
|||
The above diagram explains the process, a tap (a) followed by a finger held
|
||||
down (b) starts the drag process and logically holds the left mouse button
|
||||
down. A movement of the finger (c) will drag the selected item until the
|
||||
finger is relased (e). If needed and drag lock is enabled, the finger's
|
||||
finger is released (e). If needed and drag lock is enabled, the finger's
|
||||
position can be reset by lifting and quickly setting it down again on the
|
||||
touchpad (d). This will be interpreted as continuing move and is especially
|
||||
useful on small touchpads or with slow pointer acceleration.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ tools are usually installed, others are @ref developer_tools only.
|
|||
|
||||
libinput ships with two tools to gather information about devices:
|
||||
@ref libinput-list-devices and @ref libinput-debug-events. Both tools must
|
||||
be run as root to have acess to the kernel's @c /dev/input/event* device
|
||||
be run as root to have access to the kernel's @c /dev/input/event* device
|
||||
files.
|
||||
|
||||
@subsection libinput-list-devices
|
||||
|
|
@ -97,6 +97,6 @@ $ sudo ./tools/event-gui
|
|||
See the @c --help output for information about the available options.
|
||||
|
||||
@note The @c --grab flag puts an exclusive @c EVIOCGRAB on the device to
|
||||
avoid interference with the desktiop while testing.
|
||||
avoid interference with the desktop while testing.
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ touches, others support 5 touches like the Synaptics touchpads when using
|
|||
SMBus.
|
||||
|
||||
These touchpads usually also provide extra information. Apple touchpads
|
||||
provide an ellipsis and the orientation of the ellipsis for each touch point.
|
||||
provide an ellipse and the orientation of the ellipse for each touch point.
|
||||
Other touchpads provide a pressure value for each touch point (see @ref
|
||||
touchpads_pressure_handling).
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ located underneath the keyboard, accidental palm touches are a non-issue.
|
|||
|
||||
Pressure is usually directly related to contact area. Human fingers flatten
|
||||
out as the pressure on the pad increases, resulting in a bigger contact area
|
||||
and the firmware then calculates that back into a ressure reading.
|
||||
and the firmware then calculates that back into a pressure reading.
|
||||
|
||||
libinput uses pressure to detect accidental palm contact and thumbs, though
|
||||
pressure data is often device-specific and unreliable.
|
||||
|
|
@ -138,7 +138,7 @@ pressure data is often device-specific and unreliable.
|
|||
@subsection touchpads_circular Circular touchpads
|
||||
|
||||
Only listed for completeness, circular touchpads have not been used in
|
||||
laptops for a number of years. These touchpad shaped in an ellipsis or
|
||||
laptops for a number of years. These touchpad shaped in an ellipse or
|
||||
straight.
|
||||
|
||||
@subsection touchpads_tablets Graphics tablets
|
||||
|
|
|
|||
|
|
@ -640,9 +640,7 @@ evdev_middlebutton_handle_timeout(uint64_t now, void *data)
|
|||
{
|
||||
struct evdev_device *device = (struct evdev_device*)data;
|
||||
|
||||
evdev_middlebutton_handle_event(device,
|
||||
libinput_now(device->base.seat->libinput),
|
||||
MIDDLEBUTTON_EVENT_TIMEOUT);
|
||||
evdev_middlebutton_handle_event(device, now, MIDDLEBUTTON_EVENT_TIMEOUT);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
int
|
||||
tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
struct libinput_device *device = &tp->device->base;
|
||||
struct evdev_device *device = tp->device;
|
||||
struct tp_touch *t;
|
||||
enum libinput_pointer_axis axis;
|
||||
double *delta;
|
||||
|
|
@ -369,7 +369,7 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
case EDGE_NONE:
|
||||
if (t->scroll.direction != -1) {
|
||||
/* Send stop scroll event */
|
||||
pointer_notify_axis(device, time,
|
||||
evdev_notify_axis(device, time,
|
||||
AS_MASK(t->scroll.direction),
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
|
||||
&zero,
|
||||
|
|
@ -390,12 +390,13 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
}
|
||||
|
||||
normalized = tp_get_delta(t);
|
||||
normalized = tp_filter_motion(tp, &normalized, time);
|
||||
/* scroll is not accelerated */
|
||||
normalized = tp_filter_motion_unaccelerated(tp, &normalized, time);
|
||||
|
||||
switch (t->scroll.edge_state) {
|
||||
case EDGE_SCROLL_TOUCH_STATE_NONE:
|
||||
case EDGE_SCROLL_TOUCH_STATE_AREA:
|
||||
log_bug_libinput(device->seat->libinput,
|
||||
log_bug_libinput(tp_libinput_context(tp),
|
||||
"unexpected scroll state %d\n",
|
||||
t->scroll.edge_state);
|
||||
break;
|
||||
|
|
@ -416,11 +417,11 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
if (*delta == 0.0)
|
||||
continue;
|
||||
|
||||
pointer_notify_axis(device, time,
|
||||
AS_MASK(axis),
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
|
||||
&normalized,
|
||||
&zero_discrete);
|
||||
evdev_notify_axis(device, time,
|
||||
AS_MASK(axis),
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
|
||||
&normalized,
|
||||
&zero_discrete);
|
||||
t->scroll.direction = axis;
|
||||
|
||||
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED);
|
||||
|
|
@ -432,14 +433,14 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
|
|||
void
|
||||
tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
struct libinput_device *device = &tp->device->base;
|
||||
struct evdev_device *device = tp->device;
|
||||
struct tp_touch *t;
|
||||
const struct normalized_coords zero = { 0.0, 0.0 };
|
||||
const struct discrete_coords zero_discrete = { 0.0, 0.0 };
|
||||
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->scroll.direction != -1) {
|
||||
pointer_notify_axis(device, time,
|
||||
evdev_notify_axis(device, time,
|
||||
AS_MASK(t->scroll.direction),
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
|
||||
&zero,
|
||||
|
|
|
|||
|
|
@ -328,7 +328,8 @@ tp_gesture_twofinger_handle_state_scroll(struct tp_dispatch *tp, uint64_t time)
|
|||
delta = tp_get_average_touches_delta(tp);
|
||||
}
|
||||
|
||||
delta = tp_filter_motion(tp, &delta, time);
|
||||
/* scroll is not accelerated */
|
||||
delta = tp_filter_motion_unaccelerated(tp, &delta, time);
|
||||
|
||||
if (normalized_is_zero(delta))
|
||||
return GESTURE_2FG_STATE_SCROLL;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,18 @@ tp_filter_motion(struct tp_dispatch *tp,
|
|||
unaccelerated, tp, time);
|
||||
}
|
||||
|
||||
struct normalized_coords
|
||||
tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
uint64_t time)
|
||||
{
|
||||
if (normalized_is_zero(*unaccelerated))
|
||||
return *unaccelerated;
|
||||
|
||||
return filter_dispatch_constant(tp->device->pointer.filter,
|
||||
unaccelerated, tp, time);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_motion_history_push(struct tp_touch *t)
|
||||
{
|
||||
|
|
@ -1511,7 +1523,7 @@ static int
|
|||
tp_init_accel(struct tp_dispatch *tp, double diagonal)
|
||||
{
|
||||
int res_x, res_y;
|
||||
accel_profile_func_t profile;
|
||||
struct motion_filter *filter;
|
||||
|
||||
res_x = tp->device->abs.absinfo_x->resolution;
|
||||
res_y = tp->device->abs.absinfo_y->resolution;
|
||||
|
|
@ -1527,14 +1539,14 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
|
|||
tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
|
||||
|
||||
if (tp->device->model_flags & EVDEV_MODEL_LENOVO_X230)
|
||||
profile = touchpad_lenovo_x230_accel_profile;
|
||||
filter = create_pointer_accelerator_filter_lenovo_x230(tp->device->dpi);
|
||||
else
|
||||
profile = touchpad_accel_profile_linear;
|
||||
filter = create_pointer_accelerator_filter_touchpad(tp->device->dpi);
|
||||
|
||||
if (evdev_device_init_pointer_acceleration(tp->device, profile) == -1)
|
||||
if (!filter)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return evdev_device_init_pointer_acceleration(tp->device, filter);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
|
@ -1629,8 +1641,9 @@ tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
|
|||
tp->scroll.method = tp_scroll_get_default_method(tp);
|
||||
tp->device->base.config.scroll_method = &tp->scroll.config_method;
|
||||
|
||||
/* In mm for touchpads with valid resolution, see tp_init_accel() */
|
||||
tp->device->scroll.threshold = 5.0;
|
||||
/* In mm for touchpads with valid resolution, see tp_init_accel() */
|
||||
tp->device->scroll.threshold = 0.0;
|
||||
tp->device->scroll.direction_lock_threshold = 5.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,10 @@ struct normalized_coords
|
|||
tp_filter_motion(struct tp_dispatch *tp,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
uint64_t time);
|
||||
struct normalized_coords
|
||||
tp_filter_motion_unaccelerated(struct tp_dispatch *tp,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
uint64_t time);
|
||||
|
||||
int
|
||||
tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
|
||||
|
|
|
|||
71
src/evdev.c
71
src/evdev.c
|
|
@ -612,7 +612,7 @@ evdev_process_absolute_motion(struct evdev_device *device,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
evdev_notify_axis(struct evdev_device *device,
|
||||
uint64_t time,
|
||||
uint32_t axes,
|
||||
|
|
@ -638,6 +638,25 @@ evdev_notify_axis(struct evdev_device *device,
|
|||
&discrete);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
evdev_reject_relative(struct evdev_device *device,
|
||||
const struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
struct libinput *libinput = device->base.seat->libinput;
|
||||
|
||||
if ((e->code == REL_X || e->code == REL_Y) &&
|
||||
(device->seat_caps & EVDEV_DEVICE_POINTER) == 0) {
|
||||
log_bug_libinput_ratelimit(libinput,
|
||||
&device->nonpointer_rel_limit,
|
||||
"REL_X/Y from device '%s', but this device is not a pointer\n",
|
||||
device->devname);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_relative(struct evdev_device *device,
|
||||
struct input_event *e, uint64_t time)
|
||||
|
|
@ -645,6 +664,9 @@ evdev_process_relative(struct evdev_device *device,
|
|||
struct normalized_coords wheel_degrees = { 0.0, 0.0 };
|
||||
struct discrete_coords discrete = { 0.0, 0.0 };
|
||||
|
||||
if (evdev_reject_relative(device, e, time))
|
||||
return;
|
||||
|
||||
switch (e->code) {
|
||||
case REL_X:
|
||||
if (device->pending_event != EVDEV_RELATIVE_MOTION)
|
||||
|
|
@ -1339,20 +1361,10 @@ evdev_device_dispatch(void *data)
|
|||
rc = libevdev_next_event(device->evdev,
|
||||
LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||
if (rc == LIBEVDEV_READ_STATUS_SYNC) {
|
||||
switch (ratelimit_test(&device->syn_drop_limit)) {
|
||||
case RATELIMIT_PASS:
|
||||
log_info(libinput, "SYN_DROPPED event from "
|
||||
"\"%s\" - some input events have "
|
||||
"been lost.\n", device->devname);
|
||||
break;
|
||||
case RATELIMIT_THRESHOLD:
|
||||
log_info(libinput, "SYN_DROPPED flood "
|
||||
"from \"%s\"\n",
|
||||
device->devname);
|
||||
break;
|
||||
case RATELIMIT_EXCEEDED:
|
||||
break;
|
||||
}
|
||||
log_info_ratelimit(libinput,
|
||||
&device->syn_drop_limit,
|
||||
"SYN_DROPPED event from \"%s\" - some input events have been lost.\n",
|
||||
device->devname);
|
||||
|
||||
/* send one more sync event so we handle all
|
||||
currently pending events before we sync up
|
||||
|
|
@ -1409,12 +1421,9 @@ evdev_accel_config_get_default_speed(struct libinput_device *device)
|
|||
|
||||
int
|
||||
evdev_device_init_pointer_acceleration(struct evdev_device *device,
|
||||
accel_profile_func_t profile)
|
||||
struct motion_filter *filter)
|
||||
{
|
||||
device->pointer.filter = create_pointer_accelerator_filter(profile,
|
||||
device->dpi);
|
||||
if (!device->pointer.filter)
|
||||
return -1;
|
||||
device->pointer.filter = filter;
|
||||
|
||||
device->pointer.config.available = evdev_accel_config_available;
|
||||
device->pointer.config.set_speed = evdev_accel_config_set_speed;
|
||||
|
|
@ -1863,14 +1872,19 @@ evdev_configure_mt_device(struct evdev_device *device)
|
|||
static inline int
|
||||
evdev_init_accel(struct evdev_device *device)
|
||||
{
|
||||
accel_profile_func_t profile;
|
||||
struct motion_filter *filter;
|
||||
|
||||
if (device->dpi < DEFAULT_MOUSE_DPI)
|
||||
profile = pointer_accel_profile_linear_low_dpi;
|
||||
if (device->tags & EVDEV_TAG_TRACKPOINT)
|
||||
filter = create_pointer_accelerator_filter_trackpoint(device->dpi);
|
||||
else if (device->dpi < DEFAULT_MOUSE_DPI)
|
||||
filter = create_pointer_accelerator_filter_linear_low_dpi(device->dpi);
|
||||
else
|
||||
profile = pointer_accel_profile_linear;
|
||||
filter = create_pointer_accelerator_filter_linear(device->dpi);
|
||||
|
||||
return evdev_device_init_pointer_acceleration(device, profile);
|
||||
if (!filter)
|
||||
return -1;
|
||||
|
||||
return evdev_device_init_pointer_acceleration(device, filter);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -2167,6 +2181,7 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
device->pending_event = EVDEV_NONE;
|
||||
device->devname = libevdev_get_name(device->evdev);
|
||||
device->scroll.threshold = 5.0; /* Default may be overridden */
|
||||
device->scroll.direction_lock_threshold = 5.0; /* Default may be overridden */
|
||||
device->scroll.direction = 0;
|
||||
device->scroll.wheel_click_angle =
|
||||
evdev_read_wheel_click_prop(device);
|
||||
|
|
@ -2175,6 +2190,8 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
|
||||
/* at most 5 SYN_DROPPED log-messages per 30s */
|
||||
ratelimit_init(&device->syn_drop_limit, s2us(30), 5);
|
||||
/* at most 5 log-messages per 5s */
|
||||
ratelimit_init(&device->nonpointer_rel_limit, s2us(5), 5);
|
||||
|
||||
matrix_init_identity(&device->abs.calibration);
|
||||
matrix_init_identity(&device->abs.usermatrix);
|
||||
|
|
@ -2437,12 +2454,12 @@ evdev_post_scroll(struct evdev_device *device,
|
|||
trigger speed to start scrolling in the other direction */
|
||||
} else if (!evdev_is_scrolling(device,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
|
||||
if (fabs(delta->y) >= device->scroll.threshold)
|
||||
if (fabs(delta->y) >= device->scroll.direction_lock_threshold)
|
||||
evdev_start_scrolling(device,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
||||
} else if (!evdev_is_scrolling(device,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
|
||||
if (fabs(delta->x) >= device->scroll.threshold)
|
||||
if (fabs(delta->x) >= device->scroll.direction_lock_threshold)
|
||||
evdev_start_scrolling(device,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
|
||||
}
|
||||
|
|
|
|||
11
src/evdev.h
11
src/evdev.h
|
|
@ -167,6 +167,7 @@ struct evdev_device {
|
|||
void (*change_scroll_method)(struct evdev_device *device);
|
||||
bool button_scroll_active;
|
||||
double threshold;
|
||||
double direction_lock_threshold;
|
||||
uint32_t direction;
|
||||
struct normalized_coords buildup;
|
||||
|
||||
|
|
@ -223,6 +224,7 @@ struct evdev_device {
|
|||
|
||||
int dpi; /* HW resolution */
|
||||
struct ratelimit syn_drop_limit; /* ratelimit for SYN_DROPPED logging */
|
||||
struct ratelimit nonpointer_rel_limit; /* ratelimit for REL_* events from non-pointer devices */
|
||||
|
||||
uint32_t model_flags;
|
||||
};
|
||||
|
|
@ -286,7 +288,7 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
|
||||
int
|
||||
evdev_device_init_pointer_acceleration(struct evdev_device *device,
|
||||
accel_profile_func_t profile);
|
||||
struct motion_filter *filter);
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_touchpad_create(struct evdev_device *device);
|
||||
|
|
@ -388,6 +390,13 @@ evdev_pointer_notify_physical_button(struct evdev_device *device,
|
|||
void
|
||||
evdev_init_natural_scroll(struct evdev_device *device);
|
||||
|
||||
void
|
||||
evdev_notify_axis(struct evdev_device *device,
|
||||
uint64_t time,
|
||||
uint32_t axes,
|
||||
enum libinput_pointer_axis_source source,
|
||||
const struct normalized_coords *delta_in,
|
||||
const struct discrete_coords *discrete_in);
|
||||
void
|
||||
evdev_post_scroll(struct evdev_device *device,
|
||||
uint64_t time,
|
||||
|
|
|
|||
|
|
@ -33,16 +33,20 @@ struct motion_filter_interface {
|
|||
struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time);
|
||||
struct normalized_coords (*filter_constant)(
|
||||
struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time);
|
||||
void (*restart)(struct motion_filter *filter,
|
||||
void *data,
|
||||
uint64_t time);
|
||||
void (*destroy)(struct motion_filter *filter);
|
||||
bool (*set_speed)(struct motion_filter *filter,
|
||||
double speed);
|
||||
double speed_adjustment);
|
||||
};
|
||||
|
||||
struct motion_filter {
|
||||
double speed; /* normalized [-1, 1] */
|
||||
double speed_adjustment; /* normalized [-1, 1] */
|
||||
struct motion_filter_interface *interface;
|
||||
};
|
||||
|
||||
|
|
|
|||
570
src/filter.c
570
src/filter.c
|
|
@ -36,6 +36,26 @@
|
|||
#include "libinput-util.h"
|
||||
#include "filter-private.h"
|
||||
|
||||
/* Once normalized, touchpads see the same acceleration as mice. that is
|
||||
* technically correct but subjectively wrong, we expect a touchpad to be a
|
||||
* lot slower than a mouse. Apply a magic factor to slow down all movements
|
||||
*/
|
||||
#define TP_MAGIC_SLOWDOWN 0.4 /* unitless factor */
|
||||
|
||||
/* Convert speed/velocity from units/us to units/ms */
|
||||
static inline double
|
||||
v_us2ms(double units_per_us)
|
||||
{
|
||||
return units_per_us * 1000.0;
|
||||
}
|
||||
|
||||
/* Convert speed/velocity from units/ms to units/us */
|
||||
static inline double
|
||||
v_ms2us(double units_per_ms)
|
||||
{
|
||||
return units_per_ms/1000.0;
|
||||
}
|
||||
|
||||
struct normalized_coords
|
||||
filter_dispatch(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
|
|
@ -44,6 +64,14 @@ filter_dispatch(struct motion_filter *filter,
|
|||
return filter->interface->filter(filter, unaccelerated, data, time);
|
||||
}
|
||||
|
||||
struct normalized_coords
|
||||
filter_dispatch_constant(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
return filter->interface->filter_constant(filter, unaccelerated, data, time);
|
||||
}
|
||||
|
||||
void
|
||||
filter_restart(struct motion_filter *filter,
|
||||
void *data, uint64_t time)
|
||||
|
|
@ -62,30 +90,36 @@ filter_destroy(struct motion_filter *filter)
|
|||
|
||||
bool
|
||||
filter_set_speed(struct motion_filter *filter,
|
||||
double speed)
|
||||
double speed_adjustment)
|
||||
{
|
||||
return filter->interface->set_speed(filter, speed);
|
||||
return filter->interface->set_speed(filter, speed_adjustment);
|
||||
}
|
||||
|
||||
double
|
||||
filter_get_speed(struct motion_filter *filter)
|
||||
{
|
||||
return filter->speed;
|
||||
return filter->speed_adjustment;
|
||||
}
|
||||
|
||||
/*
|
||||
* Default parameters for pointer acceleration profiles.
|
||||
*/
|
||||
|
||||
#define DEFAULT_THRESHOLD 0.4 /* in units/ms */
|
||||
#define DEFAULT_THRESHOLD v_ms2us(0.4) /* in units/us */
|
||||
#define MINIMUM_THRESHOLD v_ms2us(0.2) /* in units/us */
|
||||
#define DEFAULT_ACCELERATION 2.0 /* unitless factor */
|
||||
#define DEFAULT_INCLINE 1.1 /* unitless factor */
|
||||
|
||||
/* for the Lenovo x230 custom accel. do not touch */
|
||||
#define X230_THRESHOLD v_ms2us(0.4) /* in units/us */
|
||||
#define X230_ACCELERATION 2.0 /* unitless factor */
|
||||
#define X230_INCLINE 1.1 /* unitless factor */
|
||||
|
||||
/*
|
||||
* Pointer acceleration filter constants
|
||||
*/
|
||||
|
||||
#define MAX_VELOCITY_DIFF 1 /* units/ms */
|
||||
#define MAX_VELOCITY_DIFF v_ms2us(1) /* units/us */
|
||||
#define MOTION_TIMEOUT ms2us(1000)
|
||||
#define NUM_POINTER_TRACKERS 16
|
||||
|
||||
|
|
@ -95,20 +129,18 @@ struct pointer_tracker {
|
|||
int dir;
|
||||
};
|
||||
|
||||
struct pointer_accelerator;
|
||||
struct pointer_accelerator {
|
||||
struct motion_filter base;
|
||||
|
||||
accel_profile_func_t profile;
|
||||
|
||||
double velocity; /* units/ms */
|
||||
double last_velocity; /* units/ms */
|
||||
struct normalized_coords last;
|
||||
double velocity; /* units/us */
|
||||
double last_velocity; /* units/us */
|
||||
|
||||
struct pointer_tracker *trackers;
|
||||
int cur_tracker;
|
||||
|
||||
double threshold; /* units/ms */
|
||||
double threshold; /* units/us */
|
||||
double accel; /* unitless factor */
|
||||
double incline; /* incline of the function */
|
||||
|
||||
|
|
@ -150,7 +182,7 @@ static double
|
|||
calculate_tracker_velocity(struct pointer_tracker *tracker, uint64_t time)
|
||||
{
|
||||
double tdelta = time - tracker->time + 1;
|
||||
return normalized_length(tracker->delta) / tdelta * 1000.0; /* units/ms */
|
||||
return normalized_length(tracker->delta) / tdelta; /* units/us */
|
||||
}
|
||||
|
||||
static inline double
|
||||
|
|
@ -220,7 +252,7 @@ calculate_velocity(struct pointer_accelerator *accel, uint64_t time)
|
|||
}
|
||||
}
|
||||
|
||||
return result; /* units/ms */
|
||||
return result; /* units/us */
|
||||
}
|
||||
|
||||
static double
|
||||
|
|
@ -253,14 +285,63 @@ calculate_acceleration(struct pointer_accelerator *accel,
|
|||
return factor; /* unitless factor */
|
||||
}
|
||||
|
||||
static inline double
|
||||
calculate_acceleration_factor(struct pointer_accelerator *accel,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data,
|
||||
uint64_t time)
|
||||
{
|
||||
double velocity; /* units/us */
|
||||
double accel_factor;
|
||||
|
||||
feed_trackers(accel, unaccelerated, time);
|
||||
velocity = calculate_velocity(accel, time);
|
||||
accel_factor = calculate_acceleration(accel,
|
||||
data,
|
||||
velocity,
|
||||
accel->last_velocity,
|
||||
time);
|
||||
accel->last_velocity = velocity;
|
||||
|
||||
return accel_factor;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
accelerator_filter(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time /* in us */)
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
double accel_value; /* unitless factor */
|
||||
struct normalized_coords accelerated;
|
||||
|
||||
accel_value = calculate_acceleration_factor(accel,
|
||||
unaccelerated,
|
||||
data,
|
||||
time);
|
||||
|
||||
accelerated.x = accel_value * unaccelerated->x;
|
||||
accelerated.y = accel_value * unaccelerated->y;
|
||||
|
||||
return accelerated;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
accelerator_filter_noop(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
return *unaccelerated;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
accelerator_filter_low_dpi(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
double velocity; /* units/ms */
|
||||
double accel_value; /* unitless factor */
|
||||
struct normalized_coords accelerated;
|
||||
struct normalized_coords unnormalized;
|
||||
|
|
@ -272,24 +353,86 @@ accelerator_filter(struct motion_filter *filter,
|
|||
unnormalized.x = unaccelerated->x * dpi_factor;
|
||||
unnormalized.y = unaccelerated->y * dpi_factor;
|
||||
|
||||
feed_trackers(accel, &unnormalized, time);
|
||||
velocity = calculate_velocity(accel, time);
|
||||
accel_value = calculate_acceleration(accel,
|
||||
data,
|
||||
velocity,
|
||||
accel->last_velocity,
|
||||
time);
|
||||
accel_value = calculate_acceleration_factor(accel,
|
||||
&unnormalized,
|
||||
data,
|
||||
time);
|
||||
|
||||
accelerated.x = accel_value * unnormalized.x;
|
||||
accelerated.y = accel_value * unnormalized.y;
|
||||
|
||||
accel->last = unnormalized;
|
||||
return accelerated;
|
||||
}
|
||||
|
||||
accel->last_velocity = velocity;
|
||||
static struct normalized_coords
|
||||
accelerator_filter_trackpoint(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
double accel_value; /* unitless factor */
|
||||
struct normalized_coords accelerated;
|
||||
struct normalized_coords unnormalized;
|
||||
double dpi_factor = accel->dpi_factor;
|
||||
|
||||
/* trackpoints with a dpi factor have a const accel set, remove that
|
||||
* and restore device units. The accel profile takes const accel
|
||||
* into account */
|
||||
dpi_factor = min(1.0, dpi_factor);
|
||||
unnormalized.x = unaccelerated->x * dpi_factor;
|
||||
unnormalized.y = unaccelerated->y * dpi_factor;
|
||||
|
||||
accel_value = calculate_acceleration_factor(accel,
|
||||
&unnormalized,
|
||||
data,
|
||||
time);
|
||||
|
||||
accelerated.x = accel_value * unnormalized.x;
|
||||
accelerated.y = accel_value * unnormalized.y;
|
||||
|
||||
return accelerated;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
accelerator_filter_x230(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
double accel_factor; /* unitless factor */
|
||||
struct normalized_coords accelerated;
|
||||
double velocity; /* units/us */
|
||||
|
||||
feed_trackers(accel, unaccelerated, time);
|
||||
velocity = calculate_velocity(accel, time);
|
||||
accel_factor = calculate_acceleration(accel,
|
||||
data,
|
||||
velocity,
|
||||
accel->last_velocity,
|
||||
time);
|
||||
accel->last_velocity = velocity;
|
||||
|
||||
accelerated.x = accel_factor * unaccelerated->x;
|
||||
accelerated.y = accel_factor * unaccelerated->y;
|
||||
|
||||
return accelerated;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
touchpad_constant_filter(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time)
|
||||
{
|
||||
struct normalized_coords normalized;
|
||||
|
||||
normalized.x = TP_MAGIC_SLOWDOWN * unaccelerated->x;
|
||||
normalized.y = TP_MAGIC_SLOWDOWN * unaccelerated->y;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
static void
|
||||
accelerator_restart(struct motion_filter *filter,
|
||||
void *data,
|
||||
|
|
@ -325,65 +468,32 @@ accelerator_destroy(struct motion_filter *filter)
|
|||
|
||||
static bool
|
||||
accelerator_set_speed(struct motion_filter *filter,
|
||||
double speed)
|
||||
double speed_adjustment)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
|
||||
assert(speed >= -1.0 && speed <= 1.0);
|
||||
assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
|
||||
|
||||
/* Note: the numbers below are nothing but trial-and-error magic,
|
||||
don't read more into them other than "they mostly worked ok" */
|
||||
|
||||
/* delay when accel kicks in */
|
||||
accel_filter->threshold = DEFAULT_THRESHOLD - speed / 4000.0;
|
||||
if (accel_filter->threshold < 0.0002)
|
||||
accel_filter->threshold = 0.0002;
|
||||
accel_filter->threshold = DEFAULT_THRESHOLD -
|
||||
v_ms2us(0.25) * speed_adjustment;
|
||||
if (accel_filter->threshold < MINIMUM_THRESHOLD)
|
||||
accel_filter->threshold = MINIMUM_THRESHOLD;
|
||||
|
||||
/* adjust max accel factor */
|
||||
accel_filter->accel = DEFAULT_ACCELERATION + speed * 1.5;
|
||||
accel_filter->accel = DEFAULT_ACCELERATION + speed_adjustment * 1.5;
|
||||
|
||||
/* higher speed -> faster to reach max */
|
||||
accel_filter->incline = DEFAULT_INCLINE + speed * 0.75;
|
||||
accel_filter->incline = DEFAULT_INCLINE + speed_adjustment * 0.75;
|
||||
|
||||
filter->speed = speed;
|
||||
filter->speed_adjustment = speed_adjustment;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface = {
|
||||
accelerator_filter,
|
||||
accelerator_restart,
|
||||
accelerator_destroy,
|
||||
accelerator_set_speed,
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter(accel_profile_func_t profile,
|
||||
int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = zalloc(sizeof *filter);
|
||||
if (filter == NULL)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface;
|
||||
|
||||
filter->profile = profile;
|
||||
filter->last_velocity = 0.0;
|
||||
filter->last.x = 0;
|
||||
filter->last.y = 0;
|
||||
|
||||
filter->trackers =
|
||||
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
|
||||
filter->cur_tracker = 0;
|
||||
|
||||
filter->threshold = DEFAULT_THRESHOLD;
|
||||
filter->accel = DEFAULT_ACCELERATION;
|
||||
filter->incline = DEFAULT_INCLINE;
|
||||
|
||||
filter->dpi_factor = dpi/(double)DEFAULT_MOUSE_DPI;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom acceleration function for mice < 1000dpi.
|
||||
* At slow motion, a single device unit causes a one-pixel movement.
|
||||
|
|
@ -397,25 +507,32 @@ create_pointer_accelerator_filter(accel_profile_func_t profile,
|
|||
double
|
||||
pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in, /* in device units (units/ms) */
|
||||
uint64_t time /* in us */)
|
||||
double speed_in, /* in device units (units/us) */
|
||||
uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
|
||||
double s1, s2;
|
||||
double max_accel = accel_filter->accel; /* unitless factor */
|
||||
const double threshold = accel_filter->threshold; /* units/ms */
|
||||
double threshold = accel_filter->threshold; /* units/us */
|
||||
const double incline = accel_filter->incline;
|
||||
double factor;
|
||||
double factor; /* unitless */
|
||||
double dpi_factor = accel_filter->dpi_factor;
|
||||
|
||||
/* dpi_factor is always < 1.0, increase max_accel, reduce
|
||||
the threshold so it kicks in earlier */
|
||||
max_accel /= dpi_factor;
|
||||
threshold *= dpi_factor;
|
||||
|
||||
s1 = min(1, 0.3 + speed_in * 10.0);
|
||||
s2 = 1 + (speed_in - threshold * dpi_factor) * incline;
|
||||
/* see pointer_accel_profile_linear for a long description */
|
||||
if (v_us2ms(speed_in) < 0.07)
|
||||
factor = 10 * v_us2ms(speed_in) + 0.3;
|
||||
else if (speed_in < threshold)
|
||||
factor = 1;
|
||||
else
|
||||
factor = incline * v_us2ms(speed_in - threshold) + 1;
|
||||
|
||||
factor = min(max_accel, s2 > 1 ? s2 : s1);
|
||||
factor = min(max_accel, factor);
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
|
@ -424,54 +541,98 @@ double
|
|||
pointer_accel_profile_linear(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in, /* 1000-dpi normalized */
|
||||
uint64_t time /* in us */)
|
||||
uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
|
||||
double s1, s2;
|
||||
const double max_accel = accel_filter->accel; /* unitless factor */
|
||||
const double threshold = accel_filter->threshold; /* units/ms */
|
||||
const double threshold = accel_filter->threshold; /* units/us */
|
||||
const double incline = accel_filter->incline;
|
||||
double factor;
|
||||
double factor; /* unitless */
|
||||
|
||||
s1 = min(1, 0.3 + speed_in * 10);
|
||||
s2 = 1 + (speed_in - threshold) * incline;
|
||||
/*
|
||||
Our acceleration function calculates a factor to accelerate input
|
||||
deltas with. The function is a double incline with a plateau,
|
||||
with a rough shape like this:
|
||||
|
||||
factor = min(max_accel, s2 > 1 ? s2 : s1);
|
||||
accel
|
||||
factor
|
||||
^
|
||||
| /
|
||||
| _____/
|
||||
| /
|
||||
|/
|
||||
+-------------> speed in
|
||||
|
||||
The two inclines are linear functions in the form
|
||||
y = ax + b
|
||||
where y is speed_out
|
||||
x is speed_in
|
||||
a is the incline of acceleration
|
||||
b is minimum acceleration factor
|
||||
|
||||
for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
|
||||
speed.
|
||||
hence 1 = a * 0.07 + 0.3
|
||||
0.3 = a * 0.00 + 0.3 => a := 10
|
||||
deceleration function is thus:
|
||||
y = 10x + 0.3
|
||||
|
||||
Note:
|
||||
* 0.07u/ms as threshold is a result of trial-and-error and
|
||||
has no other intrinsic meaning.
|
||||
* 0.3 is chosen simply because it is above the Nyquist frequency
|
||||
for subpixel motion within a pixel.
|
||||
*/
|
||||
if (v_us2ms(speed_in) < 0.07) {
|
||||
factor = 10 * v_us2ms(speed_in) + 0.3;
|
||||
/* up to the threshold, we keep factor 1, i.e. 1:1 movement */
|
||||
} else if (speed_in < threshold) {
|
||||
factor = 1;
|
||||
|
||||
} else {
|
||||
/* Acceleration function above the threshold:
|
||||
y = ax' + b
|
||||
where T is threshold
|
||||
x is speed_in
|
||||
x' is speed
|
||||
and
|
||||
y(T) == 1
|
||||
hence 1 = ax' + 1
|
||||
=> x' := (x - T)
|
||||
*/
|
||||
factor = incline * v_us2ms(speed_in - threshold) + 1;
|
||||
}
|
||||
|
||||
/* Cap at the maximum acceleration factor */
|
||||
factor = min(max_accel, factor);
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
double
|
||||
touchpad_accel_profile_linear(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
uint64_t time /* in us */)
|
||||
void *data,
|
||||
double speed_in, /* units/us */
|
||||
uint64_t time)
|
||||
{
|
||||
/* Once normalized, touchpads see the same
|
||||
acceleration as mice. that is technically correct but
|
||||
subjectively wrong, we expect a touchpad to be a lot
|
||||
slower than a mouse. Apply a magic factor here and proceed
|
||||
as normal. */
|
||||
const double TP_MAGIC_SLOWDOWN = 0.4;
|
||||
double speed_out;
|
||||
double factor; /* unitless */
|
||||
|
||||
speed_in *= TP_MAGIC_SLOWDOWN;
|
||||
|
||||
speed_out = pointer_accel_profile_linear(filter, data, speed_in, time);
|
||||
factor = pointer_accel_profile_linear(filter, data, speed_in, time);
|
||||
|
||||
return speed_out * TP_MAGIC_SLOWDOWN;
|
||||
return factor * TP_MAGIC_SLOWDOWN;
|
||||
}
|
||||
|
||||
double
|
||||
touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
uint64_t time /* in us */)
|
||||
uint64_t time)
|
||||
{
|
||||
/* Keep the magic factor from touchpad_accel_profile_linear. */
|
||||
const double TP_MAGIC_SLOWDOWN = 0.4;
|
||||
const double X230_MAGIC_SLOWDOWN = 0.4; /* unitless */
|
||||
|
||||
/* Those touchpads presents an actual lower resolution that what is
|
||||
* advertised. We see some jumps from the cursor due to the big steps
|
||||
|
|
@ -479,24 +640,219 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
|
|||
* 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;
|
||||
const double TP_MAGIC_LOW_RES_FACTOR = 4.0; /* unitless */
|
||||
double factor; /* unitless */
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
|
||||
double s1, s2;
|
||||
double f1, f2; /* unitless */
|
||||
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 */
|
||||
TP_MAGIC_LOW_RES_FACTOR; /* units/us */
|
||||
const double incline = accel_filter->incline * TP_MAGIC_LOW_RES_FACTOR;
|
||||
|
||||
speed_in *= TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
|
||||
/* Note: the magic values in this function are obtained by
|
||||
* trial-and-error. No other meaning should be interpreted.
|
||||
* The calculation is a compressed form of
|
||||
* pointer_accel_profile_linear(), look at the git history of that
|
||||
* function for an explaination of what the min/max/etc. does.
|
||||
*/
|
||||
speed_in *= X230_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
|
||||
|
||||
s1 = min(1, speed_in * 5);
|
||||
s2 = 1 + (speed_in - threshold) * incline;
|
||||
f1 = min(1, v_us2ms(speed_in) * 5);
|
||||
f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold)) * incline;
|
||||
|
||||
speed_out = min(max_accel, s2 > 1 ? s2 : s1);
|
||||
factor = min(max_accel, f2 > 1 ? f2 : f1);
|
||||
|
||||
return speed_out * TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
|
||||
return factor * X230_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
|
||||
}
|
||||
|
||||
double
|
||||
trackpoint_accel_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in, /* 1000-dpi normalized */
|
||||
uint64_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel_filter =
|
||||
(struct pointer_accelerator *)filter;
|
||||
double max_accel = accel_filter->accel; /* unitless factor */
|
||||
double threshold = accel_filter->threshold; /* units/ms */
|
||||
const double incline = accel_filter->incline;
|
||||
double factor;
|
||||
double dpi_factor = accel_filter->dpi_factor;
|
||||
|
||||
/* dpi_factor is always < 1.0, increase max_accel, reduce
|
||||
the threshold so it kicks in earlier */
|
||||
max_accel /= dpi_factor;
|
||||
threshold *= dpi_factor;
|
||||
|
||||
/* see pointer_accel_profile_linear for a long description */
|
||||
if (v_us2ms(speed_in) < 0.07)
|
||||
factor = 10 * v_us2ms(speed_in) + 0.3;
|
||||
else if (speed_in < threshold)
|
||||
factor = 1;
|
||||
else
|
||||
factor = incline * v_us2ms(speed_in - threshold) + 1;
|
||||
|
||||
factor = min(max_accel, factor);
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface = {
|
||||
.filter = accelerator_filter,
|
||||
.filter_constant = accelerator_filter_noop,
|
||||
.restart = accelerator_restart,
|
||||
.destroy = accelerator_destroy,
|
||||
.set_speed = accelerator_set_speed,
|
||||
};
|
||||
|
||||
static struct pointer_accelerator *
|
||||
create_default_filter(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = zalloc(sizeof *filter);
|
||||
if (filter == NULL)
|
||||
return NULL;
|
||||
|
||||
filter->last_velocity = 0.0;
|
||||
|
||||
filter->trackers =
|
||||
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
|
||||
filter->cur_tracker = 0;
|
||||
|
||||
filter->threshold = DEFAULT_THRESHOLD;
|
||||
filter->accel = DEFAULT_ACCELERATION;
|
||||
filter->incline = DEFAULT_INCLINE;
|
||||
|
||||
filter->dpi_factor = dpi/(double)DEFAULT_MOUSE_DPI;
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_linear(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = create_default_filter(dpi);
|
||||
if (!filter)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface;
|
||||
filter->profile = pointer_accel_profile_linear;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface_low_dpi = {
|
||||
.filter = accelerator_filter_low_dpi,
|
||||
.filter_constant = accelerator_filter_noop,
|
||||
.restart = accelerator_restart,
|
||||
.destroy = accelerator_destroy,
|
||||
.set_speed = accelerator_set_speed,
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_linear_low_dpi(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = create_default_filter(dpi);
|
||||
if (!filter)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface_low_dpi;
|
||||
filter->profile = pointer_accel_profile_linear_low_dpi;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface_touchpad = {
|
||||
.filter = accelerator_filter,
|
||||
.filter_constant = touchpad_constant_filter,
|
||||
.restart = accelerator_restart,
|
||||
.destroy = accelerator_destroy,
|
||||
.set_speed = accelerator_set_speed,
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_touchpad(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = create_default_filter(dpi);
|
||||
if (!filter)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface_touchpad;
|
||||
filter->profile = touchpad_accel_profile_linear;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface_x230 = {
|
||||
.filter = accelerator_filter_x230,
|
||||
.filter_constant = accelerator_filter_noop,
|
||||
.restart = accelerator_restart,
|
||||
.destroy = accelerator_destroy,
|
||||
.set_speed = accelerator_set_speed,
|
||||
};
|
||||
|
||||
/* The Lenovo x230 has a bad touchpad. This accel method has been
|
||||
* trial-and-error'd, any changes to it will require re-testing everything.
|
||||
* Don't touch this.
|
||||
*/
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_lenovo_x230(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = zalloc(sizeof *filter);
|
||||
if (filter == NULL)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface_x230;
|
||||
filter->profile = touchpad_lenovo_x230_accel_profile;
|
||||
filter->last_velocity = 0.0;
|
||||
|
||||
filter->trackers =
|
||||
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
|
||||
filter->cur_tracker = 0;
|
||||
|
||||
filter->threshold = X230_THRESHOLD;
|
||||
filter->accel = X230_ACCELERATION; /* unitless factor */
|
||||
filter->incline = X230_INCLINE; /* incline of the acceleration function */
|
||||
|
||||
filter->dpi_factor = 1; /* unused for this accel method */
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface_trackpoint = {
|
||||
.filter = accelerator_filter_trackpoint,
|
||||
.filter_constant = accelerator_filter_noop,
|
||||
.restart = accelerator_restart,
|
||||
.destroy = accelerator_destroy,
|
||||
.set_speed = accelerator_set_speed,
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_trackpoint(int dpi)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = create_default_filter(dpi);
|
||||
if (!filter)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface_trackpoint;
|
||||
filter->profile = trackpoint_accel_profile;
|
||||
filter->threshold = DEFAULT_THRESHOLD;
|
||||
filter->accel = DEFAULT_ACCELERATION;
|
||||
filter->incline = DEFAULT_INCLINE;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
|
|
|
|||
44
src/filter.h
44
src/filter.h
|
|
@ -34,11 +34,33 @@
|
|||
|
||||
struct motion_filter;
|
||||
|
||||
/**
|
||||
* Accelerate the given coordinates.
|
||||
* Takes a set of unaccelerated deltas and accelerates them based on the
|
||||
* current and previous motion.
|
||||
*
|
||||
* This is a superset of filter_dispatch_constant()
|
||||
*
|
||||
* @see filter_dispatch_constant
|
||||
*/
|
||||
struct normalized_coords
|
||||
filter_dispatch(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time);
|
||||
|
||||
/**
|
||||
* Apply constant motion filters, but no acceleration.
|
||||
*
|
||||
* Takes a set of unaccelerated deltas and applies any constant filters to
|
||||
* it but does not accelerate the delta in the conventional sense.
|
||||
*
|
||||
* @see filter_dispatch
|
||||
*/
|
||||
struct normalized_coords
|
||||
filter_dispatch_constant(struct motion_filter *filter,
|
||||
const struct normalized_coords *unaccelerated,
|
||||
void *data, uint64_t time);
|
||||
|
||||
void
|
||||
filter_restart(struct motion_filter *filter,
|
||||
void *data, uint64_t time);
|
||||
|
|
@ -57,9 +79,22 @@ typedef double (*accel_profile_func_t)(struct motion_filter *filter,
|
|||
double velocity,
|
||||
uint64_t time);
|
||||
|
||||
/* Pointer acceleration types */
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter(accel_profile_func_t filter,
|
||||
int dpi);
|
||||
create_pointer_accelerator_filter_linear(int dpi);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_linear_low_dpi(int dpi);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_touchpad(int dpi);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_lenovo_x230(int dpi);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelerator_filter_trackpoint(int dpi);
|
||||
|
||||
/*
|
||||
* Pointer acceleration profiles.
|
||||
|
|
@ -85,4 +120,9 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
|
|||
void *data,
|
||||
double speed_in,
|
||||
uint64_t time);
|
||||
double
|
||||
trackpoint_accel_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double speed_in,
|
||||
uint64_t time);
|
||||
#endif /* FILTER_H */
|
||||
|
|
|
|||
|
|
@ -271,6 +271,20 @@ typedef void (*libinput_source_dispatch_t)(void *data);
|
|||
#define log_bug_libinput(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__)
|
||||
#define log_bug_client(li_, ...) log_msg((li_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
|
||||
|
||||
#define log_debug_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__)
|
||||
#define log_info_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__)
|
||||
#define log_error_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__)
|
||||
#define log_bug_kernel_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
|
||||
#define log_bug_libinput_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__)
|
||||
#define log_bug_client_ratelimit(li_, r_, ...) log_msg_ratelimit((li_), (r_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
|
||||
|
||||
void
|
||||
log_msg_ratelimit(struct libinput *libinput,
|
||||
struct ratelimit *ratelimit,
|
||||
enum libinput_log_priority priority,
|
||||
const char *format, ...)
|
||||
LIBINPUT_ATTRIBUTE_PRINTF(4, 5);
|
||||
|
||||
void
|
||||
log_msg(struct libinput *libinput,
|
||||
enum libinput_log_priority priority,
|
||||
|
|
|
|||
|
|
@ -45,12 +45,6 @@
|
|||
|
||||
#define CASE_RETURN_STRING(a) case a: return #a;
|
||||
|
||||
void
|
||||
set_logging_enabled(int enabled);
|
||||
|
||||
void
|
||||
log_info(const char *format, ...);
|
||||
|
||||
/*
|
||||
* This list data structure is a verbatim copy from wayland-util.h from the
|
||||
* Wayland project; except that wl_ prefix has been removed.
|
||||
|
|
|
|||
|
|
@ -180,6 +180,31 @@ log_msg(struct libinput *libinput,
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
log_msg_ratelimit(struct libinput *libinput,
|
||||
struct ratelimit *ratelimit,
|
||||
enum libinput_log_priority priority,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
enum ratelimit_state state;
|
||||
|
||||
state = ratelimit_test(ratelimit);
|
||||
if (state == RATELIMIT_EXCEEDED)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
log_msg_va(libinput, priority, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (state == RATELIMIT_THRESHOLD)
|
||||
log_msg(libinput,
|
||||
priority,
|
||||
"WARNING: log rate limit exceeded (%d msgs per %dms). Discarding future messages.\n",
|
||||
ratelimit->burst,
|
||||
us2ms(ratelimit->interval));
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_log_set_priority(struct libinput *libinput,
|
||||
enum libinput_log_priority priority)
|
||||
|
|
@ -2046,8 +2071,9 @@ libinput_post_event(struct libinput *libinput,
|
|||
events_len *= 2;
|
||||
events = realloc(events, events_len * sizeof *events);
|
||||
if (!events) {
|
||||
fprintf(stderr, "Failed to reallocate event ring "
|
||||
"buffer");
|
||||
log_error(libinput,
|
||||
"Failed to reallocate event ring buffer. "
|
||||
"Events may be discarded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1031,7 +1031,8 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event);
|
|||
* LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
|
||||
*
|
||||
* @note It is an application bug to call this function for events of type
|
||||
* @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
* other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
|
||||
* LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
*
|
||||
* @param event The libinput touch event
|
||||
* @return The current absolute x coordinate
|
||||
|
|
@ -1050,7 +1051,8 @@ libinput_event_touch_get_x(struct libinput_event_touch *event);
|
|||
* LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
|
||||
*
|
||||
* @note It is an application bug to call this function for events of type
|
||||
* @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
* other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
|
||||
* LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
*
|
||||
* @param event The libinput touch event
|
||||
* @return The current absolute y coordinate
|
||||
|
|
@ -1068,7 +1070,8 @@ libinput_event_touch_get_y(struct libinput_event_touch *event);
|
|||
* LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
|
||||
*
|
||||
* @note It is an application bug to call this function for events of type
|
||||
* @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
* other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
|
||||
* LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
*
|
||||
* @param event The libinput touch event
|
||||
* @param width The current output screen width
|
||||
|
|
@ -1088,7 +1091,8 @@ libinput_event_touch_get_x_transformed(struct libinput_event_touch *event,
|
|||
* LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
|
||||
*
|
||||
* @note It is an application bug to call this function for events of type
|
||||
* @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
* other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
|
||||
* LIBINPUT_EVENT_TOUCH_MOTION.
|
||||
*
|
||||
* @param event The libinput touch event
|
||||
* @param height The current output screen height
|
||||
|
|
|
|||
155
test/device.c
155
test/device.c
|
|
@ -1046,6 +1046,156 @@ START_TEST(device_udev_tag_wacom_tablet)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_nonpointer_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_device("test device",
|
||||
NULL,
|
||||
EV_KEY, KEY_A,
|
||||
EV_KEY, KEY_B,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
litest_disable_log_handler(li);
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_restore_log_handler(li);
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_touchpad_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_SLOT, 0, 2, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOOL_FINGER,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_touch_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_SLOT, 0, 2, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_MT_POSITION_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
litest_disable_log_handler(li);
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
litest_restore_log_handler(li);
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_abs_rel)
|
||||
{
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *li;
|
||||
struct libinput_device *device;
|
||||
const struct input_absinfo abs[] = {
|
||||
{ ABS_X, 0, 10, 0, 0, 10 },
|
||||
{ ABS_Y, 0, 10, 0, 0, 10 },
|
||||
{ -1, -1, -1, -1, -1, -1 }
|
||||
};
|
||||
int i;
|
||||
|
||||
uinput = litest_create_uinput_abs_device("test device",
|
||||
NULL, abs,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_KEY, BTN_LEFT,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
-1);
|
||||
li = litest_create_context();
|
||||
device = libinput_path_add_device(li,
|
||||
libevdev_uinput_get_devnode(uinput));
|
||||
ck_assert(device != NULL);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_X, 1);
|
||||
libevdev_uinput_write_event(uinput, EV_REL, REL_Y, -1);
|
||||
libevdev_uinput_write_event(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
|
||||
libinput_unref(li);
|
||||
libevdev_uinput_destroy(uinput);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests(void)
|
||||
{
|
||||
|
|
@ -1094,4 +1244,9 @@ litest_setup_tests(void)
|
|||
litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_wacom_tablet, LITEST_TABLET, LITEST_ANY);
|
||||
|
||||
litest_add_no_device("device:invalid rel events", device_nonpointer_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_touchpad_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_touch_rel);
|
||||
litest_add_no_device("device:invalid rel events", device_abs_rel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ struct litest_device_interface {
|
|||
struct input_event *tablet_proximity_out_events;
|
||||
struct input_event *tablet_motion_events;
|
||||
|
||||
int min[2];
|
||||
int max[2];
|
||||
int min[2]; /* x/y axis minimum */
|
||||
int max[2]; /* x/y axis maximum */
|
||||
};
|
||||
|
||||
void litest_set_current_device(struct litest_device *device);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
#include <sys/sendfile.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "litest.h"
|
||||
|
|
@ -788,9 +790,11 @@ litest_log_handler(struct libinput *libinput,
|
|||
fprintf(stderr, "litest %s: ", priority);
|
||||
vfprintf(stderr, format, args);
|
||||
|
||||
#if 0
|
||||
if (strstr(format, "client bug: ") ||
|
||||
strstr(format, "libinput bug: "))
|
||||
litest_abort_msg("libinput bug triggered, aborting.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1927,12 +1931,17 @@ litest_print_event(struct libinput_event *event)
|
|||
break;
|
||||
case LIBINPUT_EVENT_POINTER_AXIS:
|
||||
p = libinput_event_get_pointer_event(event);
|
||||
fprintf(stderr,
|
||||
"vert %.f horiz %.2f",
|
||||
libinput_event_pointer_get_axis_value(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
|
||||
libinput_event_pointer_get_axis_value(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL));
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
if (libinput_event_pointer_has_axis(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
|
||||
y = libinput_event_pointer_get_axis_value(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
||||
if (libinput_event_pointer_has_axis(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
|
||||
x = libinput_event_pointer_get_axis_value(p,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
|
||||
fprintf(stderr, "vert %.f horiz %.2f", y, x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
109
test/touchpad.c
109
test/touchpad.c
|
|
@ -150,20 +150,17 @@ START_TEST(touchpad_2fg_scroll_slow_distance)
|
|||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
const struct input_absinfo *y;
|
||||
double y_move;
|
||||
double width, height;
|
||||
double y_move = 100;
|
||||
|
||||
if (!litest_has_2fg_scroll(dev))
|
||||
return;
|
||||
|
||||
/* We want to move > 5 mm. */
|
||||
y = libevdev_get_abs_info(dev->evdev, ABS_Y);
|
||||
if (y->resolution) {
|
||||
y_move = 7.0 * y->resolution /
|
||||
(y->maximum - y->minimum) * 100;
|
||||
} else {
|
||||
y_move = 20.0;
|
||||
}
|
||||
ck_assert_int_eq(libinput_device_get_size(dev->libinput_device,
|
||||
&width,
|
||||
&height), 0);
|
||||
y_move = 100.0/height * 7;
|
||||
|
||||
litest_enable_2fg_scroll(dev);
|
||||
litest_drain_events(li);
|
||||
|
|
@ -350,6 +347,35 @@ START_TEST(touchpad_scroll_natural_2fg)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_scroll_natural_edge)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
litest_enable_edge_scroll(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
libinput_device_config_scroll_set_natural_scroll_enabled(dev->libinput_device, 1);
|
||||
|
||||
litest_touch_down(dev, 0, 99, 20);
|
||||
litest_touch_move_to(dev, 0, 99, 20, 99, 80, 10, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
|
||||
libinput_dispatch(li);
|
||||
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -4);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_touch_down(dev, 0, 99, 80);
|
||||
litest_touch_move_to(dev, 0, 99, 80, 99, 20, 10, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
|
||||
libinput_dispatch(li);
|
||||
litest_assert_scroll(li, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, 4);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_edge_scroll)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -437,54 +463,60 @@ START_TEST(touchpad_edge_scroll_timeout)
|
|||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
double width = 0, height = 0;
|
||||
int y_movement = 30; /* in percent of height */
|
||||
int nevents = 0;
|
||||
double mm; /* one mm in percent of the device */
|
||||
|
||||
/* account for different touchpad heights, let's move 100% on a 15mm
|
||||
high touchpad, less on anything else. This number is picked at
|
||||
random, we just want deltas less than 5.
|
||||
*/
|
||||
if (libinput_device_get_size(dev->libinput_device,
|
||||
&width,
|
||||
&height) != -1) {
|
||||
y_movement = 100 * 15/height;
|
||||
}
|
||||
ck_assert_int_eq(libinput_device_get_size(dev->libinput_device,
|
||||
&width,
|
||||
&height), 0);
|
||||
mm = 100.0/height;
|
||||
|
||||
/* timeout-based scrolling is disabled when software buttons are
|
||||
* active, so switch to clickfinger. Not all test devices support
|
||||
* that, hence the extra check. */
|
||||
if (libinput_device_config_click_get_methods(dev->libinput_device) &
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER)
|
||||
litest_enable_clickfinger(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_enable_edge_scroll(dev);
|
||||
|
||||
/* move 0.5mm, enough to load up the motion history, but less than
|
||||
* the scroll threshold of 2mm */
|
||||
litest_touch_down(dev, 0, 99, 20);
|
||||
litest_touch_move_to(dev, 0, 99, 20, 99, 20 + mm/2, 8, 0);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_timeout_edgescroll();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_touch_move_to(dev, 0, 99, 20, 99, 20 + y_movement, 100, 10);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* now move slowly up to the 2mm scroll threshold. we expect events */
|
||||
litest_touch_move_to(dev, 0, 99, 20 + mm/2, 99, 20 + mm * 2, 20, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
ck_assert_notnull(event);
|
||||
|
||||
litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);
|
||||
|
||||
while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
|
||||
double axisval;
|
||||
ck_assert_int_eq(libinput_event_get_type(event),
|
||||
LIBINPUT_EVENT_POINTER_AXIS);
|
||||
ptrev = libinput_event_get_pointer_event(event);
|
||||
|
||||
axisval = libinput_event_pointer_get_axis_value(ptrev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
||||
ck_assert(axisval > 0.0);
|
||||
|
||||
/* this is to verify we test the right thing, if the value
|
||||
is greater than scroll.threshold we triggered the wrong
|
||||
condition */
|
||||
ck_assert(axisval < 5.0);
|
||||
while ((event = libinput_get_event(li))) {
|
||||
double value;
|
||||
|
||||
ptrev = litest_is_axis_event(event,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
|
||||
0);
|
||||
value = libinput_event_pointer_get_axis_value(ptrev,
|
||||
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
|
||||
ck_assert_double_lt(value, 5.0);
|
||||
libinput_event_destroy(event);
|
||||
event = libinput_get_event(li);
|
||||
nevents++;
|
||||
}
|
||||
|
||||
/* we sent 20 events but allow for some to be swallowed by rounding
|
||||
* errors, the hysteresis, etc. */
|
||||
ck_assert_int_ge(nevents, 10);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
|
@ -3450,6 +3482,7 @@ litest_setup_tests(void)
|
|||
litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_natural_edge, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:scroll", touchpad_scroll_defaults, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
|
|
|
|||
|
|
@ -39,3 +39,5 @@ event_gui_LDADD = ../src/libinput.la libshared.la $(CAIRO_LIBS) $(GTK_LIBS) $(LI
|
|||
event_gui_CFLAGS = $(CAIRO_CFLAGS) $(GTK_CFLAGS) $(LIBUDEV_CFLAGS)
|
||||
event_gui_LDFLAGS = -no-install
|
||||
endif
|
||||
|
||||
EXTRA_DIST = make-ptraccel-graphs.sh
|
||||
|
|
|
|||
79
tools/make-ptraccel-graphs.sh
Executable file
79
tools/make-ptraccel-graphs.sh
Executable file
|
|
@ -0,0 +1,79 @@
|
|||
#!/bin/bash
|
||||
|
||||
tool=`dirname $0`/ptraccel-debug
|
||||
gnuplot=/usr/bin/gnuplot
|
||||
|
||||
outfile="ptraccel-linear"
|
||||
for speed in -1 -0.75 -0.5 -0.25 0 0.5 1; do
|
||||
$tool --mode=accel --dpi=1000 --filter=linear --speed=$speed > $outfile-$speed.gnuplot
|
||||
done
|
||||
$gnuplot <<EOF
|
||||
set terminal svg enhanced background rgb 'white'
|
||||
set output "$outfile.svg"
|
||||
set xlabel "speed in units/us"
|
||||
set ylabel "accel factor"
|
||||
set style data lines
|
||||
set yrange [0:3]
|
||||
set xrange [0:0.003]
|
||||
plot "$outfile--1.gnuplot" using 1:2 title "-1.0", \
|
||||
"$outfile--0.75.gnuplot" using 1:2 title "-0.75", \
|
||||
"$outfile--0.5.gnuplot" using 1:2 title "-0.5", \
|
||||
"$outfile--0.25.gnuplot" using 1:2 title "-0.25", \
|
||||
"$outfile-0.gnuplot" using 1:2 title "0.0", \
|
||||
"$outfile-0.5.gnuplot" using 1:2 title "0.5", \
|
||||
"$outfile-1.gnuplot" using 1:2 title "1.0"
|
||||
EOF
|
||||
|
||||
outfile="ptraccel-low-dpi"
|
||||
for dpi in 200 400 800 1000; do
|
||||
$tool --mode=accel --dpi=$dpi --filter=low-dpi > $outfile-$dpi.gnuplot
|
||||
done
|
||||
|
||||
$gnuplot <<EOF
|
||||
set terminal svg enhanced background rgb 'white'
|
||||
set output "$outfile.svg"
|
||||
set xlabel "speed in units/us"
|
||||
set ylabel "accel factor"
|
||||
set style data lines
|
||||
set yrange [0:5]
|
||||
set xrange [0:0.003]
|
||||
plot "$outfile-200.gnuplot" using 1:2 title "200dpi", \
|
||||
"$outfile-400.gnuplot" using 1:2 title "400dpi", \
|
||||
"$outfile-800.gnuplot" using 1:2 title "800dpi", \
|
||||
"$outfile-1000.gnuplot" using 1:2 title "1000dpi"
|
||||
EOF
|
||||
|
||||
outfile="ptraccel-touchpad"
|
||||
$tool --mode=accel --dpi=1000 --filter=linear > $outfile-mouse.gnuplot
|
||||
$tool --mode=accel --dpi=1000 --filter=touchpad > $outfile-touchpad.gnuplot
|
||||
$gnuplot <<EOF
|
||||
set terminal svg enhanced background rgb 'white'
|
||||
set output "$outfile.svg"
|
||||
set xlabel "speed in units/us"
|
||||
set ylabel "accel factor"
|
||||
set style data lines
|
||||
set yrange [0:3]
|
||||
set xrange [0:0.003]
|
||||
plot "$outfile-mouse.gnuplot" using 1:2 title "linear (mouse)", \
|
||||
"$outfile-touchpad.gnuplot" using 1:2 title "touchpad"
|
||||
EOF
|
||||
|
||||
outfile="ptraccel-trackpoint"
|
||||
$tool --mode=accel --dpi=1000 --filter=linear > $outfile-mouse.gnuplot
|
||||
for constaccel in 1 2 3; do
|
||||
dpi=$((1000/$constaccel))
|
||||
$tool --mode=accel --dpi=$dpi --filter=trackpoint > $outfile-trackpoint-$constaccel.gnuplot
|
||||
done
|
||||
$gnuplot <<EOF
|
||||
set terminal svg enhanced background rgb 'white'
|
||||
set output "$outfile.svg"
|
||||
set xlabel "speed in units/us"
|
||||
set ylabel "accel factor"
|
||||
set style data lines
|
||||
set yrange [0:5]
|
||||
set xrange [0:0.003]
|
||||
plot "$outfile-mouse.gnuplot" using 1:2 title "linear (mouse)", \
|
||||
"$outfile-trackpoint-1.gnuplot" using 1:2 title "const accel 1", \
|
||||
"$outfile-trackpoint-2.gnuplot" using 1:2 title "const accel 2", \
|
||||
"$outfile-trackpoint-3.gnuplot" using 1:2 title "const accel 3"
|
||||
EOF
|
||||
|
|
@ -138,7 +138,7 @@ print_ptraccel_sequence(struct motion_filter *filter,
|
|||
}
|
||||
|
||||
static void
|
||||
print_accel_func(struct motion_filter *filter)
|
||||
print_accel_func(struct motion_filter *filter, accel_profile_func_t profile)
|
||||
{
|
||||
double vel;
|
||||
|
||||
|
|
@ -147,12 +147,9 @@ print_accel_func(struct motion_filter *filter)
|
|||
printf("# set ylabel \"raw accel factor\"\n");
|
||||
printf("# set style data lines\n");
|
||||
printf("# plot \"gnuplot.data\" using 1:2\n");
|
||||
for (vel = 0.0; vel < 3.0; vel += .0001) {
|
||||
double result = pointer_accel_profile_linear(filter,
|
||||
NULL,
|
||||
vel,
|
||||
0 /* time */);
|
||||
printf("%.4f\t%.4f\n", vel, result);
|
||||
for (vel = 0.0; vel < 0.003; vel += 0.0000001) {
|
||||
double result = profile(filter, NULL, vel, 0 /* time */);
|
||||
printf("%.8f\t%.4f\n", vel, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +168,12 @@ usage(void)
|
|||
"--steps=<double> ... in motion and delta modes only. Increase dx by step each round\n"
|
||||
"--speed=<double> ... accel speed [-1, 1], default 0\n"
|
||||
"--dpi=<int> ... device resolution in DPI (default: 1000)\n"
|
||||
"--filter=<linear|low-dpi|touchpad|x230|trackpoint> \n"
|
||||
" linear ... the default motion filter\n"
|
||||
" low-dpi ... low-dpi filter, use --dpi with this argument\n"
|
||||
" touchpad ... the touchpad motion filter\n"
|
||||
" x230 ... custom filter for the Lenovo x230 touchpad\n"
|
||||
" trackpoint... trackpoint motion filter\n"
|
||||
"\n"
|
||||
"If extra arguments are present and mode is not given, mode defaults to 'sequence'\n"
|
||||
"and the arguments are interpreted as sequence of delta x coordinates\n"
|
||||
|
|
@ -195,6 +198,8 @@ main(int argc, char **argv)
|
|||
double custom_deltas[1024];
|
||||
double speed = 0.0;
|
||||
int dpi = 1000;
|
||||
const char *filter_type = "linear";
|
||||
accel_profile_func_t profile = NULL;
|
||||
|
||||
enum {
|
||||
OPT_MODE = 1,
|
||||
|
|
@ -203,6 +208,7 @@ main(int argc, char **argv)
|
|||
OPT_STEP,
|
||||
OPT_SPEED,
|
||||
OPT_DPI,
|
||||
OPT_FILTER,
|
||||
};
|
||||
|
||||
while (1) {
|
||||
|
|
@ -215,6 +221,7 @@ main(int argc, char **argv)
|
|||
{"step", 1, 0, OPT_STEP },
|
||||
{"speed", 1, 0, OPT_SPEED },
|
||||
{"dpi", 1, 0, OPT_DPI },
|
||||
{"filter", 1, 0, OPT_FILTER},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
|
@ -265,6 +272,9 @@ main(int argc, char **argv)
|
|||
case OPT_DPI:
|
||||
dpi = strtod(optarg, NULL);
|
||||
break;
|
||||
case OPT_FILTER:
|
||||
filter_type = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
|
|
@ -272,8 +282,26 @@ main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
filter = create_pointer_accelerator_filter(pointer_accel_profile_linear,
|
||||
dpi);
|
||||
if (streq(filter_type, "linear")) {
|
||||
filter = create_pointer_accelerator_filter_linear(dpi);
|
||||
profile = pointer_accel_profile_linear;
|
||||
} else if (streq(filter_type, "low-dpi")) {
|
||||
filter = create_pointer_accelerator_filter_linear_low_dpi(dpi);
|
||||
profile = pointer_accel_profile_linear_low_dpi;
|
||||
} else if (streq(filter_type, "touchpad")) {
|
||||
filter = create_pointer_accelerator_filter_touchpad(dpi);
|
||||
profile = touchpad_accel_profile_linear;
|
||||
} else if (streq(filter_type, "x230")) {
|
||||
filter = create_pointer_accelerator_filter_lenovo_x230(dpi);
|
||||
profile = touchpad_lenovo_x230_accel_profile;
|
||||
} else if (streq(filter_type, "trackpoint")) {
|
||||
filter = create_pointer_accelerator_filter_trackpoint(dpi);
|
||||
profile = trackpoint_accel_profile;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid filter type %s\n", filter_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(filter != NULL);
|
||||
filter_set_speed(filter, speed);
|
||||
|
||||
|
|
@ -297,7 +325,7 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (print_accel)
|
||||
print_accel_func(filter);
|
||||
print_accel_func(filter, profile);
|
||||
else if (print_delta)
|
||||
print_ptraccel_deltas(filter, step);
|
||||
else if (print_motion)
|
||||
|
|
|
|||
246
tools/shared.c
246
tools/shared.c
|
|
@ -166,131 +166,131 @@ tools_parse_args(int argc, char **argv, struct tools_context *context)
|
|||
break;
|
||||
|
||||
switch(c) {
|
||||
case 'h':
|
||||
case OPT_HELP:
|
||||
tools_usage();
|
||||
exit(0);
|
||||
case OPT_DEVICE:
|
||||
options->backend = BACKEND_DEVICE;
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->device = optarg;
|
||||
break;
|
||||
case OPT_UDEV:
|
||||
options->backend = BACKEND_UDEV;
|
||||
if (optarg)
|
||||
options->seat = optarg;
|
||||
break;
|
||||
case OPT_GRAB:
|
||||
options->grab = 1;
|
||||
break;
|
||||
case OPT_VERBOSE:
|
||||
options->verbose = 1;
|
||||
break;
|
||||
case OPT_TAP_ENABLE:
|
||||
options->tapping = 1;
|
||||
break;
|
||||
case OPT_TAP_DISABLE:
|
||||
options->tapping = 0;
|
||||
break;
|
||||
case OPT_DRAG_LOCK_ENABLE:
|
||||
options->drag_lock = 1;
|
||||
break;
|
||||
case OPT_DRAG_LOCK_DISABLE:
|
||||
options->drag_lock = 0;
|
||||
break;
|
||||
case OPT_NATURAL_SCROLL_ENABLE:
|
||||
options->natural_scroll = 1;
|
||||
break;
|
||||
case OPT_NATURAL_SCROLL_DISABLE:
|
||||
options->natural_scroll = 0;
|
||||
break;
|
||||
case OPT_LEFT_HANDED_ENABLE:
|
||||
options->left_handed = 1;
|
||||
break;
|
||||
case OPT_LEFT_HANDED_DISABLE:
|
||||
options->left_handed = 0;
|
||||
break;
|
||||
case OPT_MIDDLEBUTTON_ENABLE:
|
||||
options->middlebutton = 1;
|
||||
break;
|
||||
case OPT_MIDDLEBUTTON_DISABLE:
|
||||
options->middlebutton = 0;
|
||||
break;
|
||||
case OPT_DWT_ENABLE:
|
||||
options->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
|
||||
break;
|
||||
case OPT_DWT_DISABLE:
|
||||
options->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
|
||||
break;
|
||||
case OPT_CLICK_METHOD:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
if (streq(optarg, "none")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_NONE;
|
||||
} else if (streq(optarg, "clickfinger")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
|
||||
} else if (streq(optarg, "buttonareas")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
|
||||
} else {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SCROLL_METHOD:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
if (streq(optarg, "none")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
|
||||
} else if (streq(optarg, "twofinger")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_2FG;
|
||||
} else if (streq(optarg, "edge")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_EDGE;
|
||||
} else if (streq(optarg, "button")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
|
||||
} else {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SCROLL_BUTTON:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->scroll_button =
|
||||
libevdev_event_code_from_name(EV_KEY,
|
||||
optarg);
|
||||
if (options->scroll_button == -1) {
|
||||
fprintf(stderr,
|
||||
"Invalid button %s\n",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SPEED:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->speed = atof(optarg);
|
||||
break;
|
||||
default:
|
||||
case 'h':
|
||||
case OPT_HELP:
|
||||
tools_usage();
|
||||
exit(0);
|
||||
case OPT_DEVICE:
|
||||
options->backend = BACKEND_DEVICE;
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->device = optarg;
|
||||
break;
|
||||
case OPT_UDEV:
|
||||
options->backend = BACKEND_UDEV;
|
||||
if (optarg)
|
||||
options->seat = optarg;
|
||||
break;
|
||||
case OPT_GRAB:
|
||||
options->grab = 1;
|
||||
break;
|
||||
case OPT_VERBOSE:
|
||||
options->verbose = 1;
|
||||
break;
|
||||
case OPT_TAP_ENABLE:
|
||||
options->tapping = 1;
|
||||
break;
|
||||
case OPT_TAP_DISABLE:
|
||||
options->tapping = 0;
|
||||
break;
|
||||
case OPT_DRAG_LOCK_ENABLE:
|
||||
options->drag_lock = 1;
|
||||
break;
|
||||
case OPT_DRAG_LOCK_DISABLE:
|
||||
options->drag_lock = 0;
|
||||
break;
|
||||
case OPT_NATURAL_SCROLL_ENABLE:
|
||||
options->natural_scroll = 1;
|
||||
break;
|
||||
case OPT_NATURAL_SCROLL_DISABLE:
|
||||
options->natural_scroll = 0;
|
||||
break;
|
||||
case OPT_LEFT_HANDED_ENABLE:
|
||||
options->left_handed = 1;
|
||||
break;
|
||||
case OPT_LEFT_HANDED_DISABLE:
|
||||
options->left_handed = 0;
|
||||
break;
|
||||
case OPT_MIDDLEBUTTON_ENABLE:
|
||||
options->middlebutton = 1;
|
||||
break;
|
||||
case OPT_MIDDLEBUTTON_DISABLE:
|
||||
options->middlebutton = 0;
|
||||
break;
|
||||
case OPT_DWT_ENABLE:
|
||||
options->dwt = LIBINPUT_CONFIG_DWT_ENABLED;
|
||||
break;
|
||||
case OPT_DWT_DISABLE:
|
||||
options->dwt = LIBINPUT_CONFIG_DWT_DISABLED;
|
||||
break;
|
||||
case OPT_CLICK_METHOD:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
if (streq(optarg, "none")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_NONE;
|
||||
} else if (streq(optarg, "clickfinger")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
|
||||
} else if (streq(optarg, "buttonareas")) {
|
||||
options->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
|
||||
} else {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SCROLL_METHOD:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
if (streq(optarg, "none")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
|
||||
} else if (streq(optarg, "twofinger")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_2FG;
|
||||
} else if (streq(optarg, "edge")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_EDGE;
|
||||
} else if (streq(optarg, "button")) {
|
||||
options->scroll_method =
|
||||
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
|
||||
} else {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SCROLL_BUTTON:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->scroll_button =
|
||||
libevdev_event_code_from_name(EV_KEY,
|
||||
optarg);
|
||||
if (options->scroll_button == -1) {
|
||||
fprintf(stderr,
|
||||
"Invalid button %s\n",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OPT_SPEED:
|
||||
if (!optarg) {
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
options->speed = atof(optarg);
|
||||
break;
|
||||
default:
|
||||
tools_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ int main(int argc, char **argv)
|
|||
if (!device)
|
||||
goto out;
|
||||
|
||||
if (udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD"))
|
||||
if (prop_value(device, "ID_INPUT_TOUCHPAD"))
|
||||
handle_touchpad(device);
|
||||
|
||||
rc = 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue