[RFC] libinputmapper: Input device configuration for graphic-servers

Peter Hutterer peter.hutterer at who-t.net
Wed May 15 22:37:49 PDT 2013


On Sun, May 12, 2013 at 04:20:59PM +0200, David Herrmann wrote:
> [bcc to gnome-shell-list and kwin, to keep discussion on wayland-devel]
 
> Without a generic graphics-server like xserver, compositors need to
> handle input devices themselves if run as wayland compositors. To
> avoid having several different conflicting implementations, I wrote up
> a small proposal and library API to have a common configuration.
> 
> How is it currently handled?
> A compositor uses udev to listen for input devices. For each
> input-device, they use some heuristics (test for KEY_*, ABS_*, ..
> event-bits) to figure out what kind of input is provided by the
> device. Unknown devices and events are ignored, devices that look
> useful are passed to the correct input-driver.
> For keyboard input, libxkbcommon is used. For
> mouse/touchpad/touchscreen input, every compositor has it's own simple
> driver (I am not aware of an attempt to put xf86-input-synaptics into
> an independent library). 

fwiw, I tried this once, but the amount of legacy junk in the X driver is
large enough that it would be better writing synaptics from scratch as a
library and hook that up instead.

> For other device types, applications handle
> input themselves (gamepads, joysticks, and so on). And then there are
> devices that have x11 drivers, but I am not aware of external drivers
> for wayland-compositors (like wacom digitizers).
> 
> I am not interested in the device-drivers itself (for now in this
> project). I think it would be nice to write a libsynapticscommon,

ftr, please don't name such an effort synaptics. the name in the X driver is
historical and should be changed, so libtouchpad is a better name.

> libmousecommon, .. which provide a libxkbcommon'ish interface for
> other device types independent of the compositor implementation, but
> that's another independent issue.
> Instead, I am more interested in the device-detection and enumeration.
> If I plug in a gamepad device, I don't want _any_ compositor to handle
> it as a mouse, just because it provides REL_X/Y values. I don't want
> compositors to erroneously handle accelerometers as mice because they
> provide ABS_X/Y values. But on the other hand, I want users to be able
> to tell compositors to handle ABS_X/Y input from their custom hardware
> as mouse input, _iff_ they want to.
> Furthermore, if a device has a buggy kernel driver and reports BTN_X
> instead of BTN_A, I want all compositors to detect that and apply a
> simple fixup button-mapping. Or allow users to remap
> buttons/axis/LEDs/EV_WHATEVER arbitrarily.
> 
> udev provides some very basic heuristics with device-tags, but talking
> to Kay Sievers, he'd like to avoid having huge detection-tables and
> heuristics in udev (which is understandable).
> 
> Dmitry Torokhov is not averse to providing device-type properties in
> the kernel input-subsystem, but on the other hand, it doesn't help us
> much. Generic HID devices might still provide any arbitrary input that
> we would have to write custom drivers/quirks for, if they don't match.
> So if no-one steps up to do all that work, I recommend providing these
> fixups in user-space. This also has the advantage, that users can
> arbitrarily modify these rules if they want crazy setups (which users
> normally want..). And we can ship fixup-rules for new devices, while
> in the meantime writing kernel drivers for them and waiting for the
> next kernel release. And don't forget the kernel drivers with broken
> mappings, which we cannot fix due to backwards-compatibility, but
> still want them to be correctly mapped in new
> compositors/applications.
> 
> 
> So what is the proposed solution?
> My recommendation is, that compositors still search for devices via
> udev and use device drivers like libxkbcommon. So linux evdev handling
> is still controlled by the compositor. However, I'd like to see
> something like my libinputmapper proposal being used for device
> detection and classification.
> 
> libinputmapper provides an "inmap_evdev" object which reads device
> information from an evdev-fd or sysfs /sys/class/input/input<num>
> path, performs some heuristics to classify it and searches it's global
> database for known fixups for broken devices.
> It then provides "capabilities" to the caller, which allow them to see
> what drivers to load on the device. And it provides a very simple
> mapping table that allows to apply fixup mappings for broken devices.
> These mappings are simple 1-to-1 mappings that are supposed to be
> applied before drivers handle the input. This is to avoid
> device-specific fixup in the drivers and move all this to the
> inputmapper. An example would be a remapping for gamepads that report
> BTN_A instead of BTN_NORTH, but we cannot fix them in the kernel for
> backwards-compatibility reasons. The gamepad-driver can then assume
> that if it receives BTN_NORTH, it is guaranteed to be BTN_NORTH and
> doesn't need to special case xbox360/etc. controllers, because they're
> broken.

I think evdev is exactly that interface and apparently it doesn't work. 

if you want a mapping table, you need a per-client table because sooner or
later you have a client that needs BTN_FOO when the kernel gives you BTN_BAR
and you can't change the client to fix it.

i.e. the same issue evdev has now, having a global remapping table just
moves the problem down by 2 years. 

a mapping table is good, but you probably want two stages of mapping: one
that's used in the compositor for truly broken devices that for some reason
can't be fixed in the kernel, and one that's used on a per-client basis. and
you'll likely want to be able to overide the client-specific from outside
the client too.

> libinputmapper would use some static heuristics for all this, but
> additionally parse user-configuration. A configuration file contains
> "[match]" entries, which specify device-configurations to load on
> mtached devices. The device-configurations then contain different
> blocks which can overwrite the auto-detected capabilities or provide
> fixup-mappings.
> But other configuration-sections can also be provided in the same
> file. For instance an [xkb] group could be specified to set XKB
> layout/variant/options. This won't be parsed by libinputmapper, but it
> would provide the matching and forward the device-configuration to the
> caller, which can pass it on to the driver.
> Additionally, API users can provide separate (local)
> configuration-files that allow users to change the configuration for
> kmscon one way and another way for gnome-shell (or similar).
> 
> One can think of these configurations to replace the old
> /etc/X11/xorg.conf.d/*.conf "InputClass" configuration items. Except
> that the "matching" is offloaded to a separate file, and the "to be
> applied configurations" are specified in "rule" files, that are linked
> to from the "match" configurations. See below for syntax-examples.
> 
> 
> I haven't implemented the library, yet. I am working on this. However,
> I wrote up an API proposal that I attached inline below. kmscon input
> handling is what I need it for, so I want something like this, anyway.
> But I thought other compositors might be interested in this, too.
> 
> Comments are welcome!
> Regards
> David
> 
> 

[...]

> /**
>  * @enum inmap_capability
>  * Generic device capabilities
>  *
>  * Device capabilities describe what generic interface is provided by the
>  * detected device. A device can support any combination of them (or none).
>  * Each interface follows specific rules. If a device does not follow these
>  * rules, we must provide a mapping table so the correct data is reported.
>  *
>  * Capabilities can be added for all kinds of generic devices. However, custom
>  * devices with model-specific features do not belong here, as their drivers
>  * need to perform device-detection themselves, anyway.
>  *
>  * Furthermore, each capability needs a well-defined protocol. They are mostly
>  * already provided by the kernel. But there are many devices and drivers
>  * which provide inconsistent behavior. That's why each capability has to
>  * be consistent and coherent and misbehaving devices get fixup mappings, if
>  * we cannot fix it in the kernel device driver itself.
>  */
> enum inmap_capability {
> /**
> * @INMAP_CAP_KEYBOARD
> * Keyboard interface
> *
> * The device is a real keyboard that is used for normal input.
> * Power-buttons and similar devices which report KEY_* events for
> * non-keyboard buttons are not considered a keyboard in this sense.
> * Only real keyboards and small extension devices (like external
> * NumPads) belong here.
> * The defined KEY_* events are not listed here as normally no
> * mapping is applied. Libraries like libxkbcommon should be used
> * for keyboard handling and mapping.
> */
> INMAP_CAP_KEYBOARD = (1 << 0),
> 
> /**
> * @INMAP_CAP_MOUSE
> * Mouse interface
> *
> * The device is a real mouse with relative motion events. Motion
> * is reported as REL_X/Y. Buttons are reported as BTN_0-BTN_9 or
> * BTN_LEFT-BTN_TASK.
> * Other mouse-like devices (especially those with absolute motion
> * events) do not belong here.
> */
> INMAP_CAP_MOUSE = (1 << 1),
> 
> /**
> * @INMAP_CAP_TOUCHPAD
> * Touchpad interface
> *
> * Touchpad devices belong here. But only those that are used as
> * pointing devices and are intended to drive a mouse device. That is,
> * the input is interpreted as relative motion, even though the
> * reported data is normally absolute.
> * Hence, touchscreens do not belong here. They are normally
> * interpreted as absolute position input.
> *
> * For multitouch devices, libmtdev defines the protocol.

kernel MT Procol B is a better term here, libmtdev merely converts A to B.

> *
> * @TODO define the protocol (see the synaptics descriptions)
> */
> INMAP_CAP_TOUCHPAD = (1 << 2),
> 
> /**
> * @INMAP_CAP_TOUCHSCREEN
> * Touchscreen interface
> *
> * Touchscreens are exactly the same as @INMAP_CAP_TOUCHPAD, but they
> * are normally attached to a single monitor and interpreted as
> * absolute positioning input.
> * Therefore, they are not included in @INMAP_CAP_TOUCHPAD, but are
> * a separate group instead. The reported protocol is the same, though.
> *
> * @sa INMAP_CAP_TOUCHPAD
> */
> INMAP_CAP_TOUCHSCREEN = (1 << 3),
> 
> /**
> * @INMAP_CAP_ACCELEROMETER
> * Accelerometer interface
> *
> * Accelerometer devices report linear acceleration data as ABS_X/Y/Z
> * and rotational acceleration as ABS_RX/Y/Z.
> *
> * @TODO this collides with ABS_X/Y of absolute pointing devices
> *       introduce ABS_ACCELX/Y/Z
> */
> INMAP_CAP_ACCELEROMETER = (1 << 4),
> 
> /**
> * @INMAP_CAP_GAMEPAD
> * Gamepad interface
> *
> * All standard gamepad devices belong here.
> *
> * @TODO define gamepad mapping (see linux-input at vger discussion)
> */
> INMAP_CAP_GAMEPAD = (1 << 5),
> 
> /**
> * @INMAP_CAP_JOYSTICK
> * Joystick interface
> *
> * All standard joystick devices belong here.
> *
> * @TODO define joystick mapping
> */
> INMAP_CAP_JOYSTICK = (1 << 6),
> };

why are gamepads and joysticks different? buttons, a few axes that may or
may not map to x/y and the rest is device-specific.
this may be in the thread, but I still haven't gone through all msgs here.


one missing section are graphics tablets but even there you could argue
they're just buttons, x/y and a few extra axes that need client-specific
handling.

> /**
>  * @defgroup context Library Context
>  * Managing library contexts
>  *
>  * A context object contains all top-level information. It can be shared
>  * between multiple device objects and provides global infrastructure to them.
>  *
>  * @{
>  */
> 
> /**
>  * @enum inmap_context_flags
>  * Context creation and operation flags
>  *
>  * Different flags that control how a context is created and how it behaves.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_new()
>  */
> enum inmap_context_flags {
> /**
> * @INMAP_CONTEXT_IGNORE_ENVIRONMENT
> * Ignore environment variables
> *
> * The context object will not use any environment variables as
> * default values if they are not explicitly set.
> *
> * @memberof inmap_context
> */
> INMAP_CONTEXT_IGNORE_ENVIRONMENT = (1 << 0),
> 
> /**
> * @INMAP_CONTEXT_MONITOR_CONF_FILES
> * Monitor configuration files
> *
> * If set, the context will monitor configuration files for runtime
> * modifications. This allows adapting to changes without restarting
> * the application.
> * Changes are not automatically applied. The application has to
> * react to these events and retrigger device detection for all
> * active devices.
> *
> * @memberof inmap_context
> * @sa inmap_context_dispatch()
> */
> INMAP_CONTEXT_MONITOR_CONF_FILES = (1 << 1),

tbh, I'd make that a required behaviour.

[still thinking about the rest]

Cheers,
  Peter

> /**
> * @INMAP_CONTEXT_NO_DEFAULT_CONF
> * Skip default configuration
> *
> * If set, the global default configuration is not parsed.
> *
> * @memberof inmap_context
> */
> INMAP_CONTEXT_NO_DEFAULT_CONF = (1 << 2),
> };
> 
> /**
>  * Create new context
>  *
>  * @param[out] out   Pointer to the new context is stored here
>  * @param[in] caps   Capabilities that are used with this context
>  * @param[in] flags  Optional flags or 0
>  *
>  * Create a new context and store a pointer to it in @out. You must specify
>  * all capabilities that you want to use with this context in @caps. This
>  * causes the context to ignore and skip all configuration options for
>  * other capabilities to save memory.
>  * You cannot modify the capabilities afterwards.
>  *
>  * You can change the behavior of the context with additional flags. See the
>  * @inmap_context_flags for a description of flags.
>  *
>  * Context objects are reference counted. Initial ref-count is 1. You can
>  * modify it via @inmap_context_ref() and @inmap_context_unref().
>  *
>  * @returns 0 on success, negative error code on failure.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_flags
>  * @sa inmap_context_ref()
>  * @sa inmap_context_unref()
>  */
> int inmap_context_new(struct inmap_context **out,
>      enum inmap_capability caps,
>      enum inmap_context_flags flags);
> 
> /**
>  * Increase context ref-count
>  *
>  * @param[in] ctx  Valid context object or NULL
>  *
>  * Increase ref-count of the given context by 1. If NULL is passed as
>  * context, then nothing is done.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_new()
>  * @sa inmap_context_unref()
>  */
> void inmap_context_ref(struct inmap_context *ctx);
> 
> /**
>  * Decrease context ref-count
>  *
>  * @param[in] ctx  Valid context object or NULL
>  *
>  * Decrease ref-count of @ctx by 1. You must not access @ctx afterwards if
>  * you do not own another reference. This function destroys @ctx if the
>  * ref-count drops to 0.
>  * If @ctx is NULL, nothing is done.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_new()
>  * @sa inmap_context_ref()
>  */
> void inmap_context_unref(struct inmap_context *ctx);
> 
> /**
>  * Set user-data
>  *
>  * @param[in] ctx        Valid context object
>  * @param[in] user_data  User-data pointer
>  *
>  * Set a user-controlled pointer field in @ctx. This allows the user to
>  * associate any data with this context. It can be retrieved via
>  * @inmap_context_get_user_data() again.
>  * This field is set to NULL during context initialization and then never
>  * modified by the library code itself. It is a fully user controlled field.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_get_user_data()
>  */
> void inmap_context_set_user_data(struct inmap_context *ctx, void *user_data);
> 
> /**
>  * Get user-data
>  *
>  * @param[in] ctx  Valid context object
>  *
>  * @returns user-data field previously set via @inmap_context_set_user_data()
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_set_user_data()
>  */
> void *inmap_context_get_user_data(struct inmap_context *ctx);
> 
> /**
>  * @enum inmap_context_log_level
>  * Log-level of context objects
>  *
>  * The log-levels are exactly the same as the kernel log-levels.
>  *
>  * @memberof inmap_context
>  */
> enum inmap_context_log_level {
> INMAP_CONTEXT_LOG_LEVEL_EMERGENCY,
> INMAP_CONTEXT_LOG_LEVEL_ALERT,
> INMAP_CONTEXT_LOG_LEVEL_CRITICAL,
> INMAP_CONTEXT_LOG_LEVEL_ERROR,
> INMAP_CONTEXT_LOG_LEVEL_WARNING,
> INMAP_CONTEXT_LOG_LEVEL_NOTICE,
> INMAP_CONTEXT_LOG_LEVEL_INFO,
> INMAP_CONTEXT_LOG_LEVEL_DEBUG,
> };
> 
> /**
>  * Set log level
>  *
>  * @param[in] ctx    Valid context object
>  * @param[in] level  New log level
>  *
>  * Change the default log-level to @level. Only log-messages with equal or
>  * higher priority are passed to the log-function. Default log-level is
>  * @INMAP_CONTEXT_LOG_LEVEL_ERROR.
>  *
>  * During context creation, the log-level is set to the value of the
>  * environment variable INMAP_LOG_LEVEL if set. It may be specified as a
>  * number or name.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_log_level
>  * @sa inmap_context_get_log_level()
>  * @sa inmap_context_set_log_fn()
>  */
> void inmap_context_set_log_level(struct inmap_context *ctx, unsigned int level);
> 
> /**
>  * Get log level
>  *
>  * @param[in] ctx  Valid context object
>  *
>  * @returns log-level previously set via inmap_context_log_leve()
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_log_level
>  * @sa inmap_context_set_log_level()
>  * @sa inmap_context_set_log_fn()
>  */
> unsigned int inmap_context_get_log_level(struct inmap_context *ctx);
> 
> /**
>  * Set log function
>  *
>  * @param[in] ctx     Valid context object
>  * @param[in] log_fn  Log-function or NULL
>  *
>  * Change the default log-function to @log_fn. If @log_fn is NULL, no
>  * logging will be done.
>  * This log-function is called for every log-message that has a higher
>  * or equal priority as the currently set log-level.
>  *
>  * The first argument is the context object, followed by the user_data field
>  * which can also be retrieved via inmap_context_get_user_data(). Then the
>  * log-level of the message, the file/line/function information where the
>  * message originated and the format/args combination with the actual
>  * log message.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_log_level
>  * @sa inmap_context_set_log_level()
>  */
> void inmap_context_set_log_fn(struct inmap_context *ctx,
>      void (*log_fn) (struct inmap_context *ctx,
>                      void *user_data,
>                      unsigned int level,
>                      const char *file,
>                      int line,
>                      const char *fn,
>                      const char *format,
>                      va_list args));
> 
> /**
>  * Return the context file-descriptor
>  *
>  * @param[in] ctx  Valid context
>  *
>  * If the context was created with the @INMAP_CONTEXT_MONITOR_CONF_FILES
>  * flag, it will allocate kernel resources to monitor configuration files.
>  * These report changes via file-descriptors. You can track these via this
>  * function.
>  * Whenever the file-descriptor is readable, you must call
>  * inmap_context_dispatch() to let the library handle the events.
>  *
>  * If you didn't use config-file tracking, this will always return -1 and
>  * there is no reason to call this or inmap_context_dispatch().
>  *
>  * @returns file-descriptor or -1 if not used
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_dispatch()
>  */
> int inmap_context_get_fd(struct inmap_context *ctx);
> 
> /**
>  * @enum inmap_context_dispatch_event
>  * Dispatch events
>  *
>  * Events that are handled by the context object and returned to the caller
>  * so they can react to it.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_dispatch()
>  */
> enum inmap_context_dispatch_event {
> /**
> * @INMAP_CONTEXT_CONF_CHANGED
> * Configuration changed
> *
> * This is returned whenever a configuration file was modified and
> * @INMAP_CONTEXT_MONITOR_CONF_FILES was used. The library itself
> * does not react to this event, so you need to reread the
> * configuration files yourself via inmap_context_conf_refresh() and
> * recreate the inmap_evdev objects that might have changed.
> *
> * @memberof inmap_context
> */
> INMAP_CONTEXT_CONF_CHANGED = (1 << 0),
> };
> 
> /**
>  * Dispatch outstanding work
>  *
>  * @param[in] ctx  Valid context object
>  *
>  * Whenever the internal file-descriptor of this context is readable (see
>  * also @inmap_context_get_fd()), you must call this function to dispatch
>  * any outstanding work.
>  * This is currently only used for the @INMAP_CONTEXT_MONITOR_CONF_FILES
>  * implementation. If @inmap_context_get_fd() does not return a valid
>  * file-descriptor, you can skip calling this function.
>  * All events that were detected are returned as bitmask so the caller can
>  * react on them.
>  *
>  * @returns @inmap_context_dispatch_event event-flags on success, negative
>  * error code on failure.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_get_fd()
>  */
> int inmap_context_dispatch(struct inmap_context *ctx);
> 
> /** @} */
> 
> /**
>  * @defgroup context-conf Library Context Configuration Files
>  * Managing configuration files
>  *
>  * Users can supply configuration files to extend the detection logic
>  * without modifying the source code. Default configurations are always
>  * used (except if INMAP_CONTEXT_NO_DEFAULT_CONF is used) but you can
>  * supply additional files for local configurations.
>  *
>  * If a configuration file is given by path or filename it can be monitored
>  * for runtime modifications if INMAP_CONTEXT_MONITOR_CONF_FILES is used.
>  * Configurations given via memory cannot be monitored.
>  *
>  * Configuration files contain matching-rules and filenames of
>  * device-configuration-files to apply for matched devices. So the main
>  * configuration file simply contains a list of names and IDs for devices
>  * that need special fixups.
>  *
>  * Syntax of configuration files is ini-style like this:
>  * @code
>  *   [match <optional-name>]
>  *   name = *name*wild*mask
>  *   bus = <bus-name>,<another-bus-name>,..
>  *   vid = <vendor-id>,<another-vendor-id>,..
>  *   pid = <product-id>,..
>  *   rules = <relative-path-to-device-conf>
>  * @endcode
>  * You can put as many of these [match] groups into a configuration file. All
>  * fields except for "rules" are optional. If a device matches a [match] block,
>  * the rules that are found in "rules" are applied to the device. Multiple
>  * blocks may match and are applied in the order as specified.
>  * Fields are matched with a logical "AND". So if "bus" and "name" are
>  * specified, the device must match both. Multiple entries in the same
>  * category are matched with a logical "OR". So if multiple "vid" entries
>  * are given, only one of them must match.
>  * Unknown rules are silently ignored. This allows to easily extend this file
>  * with further entries in the future.
>  *
>  * Rule-files contain rules that are to be applied to a device. Unknown entries
>  * are silently ignored. This allows to store additional information in
>  * these files for other libraries to use.
>  * Supported entries are:
>  * @code
>  *   [capabilities <optional-name>]
>  *   add = <cap1>,<cap2>,..
>  *   remove = <cap1>,<cap2>,..
>  *   set = <cap1>,<cap2>,..
>  * @endcode
>  * This overwrites the heuristics used to detect device capabilities. "add"
>  * causes the library to add the given capabilities to the auto-detected caps.
>  * "remove" causes the library to remove them and "set" overwrites all of
>  * them. "set" is mutually exclusive to "add" and "remove", obviously.
>  * @code
>  *   [mapping <optional-name>]
>  *   map = <type>:<code> => [<type>:]<code>,
>  *         [<type>:]<code> => [<type>:]<code>,
>  *         ..
>  * @endcode
>  * This specifies a simple mapping table. <type> must only be specified once
>  * and will automatically be kept for following entries that have no explicit
>  * <type> prefix.
>  * inmap_evdev will create a mapping table from these rules and map the
>  * specified type+code combinations to the target type+code. The "value"
>  * field cannot be modified for now.
>  *
>  * @{
>  */
> 
> /** configuration file parser flags */
> enum inmap_context_conf_flags {
> /** Allow any file type, not only regular files. */
> INMAP_CONTEXT_CONF_ALLOW_ANY = (1 << 0),
> /** Do not monitor this file. */
> INMAP_CONTEXT_CONF_DONT_MONITOR = (1 << 1),
> };
> 
> /**
>  * Add configuration file from memory buffer
>  *
>  * @param[in] ctx     Valid context object
>  * @param[in] buffer  Pointer to the memory buffer to read from. Does not
>  *                    have to be zero terminated.
>  * @param[in] length  Length of @buffer not including any possible
>  *                    terminating zero character.
>  * @param[in] flags   Optional flags for the parser or 0.
>  *
>  * Parses the buffer given in @buffer as configuration file and updates the
>  * context accordingly.
>  *
>  * @INMAP_CONTEXT_CONF_ALLOW_ANY has no effect if set and is ignored.
>  *
>  * Obviously, @INMAP_CONTEXT_MONITOR_CONF_FILES has no effect on
>  * configurations that are parsed with this function. If you want to track
>  * configuration files for changes, you must use
>  * @inmap_context_conf_add_from_path.
>  * @INMAP_CONTEXT_CONF_DONT_MONITOR is ignored, too.
>  *
>  * @returns 0 on success, negative error code on failure.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_conf_add_from_path()
>  */
> int inmap_context_conf_add_from_buffer(struct inmap_context *ctx,
>       const void *buffer, size_t length,
>       enum inmap_context_conf_flags flags);
> 
> /**
>  * Add configuration file from file path
>  *
>  * @param[in] ctx   Valid context object
>  * @param[in] path  Path to the configuration file. Must be a zero-
>  *                  terminated string.
>  *
>  * Parses the configuration file at @path and updates the context
>  * accordingly.
>  *
>  * @returns 0 on success, negative error code on failure.
>  *
>  * @memberof inmap_context
>  * @sa inmap_context_conf_add_from_buffer()
>  */
> int inmap_context_conf_add_from_path(struct inmap_context *ctx,
>     const char *path);
> 
> /**
>  * Parse configuration files
>  *
>  * @param[in] ctx  Valid context object
>  *
>  * This resets the configuration-file cache and re-reads all files. Use
>  * this whenever a configuration file changed. You also must call this
>  * after creating the context to read the default configurations.
>  *
>  * Files added via @inmap_context_conf_add_from_path() are automatically
>  * parsed while added, but can be re-parsed by calling this function.
>  *
>  * @returns 0 on success, negative error code on failure
>  *
>  * @memberof inmap_context
>  */
> int inmap_context_conf_parse(struct inmap_context *ctx);
> 
> /** @} */
> 
> /**
>  * @defgroup evdev Evdev input devices
>  * Managing evdev input device detection and rules
>  *
>  * @{
>  */
> 
> /**
>  * Create new evdev device from fd
>  *
>  * @param[in] ctx   Valid context object
>  * @param[out] out  Pointer to new evdev object is stored here
>  * @param[in] fd    File-descriptor of input evdev device
>  *
>  * Create a new inmap_evdev context and retrieve information via a normal
>  * file-descriptor. The file-descriptor is not kept by this function but
>  * only used during initialization to retrieve device-name and so on.
>  *
>  * The new evdev object will be associated with the given context. All
>  * matching rules are immediately applied and device detection will be
>  * performed.
>  *
>  * inmap_evdev objects are ref-counted. Initial ref-count will be 1.
>  *
>  * @returns 0 on success, negative error code on failure
>  *
>  * @memberof inmap_evdev
>  */
> int inmap_evdev_new_from_fd(struct inmap_context *ctx,
>    struct inmap_evdev **out,
>    int fd);
> 
> /**
>  * Create new evdev device from sysfs-path
>  *
>  * @param[in] ctx   Valid context object
>  * @param[out] out  Pointer to new evdev object is stored here
>  * @param[in] path  Path to sysfs-device directory
>  *
>  * Create a new inmap_evdev context and retrieve information via sysfs. No
>  * file-descriptor to the event-device is needed.
>  * The sysfs path @path normally points to a directory like
>  *   /sys/class/input/input<num>/
>  * Note that this must be the input-device directory, not the event/evdev
>  * device directory!
>  *
>  * The new evdev object will be associated with the given context. All
>  * matching rules are immediately applied and device detection will be
>  * performed.
>  *
>  * inmap_evdev objects are ref-counted. Initial ref-count will be 1.
>  *
>  * @returns 0 on success, negative error code on failure
>  *
>  * @memberof inmap_evdev
>  */
> int inmap_evdev_new_from_syspath(struct inmap_context *ctx,
> struct inmap_evdev **out,
> const char *path);
> 
> /**
>  * Increase inmap_evdev ref-count
>  *
>  * @param[in] evdev  Valid evdev object, or NULL
>  *
>  * Increase ref-count of @evdev by 1. Does nothing if @evdev is NULL.
>  *
>  * @memberof inmap_evdev
>  */
> void inmap_evdev_ref(struct inmap_evdev *evdev);
> 
> /**
>  * Decrease inmap_evdev ref-count
>  *
>  * @param[in] evdev  Valid evdev object, or NULL
>  *
>  * Decrease ref-count of @evdev by 1. This destroys the object immediately,
>  * iff the ref-count drops to 0. Does nothing if @evdev is NULL.
>  *
>  * @memberof inmap_evdev
>  */
> void inmap_evdev_unref(struct inmap_evdev *evdev);
> 
> /**
>  * Get device capabilities
>  *
>  * @param[in] evdev  Valid evdev object
>  *
>  * Return a bitmask of capabilities of the given device. You can use these
>  * to decide which device drivers to load on this input device.
>  *
>  * @returns bitmask of capabilities
>  *
>  * @memberof inmap_evdev
>  */
> enum inmap_capabilities inmap_evdev_get_capabilities(struct inmap_evdev *evdev);
> 
> /**
>  * Create mapping table
>  *
>  * @param[in] evdev  Valid evdev object
>  * @param[out] out   Pointer to new mapping table is stored here
>  * @param[in] caps   Capability bitmask
>  *
>  * Create new mapping tables for the capabilities given in @caps. The new
>  * table is stored in @out. If no table is available, @out will be NULL
>  * afterwards.
>  * This combines all required tables for the given capabilities in one
>  * single mapping-table. You should apply these mappings before processing
>  * the read input events.
>  *
>  * @returns 0 on success, negative error code on failure
>  *
>  * @memberof inmap_evdev
>  */
> int inmap_evdev_get_mapping(struct inmap_evdev *evdev,
>    struct inmap_mapping **out,
>    unsigned int caps);
> 
> /** @} */
> 
> /**
>  * @defgroup mapping Event mapping
>  * Mapping linux input-events
>  *
>  * @{
>  */
> 
> /**
>  * Increase ref-count of mapping table
>  *
>  * @param[in] map  Valid mapping table, or NULL
>  *
>  * Increase ref-count of @map by 1. Does nothing if @map is NULL.
>  *
>  * @memberof inmap_mapping
>  */
> void inmap_mapping_ref(struct inmap_mapping *map);
> 
> /**
>  * Decrease ref-count of mapping table
>  *
>  * @param[in] map  Valid mapping table, or NULL
>  *
>  * Decrease ref-count of @map by 1. Destroys the object iff the ref-count
>  * drops to 0. Does nothing if @map is NULL.
>  *
>  * @memberof inmap_mapping
>  */
> void inmap_mapping_unref(struct inmap_mapping *map);
> 
> /**
>  * Map linux input-event
>  *
>  * @param[in] map        Valid mapping table, or NULL
>  * @param[in,out] event  Linux input event
>  *
>  * Map the input-event in @event according to the rules in @map. If @map is
>  * NULL no mapping is applied.
>  * The mapping is performed inline, so @event will be modified by this
>  * function.
>  *
>  * @memberof inmap_mapping
>  */
> void inmap_mapping_map(struct inmap_mapping *map,
>       struct input_event *event);
> 
> /** @} */
> 
> #ifdef __cplusplus
> }
> #endif
> 
> #endif /* INMAP_H */


More information about the wayland-devel mailing list