mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-25 15:10:13 +01:00
This avoids mixing up milliseconds and usec, both by failing if we're providing just a number somewhere we expect usecs and also by making the API blindingly obvious that we're in usecs now. Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1373>
363 lines
13 KiB
C
363 lines
13 KiB
C
/*
|
|
* Copyright © 2025 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "config.h"
|
|
|
|
#include <libevdev/libevdev.h>
|
|
#include <libudev.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "util-time.h"
|
|
|
|
/* Forward declarations instead of #includes to make
|
|
* this header self-contained (bindgen, etc.) */
|
|
struct evdev_frame;
|
|
enum evdev_usage;
|
|
struct libinput;
|
|
struct libinput_device;
|
|
struct libinput_tablet_tool;
|
|
struct libinput_plugin;
|
|
enum libinput_log_priority;
|
|
enum libinput_feature;
|
|
|
|
#define plugin_log_debug(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__)
|
|
#define plugin_log_info(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__)
|
|
#define plugin_log_error(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__)
|
|
#define plugin_log_bug_kernel(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
|
|
#define plugin_log_bug_libinput(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "libinput bug: " __VA_ARGS__)
|
|
#define plugin_log_bug_client(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "client bug: " __VA_ARGS__)
|
|
#define plugin_log_bug(p_, ...) plugin_log_msg((p_), LIBINPUT_LOG_PRIORITY_ERROR, "plugin bug: " __VA_ARGS__)
|
|
|
|
void
|
|
plugin_log_msg(struct libinput_plugin *plugin,
|
|
enum libinput_log_priority priority,
|
|
const char *format,
|
|
...);
|
|
|
|
struct libinput_plugin_interface {
|
|
void (*run)(struct libinput_plugin *plugin);
|
|
/**
|
|
* Notification that the plugin is about to be destroyed.
|
|
* When this function is called, the plugin has already
|
|
* been unregistered. The plugin should free any
|
|
* resources allocated but not the struct libinput_plugin
|
|
* itself.
|
|
*/
|
|
void (*destroy)(struct libinput_plugin *plugin);
|
|
/**
|
|
* Notification about a newly added device that has **not** yet
|
|
* been added by libinput as struct libinput_device.
|
|
*/
|
|
void (*device_new)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device,
|
|
struct libevdev *evdev,
|
|
struct udev_device *udev_device);
|
|
/**
|
|
* Notification that a device (previously announced with device_new)
|
|
* was ignored by libinput and was **never** added as struct
|
|
* libinput_device.
|
|
*
|
|
* If a device was added (device_added) then this callback will
|
|
* not be called for that device.
|
|
*/
|
|
void (*device_ignored)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device);
|
|
/**
|
|
* Notification that a device was added to libinput. Called
|
|
* after the device_new callback if the device matches libinput's
|
|
* expectations.
|
|
*/
|
|
void (*device_added)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device);
|
|
/**
|
|
* Notification that a previously added device was removed.
|
|
*/
|
|
void (*device_removed)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device);
|
|
/**
|
|
* Notification that a device submitted a frame event.
|
|
*/
|
|
void (*evdev_frame)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device,
|
|
struct evdev_frame *frame);
|
|
|
|
/**
|
|
* Notification that a configuration option on a tool
|
|
* was modified.
|
|
*/
|
|
void (*tool_configured)(struct libinput_plugin *plugin,
|
|
struct libinput_tablet_tool *tool);
|
|
|
|
/**
|
|
* Notification that the given feature was disabled on
|
|
* the given device.
|
|
*/
|
|
void (*feature_disabled)(struct libinput_plugin *plugin,
|
|
struct libinput_device *device,
|
|
enum libinput_feature feature);
|
|
};
|
|
|
|
/**
|
|
* Returns a new plugin with the given interface and, optionally,
|
|
* the user data. The returned plugin has a refcount of at least 1
|
|
* and must be unref'd by the caller.
|
|
* Should an error occur, the plugin must be unregistered by
|
|
* the caller:
|
|
*
|
|
* ```
|
|
* struct libinput_plugin *plugin = libinput_plugin_new(libinput, ...);
|
|
* if (some_error_condition) {
|
|
* libinput_plugin_unregister(plugin);
|
|
* }
|
|
* libinput_plugin_unref(plugin);
|
|
* ```
|
|
*/
|
|
struct libinput_plugin *
|
|
libinput_plugin_new(struct libinput *libinput,
|
|
const char *name,
|
|
const struct libinput_plugin_interface *interface,
|
|
void *user_data);
|
|
|
|
const char *
|
|
libinput_plugin_get_name(struct libinput_plugin *plugin);
|
|
|
|
struct libinput *
|
|
libinput_plugin_get_context(struct libinput_plugin *plugin);
|
|
|
|
void
|
|
libinput_plugin_unregister(struct libinput_plugin *plugin);
|
|
|
|
void
|
|
libinput_plugin_set_user_data(struct libinput_plugin *plugin, void *user_data);
|
|
void *
|
|
libinput_plugin_get_user_data(struct libinput_plugin *plugin);
|
|
|
|
struct libinput_plugin *
|
|
libinput_plugin_ref(struct libinput_plugin *plugin);
|
|
|
|
struct libinput_plugin *
|
|
libinput_plugin_unref(struct libinput_plugin *plugin);
|
|
|
|
#ifdef DEFINE_UNREF_CLEANUP_FUNC
|
|
DEFINE_UNREF_CLEANUP_FUNC(libinput_plugin);
|
|
#endif
|
|
|
|
void
|
|
libinput_plugin_enable_device_event_frame(struct libinput_plugin *plugin,
|
|
struct libinput_device *device,
|
|
bool enable);
|
|
|
|
void
|
|
libinput_plugin_disable_device_feature(struct libinput_plugin *plugin,
|
|
struct libinput_device *device,
|
|
enum libinput_feature feature);
|
|
|
|
/**
|
|
* Mask this plugin's evdev_frame function to be called only
|
|
* if the frame **contains** the given evdev usage. Plugins
|
|
* that e.g. only care about button events should use this function
|
|
* to avoid being called for every motion event.
|
|
*
|
|
* By default the mask includes all events. Calling this function
|
|
* changes the behavior to *only* include frames with the usages.
|
|
*
|
|
* Note that the frame passed to evdev_frame function contains all
|
|
* events of that frame (i.e. including events that are not specified
|
|
* by this mask).
|
|
*/
|
|
void
|
|
libinput_plugin_enable_evdev_usage(struct libinput_plugin *plugin,
|
|
enum evdev_usage usage);
|
|
|
|
/**
|
|
* Inject a new event frame from the given plugin. This
|
|
* frame is treated as if it was just sent by the kernel's
|
|
* event node and is processed immediately, interrupting
|
|
* any other processing from this device.
|
|
*
|
|
* This function can be called any time but unlike
|
|
* libinput_plugin_append_evdev_frame() and
|
|
* libinput_plugin_prepend_evdev_frame() it starts
|
|
* processing the frame at the bottom of the plugin
|
|
* stack.
|
|
*
|
|
* The injected event will also be sent to
|
|
* the current plugin, a guard needs to be in
|
|
* place to prevent recursion.
|
|
*
|
|
* Injecting events may cause other plugins to
|
|
* behave unexpectedly (see below). In almost all cases
|
|
* it is better to use libinput_plugin_append_evdev_frame()
|
|
* or libinput_plugin_prepend_evdev_frame() to only
|
|
* affect the plugins logically *after* this
|
|
* plugin.
|
|
*
|
|
* Assuming several plugins P1, P2, and P3 and
|
|
* an event frame E, and P2 calling this function
|
|
* with an injected event I:
|
|
* - P1: receives E, optionally modifies E
|
|
* - P2: receives E, injects I
|
|
* - P1: receives I, optionally modifies I
|
|
* - P2: receives I, optionally modifies I
|
|
* - P3: receives I, optionally modifies I
|
|
* - P2: continues processing E, optionally modifies E
|
|
* - P3: receives E, optionally modifies E
|
|
*
|
|
* For P1 the injected event I is received after E,
|
|
* for P3 the injected event I is received before E.
|
|
*
|
|
* An example for event injection being harmful:
|
|
* A plugin may monitor tablet proximity state and prepent
|
|
* proximity-in events if the tablet does not send proximity-in
|
|
* events. This plugin stops monitoring events once it sees correct
|
|
* proximity-in events.
|
|
* If another plugin were to inject a proximity event (e.g. to fake a
|
|
* different tool coming into proximity), the plugin would stop
|
|
* monitoring. Future proximity events from the tablet will then
|
|
* have the wrong proximity.
|
|
* This can be avoided by appending or prepending the events instead
|
|
* of injecting them.
|
|
*/
|
|
void
|
|
libinput_plugin_inject_evdev_frame(struct libinput_plugin *libinput,
|
|
struct libinput_device *device,
|
|
struct evdev_frame *frame);
|
|
|
|
/**
|
|
* Queue an event frame for the next plugin in sequence, after
|
|
* the current event frame being processed.
|
|
*
|
|
* This function can only be called from within the evdev_frame()
|
|
* callback or within a plugin's timer func and may be used to
|
|
* queue new frames. If called multiple times with frames F1, F2, ...
|
|
* while processing the current frame C, frame sequence to be passed
|
|
* to the next plugin is C, F1, F2, ...
|
|
*
|
|
* Assuming several plugins P1, P2, P3, and P4 and an event frame E,
|
|
* and P2 and P3 calling this function with an queued event frame Q1 and Q2,
|
|
* respectively.
|
|
*
|
|
* - P1: receives E, optionally modifies E
|
|
* - P2: receives E, appends Q1, optionally modifies E
|
|
* - P3: receives E, appends Q2, optionally modifies E
|
|
* - P3: receives Q1, optionally modifies Q1
|
|
* - P4: receives E, optionally modifies E
|
|
* - P4: receives Q2, optionally modifies Q2
|
|
* - P4: receives Q1, optionally modifies Q1
|
|
*
|
|
* Once plugin processing is complete, the event sequence passed
|
|
* back to libinput is thus [E, Q2, Q1].
|
|
*
|
|
* To discard the original event frame, the plugin needs to
|
|
* call evdev_frame_reset() on the frame passed to it.
|
|
*
|
|
* It is a plugin bug to call this function from outside the
|
|
* evdev_frame() callback or a timer callback.
|
|
*
|
|
* If called within a plugin's timer callback, any frames generated by
|
|
* the plugin will only be seen by plugins after this plugin. These
|
|
* frames will be processed in the usual evdev_fame() callback and there
|
|
* is no indication that the events were queued from within a timer
|
|
* callback. Using the above example:
|
|
*
|
|
* - P1: <idle>
|
|
* - P2: timer callback invoked, appends Q1
|
|
* - P3: receives Q1, appends Q2, optionally modifies Q1
|
|
* - P4: receives Q2, optionally modifies Q2
|
|
* - P4: receives Q1, optionally modifies Q1
|
|
*
|
|
* Because there is no current frame during a timer callback
|
|
* libinput_plugin_append_evdev_frame() and
|
|
* libinput_plugin_prepend_evdev_frame() are functionally equivalent.
|
|
* If both functions are used, all events from
|
|
* libinput_plugin_prepend_evdev_frame() will be queued before
|
|
* events from libinput_plugin_append_evdev_frame().
|
|
*/
|
|
void
|
|
libinput_plugin_append_evdev_frame(struct libinput_plugin *libinput,
|
|
struct libinput_device *device,
|
|
struct evdev_frame *frame);
|
|
|
|
/**
|
|
* Identical to libinput_plugin_append_evdev_frame(), but prepends
|
|
* the event frame to the current event frame being processed.
|
|
* If called multiple times with frames F1, F2, ... while processing
|
|
* the current frame C, frame sequence to be passed to the next
|
|
* plugin is F1, F2, ..., C
|
|
*/
|
|
void
|
|
libinput_plugin_prepend_evdev_frame(struct libinput_plugin *libinput,
|
|
struct libinput_device *device,
|
|
struct evdev_frame *frame);
|
|
|
|
/**
|
|
* Create a new timer for the given plugin.
|
|
*
|
|
* The timer needs to be set with libinput_plugin_timer_set()
|
|
* before it can be used.
|
|
*
|
|
* The refcount of the returned timer is at least 1, and the caller
|
|
* must call libinput_plugin_timer_unref() to release it.
|
|
*
|
|
* The func given is the callback invoked when the timer expires.
|
|
* It is passed the user_data given here or in a subsequent
|
|
* call to libinput_plugin_timer_set_user_data().
|
|
*
|
|
* Note that event generating inside a timer is subject to
|
|
* specific behaviors, see the documentation
|
|
* to libinput_plugin_append_evdev_frame(), libinput_plugin_prepend_evdev_frame()
|
|
* and libinput_plugin_inject_evdev_frame() for details.
|
|
*/
|
|
struct libinput_plugin_timer *
|
|
libinput_plugin_timer_new(struct libinput_plugin *plugin,
|
|
const char *name,
|
|
void (*func)(struct libinput_plugin *plugin,
|
|
usec_t now,
|
|
void *user_data),
|
|
void *user_data);
|
|
|
|
struct libinput_plugin_timer *
|
|
libinput_plugin_timer_ref(struct libinput_plugin_timer *timer);
|
|
|
|
struct libinput_plugin_timer *
|
|
libinput_plugin_timer_unref(struct libinput_plugin_timer *timer);
|
|
|
|
#ifdef DEFINE_UNREF_CLEANUP_FUNC
|
|
DEFINE_UNREF_CLEANUP_FUNC(libinput_plugin_timer);
|
|
#endif
|
|
|
|
/* Set timer expire time, in absolute us CLOCK_MONOTONIC */
|
|
void
|
|
libinput_plugin_timer_set(struct libinput_plugin_timer *timer, usec_t expire);
|
|
|
|
void
|
|
libinput_plugin_timer_set_user_data(struct libinput_plugin_timer *timer,
|
|
void *user_data);
|
|
void *
|
|
libinput_plugin_timer_get_user_data(struct libinput_plugin_timer *timer);
|
|
|
|
void
|
|
libinput_plugin_timer_cancel(struct libinput_plugin_timer *timer);
|