Compare commits

...

24 commits
main ... 1.31.2

Author SHA1 Message Date
Peter Hutterer
6a3fd7e1a6 libinput 1.31.2
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2026-05-14 20:56:17 +10:00
Freeman Zhang
5366a790f1 Add Goodix haptic touchpad 27C6:0F90 support
(cherry picked from commit a1c5f35a69)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1476>
2026-05-14 16:56:34 +10:00
Freeman Zhang
9ef905a4d1 Add Elan haptic touchpad 04F3:3355 support
(cherry picked from commit 57c71c567f)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1476>
2026-05-14 16:56:32 +10:00
Peter Hutterer
a8fe92ffc2 Fix the evdev_usage_is_button check for the BTN_STYLUS group
(cherry picked from commit cdcb827365)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1476>
2026-05-14 16:52:17 +10:00
David Santamaría Rogado
d945857144 quirks: add positivo vaio fe15 right button
Signed-off-by: David Santamaría Rogado <howl.nsp@gmail.com>
(cherry picked from commit 7face63bd5)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:52:27 +10:00
Artem Proskurnev
696e465c3c quirks: add quirk for the Wareus B15
Fix:
https://gitlab.freedesktop.org/libinput/libinput/-/work_items/1267

(cherry picked from commit 488c0c9645)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:51:58 +10:00
Richie Roy Jayme
3e93e5d730 quirks: add support for Goodix touchpad GXTP5400:00 27C6:0F96
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>
(cherry picked from commit baddf1e2b6)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:51:57 +10:00
Marcin Jahn
18e4426ee5 quirks: add clevetura clvx s touchpad quirk
(cherry picked from commit bb7aa004f8)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:51:55 +10:00
Mingcong Bai
16b0861810 quirks: add Goodix pressure pad quirk for 27C6:01E7
This touchpad is found on the newly released Lenovo ThinkBook G8+ IPH.

Signed-off-by: Mingcong Bai <jeffbai@aosc.io>
(cherry picked from commit 43547b461b)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:50:14 +10:00
David Santamaría Rogado
456a374258 quirks: add some more goodix haptic touchpads
Signed-off-by: David Santamaría Rogado <howl.nsp@gmail.com>
(cherry picked from commit 1c82aa1659)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:50:08 +10:00
David Santamaría Rogado
a0692fcf09 quirks: hp omnibook ultra flip 14 touch pressure
Add pressure attributes to make libinput measure touchpad-pressure
behave right.

Signed-off-by: David Santamaría Rogado <howl.nsp@gmail.com>
(cherry picked from commit 526130fe8d)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:50:06 +10:00
David Santamaría Rogado
110e143d12 quirks: hp omnibook ultra flip 14 improve rule set
Some initial units had 14t-fh000 instead 14-fh0xxx in their product name
but they are exactly the same model.

We could match both in product version SBKPF or in board product name
8CDE. Match board as seems the way hp-wmi kernel module uses to match.

While at it rewrite the entire huge comment to a little less huge
comment but with more really interesting info.

Signed-off-by: David Santamaría Rogado <howl.nsp@gmail.com>
(cherry picked from commit b95840d36e)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:50:03 +10:00
Peter Hutterer
493a830651 touchpad: time the 3fg fast swipe timeout from the initial contact
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")
(cherry picked from commit fdd43a4fcd)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1470>
2026-04-21 12:49:31 +10:00
Peter Hutterer
174a3550e6 evdev: store the SYN_REPORT value in the frame
If the SYN_REPORT has a value of nonzero we need to keep that value in
the frame - our upper layers rely on this to detect repeat frames.

Closes #1261

(cherry picked from commit ef9624a16b)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:40:45 +10:00
Peter Hutterer
ccc8d60204 util: fix remaininig usec computation on 32 bits
Follow-up from commit dcbfbc4cf1 ("util: fix usec computation on 32 bits")
which didn't fix all instances, make this consistent.

Fixes: dcbfbc4cf1 ("util: fix usec computation on 32 bits")
(cherry picked from commit 166201d9fc)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:40:45 +10:00
GKraats
6d39bd5297 util: fix usec computation on 32 bits
Enforce the needed 64-bit computing on 32 bits.

Signed-off-by: GKraats <vd.kraats@hccnet.nl>
(cherry picked from commit dcbfbc4cf1)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:03:24 +10:00
Peter Hutterer
2d12556287 tools/record: fix delta times not being relative
Missing last_time assignment caused the delta time between events to be
the total time.

Fixes: a202ed6115 ("Use a newtype usec_t for timestamps for better type-safety")
(cherry picked from commit ad857a51a4)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:03:19 +10:00
Peter Hutterer
5be0a16dd0 tools: fix swapped fread arguments causing DMI modalias to always be "unknown"
fread(buf, sizeof(buf), 1, dmi) reads one block of 2048 bytes,
returning the number of complete blocks (0 or 1). Since DMI modalias
files are always shorter than 2048 bytes, fread returns 0 even when
data was successfully read into buf. The 'if (n > 0)' check then
always fails and the DMI string stays as "unknown".

Swap the size and nmemb arguments so fread returns the number of
bytes read instead.

Fixes: 0ecd08c134 ("tools: use __attribute__(cleanup)")

Co-Authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit c8c1c07a2a)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:03:03 +10:00
Peter Hutterer
5ce952eb25 tools: fix pencil tablet tool type in libinput-record
Co-Authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit b1f478b897)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:03:02 +10:00
Peter Hutterer
14759465f2 tools: fix swapped strstartswith arguments in find_device()
Co-Authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit 333d7131ab)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:03:00 +10:00
Peter Hutterer
d947ae8208 tablet: fix eraser button get_default_mode/get_default_button return values
Co-Authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit cd9d6c66fd)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1468>
2026-04-17 11:02:48 +10:00
Peter Hutterer
1920686963 libinput 1.31.1
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2026-04-02 11:04:12 +10:00
Peter Hutterer
49f9a81517 lua: force text mode for loading plugins
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>

(cherry picked from commit 356c498fd4)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1461>
2026-04-02 10:18:00 +10:00
Peter Hutterer
45506c7b3c lua: separate the API from the metatables
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>

(cherry picked from commit 45dfd0f030)

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1461>
2026-04-02 10:17:52 +10:00
17 changed files with 400 additions and 48 deletions

View file

@ -1,5 +1,5 @@
project('libinput', 'c',
version : '1.31.0',
version : '1.31.2',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.64.0')

View file

@ -0,0 +1,11 @@
# Do not edit this file, it will be overwritten on update
# Touchpad is not a clickpad but INPUT_PROP_BUTTONPAD is set,
# causing libinput to drop physical button events.
[Clevetura CLVX S Touchpad]
MatchUdevType=touchpad
MatchBus=bluetooth
MatchVendor=0x36F7
MatchProduct=0x5755
AttrInputProp=-INPUT_PROP_BUTTONPAD
AttrEventCode=+BTN_RIGHT

View file

@ -9,3 +9,11 @@ AttrPressureRange=10:8
MatchName=*Elan Touchpad*
AttrResolutionHint=31x31
AttrPressureRange=10:8
# Elan Hapticpad mostly used in Lenovo laptops.
[Elan Haptic Touchpad (04F3:3355)]
MatchBus=i2c
MatchVendor=0x04F3
MatchProduct=0x3355
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD

View file

@ -2,6 +2,15 @@
# "GXTP5100 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# Match vid and pid as it can have other names.
[Goodix Haptic Touchpad (27C6:01E7)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x01E7
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5100 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5100:00 27C6:01E8 Touchpad
[Goodix Haptic Touchpad (27C6:01E8)]
MatchBus=i2c
MatchVendor=0x27C6
@ -9,6 +18,42 @@ MatchProduct=0x01E8
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5100 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5100:00 27C6:01E9 Touchpad
[Goodix Haptic Touchpad (27C6:01E9)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x01E9
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5100 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5100:00 27C6:01EA Touchpad
[Goodix Haptic Touchpad (27C6:01EA)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x01EA
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5100 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5100:00 27C6:01EB Touchpad
[Goodix Haptic Touchpad (27C6:01EB)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x01EB
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5400 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5400:00 27C6:0F96 Touchpad
[Goodix Haptic Touchpad (27C6:0F96)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x0F96
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5420 Touchpad": pressure touchpad mostly used in Lenovo laptops.
# GXTP5420:00 27C6:0F95 Touchpad
[Goodix Haptic Touchpad (27C6:0F95)]
@ -17,3 +62,11 @@ MatchVendor=0x27C6
MatchProduct=0x0F95
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD
# "GXTP5420 Touchpad": pressure touchpad mostly used in Lenovo laptops.
[Goodix Haptic Touchpad (27C6:0F90)]
MatchBus=i2c
MatchVendor=0x27C6
MatchProduct=0x0F90
MatchUdevType=touchpad
AttrInputProp=+INPUT_PROP_PRESSUREPAD

View file

@ -24,28 +24,27 @@ MatchName=*Intel Virtual Button*
MatchDMIModalias=dmi:*:svnHP:pnHPElitex21013G3:*
ModelTabletModeSwitchUnreliable=1
# The HP OmniBook Ultra Flip Laptop 14-fh0xxx's custom Intel ISH firmware
# filters out events from its builtin keyboard and touchpad when the hinge is
# opened little more than 180 degrees but toggles tablet-mode when it's opened
# little less than 180 degrees.
# Do not suspend the keyboard and touchpad to let use the device in flat
# position and also give consistency with some keyboard keys controlled by the
# Video Bus device (brightness down/up), the HP WMI hotkeys device (mic mute and
# hp hubs launcher key) and the backlight getting on and off by the firmware at
# the same time it enables disables the input.
# This one is for the keyboard and...
[HP OmniBook Ultra Flip Laptop 14-fh0xxx Keyboard]
# The HP OmniBook Ultra Flip 14 toggles tablet mode at a little less than 180
# degrees and hardware switches off inputs at a little more than 180 degrees.
# We don't suspend ourselves to allow using them in flat position. It is
# possible that HP fixes this in the future (i.e. so tablet mode toggles
# after 180 degrees) so check before removing these rules.
# This rule is for the keyboard and...
[HP OmniBook Ultra Flip Laptop 14-fh0xxx and 14t-fh000 Keyboard]
MatchBus=ps2
MatchUdevType=keyboard
MatchDMIModalias=dmi:*:svnHP:pnHPOmniBookUltraFlipLaptop14-fh0xxx:*
MatchDMIModalias=dmi:*:svnHP:*:rn8CDE:*
ModelTabletModeNoSuspend=1
# ...this one is for the touchpad.
[HP OmniBook Ultra Flip Laptop 14-fh0xxx Touchpad]
# ...this rule is for the touchpad.
[HP OmniBook Ultra Flip Laptop 14-fh0xxx and 14t-fh000 Touchpad]
MatchBus=i2c
MatchUdevType=touchpad
MatchDMIModalias=dmi:*:svnHP:pnHPOmniBookUltraFlipLaptop14-fh0xxx:*
MatchDMIModalias=dmi:*:svnHP:*:rn8CDE:*
ModelTabletModeNoSuspend=1
AttrPressureRange=15:5
AttrThumbPressureThreshold=80
AttrPalmPressureThreshold=125
[HP Pavilion dm4]
MatchName=*SynPS/2 Synaptics TouchPad

View file

@ -0,0 +1,11 @@
# Do not edit this file, it will be overwritten on update
# Most Pixart Touchpad (093A:0255) devices don't have buttons so we remove right
# button in 30-vendor-pixart.quirks, but this one does.
[Positivo VAIO FE15 Touchpad]
MatchBus=i2c
MatchVendor=0x093A
MatchProduct=0x0255
MatchUdevType=touchpad
MatchDMIModalias=dmi:*:svnPositivoBahia-VAIO:pnVJFE59F11X-*:*
AttrEventCode=+BTN_RIGHT

View file

@ -0,0 +1,6 @@
# Clickpad that announces BTN_RIGHT
[Wareus B15 Touchpad]
MatchName=HTIX5288:00 36B6:C001 Touchpad
MatchUdevType=touchpad
MatchDMIModalias=dmi:*svnWareus:*pnB15*
AttrEventCode=-BTN_RIGHT

View file

@ -332,9 +332,9 @@ evdev_usage_is_button(evdev_usage_t usage)
case EVDEV_BTN_TOOL_FINGER:
case EVDEV_BTN_TOUCH:
return false;
case BTN_STYLUS:
case BTN_STYLUS2:
case BTN_STYLUS3:
case EVDEV_BTN_STYLUS:
case EVDEV_BTN_STYLUS2:
case EVDEV_BTN_STYLUS3:
return true;
case EVDEV_BTN_MISC ... EVDEV_BTN_DIGI - 1:
case EVDEV_BTN_WHEEL ... EVDEV_BTN_GEAR_UP:
@ -550,10 +550,12 @@ evdev_frame_append(struct evdev_frame *frame,
size_t nevents)
{
assert(nevents > 0);
int syn_report_value = 0;
for (size_t i = 0; i < nevents; i++) {
if (evdev_usage_eq(events[i].usage, EVDEV_SYN_REPORT)) {
nevents = i;
syn_report_value = events[i].value;
break;
}
}
@ -568,14 +570,24 @@ evdev_frame_append(struct evdev_frame *frame,
frame->count += nevents;
}
frame->events[frame->count - 1] = (struct evdev_event){
.usage = evdev_usage_from_uint32_t(EVDEV_SYN_REPORT),
.value = syn_report_value,
};
return 0;
}
static inline int
evdev_frame_append_one(struct evdev_frame *frame, evdev_usage_t usage, int32_t value)
{
if (evdev_usage_eq(usage, EVDEV_SYN_REPORT))
if (evdev_usage_eq(usage, EVDEV_SYN_REPORT)) {
frame->events[frame->count - 1] = (struct evdev_event){
.usage = evdev_usage_from_uint32_t(EVDEV_SYN_REPORT),
.value = value,
};
return 0;
}
if (frame->count >= frame->max_size)
return -ENOMEM;

View file

@ -585,8 +585,28 @@ tp_gesture_handle_event_on_state_none(struct tp_dispatch *tp,
static void
tp_gesture_set_3fg_drag_3fg_or_swipe_timer(struct tp_dispatch *tp, usec_t time)
{
libinput_timer_set(&tp->gesture.drag_3fg_or_swipe_timer,
usec_add(time, DRAG_3FG_OR_SWIPE_TIMEOUT));
usec_t expire = usec_add(tp->gesture.initial_time, DRAG_3FG_OR_SWIPE_TIMEOUT);
/* This is a hack to avoid the state machine getting even more complicated.
* For a slow drag/fast swipe we want the time from the *initial* touch point,
* not the time from when we realised the fingers are moving. IOW
* putting 3fg down, resting for 80ms and then moving fast must trigger
* a drag, not a swipe.
*
* In theory we should set the timer in the NONE/UNKNOWN states but that would
* require a whole parallel set of states like
* NONE_BUT_TIMEOUT_FOR_FAST_STATE_EXPIRED. Let's not do that, instead we set a
* negative timer and let the normal state proceed. Either we moved by the
* threshold already (in which case we shouldn't ever get here anyway) or
* we didn't in which case the neg timer will do the right thing too when it
* fires.
*/
if (usec_cmp(expire, time) < 0)
libinput_timer_set_flags(&tp->gesture.drag_3fg_or_swipe_timer,
expire,
TIMER_FLAG_ALLOW_NEGATIVE);
else
libinput_timer_set(&tp->gesture.drag_3fg_or_swipe_timer, expire);
}
static void

View file

@ -562,6 +562,12 @@ libinputplugin_unregister(lua_State *L)
return luaL_error(L, "@@unregistering@@");
}
static int
readonly_newindex(lua_State *L)
{
return luaL_error(L, "attempt to modify a read-only table");
}
static int
libinputplugin_gc(lua_State *L)
{
@ -673,7 +679,28 @@ libinputplugin_log_error(lua_State *L)
return libinputplugin_log(L, LIBINPUT_LOG_PRIORITY_ERROR);
}
static const struct luaL_Reg libinputplugin_vtable[] = {
static void
setup_vfuncs(lua_State *L,
const char *metatable_name,
const struct luaL_Reg *vfuncs,
const struct luaL_Reg *public_methods)
{
luaL_newmetatable(L, metatable_name);
luaL_setfuncs(L, vfuncs, 0);
lua_newtable(L);
luaL_setfuncs(L, public_methods, 0);
lua_setfield(L, -2, "__index");
/* set metatable.__metatable = false to prevent a script from getmetatable(),
which is blocked anyway but safe and sorry and whatnot */
lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable");
lua_pop(L, 1);
}
static const struct luaL_Reg libinputplugin_methods[] = {
{ "now", libinputplugin_now },
{ "version", libinputplugin_version },
{ "connect", libinputplugin_connect },
@ -685,18 +712,18 @@ static const struct luaL_Reg libinputplugin_vtable[] = {
{ "log_debug", libinputplugin_log_debug },
{ "log_info", libinputplugin_log_info },
{ "log_error", libinputplugin_log_error },
{ "__gc", libinputplugin_gc },
{ NULL, NULL }
};
static const struct luaL_Reg libinputplugin_meta[] = { { "__gc", libinputplugin_gc },
{ "__newindex",
readonly_newindex },
{ NULL, NULL } };
static void
libinputplugin_init(lua_State *L)
{
luaL_newmetatable(L, PLUGIN_METATABLE);
lua_pushstring(L, "__index");
lua_pushvalue(L, -2); /* push metatable */
lua_settable(L, -3); /* metatable.__index = metatable */
luaL_setfuncs(L, libinputplugin_vtable, 0);
setup_vfuncs(L, PLUGIN_METATABLE, libinputplugin_meta, libinputplugin_methods);
}
static int
@ -1073,7 +1100,7 @@ evdevdevice_gc(lua_State *L)
return 0;
}
static const struct luaL_Reg evdevdevice_vtable[] = {
static const struct luaL_Reg evdevdevice_methods[] = {
{ "info", evdevdevice_info },
{ "name", evdevdevice_name },
{ "usages", evdevdevice_usages },
@ -1087,18 +1114,17 @@ static const struct luaL_Reg evdevdevice_vtable[] = {
{ "prepend_frame", evdevdevice_prepend_frame },
{ "append_frame", evdevdevice_append_frame },
{ "disable_feature", evdevdevice_disable_feature },
{ "__gc", evdevdevice_gc },
{ NULL, NULL }
};
static const struct luaL_Reg evdevdevice_meta[] = { { "__gc", evdevdevice_gc },
{ "__newindex", readonly_newindex },
{ NULL, NULL } };
static void
evdevdevice_init(lua_State *L)
{
luaL_newmetatable(L, EVDEV_DEVICE_METATABLE);
lua_pushstring(L, "__index");
lua_pushvalue(L, -2); /* push metatable */
lua_settable(L, -3); /* metatable.__index = metatable */
luaL_setfuncs(L, evdevdevice_vtable, 0);
setup_vfuncs(L, EVDEV_DEVICE_METATABLE, evdevdevice_meta, evdevdevice_methods);
}
static void
@ -1336,7 +1362,7 @@ libinput_lua_plugin_new_from_path(struct libinput *libinput, const char *path)
return NULL;
}
int ret = luaL_loadfile(L, path);
int ret = luaL_loadfilex(L, path, "t");
if (ret == LUA_OK) {
plugin->L = steal(&L);

View file

@ -5206,7 +5206,7 @@ libinput_tablet_tool_config_eraser_button_get_default_mode(
if (!libinput_tablet_tool_config_eraser_button_get_modes(tool))
return LIBINPUT_CONFIG_ERASER_BUTTON_DEFAULT;
return tool->config.eraser_button.get_mode(tool);
return tool->config.eraser_button.get_default_mode(tool);
}
LIBINPUT_EXPORT enum libinput_config_status
@ -5246,7 +5246,7 @@ libinput_tablet_tool_config_eraser_button_get_default_button(
if (!libinput_tablet_tool_config_eraser_button_get_modes(tool))
return 0;
return tool->config.eraser_button.get_button(tool);
return tool->config.eraser_button.get_default_button(tool);
}
#ifdef HAVE_LIBWACOM

View file

@ -41,19 +41,19 @@ DECLARE_NEWTYPE(usec, uint64_t);
static inline usec_t
usec_from_millis(uint32_t millis)
{
return usec_from_uint64_t(millis * 1000);
return usec_from_uint64_t(millis * 1000ULL);
}
static inline usec_t
usec_from_seconds(uint32_t secs)
{
return usec_from_millis(secs * 1000);
return usec_from_uint64_t(secs * 1000000ULL);
}
static inline usec_t
usec_from_hours(uint32_t hours)
{
return usec_from_seconds(hours * 3600);
return usec_from_uint64_t((uint64_t)hours * 3600 * 1000000ULL);
}
static inline uint32_t
@ -83,7 +83,7 @@ usec_to_hours(usec_t us)
static inline usec_t
usec_add_millis(usec_t us, uint32_t millis)
{
return usec_from_uint64_t(usec_as_uint64_t(us) + millis * 1000);
return usec_from_uint64_t(usec_as_uint64_t(us) + millis * 1000ULL);
}
static inline usec_t
@ -101,13 +101,13 @@ us2ms_f(usec_t us)
static inline usec_t
usec_from_timeval(const struct timeval *tv)
{
return usec_from_uint64_t(tv->tv_sec * 1000000 + tv->tv_usec);
return usec_from_uint64_t(tv->tv_sec * 1000000ULL + tv->tv_usec);
}
static inline usec_t
usec_from_timespec(const struct timespec *tp)
{
return usec_from_uint64_t(tp->tv_sec * 1000000 + tp->tv_nsec / 1000);
return usec_from_uint64_t(tp->tv_sec * 1000000ULL + tp->tv_nsec / 1000);
}
static inline usec_t

View file

@ -2161,6 +2161,65 @@ START_TEST(gestures_3fg_drag_fast_swipe)
}
END_TEST
START_TEST(gestures_3fg_drag_slow_start)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
uint32_t finger_count = litest_test_param_get_u32(test_env->params, "fingers");
bool tap_enabled = litest_test_param_get_bool(test_env->params, "tap-enabled");
if (litest_slot_count(dev) < 3)
return LITEST_NOT_APPLICABLE;
if (libinput_device_config_3fg_drag_get_finger_count(dev->libinput_device) <
(int)finger_count)
return LITEST_NOT_APPLICABLE;
litest_enable_3fg_drag(dev->libinput_device, finger_count);
if (tap_enabled)
litest_enable_tap(dev->libinput_device);
else
litest_disable_tap(dev->libinput_device);
litest_drain_events(li);
/* Fingers are set down, then we do nothing, then we swipe fast. Because
* we did nothing at first even fast movement must become a 3fg drag, not
* a swipe.
*/
double y = 30.0;
for (uint32_t i = 0; i < finger_count; i++)
litest_touch_down(dev, i, 10 + i, y);
litest_checkpoint("Waiting past timeout before fast finger move");
litest_timeout_3fg_drag_or_swipe(li);
/* Now move fast */
while (y < 60.0) {
y += 2;
for (uint32_t i = 0; i < finger_count; i++) {
litest_touch_move(dev, i, 10 + i, y);
}
litest_dispatch(li);
}
drain_cancelled_swipe_gesture(li);
litest_checkpoint("Expecting button press for 3fg drag");
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
for (uint32_t i = 0; i < finger_count; i++)
litest_touch_up(dev, i);
litest_dispatch(li);
litest_assert_empty_queue(li);
litest_timeout_3fg_drag(li);
litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
TEST_COLLECTION(gestures)
{
/* clang-format off */
@ -2247,6 +2306,7 @@ TEST_COLLECTION(gestures)
"fingers", 'u', 2, 3, 4,
"tap-enabled", 'b') {
litest_add_parametrized(gestures_3fg_drag_fast_swipe, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
litest_add_parametrized(gestures_3fg_drag_slow_start, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, params);
}
/* Timing-sensitive test, valgrind is too slow */

View file

@ -526,6 +526,38 @@ START_TEST(lua_disallowed_functions)
}
END_TEST
START_TEST(lua_gc_not_accessible)
{
_destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
const char *lua =
"libinput:register({1})\n"
"assert(libinput.__gc == nil)\n"
"function check_device_gc(device)\n"
" assert(device.__gc == nil)\n"
" libinput:log_info(\"gc_not_accessible: ok\")\n"
"end\n"
"libinput:connect(\"new-evdev-device\", check_device_gc)\n";
_autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
_litest_context_destroy_ struct libinput *li =
litest_create_context_with_plugindir(tmpdir->path);
if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
litest_with_logcapture(li, capture) {
libinput_plugin_system_load_plugins(li,
LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
litest_drain_events(li);
_destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
litest_drain_events(li);
litest_assert_logcapture_no_errors(capture);
litest_assert_strv_substring(capture->infos, "gc_not_accessible: ok");
}
}
END_TEST
START_TEST(lua_frame_handler)
{
_destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
@ -1172,10 +1204,79 @@ START_TEST(lua_remove_plugin_on_timeout)
}
END_TEST
/* Pre-compiled Lua 5.4 bytecode for the following source:
*
* libinput:register({1})
* libinput:connect("new-evdev-device", function(device)
* libinput:log_info("loaded from binary lua file")
* end)
*
* To regenerate:
* luac5.4 -o /dev/stdout /tmp/plugin.lua | xxd -i
*/
static const unsigned char binary_lua_plugin[] = {
0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04,
0x08, 0x08, 0x78, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x28, 0x77, 0x40, 0x01, 0x9b, 0x40, 0x74, 0x65, 0x73, 0x74, 0x2f,
0x31, 0x30, 0x2d, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x2d, 0x70, 0x6c, 0x75,
0x67, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x80, 0x80, 0x00, 0x01, 0x04, 0x8e,
0x51, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x01, 0x13,
0x01, 0x00, 0x01, 0x52, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x80, 0x4e, 0x01,
0x01, 0x00, 0x44, 0x00, 0x03, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00,
0x02, 0x03, 0x81, 0x01, 0x00, 0xcf, 0x01, 0x00, 0x00, 0x44, 0x00, 0x04, 0x01,
0x46, 0x00, 0x01, 0x01, 0x84, 0x04, 0x89, 0x6c, 0x69, 0x62, 0x69, 0x6e, 0x70,
0x75, 0x74, 0x04, 0x89, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x04,
0x88, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x04, 0x91, 0x6e, 0x65, 0x77,
0x2d, 0x65, 0x76, 0x64, 0x65, 0x76, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x81, 0x01, 0x00, 0x00, 0x81, 0x80, 0x8d, 0x8f, 0x01, 0x00, 0x04, 0x85, 0x8b,
0x00, 0x00, 0x00, 0x94, 0x80, 0x01, 0x01, 0x83, 0x01, 0x01, 0x00, 0xc4, 0x00,
0x03, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x83, 0x04, 0x89, 0x6c, 0x69, 0x62, 0x69,
0x6e, 0x70, 0x75, 0x74, 0x04, 0x89, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x6e, 0x66,
0x6f, 0x04, 0x9c, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f,
0x6d, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6c, 0x75, 0x61, 0x20,
0x66, 0x69, 0x6c, 0x65, 0x81, 0x00, 0x00, 0x00, 0x80, 0x85, 0x01, 0x00, 0x00,
0x00, 0x01, 0x80, 0x81, 0x87, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x80, 0x85,
0x81, 0x85, 0x5f, 0x45, 0x4e, 0x56, 0x8e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xfe, 0x02, 0x80, 0x80, 0x81, 0x85, 0x5f,
0x45, 0x4e, 0x56,
};
START_TEST(lua_reject_precompiled_files)
{
_destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
/* Write the binary bytecode to a .lua file in the tmpdir.
* Binary (pre-compiled) Lua files must be rejected by the
* plugin loader for security reasons. */
_autofree_ char *path = strdup_printf("%s/10-binary-plugin.lua", tmpdir->path);
_autoclose_ int fd = open(path, O_WRONLY | O_CREAT, 0644);
litest_assert_errno_success(fd);
ssize_t written = write(fd, binary_lua_plugin, sizeof(binary_lua_plugin));
litest_assert_int_eq((int)written, (int)sizeof(binary_lua_plugin));
fsync(fd);
_litest_context_destroy_ struct libinput *li =
litest_create_context_with_plugindir(tmpdir->path);
litest_with_logcapture(li, capture) {
libinput_plugin_system_load_plugins(li,
LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
litest_drain_events(li);
size_t index = 0;
litest_assert(
strv_find_substring(capture->errors, "Failed to load", &index));
litest_assert_str_in(path, capture->errors[index]);
}
}
END_TEST
TEST_COLLECTION(lua)
{
/* clang-format off */
litest_add_no_device(lua_load_failure);
litest_add_no_device(lua_reject_precompiled_files);
litest_with_parameters(params,
"content", 'I', 6,
litest_named_i32(EMPTY),
@ -1219,6 +1320,7 @@ TEST_COLLECTION(lua)
litest_add_no_device(lua_register_multiversions);
litest_add_no_device(lua_allowed_functions);
litest_add_no_device(lua_disallowed_functions);
litest_add_no_device(lua_gc_not_accessible);
litest_add_no_device(lua_frame_handler);
litest_add_no_device(lua_device_info);

View file

@ -3168,6 +3168,49 @@ START_TEST(evdev_frames)
ARRAY_LENGTH(events));
litest_assert_int_eq(frame->max_size, ARRAY_LENGTH(events));
}
{
struct evdev_event events[] = {
{
.usage = U(EVDEV_ABS_X),
.value = 1,
},
{
.usage = U(EVDEV_ABS_Y),
.value = 2,
},
{
.usage = U(EVDEV_SYN_REPORT),
.value = 1,
},
};
_unref_(evdev_frame) *frame = evdev_frame_new(3);
int rc = evdev_frame_append(frame, events, 3);
litest_assert_neg_errno_success(rc);
litest_assert_int_eq(evdev_frame_get_count(frame),
ARRAY_LENGTH(events));
litest_assert_int_eq(frame->max_size, ARRAY_LENGTH(events));
size_t nevents;
rc = memcmp(evdev_frame_get_events(frame, &nevents),
events,
sizeof(events));
litest_assert_int_eq(rc, 0);
litest_assert_int_eq(nevents, ARRAY_LENGTH(events));
for (int v = 0; v < 2; v++) {
/* Appending SYN_REPORT changes the value to zero */
rc = evdev_frame_append_one(frame, U(EVDEV_SYN_REPORT), v);
litest_assert_neg_errno_success(rc);
litest_assert_int_eq(evdev_frame_get_count(frame),
ARRAY_LENGTH(events));
struct evdev_event *evs =
evdev_frame_get_events(frame, &nevents);
litest_assert(evdev_usage_eq(evs[2].usage, EVDEV_SYN_REPORT));
litest_assert_int_eq(evs[2].value, v);
}
}
}
END_TEST

View file

@ -257,6 +257,7 @@ print_evdev_event(struct record_device *dev, struct input_event *ev)
usec_t time = input_event_time(ev);
usec_t dt = usec_delta(time, last_time);
last_time = time;
snprintf(desc,
sizeof(desc),
@ -908,7 +909,7 @@ print_tablet_tool_proximity_event(struct record_device *dev, struct libinput_eve
tool_type = "brush";
break;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
tool_type = "brush";
tool_type = "pencil";
break;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
tool_type = "airbrush";
@ -1404,7 +1405,7 @@ print_system_header(FILE *fp)
_autofree_ char *dmistr = strdup("unknown"); //
if (dmi) {
char buf[2048] = "unknown";
size_t n = fread(buf, sizeof(buf), 1, dmi); // NOLINT: unix.Stream
size_t n = fread(buf, 1, sizeof(buf), dmi); // NOLINT: unix.Stream
if (n > 0) {
free(dmistr);
dmistr = strndup(buf, n - 1);

View file

@ -787,7 +787,7 @@ find_device(const char *udev_tag)
continue;
const char *sysname = udev_device_get_sysname(device);
if (!strstartswith("event", sysname)) {
if (!strstartswith(sysname, "event")) {
continue;
}