Previously we had ei_seat.capabilities and ei_device.capabilities,
both referring to the same enum. The seat caps were used to bind,
the device caps were used to announce capabilities.
The device caps were already mostly superfluous as the information
they carried was implicitly available by the set of interfaces
the device announced - if the device has a keyboard interface
it must also have the keyboard capability.
So let's drop the separate enum and make the capabilities
the set of supported interfaces. In the device we can drop the
event directly and just send the interface list. In the seat
we have a capability event that sends each *possible* interface
with a custom-assigned mask. The client can then use that mask
to bind to the capability as before.
For example:
<- ei_seat.capability(0x1, "ei_pointer")
<- ei_seat.capability(0x4, "ei_keyboard")
<- ei_seat.capability(0x8, "ei_touchscreen")
<- ei_seat.done()
-> ei_seat.bind(0x4 | 0x8) # bind to keyboard and touchscreen
<- ei_seat.device()
-> ei_device.interface("ei_keyboard")
-> ei_device.interface("ei_touchscreen")
<- ei_device.done()
In the generated bindings we simply use the interface index
to generate the masks, but the protocol at least states that
the mask may not be constant.
Because the button/scroll interfaces are not exposed by the C API, some
of the handling is a bit awkward since we need to use both depending
whether we have pointer/pointer_absolute selected.
Fixes#28
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Split the ei_pointer protocol interface into ei_pointer,
ei_pointer_absolute, ei_scroll and ei_button.
This gets rid of the slightly awkward pointer vs pointer absolute
handling. Those were two different capabilities but tied to the same
interface.
Plus it paves the way for devices that are keyboards with scroll
buttons, etc.
The protocol name on an interface is a fixed string that is part of
the ABI since it's used in a few messages (e.g.
ei_handshake.interface_version). To avoid typos, let's expose that
string in the scanner and #define it in the generated sources.
As the protocol spec says, EIS should treat this as already disconnected
and not touch the connection.
This fixes a memleak if a client connects and immediately disconnects -
when EIS processes the EIS_EVENT_CLIENT_CONNECT it may set up a bunch of
things like seats (the eis-demo-server does this). Then, later, when
the EIS_EVENTE_CLIENT_DISCONNECT is processed, it calls
eis_client_disconnect() but we were already in the disconnected state
and the seats would not get released.
Previously, we'd send one interface_version event for "ei_handshake"
immediately but all others after the client requests handshake.finish.
This was too confusing to document and not clear how it would work, so
let's make this simpler by splitting it up.
There is now a handshake_version event from the server, sent immediately
on connection that denotes the maximum version number for the interface.
And a handshake_version request from the client which must be the first
one by the client.
This tests the protocol layer which is hard to test using libei/libeis.
Similar to the generated C bindings we compile a eiproto.py file that is
then used in the test to talk protocol directly to the eis-demo-server
that we start up.
By sending the specific messages and checking things happen as we expect
on the socket we can verify that the EIS implementation is correct (and
robust enough).
In theory this could also be used to test some other binary with an EIS
implementation and the scaffolding is there to set LIBEI_TEST_SERVER to
that binary. Wether this works is untested though...