Fixes biaxial button-scrolling. Replaces the previous delta-length
threshold for breaking out of axis-lock with a perpendicular-distance
threshold combined with delta tilting toward the locked axis line.
A few not-really-an-issue fixes found by Claude:
1. ctx->buttons_down[number]: the 'number' value comes from
libinput_event_tablet_pad_get_button_number() and is written into
a fixed-size array of 32 elements without bounds checking. A crafted
or malicious device reporting button numbers >= 32 causes a stack
buffer overflow.
2. ctx->ring[number], ctx->strip[number], ctx->dial[number]: these are
fixed-size arrays of 2 elements each. Ring/strip/dial numbers from
libinput events are used as indices without bounds checking. Values
>= 2 cause out-of-bounds writes.
3. assert()-based error handling for open() and libevdev_new_from_fd():
assert() is compiled to a no-op in release builds (NDEBUG). This
means that in release builds, a failed open() returns fd=-1, and
libevdev_new_from_fd() is called with an invalid fd. The result is
undefined behavior.
4. Variable-length array (VLA) 'empty[termwidth]' in print_bar():
termwidth comes from an ioctl(TIOCGWINSZ) call and could be very
large, causing a stack overflow. Replace with a fixed-size buffer.
None of these really matter for a niche debugging tool.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1467>
safe_strdup() handles NULL correctly instead of just blowing up. This
shouldn't matter because without a name our plugins won't get here but
let's do this anwyay.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1467>
stat() follows symbolic links which is definitely something we don't
want. If an attacker can place a symlink inside a directory being
recursively deleted (e.g. a temporary directory), stat() will report the
type of the symlink's target rather than the symlink itself. If the
target is a directory, rmdir_r() will follow the symlink and recursively
delete the target directory's contents outside the intended directory
tree.
This has no real effect, this is only used in the test suite.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1467>
This is purely to make Claude happy, the function is ifdef'd out and to
actually hit the limit we'd need more than ~25 slots active.
Anyway, the strv helpers make for much nicer code anyway.
Co-Authored-by: Claude Code <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1467>
The implementation accepts LIBINPUT_EVENT_GESTURE_HOLD_END in
require_event_type() but the API documentation only listed SWIPE_END
and PINCH_END. This was likely missed when hold gesture support was
added.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
The code in libinput-plugin-lua.c filters udev properties with
strstartswith(key, "ID_INPUT_") which requires a trailing underscore.
The bare 'ID_INPUT' property does not match this filter and is never
included in the properties table provided to plugins.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
The --multiple flag is deprecated and a no-op in the current code
(libinput-record.c). Multiple devices can simply be specified as
arguments on the commandline. Update the documentation to reflect
the current usage.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
The example output showed 'Name: /dev/input/eventN' but the actual code
(libinput-replay.py) prints '/dev/input/eventN: Name'. Update the
example to match the actual output format.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
ClickPads support both two-finger scrolling and edge scrolling, not
two-finger scrolling only. The code in evdev-mt-touchpad.c always
includes LIBINPUT_CONFIG_SCROLL_EDGE in the supported methods and adds
LIBINPUT_CONFIG_SCROLL_2FG if the touchpad supports 2+ touches.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
The simplified table showed 'Finger 1 down' producing '<no event>' but
all the detailed examples later in the same document show that a single
finger down triggers a hold begin event with finger count 1, followed by
a cancel and new begin when the second finger arrives. Update the
simplified table to be consistent with the detailed examples and the
actual implementation.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
There is no LIBINPUT_EVENT_GESTURE_HOLD_UPDATE event in the API.
When a finger is detected as thumb/palm during a hold and other fingers
remain, the implementation cancels the current hold and starts a new one
with an updated finger count. Update the documentation to describe the
actual behavior.
Co-authored-by: Claude <noreply@anthropic.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1469>
We differ between a fast 3fg swipe and a 3fg drag based on whether we
move 5mm within 80ms of contact. Alas, the code started the timeout once
we had enough motion, not on initial contact.
Three fingers down, then resting for >80ms, then moving 5mm within the
subsequent 80ms would thus trigger a fast swipe because the timer wasn't
set until sufficient movement happened. Fix this by setting the timer
based on the initial touch point's time. This requires potentially
setting a negative timer to avoid duplicating parts of the state
machine.
Closes#1266
Fixes: fe1d44637f ("touchpad: add support for fast swipe when 3fg drag is enabled")
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1466>
The arbitration rectangle previously only covered a region from 100mm
above the pen tip to 150mm below it (250mm total). This let a few
unintentional touches through such as when some of the fingers are
extended while using the pen. Likewise, a large hand could fall below
the bottom edge of the rectangle.
Change the rect to span the full height and width of the tablet while
keeping the same horizontal logic (200mm wide, starting 20mm from the
pen tip toward the hand side). Simplify a few things too, there is no
need for clipping the rect.
Related: #1276
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1463>
luaL_loadfile() by default allows for both text files and precompiled
lua files. Precompiled files are not verified on load allowing for a
sandbox escape.
CVE-2026-35093
Fixes: #1271
Found-by: Koen Tange <koen@monokles.eu>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1459>
Previously we had one vtable for the libinputplugin and EvdevDevice
objects. This allowed plugins to call __gc(), a decidedly internal
method.
This fixes a use-after-free: A plugin that called EvdevDevice::__gc()
frees the plugin's copy of device->name but leaves the pointer in-place,
a subsequent call will thus cause a UAF read.
Fix this by separating what is the object's metatable from the public
methods that are accessible to a plugin.
CVE-2026-35094
Fixes: #1272
Found-by: Koen Tange <koen@monokles.eu>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1459>
This commit adds a specific vendor HWID for Goodix Haptic Touchpad to
improve detection and handling.
Signed-off-by: Richie Roy Jayme <rjayme.jp@gmail.com>
Signed-off-by: Richie Roy Jayme <rjayme2@lenovo.com>
Reviewed-by: Vishnu Sankar <vishnuocv@gmail.com>
Reviewed-by: Vishnu Sankar <vsankar@lenovo.com>
Tested-by: Ameer Ivan Julkarnain <ajulkarnain1@lenovo.com>
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1455>
If drag-lock is disabled but we're in a tap-and-drag state and the
finger is released near the edge (within 5mm), enable automatic drag
lock for 400ms. This allows a user to quickly reset the finger and
continue with the drag.
The 400ms is a randomly guessed timeout - if you're using tap-and-drag
without draglock, finger dexterity should be high enough that resetting
the single finger can be done quickly but it's also short enough to not
make the occasional delayed button be painful in day-to-day use.
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1447>