proto: Define new ei_stylus protocol [4th DRAFT]

Updates to the ei_stylus protocol from the previous draft.

  - Protocol documentation is rewritten to better support allowing each
    ei_device with this interface to represent a unique physical stylus.
    (Previous drafts were written more from the POV of the digitizer
    which may see different physical styli come and go.)

  - Capabilities are now a static, negotiated property of each stylus
    instead of dynamically changing on proximity.

  - Introduce "erase_start" and "erase_end" (and an "erase" capability)
    that signals when a tool's eraser function is active. This allows
    a stylus to start/stop erasing without having to change identity.

  - Tool type has been removed. The tool type is now implied through the
    set of capabilities and whether the tool is erasing or not.

  - Numerous minor nits of all sorts have been found and corrected.

This commit does *not* introduce a new "ei_device.ready" request or any
way of allowing the client to request more stylus devices from the server.
Such requests may be coming in the future, however.
This commit is contained in:
Jason Gerecke 2025-06-17 15:36:12 -07:00
parent 621e36543a
commit f07b39c93d

View file

@ -743,8 +743,9 @@
any relative movement on this region for that movement to match the same
*physical* movement on another region.
It is an EIS implementation bug to advertise the touch and/or absolute pointer capability
on a device_type.virtual device without advertising an ei_region for this device.
It is an EIS implementation bug to advertise the touch, absolute pointer, and/or
stylus capabilities on a device_type.virtual device without advertising an ei_region
for this device.
This event is optional and sent immediately after object creation. Where a device
has multiple regions, this event is sent once for each region.
@ -1599,32 +1600,39 @@
<description summary="stylus object">
Interface for stylus requests and events.
A stylus is an absolute pointing tool commonly used for writing,
drawing, and other tasks traditionally accomplished with a pen or
pencil. Physical styli are used with digitizers (e.g. graphics tablets
or specially-enabled touchscreens) that sense location and may relay
other information such as pressure, tilt angles, etc. This interface
provides a basic representation of an individual stylus tool. If
multiple styli need to be tracked or in proximity simultaneously,
multiple stylus objects must be created. Similarly, if a stylus or
digitizer has other features (e.g. buttons or touch input) that need to
be represented, other EI objects or interfaces may need to be created.
A stylus is an absolute pointing tool commonly used for writing, drawing,
and other tasks traditionally accomplished with a pen or pencil. This
interface represents the various semantics and properties common to these
kinds of tools. An ei_device may use this interface alone or in
combination with other interfaces to emulate tools with additional
features. For example, a tool with physical buttons may be emulated by
creating an ei_device that has both this and an ei_button interface.
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.
When adding this interface to an ei_device, the server and client are
required to negotiate tool capabilities. Negotiation is performed by the
server first sending ei_stylus.tool_capabilities prior to ei_device.done
and then the client responding with ei_stylus.bind_tool_capabilities
prior to starting emulation for the first time.
This 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.
This interface may be used on both ei_device.device_type.virtual and
ei_device.device_type.physical devices. As an interface with absolute
motion, virtual devices must declare an arbitrary set of regions that
are be valid for motion events. For physical devices, the server must
send an ei_device.dimensions that reflects the size of the active area
of the stylus' digitizer. This size **must not** include any
"[out-of-bounds][OOB]" margin that may exist (e.g. a digitizer with a
404 x 229 mm active area and 2mm margin on all sides should have a
declared size of only 400 x 225 mm).
Implementations are free to decide how they handle multiple styli. For
example, a sender that is capable of distinguishing two styli (e.g. by
serial number) may choose to use a unique ei_device object for each
stylus, making it possible for the receiver to keep track of which tool
is in use. Senders are not obligated to do this; it is equally valid for
them to discard any distinguishing information that they may (or may not)
have and use a single ei_device for all styli. Similarly, receivers are
free to choose whether to use or discard information about the source
ei_device after processing.
This interface is only provided once per device and where a client
requests ei_stylus.release the interface does not get re-initialized. An
@ -1704,14 +1712,15 @@
This enum denotes capability types for the ei_stylus.
A capability describes a particular type of data that may be reported
by a device or tool.
by a device or tool. Each capability is a bit flag that may be set in
a mask describing a full set of capabilities.
</description>
<entry name="motion" value="1" summary="motion data may be reported"/>
<entry name="erase" value="1" summary="the tool may act as an eraser"/>
<entry name="pressure" value="2" summary="pressure data may be reported"/>
<entry name="distance" value="3" summary="distance data may be reported"/>
<entry name="tilt" value="4" summary="tilt data may be reported"/>
<entry name="rotation" value="5" summary="rotation data may be reported"/>
<entry name="slider" value="6" summary="slider data may be reported"/>
<entry name="distance" value="4" summary="distance data may be reported"/>
<entry name="tilt" value="8" summary="tilt data may be reported"/>
<entry name="rotation" value="16" summary="rotation data may be reported"/>
<entry name="slider" value="32" summary="slider data may be reported"/>
</enum>
<request name="release" since="1">
@ -1722,6 +1731,25 @@
</description>
</request>
<request name="bind_tool_capabilities" since="1">
<description summary="stylus tool capability bind request">
Request to bind to a given set of tool capabilities. This is used
by clients to describe which subset of server-supported capabilities
may be sent by this particular stylus.
Clients are required to send this in response to the
ei_stylus.tool_capabilities event. It is required to be sent prior to
the first ei_device.start_emulating request. It is a protocol violation
to not provide this feedback back to the server. It is a protocol
violation to include capabilities that were not present in the server
event.
It is a protocol violation to send requests or events for unbound
capabilities.
</description>
<arg name="capabilities" type="uint64" summary="A mask of capabilities that the client wishes to handle"/>
</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 digitizer. The
@ -1749,12 +1777,13 @@
automatically transitions to an "out of proximity" state.
Once a stylus is "out of proximity", all other state information
(e.g. tool type, up/down state, axis values) is considered invalid and
must be cleared on both the sending and receiving side.
(e.g. tool type, up / down / erase state, axis values) is considered
invalid and must be cleared on both the sending and receiving side.
The frame containing this request may contain updates of the stylus
state (location, tilt, etc.) that represents its final known valid
properties.
properties. It should not contain events that attempt to explicitly
reset state.
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
@ -1763,44 +1792,46 @@
</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].
<request name="erase_start" since="1" context-type="sender">
<description summary="erase start request">
Notification that the stylus's eraser feature has been activated.
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.
Physical styli often include some kind of eraser feature, activated by
flipping the tool over or holding a button down. These button-activated
tools in particular may start or stop erasing without ever leaving
proximity.
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.
The default state for tools is "not erasing".
[event-codes]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h
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.erase_start and
ei_stylus.erase_stop to share the same ei_device.frame. It is a client
bug to send this request when the ei_stylus.capability.erase capability
is not bound. The EIS implementation may ignore unbound requests and /
or disconnect the client.
</description>
<arg name="code" type="uint32" summary="The Linux kernel input event code specifying the stylus type."/>
</request>
<request name="tool_capability" since="1" context-type="sender">
<description summary="stylus tool capability request">
Notification that the tool entering proximity has a particular
capability. Sending this request one or more times provides the
receiver with information about what kind of events it should
expect to receive.
<request name="erase_stop" since="1" context-type="sender">
<description summary="erase stop request">
Notification that the stylus's eraser feature has been deactivated.
Senders are not required to generate this request. If no capabilities
are sent for a particular proximity, then receivers should treat it
as signaling that the tool has unknown capabilities and assume that
all defined capabilities are potentially valid.
Physical styli often include some kind of eraser feature, activated by
flipping the tool over or holding a button down. These button-activated
tools in particular may start or stop erasing without ever leaving
proximity.
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. It is a protocol violation to send a
tool capability that is outside the set of device capabilities.
The default state for tools is "not erasing".
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.erase_start and
ei_stylus.erase_stop to share the same ei_device.frame. It is a client
bug to send this request when the ei_stylus.capability.erase capability
is not bound. The EIS implementation may ignore unbound requests and /
or disconnect the client.
</description>
<arg name="capability" type="uint32" enum="capability" summary="A capability of this tool"/>
</request>
<request name="down" since="1" context-type="sender">
@ -1810,13 +1841,13 @@
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).
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.
time. It is a protocol violation to for ei_stylus.down and ei_stylus.up
to share the same ei_device.frame.
</description>
</request>
@ -1828,12 +1859,12 @@
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).
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.
time. It is a protocol violation to for ei_stylus.down and ei_stylus.up
to share the same ei_device.frame.
</description>
</request>
@ -1844,9 +1875,9 @@
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.dimension (for physical devices) or one of the device's
ei_device.region (for virtual devices). It is a client bug to send a
location that exists outside of these locations.The EIS implementation
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
@ -1866,8 +1897,8 @@
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
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
@ -1876,10 +1907,10 @@
> [!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.
> contact _does_ imply a non-zero pressure. If a client has bound the
> pressure capability, it is a bug to not ensure `p &gt; 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>
@ -1893,8 +1924,8 @@
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
digitizer and `d=1.0` indicates the stylus is at some arbitrary
The value `d = 0.0` indicates the stylus is in physical contact with the
digitizer 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
@ -1903,8 +1934,8 @@
> [!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
> contact _does_ imply physical contact. If a client has bound the
> distance capability, it is a 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>
@ -1913,7 +1944,7 @@
<request name="tilt" since="1" context-type="sender">
<description summary="stylus tilt request">
Notification of the styluss tilt angles.
Notification of the stylus's tilt angles.
The valid range for each tilt angle is `-90.0 &lt;= tilt_[xy] &lt;=
+90.0`. It is a client bug to send values outside of this range. The
@ -1921,9 +1952,10 @@
the client.
Each tilt angle is measured relative to the digitizer's 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.
`(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
@ -1935,14 +1967,14 @@
<request name="rotation" since="1" context-type="sender">
<description summary="stylus rotation request">
Notification of the styluss barrel rotation angle.
Notification of the stylus's barrel rotation angle.
The valid range for barrel rotation is `0.0 &lt;= r &lt; 360.0`. 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
The value `r = 0.0` indicates the stylus is being held at its neutral
rotation angle. Angles increase in value as the stylus is rotated
clockwise while held.
@ -1955,15 +1987,16 @@
<request name="slider" since="1" context-type="sender">
<description summary="stylus slider request">
Notification of the relative position of the styluss slider.
Notification of the relative position of the stylus's 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".
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
@ -1983,7 +2016,18 @@
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."/>
<arg name="serial" type="uint32" summary="This event's serial number."/>
</event>
<event name="tool_capabilities" since="1">
<description summary="stylus tool capabilities event">
See the ei_stylus.bind_tool_capabilities request for more details.
The server sends this event after attaching the ei_stylus interface
to an ei_device. This event describes the set of capabilities that
the server is willing to let the client to bind to.
</description>
<arg name="capabilities" type="uint64" summary="A capability mask for the events available through this interface"/>
</event>
<event name="proximity_in" since="1" context-type="receiver">
@ -1993,39 +2037,37 @@
</event>
<event name="proximity_out" since="1" context-type="receiver">
<description summary="stylus proximity out request">
<description summary="stylus proximity out event">
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.
<event name="erase_start" since="1" context-type="receiver">
<description summary="erase start event">
See the ei_stylus.erase_start request for more details.
</description>
<arg name="code" type="uint32" summary="The Linux kernel input event code specifying the stylus type."/>
</event>
<request name="tool_capability" since="1" context-type="sender">
<description summary="stylus tool capability request">
See the ei_stylus.tool_capability request for more details.
<event name="erase_stop" since="1" context-type="receiver">
<description summary="erase stop event">
See the ei_stylus.erase_stop request for more details.
</description>
<arg name="capability" type="uint32" enum="capability" summary="A capability of this tool"/>
</request>
</event>
<event name="down" since="1" context-type="receiver">
<description summary="stylus down request">
<description summary="stylus down event">
See the ei_stylus.down request for more details.
</description>
</event>
<event name="up" since="1" context-type="receiver">
<description summary="stylus up request">
<description summary="stylus up event">
See the ei_stylus.up request for more details.
</description>
</event>
<event name="motion" since="1" context-type="receiver">
<description summary="stylus motion request">
<description summary="stylus motion event">
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."/>
@ -2033,21 +2075,21 @@
</event>
<event name="pressure" since="1" context-type="receiver">
<description summary="stylus pressure request">
<description summary="stylus pressure event">
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">
<description summary="stylus distance event">
See the ei_stylus.distance request for more details.
</description>
<arg name="d" type="float" summary="The tip-to-digitizer distance as a normalized value."/>
</event>
<event name="tilt" since="1" context-type="receiver">
<description summary="stylus tilt request">
<description summary="stylus tilt event">
See the ei_stylus.tilt request for more details.
</description>
<arg name="tilt_x" type="float" summary="The angle in degrees of the stylus along the digitizer X axis."/>
@ -2055,14 +2097,14 @@
</event>
<event name="rotation" since="1" context-type="receiver">
<description summary="stylus rotation request">
<description summary="stylus rotation event">
See the ei_stylus.rotation request for more details.
</description>
<arg name="r" type="float" 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">
<description summary="stylus slider event">
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."/>