Commit graph

682 commits

Author SHA1 Message Date
Peter Hutterer
8d6d23e84d eis: end any ongoing touch in response to touch_end
Even if the client is no longer emulating (and we're not queuing an
event) our local touch must be ended. Otherwise our touch will live on
forever, despite the client thinking it has ended properly.

This can't be triggered with libei because we can't send touch events
while not emulating and the only way to get into this state is pausing
the device - which already resets the state. But let's add a test case
anyway, in the hope that one day it picks up a bug.
2025-12-16 10:34:20 +10:00
Peter Hutterer
c21bdbe036 eis: keep track of touch IDs and don't allow duplicate ones
A client sending duplicate touch IDs will be disconnected but
motion or end events for touches that no longer exist will be silently
ignored.

The tracking state uses a uint64_t to store currently valid touch ids -
since the whole range of touch ids are uint32_t (including zero) this is
the simple way of using an out-of-range marker value (UINT64_MAX)
2025-12-16 10:34:20 +10:00
Peter Hutterer
b3a40f2f15 eis: quietly ignore double key presses and releases
This is only implemented on the EIS side of things because that side is
mostly what we want to protect (read: the compositors). The duplicates
are still sent on the protocol.
2025-12-16 10:34:20 +10:00
Peter Hutterer
254e8be1c5 ei: match the EI_EVENT_DEVICE_PAUSED docs with the protocol
This is a behavior break if we're looking at the documentation only but
the protocol has required the logical reset of the device since libei
0.5 - this here is just stale documentation that didn't get updated.

And keeping the state across paused/resume is too hard to get right
anyway.
2025-12-16 10:34:20 +10:00
Peter Hutterer
08d7d5918f util: free the test parameters after the run
And also ensure we have the null-termination even if
MUNIT_TEST_MAX_PARAMS are given.

Fixes: 2996a66b37 ("util: add support for parametrized tests")
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/372>
2025-12-16 00:32:21 +00:00
Peter Hutterer
73ec8dee9f eis: allow pausing the device when it is emulating
The whole point of pausing a device is to terminate the client's ability
to send events.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/367>
2025-12-15 10:51:16 +10:00
Peter Hutterer
fe47a0a1f7 Unref frame events when discarding an empty frame
Otherwise we leak that frame event.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/366>
2025-12-12 16:20:03 +10:00
Peter Hutterer
26e671f192 Swap the object id logging order
This gives us a same-sized prefix for messages, making visual parsing of
logs a bit easier.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/366>
2025-12-12 16:20:03 +10:00
Peter Hutterer
2996a66b37 util: add support for parametrized tests
munit supports test parameters (char* only) but the setup is a big
awkward/impossible in C to define statically. So lets simply pass the
parameters as one NULL-terminated string list and require names to be
prefixed with an @. During the test setup we can split that list up into
multiple parameters and pass those to the munit setup where they're
accessible via another wrapper macro:

MUNIT_TEST_WITH_PARAMS(test_foo, "@x", "1", "2", "@y", "100", "200") {
   const char *x = MUNIT_TEST_PARAM("@x");
   const char *y = MUNIT_TEST_PARAM("@y");
}

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/365>
2025-12-03 14:51:55 +10:00
Peter Hutterer
d55da9466c meson.build: apply consistent indentation
Mostly whitespace changes, the non-whitespace ones are adding trailing
commas on last arguments and moving the closing ) into a separate line
for multiline function calls.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/364>
2025-11-06 10:56:01 +10:00
Peter Hutterer
2821282dc9 libei: include math.h for fmod
For correctness only, looks like math.h is already pulled in from
elsewhere anyway.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/362>
2025-11-03 15:27:38 +10:00
Peter Hutterer
39a222868f proto: add a device ready request
The protocol currently supports a ei_device.done event to notify
the ei client that the initial description of the device is complete.
For some future use-cases the client may need to futher negotiate
properties of the device. For example for tablet tools the client may
narrow down capabilities of the tool.

The sequence with the new request is thus e.g.
     -> ei_seat.device
     -> ei_device.name
     -> ei_device.interface
     -> ei_device.interface
     -> ei_device.done
     <- ei_device.ready
     -> ei_device.resumed

In libei the request is sent automatically on unref of
the DEVICE_ADDED event. This makes clients immediately compatible
and for the typical (future) use-case of device configuration. Said
configuration will likely be handled in response to the DEVICE_ADDED
event anyway.

In libeis, a new EIS_EVENT_DEVICE_READY event that is sent when the client
sends that same event on the protocol, informing the EIS implementation
that this device is ready. For clients that do not support that version
the event is emulated immediately after sending ei_device.done.

This requires a flag bit to be long-term maintainable. The typical
EIS implementation currently calls eis_device_add() immediately
followed by eis_device_resume(). This doesn't leave any room to
wait for the client's ei_device.ready request.

One backwards-compatible solution could be to buffer the
eis_device_resume() until the ei_device.ready has been received but this
is fraught with hairy corner cases, e.g. if the client is a receiver
context we would also have to buffer all events immediately sent to the
client.

So instead, we have a flag in the context and if set by the caller, we
change the internal behavior to match ei_device interface version 3.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/346>
2025-10-17 13:38:47 +10:00
Peter Hutterer
7141566924 doc: two doxygen typo fixes
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/361>
2025-10-17 13:30:48 +10:00
Jan Beich
4f11112be0 eis: implement getting client PID for BSDs after 70cfc6eed2
src/libeis-socket.c:192:15: error: variable has incomplete type 'struct ucred'
  192 |         struct ucred ucred;
      |                      ^
src/libeis-socket.c:192:9: note: forward declaration of 'struct ucred'
  192 |         struct ucred ucred;
      |                ^
src/libeis-socket.c:194:65: error: use of undeclared identifier 'SO_PEERCRED'
  194 |         int rc = getsockopt(source_get_fd(client->source), SOL_SOCKET, SO_PEERCRED, &ucred, &len);
      |                                                                        ^

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/357>
2025-08-26 09:33:24 +02:00
Jonas Ådahl
5e57b1ed5f ei: Expose ei_event_ref()
As with eis, expose ei_event_ref() as well, for consistency.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/340>
2025-08-21 17:08:53 +02:00
Jonas Ådahl
42b9a89371 eis: Expose eis_event_ref()
This makes handling prolonged synchronization sequences easier, as one
doesn't have to work around only being allowed to hold one reference.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/340>
2025-08-21 17:08:53 +02:00
Jonas Ådahl
8d86ada12d ei: Send sync done event on last event unref
This allows the application to hold the sync event for a while longer,
e.g. to ensure previous events from ei have passed through relevant
plumbing and reached their internally intended targets, which might
happen synchronously between each processed ei event.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/340>
2025-08-21 17:08:53 +02:00
Jonas Ådahl
1010cdff3c eis: Send sync done event on last event unref
This allows the application to hold the sync event for a while longer,
e.g. to ensure previous events from EIS have passed through relevant
plumbing and reached their internally intended targets, which might
happen synchronously between each processed EIS event.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/340>
2025-08-21 17:03:27 +02:00
Peter Hutterer
3b98946b9a eis: only send scroll/button capabilities if the client supports them
Commit a902d5dbd8 ("protocol: replace the capabilities enum with an interface list")
added automatic handling for button/scroll interfaces on the protocol
because the libeis C API didn't have those as separate interfaces yet.
Any EIS implementation with POINTER/POINTER_ABSOLUTE would always
announce BUTTON/SCROLL capabilities.

Later in commit e6954b76d3 ("eis: change the API to match the protocol interfaces closer")
the required C APIs were added but this handling was never removed so an
EIS implementation always replied with button/scroll capabilities even
where not set. Fix this by removing this automatic announcement.

Fixes: e6954b76d3 ("eis: change the API to match the protocol interfaces closer")
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/353>
2025-08-05 07:02:57 +00:00
Peter Hutterer
7347aeacd2 eis: only send interface versions that the client announced
Do not reply with interfaces that the client never requested.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/353>
2025-08-05 07:02:57 +00:00
Peter Hutterer
1faaacda6e eis: send the interface version for the scroll interface
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/353>
2025-08-05 07:02:57 +00:00
Peter Hutterer
45c526bcc9 ei: indentation fix
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/351>
2025-07-24 11:07:32 +10:00
Peter Hutterer
297f95efac utils: add the etrace macro
Same as the existing trace but prints to stderr. And #include stdio so
we can use this file as-is instead of needing extra includes.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/351>
2025-07-24 11:07:32 +10:00
Peter Hutterer
55335b9030 libei: fix the docs for the various _unref functions
Copy/paste from ei_unref but none of the others will disconnect the
context.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/349>
2025-07-24 00:54:06 +00:00
Peter Hutterer
12237f19ea ei: don't use the connection until we have one
If we're in EI_STATE_BACKEND ei->connection is NULL, causing a segfault
if in this state we unref our ei context.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/350>
2025-07-18 13:26:01 +10:00
Jonas Ådahl
6194880aa9 libeis: remove leftover debug log
Fixes: 73e0e8d339 ("eis: add EI_EVENT_SYNC as opaque event to correctly schedule callbacks")
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/348>
2025-07-16 13:42:13 +10:00
Peter Hutterer
5567524ecc Swap accidental trailing comma for a semicolon
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/347>
2025-07-11 00:59:06 +00:00
Jason Gerecke
883a60d4e6 oeffis: Correct spelling errors in log messages
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/343>
2025-07-02 14:03:34 -07:00
Jason Gerecke
6aa4dc0c7e doc: Correct spelling errors in the code documentation
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/343>
2025-07-02 14:03:34 -07:00
David Redondo
70cfc6eed2 Make it possible to fetch the pid of a client in socket mode
This is useful to get some more info about clients that try to
connect.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/339>
2025-07-01 08:50:48 +02:00
Kacper Piwiński
54e71e6dd5 util: don't call function in macro argument
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/342>
2025-06-29 07:48:45 +00:00
Kacper Piwiński
1b11d10ff2 util: use already computed strlen
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/342>
2025-06-29 07:43:34 +00:00
Peter Hutterer
edc8ea045a eis: don't warn about EPIPE, just debug-log it
While it's not the friendliest way of a client to exit, we do need to
expect clients to disconnect any time and that shouldn't trigger
warnings, it's somewhat expected behavior.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/337>
2025-06-16 11:20:21 +10:00
Peter Hutterer
dbeff9a90d test: add a bunch of strv helpers
Taken from libinput

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/337>
2025-06-16 11:20:21 +10:00
Jason Gerecke
50ff529a76 Fix MIT license header text
Corrects an issue where a wild search-and-replace mangled the license
texts on protocol implementations.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/335>
2025-05-29 23:07:48 +00:00
Jonas Ådahl
ee27dd5c92 ei-device: Don't leak fd when receiving the keymap
The ei_keymap dups the file descriptor, so lets close the one we
received from the demarshaller.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/334>
2025-05-22 22:43:35 +02:00
Peter Hutterer
daba46a2ae eis: if a client is slow, queue up messages for future delivery
If a receiver client stops calling ei_dispatch for a while eventually
we fill up the send buffer, causing messages to be quietly dropped.
When the client resumes the message stream resumes with whatever we send
next but that can leave the client in an inconsistent state.

deskflow hit this in the server-side where our event sequence of pointer
motion+frames eventually filled up the buffer, causing
eis_device_stop_emulating() to be silently dropped. On the next
InputCapture sequence eis_device_start_emulating() was sent to an
already emulating client (as seen by the client).

This patch adds a secondary queue, if we fail to send a message with
EAGAIN queue it up and flush that queue whenever the next message is
sent. Meanwhile any newly added messages go straight into that queue.

The caveat here: a nonresponding client will eventually trigger OOM,
there is no upper limit on the messages yet

This is the libeis version of
commit 69e973e6b3 ("ei: queue unsent messages for later delivery if our buffer is full")

Closes: #79
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/331>
2025-05-02 15:40:47 +10:00
Peter Hutterer
247a3d49d7 ei: print the sequence number on error for a start_emulating event
This may help debugging which sequence triggered an error.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/330>
2025-05-02 05:39:52 +00:00
Corentin Noël
eda5b90760 meson.build: Use the correct name for the libraries overrides
The libraries are actually suffixed with the API number, use the same value as
their pkgconfig basenames.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/326>
2025-03-26 15:33:34 +01:00
Erik Jensen
1152c038ee Specify MODIFIERS to be sent for any state change.
Updates protocol and API documentation to specify that the modifiers
event should be sent by the EIS implementation every time the modifier
or group state changes, including when the change is triggered by key
events on the emulated keyboard.

The previous approach of expecting the client to track modifier state
using xkb_state_update_key() for injected keys resulted in multiple
opportunities for the client and server to get out of sync (both due to
unavoidable race conditions and due the client not having access to the
complete state used by the server to calculate state changes), with no
way for the client to ensure it had a correct modifier map short of
unbinding and rebinding the seat.

The new approach allows the client to track state solely by applying
modifiers events with xkb_state_update_mask(), simplifying client
implementation. Because the event is sent for all changes, the client
can use ei_connection.sync / ei_ping() to ensure that it has received
the latest state incorporating all key requests sent prior to the sync
request (along with any externally-caused modifier state changes that
may have occured up to the time the sync message was received).

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/318>
2024-12-18 04:41:11 +00:00
Peter Hutterer
564f14a739 ei: add EI_EVENT_SYNC as opaque event to correctly schedule callbacks
See the corresponding eis commit for details.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
73e0e8d339 eis: add EI_EVENT_SYNC as opaque event to correctly schedule callbacks
This event is required to fix an issue with the current
ei_callback.done handling in libeis: previously we would imediately send
the ei_callback.done upon receiving ei_connection.sync from the client.
This results in incorrect behavior as we may have events in the queue
(and/or pending a frame) that the EIS implementation hasn't seen yet.
For example a client sending:
- ei_pointer.motion
- ei_connection.sync
- ei_device.frame
- ei_connection.sync

Will queue a motion + frame event on the EIS side during eis_dispatch()
but immediately receive done events for both sync requests.

This could be handled purely internally by keeping the sync event in the
queue but hidden to the caller - and automatically calling done when
it's that events turn, i.e. something like:

```
  struct eis_event *eis_get_event(struct eis) {
      struct eis_event *e = first_event(eis);
      if (e == EIS_EVENT_SYNC) {
           eis_callback_send_done(e);
           eis_event_unref(e);
           e = next_event(eis);
      }
      return e;
  }
```

but that opens us up to a set of potential bugs detailed in
https://gitlab.freedesktop.org/libinput/libei/-/issues/71#note_2694603

So let's go the easy route by having a new event type that does nothing
other than eis_event_unref() in the EIS implementation. This way we can
queue the event and have everything behave in-order and as expected.

Closes #71

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
e40796402b eis: add eis_ping() and the matching EIS_EVENT_PONG
Identical to "ei: add ei_ping() and the matching EI_EVENT_PONG" but for
libeis.

This wraps around ei_connection.ping to allow a C API user to add
synchronization points.

Closes #69

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
a278c7b371 ei: add ei_ping() and the matching EI_EVENT_PONG
This wraps around ei_connection.sync to allow a C API user to add
synchronization points.

Closes #69

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
2cc5e56e28 eis: revamp the internal sync callback
Identical to "ei: revamp the internal sync callback" but for libeis.

In prep work for exposing some of this to the caller, this adds a new
object that carries the our callbacks including the user data (if any).
This is an internal system only and is only used in the handshake
implementation where we don't have userdata anyway.

The new approach is: the callback has an object with a done() and
destroy() callback and the user data, done() is called when we receive
the message from the protocol, destroy() on destroy regardless whether
we got done() first.

This allows a caller to clean up user data even where the callback was
not triggered because we got disconnected first.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
95eb3c4bb3 ei: revamp the internal sync callback
In prep work for exposing some of this to the caller, this adds a new
object that carries the our callbacks including the user data (if any).
This is an internal system only and is only used in the handshake
implementation where we don't have userdata anyway.

The new approach is: the callback has an object with a done() and
destroy() callback and the user data, done() is called when we receive
the message from the protocol, destroy() on destroy regardless whether
we got done() first.

This allows a caller to clean up user data even where the callback was
not triggered because we got disconnected first.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/316>
2024-12-18 04:30:01 +00:00
Peter Hutterer
91e0b8961b doc: specifically mention that unknown events must be unref'd
And document the event type enums as non-exhaustive.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/322>
2024-12-17 16:00:59 +10:00
Peter Hutterer
9c35a57cfe doc: fix some linewrapping issues
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/322>
2024-12-17 15:59:02 +10:00
Peter Hutterer
b1c1c5d579 Add the ei_touchscreen.cancel event and ei_touch_cancel()
In the protocol it's a new request/event that is sent instead of the
touch up event.

In the library this is implemented as ei_touch_cancel() which
transparently sends cancel() or up depending on the EIS implementation
support. This is mirrored for the EIS implementation.

Where touch cancel is received as an event it is presented
as EI_EVENT_TOUCH_UP with an ei_event_touch_is_cancel() flag to
check if it was a cancel. This is required for backwards compatbility,
we cannot replace the TOUCH_UP event with a TOUCH_CANCEL event without
breaking existing callers. To add a new event type we would need clients
announcing support for those event types but that's an effort that's
better postponed until we have a stronger need for it (see #68).

Closes #60

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/308>
2024-12-17 15:12:56 +10:00
Peter Hutterer
561cfd009e doc: unwinding state before stop_emulating is the caller's responsibility
Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/308>
2024-12-11 10:09:34 +10:00