Skip to content

Draft: plugins: add a plugin system for modifying evdev event behavior

Peter Hutterer requested to merge whot/libinput:wip/lua-plugins into main

This patch adds a plugin system at the evdev level to allow for modification of evdev events (and devices) before libinput sees those events.

Plugins are implemented in Lua and are sandboxed and restricted in what they can do: no IO, no network, not much of anything else.

A plugin is notifified 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.type == evdev.EV_KEY then
              if v.code == evdev.BTN_RIGHT then
                  v.code = evdev.BTN_LEFT
              elseif v.code == evdev.BTN_LEFT then
                  v.code = evdev.BTN_RIGHT
              end
          end
      end
      return frame
  end

  function device_new(plugin, device)
      local codes = device:event_codes()
      if codes[evdev.EV_KEY] and codes[evdev.EV_KEY][evdev.BTN_LEFT] and codes[evdev.EV_KEY][evdev.BTN_RIGHT] then
          device:connect("evdev-frame", frame)
      end
  end

  libinput:connect("new-evdev-device", device_new)

Plugins are only loaded if the compositor calls libinput_plugin_system_load() - i.e. by default plugins are simply ignored.

Our debugging tools have an --enable-plugins and --disable-plugins option that load from the default data paths (/etc/libinput/plugins and /usr/share/libinput/plugins) and from the $builddir/plugins directory.


Still draft because it's the first working version but needs a lot more error checking esp. in the lua arg parsing - general rule will be that any lua error should unload the plugin. A few things that do not yet work but should work eventually:

  • definitely: timers to schedule events (this would allow for things like custom button debouncing and dwt)
    • possibly: modify the timestamp of an evdev frame and have libinput automatically schedule it for the future
  • definitely: injecting new event frames (right now we can only modify the current frame)
  • probably: ability for plugins to disable certain libinput features, I'm thinking of something like device.disable("button-debouncing") which will wholesale disable that particular part of the libinput code.
  • possibly: notifications if a configuration is toggled on a libinput device. This allows for plugins to do things when e.g. tapping is enabled

Notably: the whole point of this is to make it possible to add functionality that affects users but that cannot or will not be added to libinput proper. These are custom timeouts/behaviors (#992, #619), unquirkable hardware issues (Logitech devices on Bolt receivers), etc. The point of this is not to add a generic configuration mechanism to libinput, or some way to add new devices to libinput via scripts, or ...

Anyway, the current state should be good enough at least to figure out if Lua is fast enough event frame processing, otherwise the whole exercise was for naught anyway...

cc @JoseExposito, @carlosg, @satrmb

Edited by Peter Hutterer

Merge request reports

Loading