Add concept of active/passive libei contexts

A libei context can be initialized as active or passive context -
an "active" context sends events, a "passive" context receives events.
The EIS context supports both simultaneously, it is up to the
implementation to disconnect libei clients that it does not want to
suppport.

For example, the xdotool use-case creates an active libei context. The
EIS implementation controls and sets up the devices, but libei
sends the events.

In an input-capturing use-case, the EIS implementation controls
and sets up the devices **and** sends the events. libei is merely the
receiver for any event, it cannot send events. Thus this use-case
requires a passive libei context.

Most of this code is copy/paste with minor modifications - libei already
had the code to send events, libeis had the code to receive events, so
the vast majority of this patch is copying the code into the respective
other library, swap "ei" and "eis" and then apply the various minor
modifications needed to hook into the existing library.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2022-02-25 14:41:28 +10:00
parent 72cfef9a56
commit faa9500afe
17 changed files with 2105 additions and 15 deletions

View file

@ -60,6 +60,7 @@ message ConfigureCapabilities {
message Connect {
string name = 1;
bool is_active = 2;
}
message ConnectDone {
@ -195,6 +196,7 @@ message Connected {
}
message Disconnected {
bool is_active = 2;
}
message SeatAdded {
@ -256,6 +258,7 @@ message KeyboardModifiers {
message ServerMessage {
oneof msg {
/* Server setup and configuration */
Connected connected = 2;
Disconnected disconnected = 3;
SeatAdded seat_added = 4;
@ -269,6 +272,21 @@ message ServerMessage {
DevicePaused device_paused = 12;
KeyboardModifiers keyboard_modifiers = 13;
Property property = 14;
/* Events */
StartEmulating start_emulating = 20;
StopEmulating stop_emulating = 21;
PointerRelative pointer_relative = 22;
PointerAbsolute pointer_absolute = 23;
PointerScroll pointer_scroll = 24;
PointerScrollDiscrete pointer_scroll_discrete = 25;
PointerScrollStop pointer_scroll_stop = 26;
PointerButton pointer_button = 27;
KeyboardKey keyboard_key = 28;
TouchDown touch_down = 29;
TouchMotion touch_motion = 30;
TouchUp touch_up = 31;
Frame frame = 32;
}
}

View file

@ -638,3 +638,265 @@ ei_device_frame(struct ei_device *device)
ei_send_frame(device);
}
void
ei_device_event_start_emulating(struct ei_device *device)
{
switch (device->state) {
case EI_DEVICE_STATE_DEAD:
case EI_DEVICE_STATE_NEW:
case EI_DEVICE_STATE_PAUSED:
case EI_DEVICE_STATE_EMULATING:
break;
case EI_DEVICE_STATE_RESUMED:
ei_queue_device_start_emulating_event(device);
device->state = EI_DEVICE_STATE_EMULATING;
break;
case EI_DEVICE_STATE_REMOVED_FROM_CLIENT:
case EI_DEVICE_STATE_REMOVED_FROM_SERVER:
break;
}
}
void
ei_device_event_stop_emulating(struct ei_device *device)
{
switch (device->state) {
case EI_DEVICE_STATE_DEAD:
case EI_DEVICE_STATE_NEW:
case EI_DEVICE_STATE_PAUSED:
case EI_DEVICE_STATE_RESUMED:
break;
case EI_DEVICE_STATE_EMULATING:
ei_queue_device_stop_emulating_event(device);
device->state = EI_DEVICE_STATE_RESUMED;
break;
case EI_DEVICE_STATE_REMOVED_FROM_CLIENT:
case EI_DEVICE_STATE_REMOVED_FROM_SERVER:
break;
}
}
int
ei_device_event_frame(struct ei_device *device)
{
if (device->state != EI_DEVICE_STATE_RESUMED)
return -EINVAL;
ei_queue_frame_event(device);
return 0;
}
int
ei_device_event_pointer_rel(struct ei_device *device, double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_rel_event(device, x, y);
return 0;
}
static inline bool
ei_device_in_region(struct ei_device *device, double x, double y)
{
struct ei_region *r;
list_for_each(r, &device->regions, link) {
if (ei_region_contains(r, x, y))
return true;
}
return false;
}
int
ei_device_event_pointer_abs(struct ei_device *device,
double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not an absolute pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
if (!ei_device_in_region(device, x, y))
return -EINVAL;
ei_queue_pointer_abs_event(device, x, y);
return 0;
}
int
ei_device_event_pointer_button(struct ei_device *device,
uint32_t button, bool is_press)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_button_event(device, button, is_press);
return 0;
}
int
ei_device_event_pointer_scroll(struct ei_device *device,
double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_scroll_event(device, x, y);
return 0;
}
int
ei_device_event_pointer_scroll_discrete(struct ei_device *device,
int32_t x, int32_t y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_scroll_discrete_event(device, x, y);
return 0;
}
int
ei_device_event_pointer_scroll_stop(struct ei_device *device, bool x, bool y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_scroll_stop_event(device, x, y);
return 0;
}
int
ei_device_event_pointer_scroll_cancel(struct ei_device *device, bool x, bool y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) &&
!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_pointer_scroll_cancel_event(device, x, y);
return 0;
}
int
ei_device_event_keyboard_key(struct ei_device *device,
uint32_t key, bool is_press)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a keyboard\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_keyboard_key_event(device, key, is_press);
return 0;
}
int
ei_device_event_touch_down(struct ei_device *device, uint32_t touchid, double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a touch device\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_touch_down_event(device, touchid, x, y);
return 0;
}
int
ei_device_event_touch_motion(struct ei_device *device, uint32_t touchid, double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a touch device\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_touch_motion_event(device, touchid, x, y);
return 0;
}
int
ei_device_event_touch_up(struct ei_device *device, uint32_t touchid)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) {
log_bug_client(ei_device_get_context(device),
"%s: device is not a touch device\n", __func__);
return -EINVAL;
}
if (device->state != EI_DEVICE_STATE_EMULATING)
return -EINVAL;
ei_queue_touch_up_event(device, touchid);
return 0;
}

View file

@ -50,6 +50,20 @@ ei_event_type_to_string(enum ei_event_type type)
CASE_RETURN_STRING(EI_EVENT_DEVICE_RESUMED);
CASE_RETURN_STRING(EI_EVENT_KEYBOARD_MODIFIERS);
CASE_RETURN_STRING(EI_EVENT_PROPERTY);
CASE_RETURN_STRING(EI_EVENT_FRAME);
CASE_RETURN_STRING(EI_EVENT_DEVICE_START_EMULATING);
CASE_RETURN_STRING(EI_EVENT_DEVICE_STOP_EMULATING);
CASE_RETURN_STRING(EI_EVENT_POINTER_MOTION);
CASE_RETURN_STRING(EI_EVENT_POINTER_MOTION_ABSOLUTE);
CASE_RETURN_STRING(EI_EVENT_POINTER_BUTTON);
CASE_RETURN_STRING(EI_EVENT_POINTER_SCROLL);
CASE_RETURN_STRING(EI_EVENT_POINTER_SCROLL_STOP);
CASE_RETURN_STRING(EI_EVENT_POINTER_SCROLL_CANCEL);
CASE_RETURN_STRING(EI_EVENT_POINTER_SCROLL_DISCRETE);
CASE_RETURN_STRING(EI_EVENT_KEYBOARD_KEY);
CASE_RETURN_STRING(EI_EVENT_TOUCH_DOWN);
CASE_RETURN_STRING(EI_EVENT_TOUCH_UP);
CASE_RETURN_STRING(EI_EVENT_TOUCH_MOTION);
}
assert(!"Unhandled event type");
@ -73,6 +87,21 @@ ei_event_destroy(struct ei_event *event)
free(event->prop.name);
free(event->prop.value);
break;
case EI_EVENT_FRAME:
case EI_EVENT_DEVICE_START_EMULATING:
case EI_EVENT_DEVICE_STOP_EMULATING:
case EI_EVENT_POINTER_MOTION:
case EI_EVENT_POINTER_MOTION_ABSOLUTE:
case EI_EVENT_POINTER_BUTTON:
case EI_EVENT_POINTER_SCROLL:
case EI_EVENT_POINTER_SCROLL_STOP:
case EI_EVENT_POINTER_SCROLL_CANCEL:
case EI_EVENT_POINTER_SCROLL_DISCRETE:
case EI_EVENT_KEYBOARD_KEY:
case EI_EVENT_TOUCH_DOWN:
case EI_EVENT_TOUCH_UP:
case EI_EVENT_TOUCH_MOTION:
break;
}
ei_device_unref(event->device);
ei_seat_unref(event->seat);
@ -200,3 +229,196 @@ ei_event_property_get_permissions(struct ei_event *event)
return event->prop.permissions;
}
_public_ double
ei_event_pointer_get_dx(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.dx;
}
_public_ double
ei_event_pointer_get_dy(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.dy;
}
_public_ double
ei_event_pointer_get_absolute_x(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.absx;
}
_public_ double
ei_event_pointer_get_absolute_y(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.absy;
}
_public_ uint32_t
ei_event_pointer_get_button(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.button;
}
_public_ bool
ei_event_pointer_get_button_is_press(struct ei_event *event)
{
require_event_type(event, false,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.button_is_press;
}
_public_ double
ei_event_pointer_get_scroll_x(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.sx;
}
_public_ double
ei_event_pointer_get_scroll_y(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.sy;
}
_public_ int32_t
ei_event_pointer_get_scroll_discrete_x(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.sdx;
}
_public_ int32_t
ei_event_pointer_get_scroll_discrete_y(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_MOTION,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.sdy;
}
_public_ bool
ei_event_pointer_get_scroll_stop_x(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_SCROLL_STOP,
EI_EVENT_POINTER_SCROLL_CANCEL);
return event->pointer.stop_x;
}
_public_ bool
ei_event_pointer_get_scroll_stop_y(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_POINTER_SCROLL_STOP,
EI_EVENT_POINTER_SCROLL_CANCEL);
return event->pointer.stop_y;
}
_public_ uint32_t
ei_event_keyboard_get_key(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_KEYBOARD_KEY);
return event->keyboard.key;
}
_public_ bool
ei_event_keyboard_get_key_is_press(struct ei_event *event)
{
require_event_type(event, false,
EI_EVENT_KEYBOARD_KEY);
return event->keyboard.key_is_press;
}
_public_ uint32_t
ei_event_touch_get_id(struct ei_event *event)
{
require_event_type(event, 0,
EI_EVENT_TOUCH_DOWN,
EI_EVENT_TOUCH_UP,
EI_EVENT_TOUCH_MOTION);
return event->touch.touchid;
}
_public_ double
ei_event_touch_get_x(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_TOUCH_DOWN,
EI_EVENT_TOUCH_MOTION);
return event->touch.x;
}
_public_ double
ei_event_touch_get_y(struct ei_event *event)
{
require_event_type(event, 0.0,
EI_EVENT_TOUCH_DOWN,
EI_EVENT_TOUCH_MOTION);
return event->touch.y;
}

View file

@ -67,6 +67,8 @@ struct ei {
} log;
const struct ei_proto_requests *requests;
bool is_active;
};
enum ei_seat_state {
@ -183,6 +185,23 @@ struct ei_event {
char *value;
uint32_t permissions;
} prop;
struct {
double dx, dy; /* relative motion */
double absx, absy; /* absolute motion */
double sx, sy; /* scroll */
int32_t sdx, sdy; /* discrete scroll */
bool stop_x, stop_y; /* scroll stop */
uint32_t button;
bool button_is_press;
} pointer;
struct {
uint32_t key;
bool key_is_press;
} keyboard;
struct {
uint32_t touchid;
double x, y;
} touch;
};
};
@ -265,6 +284,50 @@ ei_insert_device_removed_event(struct ei_device *device);
void
ei_queue_seat_removed_event(struct ei_seat *seat);
void
ei_queue_device_start_emulating_event(struct ei_device *device);
void
ei_queue_device_stop_emulating_event(struct ei_device *device);
void
ei_queue_frame_event(struct ei_device *device);
void
ei_queue_pointer_rel_event(struct ei_device *device, double x, double y);
void
ei_queue_pointer_abs_event(struct ei_device *device, double x, double y);
void
ei_queue_pointer_button_event(struct ei_device *device, uint32_t button, bool is_press);
void
ei_queue_keyboard_key_event(struct ei_device *device, uint32_t key, bool is_press);
void
ei_queue_pointer_scroll_event(struct ei_device *device, double x, double y);
void
ei_queue_pointer_scroll_discrete_event(struct ei_device *device, int32_t x, int32_t y);
void
ei_queue_pointer_scroll_stop_event(struct ei_device *device, bool x, bool y);
void
ei_queue_pointer_scroll_cancel_event(struct ei_device *device, bool x, bool y);
void
ei_queue_touch_down_event(struct ei_device *device, uint32_t touchid,
double x, double y);
void
ei_queue_touch_motion_event(struct ei_device *device, uint32_t touchid,
double x, double y);
void
ei_queue_touch_up_event(struct ei_device *device, uint32_t touchid);
struct ei_device *
ei_device_new(struct ei_seat *seat, uint32_t deviceid);
@ -277,6 +340,53 @@ ei_device_done(struct ei_device *device);
void
ei_device_removed_by_server(struct ei_device *device);
int
ei_device_event_frame(struct ei_device *device);
void
ei_device_event_start_emulating(struct ei_device *device);
void
ei_device_event_stop_emulating(struct ei_device *device);
int
ei_device_event_pointer_rel(struct ei_device *device,
double x, double y);
int
ei_device_event_pointer_abs(struct ei_device *device,
double x, double y);
int
ei_device_event_pointer_button(struct ei_device *device,
uint32_t button, bool is_press);
int
ei_device_event_pointer_scroll(struct ei_device *device,
double x, double y);
int
ei_device_event_pointer_scroll_stop(struct ei_device *device, bool x, bool y);
int
ei_device_event_pointer_scroll_cancel(struct ei_device *device, bool x, bool y);
int
ei_device_event_pointer_scroll_discrete(struct ei_device *device,
int32_t x, int32_t y);
int
ei_device_event_keyboard_key(struct ei_device *device,
uint32_t key, bool is_press);
int
ei_device_event_touch_down(struct ei_device *device, uint32_t tid,
double x, double y);
int
ei_device_event_touch_motion(struct ei_device *device, uint32_t tid,
double x, double y);
int
ei_device_event_touch_up(struct ei_device *device, uint32_t tid);
int
ei_send_pointer_rel(struct ei_device *device,
double x, double y);

View file

@ -64,7 +64,7 @@ ei_proto_handle_message(struct ei *ei,
rc = call(connected, ei);
break;
case SERVER_MESSAGE__MSG_DISCONNECTED:
rc = call(disconnected, ei);
rc = call(disconnected, ei, proto->disconnected->is_active);
break;
case SERVER_MESSAGE__MSG_SEAT_ADDED:
rc = call(seat_added, ei,
@ -132,6 +132,80 @@ ei_proto_handle_message(struct ei *ei,
proto->property->value[0] ? proto->property->value : NULL,
proto->property->permissions);
break;
/* Events */
case SERVER_MESSAGE__MSG_START_EMULATING:
rc = call(start_emulating, ei,
proto->start_emulating->deviceid);
break;
case SERVER_MESSAGE__MSG_STOP_EMULATING:
rc = call(stop_emulating, ei,
proto->stop_emulating->deviceid);
break;
case SERVER_MESSAGE__MSG_POINTER_RELATIVE:
rc = call(rel, ei,
proto->pointer_relative->deviceid,
proto->pointer_relative->x,
proto->pointer_relative->y);
break;
case SERVER_MESSAGE__MSG_POINTER_ABSOLUTE:
rc = call(abs, ei,
proto->pointer_absolute->deviceid,
proto->pointer_absolute->x,
proto->pointer_absolute->y);
break;
case SERVER_MESSAGE__MSG_POINTER_BUTTON:
rc = call(button, ei,
proto->pointer_button->deviceid,
proto->pointer_button->button,
proto->pointer_button->state);
break;
case SERVER_MESSAGE__MSG_POINTER_SCROLL:
rc = call(scroll, ei,
proto->pointer_scroll->deviceid,
proto->pointer_scroll->x,
proto->pointer_scroll->y);
break;
case SERVER_MESSAGE__MSG_POINTER_SCROLL_STOP:
rc = call(scroll_stop, ei,
proto->pointer_scroll_stop->deviceid,
proto->pointer_scroll_stop->x,
proto->pointer_scroll_stop->y,
proto->pointer_scroll_stop->is_cancel);
break;
case SERVER_MESSAGE__MSG_POINTER_SCROLL_DISCRETE:
rc = call(scroll_discrete, ei,
proto->pointer_scroll_discrete->deviceid,
proto->pointer_scroll_discrete->x,
proto->pointer_scroll_discrete->y);
break;
case SERVER_MESSAGE__MSG_KEYBOARD_KEY:
rc = call(key, ei,
proto->keyboard_key->deviceid,
proto->keyboard_key->key,
proto->keyboard_key->state);
break;
case SERVER_MESSAGE__MSG_TOUCH_DOWN:
rc = call(touch_down, ei,
proto->touch_down->deviceid,
proto->touch_down->touchid,
proto->touch_down->x,
proto->touch_down->y);
break;
case SERVER_MESSAGE__MSG_TOUCH_MOTION:
rc = call(touch_motion, ei,
proto->touch_motion->deviceid,
proto->touch_motion->touchid,
proto->touch_motion->x,
proto->touch_motion->y);
break;
case SERVER_MESSAGE__MSG_TOUCH_UP:
rc = call(touch_up, ei,
proto->touch_up->deviceid,
proto->touch_up->touchid);
break;
case SERVER_MESSAGE__MSG_FRAME:
rc = call(frame, ei, proto->frame->deviceid);
break;
default:
rc = -EBADMSG;
break;
@ -240,6 +314,7 @@ ei_proto_send_connect(struct ei *ei)
prepare_msg(CONNECT, Connect, connect);
connect.name = ei->name;
connect.is_active = ei->is_active;
return ei_proto_send_msg(ei, &msg);
}

View file

@ -35,7 +35,7 @@
/* callbacks invoked during ei_proto_parse_message() */
struct ei_proto_interface {
int (*connected)(struct ei *ei);
int (*disconnected)(struct ei *ei);
int (*disconnected)(struct ei *ei, bool is_active);
int (*seat_added)(struct ei *ei, uint32_t seatid,
const char *name, uint32_t capabilities);
int (*seat_removed)(struct ei *ei, uint32_t seatid);
@ -58,6 +58,23 @@ struct ei_proto_interface {
int (*property)(struct ei *ei,
const char *name, const char *value,
uint32_t permissions);
/* events */
int (*start_emulating)(struct ei *ei, uint32_t deviceid);
int (*stop_emulating)(struct ei *ei, uint32_t deviceid);
int (*rel)(struct ei *ei, uint32_t deviceid, double x, double y);
int (*abs)(struct ei *ei, uint32_t deviceid, double x, double y);
int (*button)(struct ei *ei, uint32_t deviceid, uint32_t button, bool is_press);
int (*key)(struct ei *ei, uint32_t deviceid, uint32_t key, bool is_press);
int (*scroll)(struct ei *ei, uint32_t deviceid, double x, double y);
int (*scroll_stop)(struct ei *ei, uint32_t deviceid, bool x, bool y, bool is_cancel);
int (*scroll_discrete)(struct ei *ei, uint32_t deviceid, int32_t x, int32_t y);
int (*touch_down)(struct ei *ei, uint32_t deviceid,
uint32_t tid, double x, double y);
int (*touch_motion)(struct ei *ei, uint32_t deviceid,
uint32_t tid, double x, double y);
int (*touch_up)(struct ei *ei, uint32_t deviceid, uint32_t tid);
int (*frame) (struct ei *ei, uint32_t deviceid);
};
struct ei_proto_requests {

View file

@ -132,8 +132,8 @@ set_prop_type(struct ei *ei)
ei_property_update(ei, "ei.connection.type", "socket", EI_PROPERTY_PERM_NONE);
}
_public_ struct ei *
ei_new(void *user_data)
static struct ei *
ei_create_context(bool is_active, void *user_data)
{
_unref_(ei) *ei = ei_create(NULL);
@ -151,6 +151,7 @@ ei_new(void *user_data)
ei->user_data = user_data;
ei->backend = NULL;
ei->is_active = is_active;
set_prop_pid(ei);
set_prop_cmdline(ei);
@ -159,6 +160,24 @@ ei_new(void *user_data)
return steal(&ei);
}
_public_ struct ei *
ei_new(void *user_data)
{
return ei_new_active(user_data);
}
_public_ struct ei *
ei_new_active(void *user_data)
{
return ei_create_context(true, user_data);
}
_public_ struct ei *
ei_new_passive(void *user_data)
{
return ei_create_context(false, user_data);
}
_public_ int
ei_get_fd(struct ei *ei)
{
@ -319,6 +338,177 @@ queue_property_event(struct ei *ei, const char *name,
queue_event(ei, e);
}
void
ei_queue_frame_event(struct ei_device *device)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_FRAME;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_device_start_emulating_event(struct ei_device *device)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_DEVICE_START_EMULATING;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_device_stop_emulating_event(struct ei_device *device)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_DEVICE_STOP_EMULATING;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_rel_event(struct ei_device *device,
double dx, double dy)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_MOTION;
e->pointer.dx = dx;
e->pointer.dy = dy;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_abs_event(struct ei_device *device,
double x, double y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_MOTION_ABSOLUTE;
e->pointer.absx = x;
e->pointer.absy = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_button_event(struct ei_device *device, uint32_t button,
bool is_press)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_BUTTON;
e->pointer.button = button;
e->pointer.button_is_press = is_press;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_scroll_event(struct ei_device *device,
double x, double y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_SCROLL;
e->pointer.sx = x;
e->pointer.sy = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_scroll_discrete_event(struct ei_device *device,
int32_t x, int32_t y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_SCROLL_DISCRETE;
e->pointer.sdx = x;
e->pointer.sdy = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_scroll_stop_event(struct ei_device *device, bool x, bool y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_SCROLL_STOP;
e->pointer.stop_x = x;
e->pointer.stop_y = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_pointer_scroll_cancel_event(struct ei_device *device, bool x, bool y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_POINTER_SCROLL_CANCEL;
e->pointer.stop_x = x;
e->pointer.stop_y = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_keyboard_key_event(struct ei_device *device, uint32_t key,
bool is_press)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_KEYBOARD_KEY;
e->keyboard.key = key;
e->keyboard.key_is_press = is_press;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_touch_down_event(struct ei_device *device, uint32_t touchid,
double x, double y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_TOUCH_DOWN;
e->touch.touchid = touchid,
e->touch.x = x;
e->touch.y = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_touch_motion_event(struct ei_device *device, uint32_t touchid,
double x, double y)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_TOUCH_MOTION;
e->touch.touchid = touchid,
e->touch.x = x;
e->touch.y = y;
queue_event(ei_device_get_context(device), e);
}
void
ei_queue_touch_up_event(struct ei_device *device, uint32_t touchid)
{
struct ei_event *e = ei_event_new_for_device(device);
e->type = EI_EVENT_TOUCH_UP;
e->touch.touchid = touchid,
queue_event(ei_device_get_context(device), e);
}
void
ei_disconnect(struct ei *ei)
{
@ -838,10 +1028,204 @@ static int handle_msg_connected(struct ei *ei) {
return 0;
}
static int handle_msg_disconnected(struct ei *ei) {
static int handle_msg_disconnected(struct ei *ei, bool is_active) {
if (ei->is_active == is_active) {
log_bug_client(ei, "Unable to connect %s ei context to %s EIS implementation\n",
is_active ? "active" : "passive",
is_active ? "active" : "passive");
}
return -ECANCELED;
}
#define DISCONNECT_IF_ACTIVE_CONTEXT(ei_) do {\
if (ei_->is_active) { \
log_bug_client(ei_, "Invalid event from passive EIS context. Disconnecting\n"); \
return -ECANCELED; \
} \
} while(0)
static int
handle_msg_start_emulating(struct ei *ei, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
ei_device_event_start_emulating(device);
return 0;
}
static int
handle_msg_stop_emulating(struct ei *ei, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
ei_device_event_stop_emulating(device);
return 0;
}
static int
handle_msg_frame(struct ei *ei, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_frame(device);
return 0;
}
static int
handle_msg_pointer_rel(struct ei *ei, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_pointer_rel(device, x, y);
return -EINVAL;
}
static int
handle_msg_pointer_abs(struct ei *ei, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_pointer_abs(device, x, y);
return -EINVAL;
}
static int
handle_msg_pointer_button(struct ei *ei, uint32_t deviceid,
uint32_t button, bool state)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_pointer_button(device, button, state);
return -EINVAL;
}
static int
handle_msg_pointer_scroll(struct ei *ei, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_pointer_scroll(device, x, y);
return -EINVAL;
}
static int
handle_msg_pointer_scroll_discrete(struct ei *ei, uint32_t deviceid,
int32_t x, int32_t y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_pointer_scroll_discrete(device, x, y);
return -EINVAL;
}
static int
handle_msg_pointer_scroll_stop(struct ei *ei, uint32_t deviceid,
bool x, bool y, bool is_cancel)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device) {
if (is_cancel)
return ei_device_event_pointer_scroll_cancel(device, x, y);
else
return ei_device_event_pointer_scroll_stop(device, x, y);
}
return -EINVAL;
}
static int
handle_msg_keyboard_key(struct ei *ei, uint32_t deviceid,
uint32_t key, bool state)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_keyboard_key(device, key, state);
return -EINVAL;
}
static int
handle_msg_touch_down(struct ei *ei, uint32_t deviceid,
uint32_t touchid, double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_touch_down(device, touchid, x, y);
return -EINVAL;
}
static int
handle_msg_touch_motion(struct ei *ei, uint32_t deviceid,
uint32_t touchid, double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_touch_motion(device, touchid, x, y);
return -EINVAL;
}
static int
handle_msg_touch_up(struct ei *ei, uint32_t deviceid, uint32_t touchid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
struct ei_device *device = ei_find_device(ei, deviceid);
if (device)
return ei_device_event_touch_up(device, touchid);
return -EINVAL;
}
static const struct ei_proto_interface intf_state_backend = {
/* Everything triggers -EPROTO */
.connected = NULL,
@ -865,6 +1249,21 @@ static const struct ei_proto_interface intf_state_connected = {
.device_done = handle_msg_device_added_done,
.keyboard_modifiers = handle_msg_keyboard_modifiers,
.property = handle_msg_property,
/* events */
.start_emulating = handle_msg_start_emulating,
.stop_emulating = handle_msg_stop_emulating,
.rel = handle_msg_pointer_rel,
.abs = handle_msg_pointer_abs,
.button = handle_msg_pointer_button,
.scroll = handle_msg_pointer_scroll,
.scroll_stop = handle_msg_pointer_scroll_stop,
.scroll_discrete = handle_msg_pointer_scroll_discrete,
.key = handle_msg_keyboard_key,
.touch_down = handle_msg_touch_down,
.touch_motion = handle_msg_touch_motion,
.touch_up = handle_msg_touch_up,
.frame = handle_msg_frame,
};
static const struct ei_proto_interface *interfaces[] = {

View file

@ -38,6 +38,12 @@ extern "C" {
* libei is the client-side module. This API should be used by processes
* that need to emulate devices.
*
* libei clients come in "active" and "passive" modes, depending on whether
* the client sends or receives events. A libeis context however is both
* active and passive at the same time, it is up to the implementation to
* disconnect clients that it does not want to allow. See
* eis_client_is_active() for details.
*
* @{
*/
@ -278,11 +284,65 @@ enum ei_event_type {
* This event may arrive while a device is paused.
*/
EI_EVENT_KEYBOARD_MODIFIERS,
/**
* "Hardware" frame event. This event **must** be sent by the server
* and notifies the client that the previous set of events belong to
* the same logical hardware event.
*
* These events are only generated on a passive ei context.
*
* This event is most commonly used to implement multitouch (multiple
* touches may update within the same hardware scanout cycle).
*/
EI_EVENT_FRAME = 100,
/**
* The server is about to send events for a device. This event should
* be used by the client to clear the logical state of the emulated
* devices and/or provide UI to the user.
*
* These events are only generated on a passive ei context.
*
* Note that a server start multiple emulating sequences
* simultaneously, depending on the devices available.
* For example, in a synergy-like situation, the server
* may start sending pointer and keyboard once the remote device
* logically entered the screen.
*/
EI_EVENT_DEVICE_START_EMULATING = 200,
EI_EVENT_DEVICE_STOP_EMULATING,
/* These events are only generated on a passive ei context. */
EI_EVENT_POINTER_MOTION = 300,
EI_EVENT_POINTER_MOTION_ABSOLUTE,
EI_EVENT_POINTER_BUTTON,
EI_EVENT_POINTER_SCROLL,
EI_EVENT_POINTER_SCROLL_STOP,
EI_EVENT_POINTER_SCROLL_CANCEL,
EI_EVENT_POINTER_SCROLL_DISCRETE,
EI_EVENT_KEYBOARD_KEY = 400,
EI_EVENT_TOUCH_DOWN = 500,
EI_EVENT_TOUCH_UP,
EI_EVENT_TOUCH_MOTION,
};
/**
* Create a new ei context. The context is refcounted and must be released
* with ei_unref().
* This is an alias for @ref ei_new_active.
*/
struct ei *
ei_new(void *user_data);
/**
* Create a new active ei context. The context is refcounted and must be
* released with ei_unref().
*
* An active ei context sends events to the EIS implementation but cannot
* receive events. An active ei context can only connect to a passive EIS
* implementation, connecting to an active EIS implementation will immediately
* disconnect the client.
*
* A context supports exactly one backend, set up with one of
* ei_setup_backend_socket() or ei_setup_backend_fd().
@ -295,7 +355,29 @@ enum ei_event_type {
* @see ei_setup_backend_socket
*/
struct ei *
ei_new(void *user_data);
ei_new_active(void *user_data);
/**
* Create a new passive ei context. The context is refcounted and must be
* released with ei_unref().
*
* A passive ei context receives events from the EIS implementation but cannot
* send events. A passive ei context can only connect to an active EIS
* implementation, connecting to a passive EIS implementation will immediately
* disconnect the client.
*
* A context supports exactly one backend, set up with one of
* ei_setup_backend_socket() or ei_setup_backend_fd().
*
* @param user_data An opaque pointer to be returned with ei_get_user_data()
*
* @see ei_set_user_data
* @see ei_get_user_data
* @see ei_setup_backend_fd
* @see ei_setup_backend_socket
*/
struct ei *
ei_new_passive(void *user_data);
enum ei_log_priority {
EI_LOG_PRIORITY_DEBUG = 10,
@ -1298,6 +1380,131 @@ ei_event_property_get_value(struct ei_event *event);
uint32_t
ei_event_property_get_permissions(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_MOTION return the relative x
* movement in logical pixels.
*/
double
ei_event_pointer_get_dx(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_MOTION return the relative y
uint32_* movement in logical pixels.
*/
double
ei_event_pointer_get_dy(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_MOTION_ABSOLUTE return the x
* position in logical pixels.
*/
double
ei_event_pointer_get_absolute_x(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_MOTION_ABSOLUTE return the y
* position in logical pixels.
*/
double
ei_event_pointer_get_absolute_y(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_BUTTON return the button
* code as defined in linux/input-event-codes.h
*/
uint32_t
ei_event_pointer_get_button(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_BUTTON return true if the
* event is a button press, false for a release.
*/
bool
ei_event_pointer_get_button_is_press(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL return the x scroll
* distance in logical pixels.
*/
double
ei_event_pointer_get_scroll_x(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL return the y scroll
* distance in logical pixels.
*/
double
ei_event_pointer_get_scroll_y(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL_CANCEL return whether the
* x axis has cancelled scrolling.
*/
bool
ei_event_pointer_get_scroll_stop_x(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL_STOP return whether the
* y axis has stopped scrolling.
*/
bool
ei_event_pointer_get_scroll_stop_y(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL_DISCRETE return the x
* scroll distance in fractions or multiples of 120.
*/
int32_t
ei_event_pointer_get_scroll_discrete_x(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_POINTER_SCROLL_DISCRETE return the y
* scroll distance in fractions or multiples of 120.
*/
int32_t
ei_event_pointer_get_scroll_discrete_y(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_KEYBOARD_KEY return the key code (as
* defined in include/linux/input-event-codes.h).
*/
uint32_t
ei_event_keyboard_get_key(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_KEYBOARD_KEY return true if the
* event is a key down, false for a release.
*/
bool
ei_event_keyboard_get_key_is_press(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_TOUCH_DOWN, @ref
* EI_EVENT_TOUCH_MOTION, or @ref EI_EVENT_TOUCH_UP, return the tracking
* ID of the touch.
*
* The tracking ID is a unique identifier for a touch and is valid from
* touch down through to touch up but may be re-used in the future.
* The tracking ID is randomly assigned to a touch, a client
* must not expect any specific value.
*/
uint32_t
ei_event_touch_get_id(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_TOUCH_DOWN, or @ref
* EI_EVENT_TOUCH_MOTION, return the x coordinate of the touch.
*/
double
ei_event_touch_get_x(struct ei_event *event);
/**
* For an event of type @ref EI_EVENT_TOUCH_DOWN, or @ref
* EI_EVENT_TOUCH_MOTION, return the y coordinate of the touch.
*/
double
ei_event_touch_get_y(struct ei_event *event);
/**
* @}
*/

View file

@ -79,6 +79,12 @@ eis_client_get_context(struct eis_client *client)
return eis_client_parent(client);
}
_public_ bool
eis_client_is_active(struct eis_client *client)
{
return client->is_active;
}
static struct eis_device *
eis_client_find_device(struct eis_client *client, uint32_t deviceid)
{
@ -268,9 +274,19 @@ client_msg_unbind_seat(struct eis_client *client, uint32_t seatid)
return seat ? 0 : -EINVAL;
}
#define DISCONNECT_IF_ACTIVE_CONTEXT(client_) do { \
struct eis *_ctx = eis_client_get_context(client_); \
if (_ctx->is_active) { \
log_bug_client(_ctx, "Invalid event from passive ei context. Disconnecting client\n"); \
return -EINVAL; \
} \
} while(0)
static int
client_msg_start_emulating(struct eis_client *client, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -282,6 +298,8 @@ client_msg_start_emulating(struct eis_client *client, uint32_t deviceid)
static int
client_msg_stop_emulating(struct eis_client *client, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -293,6 +311,8 @@ client_msg_stop_emulating(struct eis_client *client, uint32_t deviceid)
static int
client_msg_frame(struct eis_client *client, uint32_t deviceid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -305,6 +325,8 @@ static int
client_msg_pointer_rel(struct eis_client *client, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -317,6 +339,8 @@ static int
client_msg_pointer_abs(struct eis_client *client, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -329,6 +353,8 @@ static int
client_msg_pointer_button(struct eis_client *client, uint32_t deviceid,
uint32_t button, bool state)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -341,6 +367,8 @@ static int
client_msg_pointer_scroll(struct eis_client *client, uint32_t deviceid,
double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -353,6 +381,8 @@ static int
client_msg_pointer_scroll_discrete(struct eis_client *client, uint32_t deviceid,
int32_t x, int32_t y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -365,6 +395,8 @@ static int
client_msg_pointer_scroll_stop(struct eis_client *client, uint32_t deviceid,
bool x, bool y, bool is_cancel)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device) {
@ -381,6 +413,8 @@ static int
client_msg_keyboard_key(struct eis_client *client, uint32_t deviceid,
uint32_t key, bool state)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -393,6 +427,8 @@ static int
client_msg_touch_down(struct eis_client *client, uint32_t deviceid,
uint32_t touchid, double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -405,6 +441,8 @@ static int
client_msg_touch_motion(struct eis_client *client, uint32_t deviceid,
uint32_t touchid, double x, double y)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -416,6 +454,8 @@ client_msg_touch_motion(struct eis_client *client, uint32_t deviceid,
static int
client_msg_touch_up(struct eis_client *client, uint32_t deviceid, uint32_t touchid)
{
DISCONNECT_IF_ACTIVE_CONTEXT(client);
struct eis_device *device = eis_client_find_device(client, deviceid);
if (device)
@ -450,11 +490,13 @@ client_msg_configure_capabilities(struct eis_client *client, uint32_t allowed_ca
}
static int
client_msg_connect(struct eis_client *client, const char *name)
client_msg_connect(struct eis_client *client, const char *name, bool is_active)
{
if (client->name == NULL)
client->name = xstrdup(name);
client->is_active = is_active;
return 0;
}
@ -589,6 +631,7 @@ eis_client_new(struct eis *eis, int fd)
static uint32_t client_id;
struct eis_client *client = eis_client_create(&eis->object);
client->is_active = true;
client->id = ++client_id;
list_init(&client->seats);
list_init(&client->seats_pending);

View file

@ -31,6 +31,7 @@
#include "util-io.h"
#include "libeis-private.h"
#include "libeis-proto.h"
_public_
OBJECT_IMPLEMENT_REF(eis_keymap);
@ -247,6 +248,9 @@ eis_device_remove(struct eis_device *device)
if (device->state == EIS_DEVICE_STATE_DEAD)
return;
if (device->state == EIS_DEVICE_STATE_EMULATING)
eis_device_stop_emulating(device);
device->state = EIS_DEVICE_STATE_DEAD;
eis_client_remove_device(eis_device_get_client(device), device);
list_remove(&device->link);
@ -267,6 +271,331 @@ eis_device_has_capability(struct eis_device *device,
return false;
}
#define handle_request_noargs(device_, func_) { \
struct eis *eis = eis_device_get_context(device); \
eis->requests->func_(device_, device->id); \
}
#define handle_request(device_, func_, ...) { \
struct eis *eis = eis_device_get_context(device); \
eis->requests->func_(device_, device->id, __VA_ARGS__); \
}
_public_ void
eis_device_start_emulating(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_RESUMED)
return;
device->state = EIS_DEVICE_STATE_EMULATING;
handle_request_noargs(device, start_emulating);
}
_public_ void
eis_device_stop_emulating(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
device->state = EIS_DEVICE_STATE_RESUMED;
handle_request_noargs(device, stop_emulating);
}
_public_ void
eis_device_pointer_motion(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a pointer\n", __func__);
return;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
handle_request(device, rel, x, y);
}
_public_ void
eis_device_pointer_motion_absolute(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not an absolute pointer\n", __func__);
return;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
return;
}
}
handle_request(device, abs, x, y);
}
_public_ void
eis_device_pointer_button(struct eis_device *device,
uint32_t button, bool is_press)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a pointer\n", __func__);
return;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Ignore anything < BTN_MOUSE. Avoids the common error of sending
* numerical buttons instead of BTN_LEFT and friends. */
if (button < 0x110) {
log_bug_client(eis_device_get_context(device),
"%s: button code must be one of BTN_*\n", __func__);
return;
}
handle_request(device, button, button, is_press);
}
static inline void
eis_device_resume_scrolling(struct eis_device *device, double x, double y)
{
if (x) {
device->scroll.x_is_stopped = false;
device->scroll.x_is_cancelled = false;
}
if (y) {
device->scroll.y_is_stopped = false;
device->scroll.y_is_cancelled = false;
}
}
_public_ void
eis_device_pointer_scroll(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
eis_device_resume_scrolling(device, x, y);
handle_request(device, scroll, x, y);
}
_public_ void
eis_device_pointer_scroll_stop(struct eis_device *device, bool x, bool y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Filter out duplicate scroll stop requests */
if (x && !device->scroll.x_is_stopped)
device->scroll.x_is_stopped = true;
else
x = false;
if (y && !device->scroll.y_is_stopped)
device->scroll.y_is_stopped = true;
else
y = false;
if (x || y)
handle_request(device, scroll_stop, x, y, false);
}
_public_ void
eis_device_pointer_scroll_cancel(struct eis_device *device, bool x, bool y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Filter out duplicate scroll cancelled requests */
if (x && !device->scroll.x_is_cancelled) {
device->scroll.x_is_stopped = true;
device->scroll.x_is_cancelled = true;
} else {
x = false;
}
if (y && !device->scroll.y_is_cancelled) {
device->scroll.y_is_stopped = true;
device->scroll.y_is_cancelled = true;
} else {
y = false;
}
if (x || y)
handle_request(device, scroll_stop, x, y, true);
}
_public_ void
eis_device_pointer_scroll_discrete(struct eis_device *device,
int32_t x, int32_t y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer\n", __func__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
eis_device_resume_scrolling(device, x, y);
handle_request(device, scroll_discrete, x, y);
}
_public_ void
eis_device_keyboard_key(struct eis_device *device,
uint32_t key, bool is_press)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a keyboard\n", __func__);
return;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
handle_request(device, key, key, is_press);
}
_public_
OBJECT_IMPLEMENT_REF(eis_touch);
_public_
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_touch);
_public_
OBJECT_IMPLEMENT_GETTER(eis_touch, device, struct eis_device*);
_public_
OBJECT_IMPLEMENT_GETTER(eis_touch, user_data, void *);
_public_
OBJECT_IMPLEMENT_SETTER(eis_touch, user_data, void *);
static void
eis_touch_destroy(struct eis_touch *touch)
{
eis_touch_up(touch);
eis_device_unref(touch->device);
}
static
OBJECT_IMPLEMENT_CREATE(eis_touch);
_public_ struct eis_touch *
eis_device_touch_new(struct eis_device *device)
{
static uint32_t tracking_id = 0;
/* Not using the device as parent object because we need a ref
* to it */
struct eis_touch *touch = eis_touch_create(NULL);
touch->device = eis_device_ref(device);
touch->state = TOUCH_IS_NEW;
touch->tracking_id = ++tracking_id;
return touch;
}
_public_ void
eis_touch_down(struct eis_touch *touch, double x, double y)
{
struct eis_device *device = eis_touch_get_device(touch);
if (touch->state != TOUCH_IS_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a keyboard\n", __func__);
return;
}
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
log_bug_client(eis_device_get_context(device),
"%s: invalid x/y coordinates\n", __func__);
touch->state = TOUCH_IS_UP;
return;
}
}
touch->state = TOUCH_IS_DOWN;
handle_request(device, touch_down, touch->tracking_id, x, y);
}
_public_ void
eis_touch_motion(struct eis_touch *touch, double x, double y)
{
if (touch->state != TOUCH_IS_DOWN)
return;
struct eis_device *device = eis_touch_get_device(touch);
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
log_bug_client(eis_device_get_context(device),
"%s: invalid x/y coordinates\n", __func__);
eis_touch_up(touch);
return;
}
}
handle_request(device, touch_motion, touch->tracking_id, x, y);
}
_public_ void
eis_touch_up(struct eis_touch *touch)
{
struct eis_device *device = eis_touch_get_device(touch);
if (touch->state != TOUCH_IS_DOWN) {
log_bug_client(eis_device_get_context(device),
"%s: touch is not currently down\n", __func__);
return;
}
touch->state = TOUCH_IS_UP;
handle_request(device, touch_up, touch->tracking_id);
}
_public_ void
eis_device_frame(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_RESUMED)
return;
handle_request_noargs(device, frame);
}
int
eis_device_event_frame(struct eis_device *device)
{

View file

@ -54,6 +54,8 @@ struct eis {
} log;
const struct eis_proto_requests *requests;
bool is_active;
};
enum eis_client_state {
@ -71,7 +73,7 @@ struct eis_client {
uint32_t id;
enum eis_client_state state;
char *name;
bool is_active;
struct list seats;
struct list seats_pending;
@ -139,6 +141,26 @@ struct eis_device {
struct list regions_new; /* not yet added */
struct eis_keymap *keymap;
struct {
bool x_is_stopped, y_is_stopped;
bool x_is_cancelled, y_is_cancelled;
} scroll;
};
struct eis_touch {
struct object object;
struct eis_device *device;
void *user_data;
uint32_t tracking_id;
enum {
TOUCH_IS_NEW,
TOUCH_IS_DOWN,
TOUCH_IS_UP,
} state;
double x, y;
};
struct eis_event {

View file

@ -66,6 +66,20 @@ log_wire_message(struct eis *eis, const ServerMessage *msg)
MSG_STRING_CASE(DEVICE_PAUSED);
MSG_STRING_CASE(KEYBOARD_MODIFIERS);
MSG_STRING_CASE(PROPERTY);
/* events */
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(FRAME);
break;
}
if (message == NULL)
@ -118,7 +132,10 @@ eis_proto_send_msg_with_fds(struct eis_client *client, const ServerMessage *msg,
static int
eis_proto_send_disconnected(struct eis_client *client)
{
struct eis *eis = eis_client_get_context(client);
prepare_msg(DISCONNECTED, Disconnected, disconnected);
disconnected.is_active = eis->is_active;
return eis_proto_send_msg(client, &msg);
}
@ -271,6 +288,167 @@ eis_proto_send_property(struct eis_client *client, const char *name,
return eis_proto_send_msg(client, &msg);
}
static int
eis_proto_send_start_emulating(struct eis_device *device, uint32_t deviceid)
{
prepare_msg(START_EMULATING, StartEmulating, start_emulating);
start_emulating.deviceid = device->id;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_stop_emulating(struct eis_device *device, uint32_t deviceid)
{
prepare_msg(STOP_EMULATING, StopEmulating, stop_emulating);
stop_emulating.deviceid = device->id;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_rel(struct eis_device *device, uint32_t deviceid, 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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_abs(struct eis_device *device, uint32_t deviceid, 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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_button(struct eis_device *device, uint32_t deviceid,
uint32_t button, bool is_press)
{
prepare_msg(POINTER_BUTTON, PointerButton, pointer_button);
pointer_button.deviceid = device->id;
pointer_button.button = button;
pointer_button.state = is_press;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_key(struct eis_device *device, uint32_t deviceid,
uint32_t key, bool is_press)
{
prepare_msg(KEYBOARD_KEY, KeyboardKey, keyboard_key);
keyboard_key.deviceid = device->id;
keyboard_key.key = key;
keyboard_key.state = is_press;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_scroll(struct eis_device *device, uint32_t deviceid,
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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_scroll_stop(struct eis_device *device, uint32_t deviceid,
bool x, bool y, bool is_cancel)
{
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 = is_cancel;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_scroll_discrete(struct eis_device *device, uint32_t deviceid,
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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_touch_down(struct eis_device *device, uint32_t deviceid,
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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_touch_motion(struct eis_device *device, uint32_t deviceid,
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 eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_touch_up(struct eis_device *device, uint32_t deviceid, uint32_t tid)
{
prepare_msg(TOUCH_UP, TouchUp, touch_up);
touch_up.deviceid = device->id;
touch_up.touchid = tid;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static int
eis_proto_send_frame(struct eis_device *device, uint32_t deviceid)
{
prepare_msg(FRAME, Frame, frame);
frame.deviceid = device->id;
return eis_proto_send_msg(eis_device_get_client(device), &msg);
}
static const struct eis_proto_requests requests = {
.disconnected = eis_proto_send_disconnected,
.connected = eis_proto_send_connected,
@ -285,6 +463,21 @@ static const struct eis_proto_requests requests = {
.device_region = eis_proto_send_device_region,
.keyboard_modifiers = eis_proto_send_keyboard_modifiers,
.property = eis_proto_send_property,
/* events */
.start_emulating = eis_proto_send_start_emulating,
.stop_emulating = eis_proto_send_stop_emulating,
.rel = eis_proto_send_rel,
.abs = eis_proto_send_abs,
.button = eis_proto_send_button,
.scroll = eis_proto_send_scroll,
.scroll_stop = eis_proto_send_scroll_stop,
.scroll_discrete = eis_proto_send_scroll_discrete,
.key = eis_proto_send_key,
.touch_down = eis_proto_send_touch_down,
.touch_motion = eis_proto_send_touch_motion,
.touch_up = eis_proto_send_touch_up,
.frame = eis_proto_send_frame,
};
const struct eis_proto_requests *
@ -318,7 +511,7 @@ eis_proto_handle_message(struct eis_client *client,
int rc;
switch (proto->msg_case) {
case CLIENT_MESSAGE__MSG_CONNECT:
rc = call(connect, client, proto->connect->name);
rc = call(connect, client, proto->connect->name, proto->connect->is_active);
break;
case CLIENT_MESSAGE__MSG_CONNECT_DONE:
rc = call(connect_done, client);

View file

@ -36,7 +36,7 @@
/* callbacks invoked during eis_proto_parse_message() */
struct eis_proto_interface {
int (*connect)(struct eis_client *client, const char *name);
int (*connect)(struct eis_client *client, const char *name, bool is_active);
int (*connect_done)(struct eis_client *client);
int (*disconnect)(struct eis_client *client);
int (*bind_seat)(struct eis_client *client, uint32_t seatid, uint32_t capabilities);
@ -81,6 +81,23 @@ struct eis_proto_requests {
const struct eis_xkb_modifiers *mods);
int (*property)(struct eis_client *client, const char *name,
const char *value, uint32_t permissions);
/* events */
int (*start_emulating)(struct eis_device *device, uint32_t deviceid);
int (*stop_emulating)(struct eis_device *device, uint32_t deviceid);
int (*rel)(struct eis_device *device, uint32_t deviceid, double x, double y);
int (*abs)(struct eis_device *device, uint32_t deviceid, double x, double y);
int (*button)(struct eis_device *device, uint32_t deviceid, uint32_t button, bool is_press);
int (*key)(struct eis_device *device, uint32_t deviceid, uint32_t key, bool is_press);
int (*scroll)(struct eis_device *device, uint32_t deviceid, double x, double y);
int (*scroll_stop)(struct eis_device *device, uint32_t deviceid, bool x, bool y, bool is_cancel);
int (*scroll_discrete)(struct eis_device *device, uint32_t deviceid, int32_t x, int32_t y);
int (*touch_down)(struct eis_device *device, uint32_t deviceid,
uint32_t tid, double x, double y);
int (*touch_motion)(struct eis_device *device, uint32_t deviceid,
uint32_t tid, double x, double y);
int (*touch_up)(struct eis_device *device, uint32_t deviceid, uint32_t tid);
int (*frame) (struct eis_device *device, uint32_t deviceid);
};
int

View file

@ -39,6 +39,18 @@ extern "C" {
* libeis is the server-side module. This API should be used by processes
* that have control over input devices, e.g. Wayland compositors.
*
* libei clients come in "active" and "passive" modes, depending on whether
* the client sends or receives events. A libeis context however is both
* active and passive at the same time, it is up to the implementation to
* disconnect clients that it does not want to allow. See
* eis_client_is_active() for details.
*
* Note that usually the differentiation between active and passive client
* has an effect on the devices that should be sent to the client. Active
* clients typically expect devices representing the available screen area so
* they can control input, passive clients typically expect devices
* representing the physical input devices.
*
* @{
*/
@ -48,6 +60,7 @@ struct eis_device;
struct eis_seat;
struct eis_event;
struct eis_keymap;
struct eis_touch;
/**
* @struct eis_region
@ -144,6 +157,8 @@ enum eis_event_type {
* and notifies the server that the previous set of events belong to
* the same logical hardware event.
*
* These events are only generated on a passive EIS context.
*
* This event is most commonly used to implement multitouch (multiple
* touches may update within the same hardware scanout cycle).
*/
@ -154,7 +169,9 @@ enum eis_event_type {
* be used by the server to clear the logical state of the emulated
* devices and/or provide UI to the user.
*
* Note that a client may need to start multiple emulating sequences
* These events are only generated on a passive EIS context.
*
* Note that a client start multiple emulating sequences
* simultaneously, depending on the devices it received from the
* server. For example, in a synergy-like situation, the client
* may start emulating of pointer and keyboard once the remote device
@ -169,6 +186,8 @@ enum eis_event_type {
*/
EIS_EVENT_DEVICE_STOP_EMULATING,
/* These events are only generated on a passive EIS context */
/**
* A relative motion event with delta coordinates
*/
@ -286,6 +305,14 @@ eis_get_user_data(struct eis *eis);
void
eis_set_user_data(struct eis *eis, void *user_data);
/**
* Returns true if the client is active, false otherwise. An active client may
* send events to the EIS implementation, a passive client expects to receive
* events from the EIS implementation.
*/
bool
eis_client_is_active(struct eis_client *client);
/**
* See eis_client_property_set_with_permissions(), but the permissions are
* left as-is. If the property does not exist, it is created with permissions
@ -842,6 +869,88 @@ eis_device_keyboard_send_xkb_modifiers(struct eis_device *device,
uint32_t locked,
uint32_t group);
/** see @ref ei_device_start_emulating */
void
eis_device_start_emulating(struct eis_device *device);
/** see @ref ei_device_stop_emulating */
void
eis_device_stop_emulating(struct eis_device *device);
/** see @ref ei_device_frame */
void
eis_device_frame(struct eis_device *device);
/** see @ref ei_device_pointer_motion */
void
eis_device_pointer_motion(struct eis_device *device, double x, double y);
/** see @ref ei_device_pointer_motion_absolute */
void
eis_device_pointer_motion_absolute(struct eis_device *device,
double x, double y);
/** see @ref ei_device_pointer_button */
void
eis_device_pointer_button(struct eis_device *device,
uint32_t button, bool is_press);
/** see @ref ei_device_pointer_scroll */
void
eis_device_pointer_scroll(struct eis_device *device, double x, double y);
/** see @ref ei_device_pointer_scroll_discrete */
void
eis_device_pointer_scroll_discrete(struct eis_device *device, int32_t x, int32_t y);
/** see @ref ei_device_pointer_scroll_stop */
void
eis_device_pointer_scroll_stop(struct eis_device *device, bool stop_x, bool stop_y);
/** see @ref ei_device_pointer_scroll_cancel */
void
eis_device_pointer_scroll_cancel(struct eis_device *device, bool cancel_x, bool cancel_y);
/** see @ref ei_device_keyboard_key */
void
eis_device_keyboard_key(struct eis_device *device, uint32_t keycode, bool is_press);
/** see @ref ei_device_touch_new */
struct eis_touch *
eis_device_touch_new(struct eis_device *device);
/** see @ref ei_touch_down */
void
eis_touch_down(struct eis_touch *touch, double x, double y);
/** see @ref ei_touch_motion */
void
eis_touch_motion(struct eis_touch *touch, double x, double y);
/** see @ref ei_touch_up */
void
eis_touch_up(struct eis_touch *touch);
/** see @ref ei_touch_ref */
struct eis_touch *
eis_touch_ref(struct eis_touch *touch);
/** see @ref ei_touch_unref */
struct eis_touch *
eis_touch_unref(struct eis_touch *touch);
/** see @ref ei_touch_set_user_data */
void
eis_touch_set_user_data(struct eis_touch *touch, void *user_data);
/** see @ref ei_touch_get_user_data */
void *
eis_touch_get_user_data(struct eis_touch *touch);
/** see @ref ei_touch_get_device */
struct eis_device *
eis_touch_get_device(struct eis_touch *touch);
/**
* For an event of type @ref EIS_EVENT_SEAT_BIND, return the capabilities
* requested by the client.

View file

@ -314,15 +314,17 @@ peck_log_handler(struct logger *logger,
}
struct peck *
peck_new(void)
peck_new_context(enum peck_ei_mode ei_mode)
{
struct peck *peck = peck_create(NULL);
assert(ei_mode == PECK_EI_PASSIVE || ei_mode == PECK_EI_ACTIVE);
int sv[2];
int rc = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, sv);
munit_assert_int(rc, ==, 0);
struct ei *ei = ei_new(peck);
struct ei *ei = ei_mode == PECK_EI_PASSIVE ? ei_new_passive(peck) : ei_new_active(peck);
ei_set_user_data(ei, peck);
ei_log_set_handler(ei, peck_ei_log_handler);
ei_log_set_priority(ei, EI_LOG_PRIORITY_DEBUG);
@ -352,6 +354,12 @@ peck_new(void)
return peck;
}
struct peck *
peck_new(void)
{
return peck_new_context(PECK_EI_ACTIVE);
}
void
peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior)
{
@ -1014,6 +1022,20 @@ peck_ei_event_type_name(enum ei_event_type type)
CASE_STRING(DEVICE_RESUMED);
CASE_STRING(KEYBOARD_MODIFIERS);
CASE_STRING(PROPERTY);
CASE_STRING(FRAME);
CASE_STRING(DEVICE_START_EMULATING);
CASE_STRING(DEVICE_STOP_EMULATING);
CASE_STRING(POINTER_MOTION);
CASE_STRING(POINTER_MOTION_ABSOLUTE);
CASE_STRING(POINTER_BUTTON);
CASE_STRING(POINTER_SCROLL);
CASE_STRING(POINTER_SCROLL_STOP);
CASE_STRING(POINTER_SCROLL_CANCEL);
CASE_STRING(POINTER_SCROLL_DISCRETE);
CASE_STRING(KEYBOARD_KEY);
CASE_STRING(TOUCH_DOWN);
CASE_STRING(TOUCH_UP);
CASE_STRING(TOUCH_MOTION);
}
#undef CASE_STRING
assert(!"Unhandled ei event type");

View file

@ -31,6 +31,11 @@
#include "util-mem.h"
enum peck_ei_mode {
PECK_EI_PASSIVE = 20,
PECK_EI_ACTIVE,
};
/**
* An enum to define basic server behavior in peck_dispatch_eis().
* Where a flag is **not** set for any specific behaviour, that event will
@ -134,6 +139,9 @@ struct peck;
struct peck *
peck_new(void);
struct peck *
peck_new_context(enum peck_ei_mode ei_mode);
void _peck_mark(struct peck *peck, const char *func, int line);
/** Add debug marker to the log output */
#define peck_mark(peck_) _peck_mark(peck_, __func__, __LINE__)

View file

@ -860,6 +860,43 @@ MUNIT_TEST(test_ei_disconnect_after_unbind_after_received)
return MUNIT_OK;
}
MUNIT_TEST(test_client_is_active)
{
_unref_(peck) *peck = peck_new_context(PECK_EI_ACTIVE);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
struct eis_client *client = eis_event_get_client(connect);
munit_assert_true(eis_client_is_active(client));
}
return MUNIT_OK;
}
MUNIT_TEST(test_client_is_passive)
{
_unref_(peck) *peck = peck_new_context(PECK_EI_PASSIVE);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
struct eis_client *client = eis_event_get_client(connect);
munit_assert_false(eis_client_is_active(client));
}
return MUNIT_OK;
}
/* Emulates the XWayland behavior for calling
* xdotool mousemove_relative -- -1 10
*/