mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-07 12:20:15 +01:00
The internal enumerator name changed. Signed-off-by: David Redondo <kde@david-redondo.de>
498 lines
13 KiB
C
498 lines
13 KiB
C
/*
|
|
* Copyright © 2020 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "util-object.h"
|
|
#include "util-io.h"
|
|
|
|
#include "proto/ei.pb-c.h"
|
|
#include "libei-proto.h"
|
|
#include "brei-shared.h"
|
|
|
|
static void servermessage_cleanup(ServerMessage **m) {
|
|
if (*m)
|
|
server_message__free_unpacked(*m, NULL);
|
|
}
|
|
#define _cleanup_servermessage_ _cleanup_(servermessage_cleanup)
|
|
|
|
|
|
int
|
|
ei_proto_handle_message(struct ei *ei,
|
|
const struct ei_proto_interface *interface,
|
|
struct brei_message *bmsg)
|
|
{
|
|
_cleanup_servermessage_ ServerMessage *proto = server_message__unpack(NULL,
|
|
bmsg->len,
|
|
(const unsigned char*)bmsg->data);
|
|
if (!proto)
|
|
return -EAGAIN;
|
|
|
|
#define call(field, ...) \
|
|
({ \
|
|
int r = (interface->field == NULL) ? -EPROTO : interface->field(__VA_ARGS__); \
|
|
log_debug(ei, "message type '" #field "': %d\n", r); \
|
|
r; \
|
|
})
|
|
|
|
int rc;
|
|
switch (proto->msg_case) {
|
|
case SERVER_MESSAGE__MSG_CONNECTED:
|
|
rc = call(connected, ei);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DISCONNECTED:
|
|
rc = call(disconnected, ei);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_SEAT_ADDED:
|
|
rc = call(seat_added, ei,
|
|
proto->seat_added->seatid,
|
|
proto->seat_added->name, proto->seat_added->capabilities);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_SEAT_REMOVED:
|
|
rc = call(seat_removed, ei,
|
|
proto->seat_removed->seatid);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_ADDED:
|
|
rc = call(device_added, ei,
|
|
proto->device_added->deviceid,
|
|
proto->device_added->seatid,
|
|
proto->device_added->name,
|
|
proto->device_added->capabilities);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_DONE:
|
|
rc = call(device_done, ei,
|
|
proto->device_done->deviceid);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_KEYMAP:
|
|
{
|
|
int fd = brei_message_take_fd(bmsg);
|
|
rc = call(device_keymap, ei,
|
|
proto->device_keymap->deviceid,
|
|
proto->device_keymap->keymap_type,
|
|
fd,
|
|
proto->device_keymap->keymap_size);
|
|
xclose(fd);
|
|
}
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_REGION:
|
|
rc = call(device_region, ei,
|
|
proto->device_region->deviceid,
|
|
proto->device_region->offset_x,
|
|
proto->device_region->offset_y,
|
|
proto->device_region->width,
|
|
proto->device_region->height,
|
|
proto->device_region->scale);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_KEYBOARD_MODIFIERS:
|
|
rc = call(keyboard_modifiers, ei,
|
|
proto->keyboard_modifiers->deviceid,
|
|
proto->keyboard_modifiers->depressed,
|
|
proto->keyboard_modifiers->latched,
|
|
proto->keyboard_modifiers->locked,
|
|
proto->keyboard_modifiers->group);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_REMOVED:
|
|
rc = call(device_removed, ei,
|
|
proto->device_removed->deviceid);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_RESUMED:
|
|
rc = call(device_resumed, ei,
|
|
proto->device_resumed->deviceid);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_DEVICE_PAUSED:
|
|
rc = call(device_paused, ei,
|
|
proto->device_paused->deviceid);
|
|
break;
|
|
case SERVER_MESSAGE__MSG_PROPERTY:
|
|
rc = call(property, ei,
|
|
proto->property->name,
|
|
proto->property->value[0] ? proto->property->value : NULL,
|
|
proto->property->permissions);
|
|
break;
|
|
default:
|
|
rc = -EBADMSG;
|
|
break;
|
|
}
|
|
|
|
return rc < 0 ? rc : (int)bmsg->len;
|
|
}
|
|
|
|
static inline void
|
|
log_wire_message(struct ei *ei, const ClientMessage *msg, int error)
|
|
{
|
|
const char *message = NULL;
|
|
|
|
#define MSG_STRING_CASE(_name) \
|
|
case CLIENT_MESSAGE__MSG_##_name: message = #_name; break;
|
|
|
|
switch (msg->msg_case) {
|
|
#if PROTOBUF_C_VERSION_NUMBER >= 1004000
|
|
case _CLIENT_MESSAGE__MSG__CASE_IS_INT_SIZE:
|
|
#else
|
|
case _CLIENT_MESSAGE__MSG_IS_INT_SIZE:
|
|
#endif
|
|
/* protobuf-internal thing */
|
|
return;
|
|
case CLIENT_MESSAGE__MSG__NOT_SET:
|
|
abort();
|
|
MSG_STRING_CASE(CONNECT);
|
|
MSG_STRING_CASE(CONNECT_DONE);
|
|
MSG_STRING_CASE(DISCONNECT);
|
|
MSG_STRING_CASE(BIND_SEAT);
|
|
MSG_STRING_CASE(UNBIND_SEAT);
|
|
MSG_STRING_CASE(CLOSE_DEVICE);
|
|
MSG_STRING_CASE(START_EMULATING);
|
|
MSG_STRING_CASE(STOP_EMULATING);
|
|
MSG_STRING_CASE(POINTER_RELATIVE);
|
|
MSG_STRING_CASE(POINTER_ABSOLUTE);
|
|
MSG_STRING_CASE(POINTER_BUTTON);
|
|
MSG_STRING_CASE(POINTER_SCROLL);
|
|
MSG_STRING_CASE(POINTER_SCROLL_STOP);
|
|
MSG_STRING_CASE(POINTER_SCROLL_DISCRETE);
|
|
MSG_STRING_CASE(KEYBOARD_KEY);
|
|
MSG_STRING_CASE(TOUCH_DOWN);
|
|
MSG_STRING_CASE(TOUCH_MOTION);
|
|
MSG_STRING_CASE(TOUCH_UP);
|
|
MSG_STRING_CASE(CONFIGURE_NAME);
|
|
MSG_STRING_CASE(CONFIGURE_CAPABILITIES);
|
|
MSG_STRING_CASE(FRAME);
|
|
MSG_STRING_CASE(PROPERTY);
|
|
}
|
|
if (message == NULL)
|
|
assert(!"Unimplemented message type");
|
|
|
|
log_debug(ei, "sending wire message %s (%s)\n", message,
|
|
strerror(-error));
|
|
|
|
#undef MSG_STRING_CASE
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_msg(struct ei *ei, const ClientMessage *msg)
|
|
{
|
|
size_t msglen = client_message__get_packed_size(msg);
|
|
Packet packet = PACKET__INIT;
|
|
packet.length = msglen;
|
|
size_t packetlen = packet__get_packed_size(&packet);
|
|
|
|
uint8_t buf[packetlen + msglen];
|
|
packet__pack(&packet, buf);
|
|
client_message__pack(msg, buf + packetlen);
|
|
|
|
int rc = min(0, xsend(source_get_fd(ei->source), buf, sizeof(buf)));
|
|
|
|
log_wire_message(ei, msg, rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
_unused_ static int
|
|
ei_proto_send_msg_with_fds(struct ei *ei, const ClientMessage *msg, int *fds)
|
|
{
|
|
size_t msglen = client_message__get_packed_size(msg);
|
|
Packet packet = PACKET__INIT;
|
|
packet.length = msglen;
|
|
size_t packetlen = packet__get_packed_size(&packet);
|
|
|
|
uint8_t buf[packetlen + msglen];
|
|
packet__pack(&packet, buf);
|
|
client_message__pack(msg, buf + packetlen);
|
|
|
|
int rc = min(0, xsend_with_fd(source_get_fd(ei->source), buf, sizeof(buf), fds));
|
|
log_wire_message(ei, msg, rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#define prepare_msg(_type, _struct, _field) \
|
|
ClientMessage msg = CLIENT_MESSAGE__INIT; \
|
|
_struct _field = _type##__INIT; \
|
|
msg.msg_case = CLIENT_MESSAGE__MSG_##_type; \
|
|
msg._field = &_field
|
|
|
|
static int
|
|
ei_proto_send_connect(struct ei *ei)
|
|
{
|
|
prepare_msg(CONNECT, Connect, connect);
|
|
|
|
connect.name = ei->name;
|
|
|
|
return ei_proto_send_msg(ei, &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_connect_done(struct ei *ei)
|
|
{
|
|
prepare_msg(CONNECT_DONE, ConnectDone, connect_done);
|
|
|
|
return ei_proto_send_msg(ei, &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_disconnect(struct ei *ei)
|
|
{
|
|
prepare_msg(DISCONNECT, Disconnect, disconnect);
|
|
|
|
return ei_proto_send_msg(ei, &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_bind_seat(struct ei_seat *seat, uint32_t capabilities)
|
|
{
|
|
prepare_msg(BIND_SEAT, BindSeat, bind_seat);
|
|
|
|
bind_seat.seatid = seat->id;
|
|
bind_seat.capabilities = capabilities;
|
|
|
|
return ei_proto_send_msg(ei_seat_get_context(seat), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_unbind_seat(struct ei_seat *seat)
|
|
{
|
|
prepare_msg(UNBIND_SEAT, UnbindSeat, unbind_seat);
|
|
|
|
unbind_seat.seatid = seat->id;
|
|
|
|
return ei_proto_send_msg(ei_seat_get_context(seat), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_close_device(struct ei_device *device)
|
|
{
|
|
prepare_msg(CLOSE_DEVICE, CloseDevice, close_device);
|
|
|
|
close_device.deviceid = device->id;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_start_emulating(struct ei_device *device)
|
|
{
|
|
prepare_msg(START_EMULATING, StartEmulating, start_emulating);
|
|
|
|
start_emulating.deviceid = device->id;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_stop_emulating(struct ei_device *device)
|
|
{
|
|
prepare_msg(STOP_EMULATING, StopEmulating, stop_emulating);
|
|
|
|
stop_emulating.deviceid = device->id;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_rel(struct ei_device *device, double x, double y)
|
|
{
|
|
prepare_msg(POINTER_RELATIVE, PointerRelative, pointer_relative);
|
|
|
|
pointer_relative.deviceid = device->id;
|
|
pointer_relative.x = x;
|
|
pointer_relative.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_abs(struct ei_device *device, double x, double y)
|
|
{
|
|
prepare_msg(POINTER_ABSOLUTE, PointerAbsolute, pointer_absolute);
|
|
|
|
pointer_absolute.deviceid = device->id;
|
|
pointer_absolute.x = x;
|
|
pointer_absolute.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_button(struct ei_device *device, uint32_t b, bool is_press)
|
|
{
|
|
prepare_msg(POINTER_BUTTON, PointerButton, pointer_button);
|
|
|
|
pointer_button.deviceid = device->id;
|
|
pointer_button.button = b;
|
|
pointer_button.state = is_press;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_scroll(struct ei_device *device, double x, double y)
|
|
{
|
|
prepare_msg(POINTER_SCROLL, PointerScroll, pointer_scroll);
|
|
|
|
pointer_scroll.deviceid = device->id;
|
|
pointer_scroll.x = x;
|
|
pointer_scroll.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_scroll_stop(struct ei_device *device, bool x, bool y)
|
|
{
|
|
prepare_msg(POINTER_SCROLL_STOP, PointerScrollStop, pointer_scroll_stop);
|
|
|
|
pointer_scroll_stop.deviceid = device->id;
|
|
pointer_scroll_stop.x = x;
|
|
pointer_scroll_stop.y = y;
|
|
pointer_scroll_stop.is_cancel = false;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_scroll_cancel(struct ei_device *device, bool x, bool y)
|
|
{
|
|
prepare_msg(POINTER_SCROLL_STOP, PointerScrollStop, pointer_scroll_stop);
|
|
|
|
pointer_scroll_stop.deviceid = device->id;
|
|
pointer_scroll_stop.x = x;
|
|
pointer_scroll_stop.y = y;
|
|
pointer_scroll_stop.is_cancel = true;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_scroll_discrete(struct ei_device *device, int32_t x, int32_t y)
|
|
{
|
|
prepare_msg(POINTER_SCROLL_DISCRETE, PointerScrollDiscrete, pointer_scroll_discrete);
|
|
|
|
pointer_scroll_discrete.deviceid = device->id;
|
|
pointer_scroll_discrete.x = x;
|
|
pointer_scroll_discrete.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_key(struct ei_device *device, uint32_t k, bool is_press)
|
|
{
|
|
prepare_msg(KEYBOARD_KEY, KeyboardKey, keyboard_key);
|
|
|
|
keyboard_key.deviceid = device->id;
|
|
keyboard_key.key = k;
|
|
keyboard_key.state = is_press;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
|
|
static int
|
|
ei_proto_send_touch_down(struct ei_device *device, uint32_t tid, double x, double y)
|
|
{
|
|
prepare_msg(TOUCH_DOWN, TouchDown, touch_down);
|
|
|
|
touch_down.deviceid = device->id;
|
|
touch_down.touchid = tid;
|
|
touch_down.x = x;
|
|
touch_down.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_touch_motion(struct ei_device *device, uint32_t tid, double x, double y)
|
|
{
|
|
prepare_msg(TOUCH_MOTION, TouchMotion, touch_motion);
|
|
|
|
touch_motion.deviceid = device->id;
|
|
touch_motion.touchid = tid;
|
|
touch_motion.x = x;
|
|
touch_motion.y = y;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_touch_up(struct ei_device *device, uint32_t tid)
|
|
{
|
|
prepare_msg(TOUCH_UP, TouchUp, touch_up);
|
|
|
|
touch_up.deviceid = device->id;
|
|
touch_up.touchid = tid;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_frame(struct ei_device *device)
|
|
{
|
|
prepare_msg(FRAME, Frame, frame);
|
|
|
|
frame.deviceid = device->id;
|
|
|
|
return ei_proto_send_msg(ei_device_get_context(device), &msg);
|
|
}
|
|
|
|
static int
|
|
ei_proto_send_property(struct ei *ei, const char *name, const char *value, uint32_t permissions)
|
|
{
|
|
prepare_msg(PROPERTY, Property, property);
|
|
|
|
property.name = (char*)name;
|
|
property.value = value ? (char*)value : "";
|
|
property.permissions = permissions;
|
|
|
|
return ei_proto_send_msg(ei, &msg);
|
|
}
|
|
|
|
static const struct ei_proto_requests requests = {
|
|
.connect = ei_proto_send_connect,
|
|
.connect_done = ei_proto_send_connect_done,
|
|
.disconnect = ei_proto_send_disconnect,
|
|
.bind_seat = ei_proto_send_bind_seat,
|
|
.unbind_seat = ei_proto_send_unbind_seat,
|
|
.close_device = ei_proto_send_close_device,
|
|
.start_emulating = ei_proto_send_start_emulating,
|
|
.stop_emulating = ei_proto_send_stop_emulating,
|
|
.rel = ei_proto_send_rel,
|
|
.abs = ei_proto_send_abs,
|
|
.button = ei_proto_send_button,
|
|
.scroll = ei_proto_send_scroll,
|
|
.scroll_stop = ei_proto_send_scroll_stop,
|
|
.scroll_cancel = ei_proto_send_scroll_cancel,
|
|
.scroll_discrete = ei_proto_send_scroll_discrete,
|
|
.key = ei_proto_send_key,
|
|
.touch_down = ei_proto_send_touch_down,
|
|
.touch_motion = ei_proto_send_touch_motion,
|
|
.touch_up = ei_proto_send_touch_up,
|
|
.frame = ei_proto_send_frame,
|
|
.property = ei_proto_send_property,
|
|
};
|
|
|
|
const struct ei_proto_requests *
|
|
ei_proto_get_requests(void)
|
|
{
|
|
return &requests;
|
|
}
|