mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 08:00:08 +01:00
This patch adds support for Lua scripts to modify evdev devices and
event frames before libinput sees those events.
Plugins in Lua are sandboxed and restricted in what they can do: no IO,
no network, not much of anything else.
A plugin is notified about a new device before libinput handles it and
it can thus modify that device (changes are passed through to our libevdev
context). A plugin can then also connect an evdev frame handler which
gives it access to the evdev frames before libinput processes them. The
example plugin included shows how to swap left/right mouse buttons:
libinput:register({1})
function frame(device, frame)
for _, v in ipairs(frame.events) do
if v.usage == evdev.BTN_RIGHT then
v.usage = evdev.BTN_LEFT
elseif v.usage == evdev.BTN_LEFT then
v.usage = evdev.BTN_RIGHT
end
end
return frame
end
function device_new(plugin, device)
local usages = device:usages()
if usages[evdev.BTN_LEFT] and usages[evdev.BTN_RIGHT] then
device:connect("evdev-frame", frame)
end
end
libinput:connect("new-evdev-device", device_new)
A few other example plugins are included in this patch
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1192>
87 lines
3.5 KiB
Lua
87 lines
3.5 KiB
Lua
-- SPDX-License-Identifier: MIT
|
|
--
|
|
-- This is an example libinput plugin
|
|
--
|
|
-- This plugin swaps left and right buttons on any device that has both buttons.
|
|
|
|
-- Let's create a plugin. A single Lua script may create more than one
|
|
-- plugin instance but that's a bit of a nice use-case. Most scripts
|
|
-- should be a single plugin.
|
|
|
|
-- A plugin needs to be registered to activate. If it isn't, it is
|
|
-- cleaned up immediately. In the register call we supply
|
|
-- the list of plugin versions we support. Currently we only
|
|
-- have version 1.
|
|
--
|
|
-- UNCOMMENT THIS LINE TO ACTIVATE THE PLUGIN
|
|
-- libinput:register({1})
|
|
|
|
-- Note to the reader: it will be easier to understand this example
|
|
-- if you read it bottom-up from here on.
|
|
|
|
-- The callback for our "evdev-frame" signal.
|
|
-- These frames are sent *before* libinput gets to handle them so
|
|
-- any modifications will affect libinput.
|
|
function frame(device, frame, time_in_microseconds)
|
|
-- Frame is a table in the form
|
|
-- { { usage: 123, value: 3 }, ... }
|
|
-- Let's use the evdev module to make it more readable, evdev.KEY_A
|
|
-- is simply the value (0x1 << 16) | 0x1 (see linux/input-event-codes.h)
|
|
for _, v in ipairs(frame) do
|
|
-- If we get a right button event, change it to left, and
|
|
-- vice versa. Because this happens before libinput (or the next
|
|
-- plugin in the precedence order) sees the
|
|
-- frame it doesn't know that the swap happend.
|
|
if v.usage == evdev.BTN_RIGHT then
|
|
v.usage = evdev.BTN_LEFT
|
|
elseif v.usage == evdev.BTN_LEFT then
|
|
v.usage = evdev.BTN_RIGHT
|
|
end
|
|
end
|
|
-- We changed the frame, let's return it. If we return nil
|
|
-- the original frame is being used as-is.
|
|
return frame
|
|
end
|
|
|
|
-- This is a timer callback. It is invoked after one second
|
|
-- (see below) but only once - re-set the timer so
|
|
-- it goes off every second.
|
|
function timer_expired(time_in_microseconds)
|
|
libinput:timer_set_absolute(time_in_microseconds + 1000000)
|
|
end
|
|
|
|
-- Callback for the "new-evdev-device" signal, see below
|
|
-- The argument is the EvdevDevice object, see the documentation.
|
|
function device_new(device)
|
|
-- A table of evdev usages available on our device.
|
|
-- Using the evdev module makes it more readable but you can
|
|
-- use numbers (which is what evdev.EV_KEY and
|
|
-- friends resolve to anyway).
|
|
local usages = device:usages()
|
|
if usages[evdev.BTN_LEFT] and usages[evdev.BTN_RIGHT] then
|
|
-- The "evdev-frame" callback is invoked whenever the device
|
|
-- provided us with one evdev frame, i.e. a bunch of events up
|
|
-- to excluding EV_SYN SYN_REPORT.
|
|
device:connect("evdev-frame", frame)
|
|
end
|
|
|
|
-- The device has udev information, let's print it out. Right
|
|
-- now all we get are the ID_INPUT_ bits.
|
|
-- If this is empty we know libinput will ignore this device anyway
|
|
local udev_info = device:udev_properties()
|
|
for k, v in pairs(udev_info) do
|
|
log.debug(k .. "=" .. v)
|
|
end
|
|
end
|
|
|
|
-- Let's connect to the "new-evdev-device" signal. This function
|
|
-- is invoked when libinput detects a new evdev device (but before
|
|
-- that device is actually available to libinput as libinput device).
|
|
-- This allows us to e.g. change properties on the device.
|
|
libinput:connect("new-evdev-device", device_new)
|
|
|
|
-- Set our timer to expire 1s from now (in microseconds).
|
|
-- Timers are absolute, so they need to be added to the
|
|
-- current time
|
|
libinput:connect("timer-expired", timer_expired)
|
|
libinput:timer_set_relative(1000000)
|