proto: Define new ei_stylus protocol [2nd DRAFT]

Define a new protocol that provides a representation for styli. This
protocol allows libei to transport pen events from a graphics tablet.

This protocol is an unimplemented draft. A normal build will not compile
until the associated implementation is written, so it is recommended to
configure Meson to only build the documentation for the time being:

    $ meson setup out -Ddocumentation=protocol -Dlibei=disabled \
      -Dlibeis=disabled -Dliboeffis=disabled
    $ ninja -C out
This commit is contained in:
Jason Gerecke 2025-05-29 08:56:12 -07:00
parent edc8ea045a
commit 844741dbea

View file

@ -6,6 +6,7 @@
Copyright © 2010-2011 Intel Corporation
Copyright © 2012-2013 Collabora, Ltd.
Copyright © 2023 Red Hat, Inc.
Copyright © 2025 Wacom Co., Ltd.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
@ -771,6 +772,7 @@
- "ei_button"
- "ei_keyboard"
- "ei_touchscreen"
- "ei_stylus"
The interface version is equal or less to the client-supported
version in ei_handshake.interface_version for the respective interface.
@ -1592,4 +1594,366 @@
<arg name="touchid" type="uint32"/>
</event>
</interface>
<interface name="ei_stylus" version="1">
<description summary="stylus object">
Interface for stylus requests and events.
This interface is only provided once per device and where a client
requests ei_stylus.release the interface does not get re-initialized.
An EIS implmentation may adjust the behavior of the device
(including removing the device) if the interface is released.
Note that for a client to receive objects of this type, it must announce
support for the interface in ei_handshake.interface_version.
## Overview
This interface describes a stylus. A stylus is an absolute pointing tool
providing precise location and associated properties (e.g. pressure,
tilt, etc.). A stylus object is only capable of representing a single
stylus in proximity at a time. If multiple styli need to be in
proximity simultaneously, multiple stylus objects must be created.
The stylus capability may be associated with either physical or virtual
ei_device objects. In all cases, styli are absolute devices and
require an ei_device.dimension or at least one ei_device.region.
All motion events are required to lie within the defined physical
dimensions or within regions. In the case of physical devices with an
"[out-of-bounds][OOB]" margin, this margin should not be included in
the ei_device.dimension. For example: a device with a 400mm x 225mm
in-bounds area surrounded by a 2mm out-of-bounds margin on all sides
should declare an ei_device.dimension of 400mm x 225mm and not send
motion events that occur in the out-of-bounds margin.
The stylus protocol is stateful and relies on ei_device.frame to
delimit state changes. Only those properties, axes, and other values
that have changed from one frame to the next are required to be sent.
The stylus protocol does not communicate any information about the
physical(or virtual) capabilities of an individual tool. Receivers
should be prepared to receive "any" type of data and must either
appropriately handle or ignore events as desired.
[OOB]: https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#out-of-bounds-motion-events
</description>
<!-- ei_stylus client requests version 1 -->
<request name="release" since="1">
<description summary="stylus removal request">
Notification that the client is no longer interested in this stylus
object. The EIS implementation will release any resources related to
this object and send the ei_stylus.destroyed event once complete.
</description>
</request>
<request name="proximity_in" since="1" context-type="sender">
<description summary="sylus proximity in request">
Notification that a stylus is entering proximity of its tablet. The
stylus object transitions from an "out of proximity" state to an "in
proximity" state once the following ei_device.frame request has been
processed.
It is a protocol violation to send this request while the stylus object
is already in or entering proximity. It is a protocol violation to send
ei_stylus.proximity_in and ei_device.proximity_out in the same
frame. It is a protocol violation to not include ei_stylus.motion in
the same frame.
</description>
</request>
<request name="proximity_out" since="1" context-type="sender">
<description summary="stylus proximity out request">
Notification that the the stylus is leaving proximity of its tablet. The
stylus object transitions from an "in proximity" state to an "out of
proximity" state once the following ei_device.frame request has been
processed.
While a stylus is "out of proximity", all other state information
(e.g. tool type, up/down state, axis values) is invalid and must be
cleared on both the sending and receiving side.
It is a protocol violation to send this request while the stylus object
is already leaving or out of proximity. It is a protocol violation to
send ei_stylus.proximity_in and ei_device.proximity_out in the same
frame.
</description>
</request>
<request name="tool_type" since="1" context-type="sender">
<description summary="stylus tool type request">
Notification of the type of stylus entering proximity. Tool types are
identified with standard Linux [kernel input event codes][event-codes].
Senders are not required to generate this request. Receivers are
required to recognize at least `BTN_TOOL_PEN` (0x140) and
`BTN_TOOL_RUBBER` (0x141). Receivers may choose to treat styli as
`BTN_TOOL_PEN` if they do not recognize the type or do not receive this
event.
This request may only be sent in the same ei_device.frame as the
ei_stylus.proximity_in event. It is a protocol violation to send this
request at any other time.
[event-codes]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h
</description>
<arg name="type" type="uint32" summary="The Linux kernel input event code specifying the stylus type."/>
</request>
<request name="down" since="1" context-type="sender">
<description summary="stylus down request">
Notification that the stylus has come into logical contact with the
tablet.
Senders are required to generate this request to signal logical contact.
Receivers are free to treat the stylus as "up" in the absence of this
event, regardless of other axis values that may be present
(e.g. pressure, distance).
This request may only be sent while the stylus is entering or in
proximity. It is a protocol violation to send this request at any other
time. It is a protocol violation to for ei_stylus.down and
ei_stylus.up to share the same ei_device.frame.
</description>
</request>
<request name="up" since="1" context-type="sender">
<description summary="stylus up request">
Notification that the stylus has left logical contact with the tablet.
Senders are required to generate this request to signal the loss of
logical contact. Receivers are free to treat the stylus as "down" in
the absence of this event, regardless of other axis values that may be
present(e.g. pressure, distance).
This request may only be sent while the stylus is in or leaving
proximity. It is a protocol violation to send this request at any other
time . It is a protocol violation to for ei_stylus.down and
ei_stylus.up to share the same ei_device.frame.
</description>
</request>
<request name="motion" since="1" context-type="sender">
<description summary="stylus motion request">
Notification that the stylus has been moved to the given absolute
coordinates. The interpretation of values depends on if the device is
physical (mm) or virtual (pixels). Fractional pixels are allowed.
Valid `(x, y)` locations are those that exist inside of the
ei_device.dimension (for physical devices) or one of the devices
ei_device.region (for virtual devices). It is a client bug to send a
location that exists outside of these locations.The EIS implementation
may clamp out-of-range values and / or disconnect the client.
This request is required to be in the same frame as
ei_stylus.proximity_in. It may also be sent while the stylus is in or
leaving proximity. It is a protocol violation to send this request at
any other time.
</description>
<arg name="x" type="float" summary="The x position of the stylus in mm or logical pixels"/>
<arg name="y" type="float" summary="The y position of the stylus in mm or logical pixels"/>
</request>
<request name="pressure" since="1" context-type="sender">
<description summary="stylus pressure request">
Notification of the relative amount of pressure exerted on the stylus.
The valid range for pressure is `0.0 &lt;= p &lt;= 1.0`. It is a client
bug to send values outside of this range. The EIS implementation may
clamp out-of-range values and / or disconnect the client.
The value `p=0.0` indicates the stylus is experiencing "minimum" or "no"
pressure, and `p=1.0` indicates the stylus is measuring some
arbitrary "maximum pressure".
This request may only be sent while the stylus is entering, in, or
leaving proximity. It is a protocol violation to send this request at
any other time.
> [!IMPORTANT]
> Non-zero pressure does not imply logical contact, but logical
> contact _does_ imply a non-zero pressure. If a client chooses to send
> pressure values, it is a client bug to not ensure `p>0.0` when sending
> ei_stylus.down. The EIS implementation may correct illegal values
> and / or disconnect the client.
</description>
<arg name="p" type="float" summary="The tip pressure as a normalized value."/>
</request>
<request name="distance" since="1" context-type="sender">
<description summary="stylus distance request">
Notification of the relative distance between the stylus and tablet.
The valid range for distance is `0.0 &lt;= d &lt;= 1.0`. It is a client
bug to send values outside of this range. The EIS implementation may
clamp out-of-range values and / or disconnect the client.
The value `d=0.0` indicates the stylus is in physical contact with the
tablet and `d=1.0` indicates the stylus is at some arbitrary "maximum
distance".
This request may only be sent while the stylus is entering, in, or
leaving proximity. It is a protocol violation to send this request at
any other time.
> [!IMPORTANT]
> Physical contact does not imply logical contact, but logical
> contact _does_ imply physical contact. If a client chooses to send
> distance values, it is a client bug to not ensure that `d=0.0` when
> sending ei_stylus.down. The EIS implementation may correct illegal
> values and / or disconnect the client.
</description>
<arg name="d" type="float" summary="The tip-to-tablet distance as a normalized value."/>
</request>
<request name="tilt" since="1" context-type="sender">
<description summary="stylus tilt request">
Notification of the styluss tilt angles.
The valid range for each tilt angle is `-90 &lt;= tilt_[xy] &lt;= +90`.
It is a client bug to send values outside of this range. The EIS
implementation may clamp out-of-range values and / or disconnect the
client.
Each tilt angle is measured relative to the tablets Z axis. The pair
`(tilt_x=0, tilt_y=0)` indicates the stylus is being held parallel to
the Z axis, while `(tilt_x=90, tilt_y=0)` and `(tilt_x=0, tilt_y=90)`
indicate the stylus parallel to the +X and +Y axes, respectively.
This request may only be sent while the stylus is entering, in, or
leaving proximity. It is a protocol violation to send this request at
any other time.
</description>
<arg name="tilt_x" type="uint32" summary="The angle in degrees of the stylus along the tablet X axis."/>
<arg name="tilt_y" type="uint32" summary="The angle in degrees of the stylus along the tablet Y axis."/>
</request>
<request name="rotation" since="1" context-type="sender">
<description summary="stylus rotation request">
Notification of the styluss barrel rotation angle.
The valid range for barrel rotation is `0 &lt;= r &lt; 360`. It is a
client bug to send values outside of this range. The EIS implementation
may reduce out-of-range values modulo 360 and / or disconnect the
client.
The value `r=0` indicates the stylus is being held at its neutral
rotation angle. Angles increase in value as the stylus is rotated
clockwise while held.
This request may only be sent while the stylus is entering, in, or
leaving proximity. It is a protocol violation to send this request at
any other time.
</description>
<arg name="r" type="uint32" summary="The angle in degrees of the stylus about its own Z axis."/>
</request>
<request name="slider" since="1" context-type="sender">
<description summary="stylus slider request">
Notification of the relative position of the styluss slider.
The valid range for slider position is `-1.0 &lt;= s &lt;= +1.0`. It is
a client bug to send values outside of this range. The EIS
implementation may clamp out-of-range values and / or disconnect the
client.
The value `s=0.0` indicates the slider is in its neutral position, while
`s=+1.0` indicates "full forward" and `s=-1.0` "full backward".
This request may only be sent while the stylus is entering, in, or
leaving proximity. It is a protocol violation to send this request at
any other time.
</description>
<arg name="s" type="float" summary="The position of a slider present on the tool, as a normalized value."/>
</request>
<!-- ei_stylus events version 1 -->
<event name="destroyed" type="destructor" since="1">
<description summary="stylus removal notification">
This object has been removed and a client should release all associated
resources.
This object will be destroyed by the EIS implementation immediately
after this event is sent and as such the client must not attempt to use
it after that point.
</description>
<arg name="serial" type="uint32" summary="This events serial number."/>
</event>
<event name="proximity_in" since="1" context-type="receiver">
<description summary="sylus proximity in event">
See the ei_stylus.proximity_in request for more details.
</description>
</event>
<event name="proximity_out" since="1" context-type="receiver">
<description summary="stylus proximity out request">
See the ei_stylus.proximity_out request for more details.
</description>
</event>
<event name="tool_type" since="1" context-type="receiver">
<description summary="stylus tool type request">
See the ei_stylus.tool_type request for more details.
</description>
<arg name="type" type="uint32" summary="The Linux kernel input event code specifying the stylus type."/>
</event>
<event name="down" since="1" context-type="receiver">
<description summary="stylus down request">
See the ei_stylus.down request for more details.
</description>
</event>
<event name="up" since="1" context-type="receiver">
<description summary="stylus up request">
See the ei_stylus.up request for more details.
</description>
</event>
<event name="motion" since="1" context-type="receiver">
<description summary="stylus motion request">
See the ei_stylus.motion request for more details.
</description>
<arg name="x" type="float" summary="The x position of the stylus in mm or logical pixels"/>
<arg name="y" type="float" summary="The y position of the stylus in mm or logical pixels"/>
</event>
<event name="pressure" since="1" context-type="receiver">
<description summary="stylus pressure request">
See the ei_stylus.pressure request for more details.
</description>
<arg name="p" type="float" summary="The tip pressure as a normalized value."/>
</event>
<event name="distance" since="1" context-type="receiver">
<description summary="stylus distance request">
See the ei_stylus.distance request for more details.
</description>
<arg name="d" type="float" summary="The tip-to-tablet distance as a normalized value."/>
</event>
<event name="tilt" since="1" context-type="receiver">
<description summary="stylus tilt request">
See the ei_stylus.tilt request for more details.
</description>
<arg name="tilt_x" type="uint32" summary="The angle in degrees of the stylus along the tablet X axis."/>
<arg name="tilt_y" type="uint32" summary="The angle in degrees of the stylus along the tablet Y axis."/>
</event>
<event name="rotation" since="1" context-type="receiver">
<description summary="stylus rotation request">
See the ei_stylus.rotation request for more details.
</description>
<arg name="r" type="uint32" summary="The angle in degrees of the stylus about its own Z axis."/>
</event>
<event name="slider" since="1" context-type="receiver">
<description summary="stylus slider request">
See the ei_stylus.slider request for more details.
</description>
<arg name="s" type="float" summary="The position of a slider present on the tool, as a normalized value."/>
</event>
</interface>
</protocol>