Add support for absolute pointer motion events

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2020-09-22 13:17:54 +10:00
parent 09ad65d5c6
commit 90d2b1b980
17 changed files with 262 additions and 4 deletions

View file

@ -103,6 +103,12 @@ message PointerRelative {
double y = 3;
}
message PointerAbsolute {
uint32 deviceid = 1;
double x = 2;
double y = 3;
}
message PointerButton {
uint32 deviceid = 1;
uint32 button = 2;
@ -122,10 +128,11 @@ message ClientMessage {
AddDevice add_device = 3;
RemoveDevice remove_device = 4;
PointerRelative rel = 5;
PointerButton button = 6;
KeyboardKey key = 7;
ConfigureName configure_name = 8;
ConfigureCapabilities configure_caps = 9;
PointerAbsolute abs = 6;
PointerButton button = 7;
KeyboardKey key = 8;
ConfigureName configure_name = 9;
ConfigureCapabilities configure_caps = 10;
}
}

View file

@ -211,6 +211,12 @@ ei_device_set_keymap(struct ei_device *device,
_public_ void
ei_device_add(struct ei_device *device)
{
if (ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) &&
(device->abs.dim.width == 0 || device->abs.dim.height == 0))
log_bug(ei_device_get_context(device),
"device %s is missing an abs pointer range\n",
device->name);
ei_add_device(device);
ei_device_set_state(device, EI_DEVICE_STATE_CONNECTING);
}
@ -337,6 +343,23 @@ ei_device_pointer_motion(struct ei_device *device,
ei_pointer_rel(device, x, y);
}
_public_ void
ei_device_pointer_motion_absolute(struct ei_device *device,
double x, double y)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE))
return;
if (device->state != EI_DEVICE_STATE_RESUMED)
return;
if (x < 0 || x >= device->abs.dim.width ||
y < 0 || y >= device->abs.dim.height)
return;
ei_pointer_abs(device, x, y);
}
_public_ void
ei_device_pointer_button(struct ei_device *device,
uint32_t button, bool is_press)

View file

@ -120,6 +120,10 @@ int
ei_pointer_rel(struct ei_device *device,
double x, double y);
int
ei_pointer_abs(struct ei_device *device,
double x, double y);
int
ei_pointer_button(struct ei_device *device,
uint32_t button, bool is_press);

View file

@ -146,6 +146,7 @@ log_wire_message(struct ei *ei, const ClientMessage *msg, int error)
MSG_STRING_CASE(ADD_DEVICE);
MSG_STRING_CASE(REMOVE_DEVICE);
MSG_STRING_CASE(REL);
MSG_STRING_CASE(ABS);
MSG_STRING_CASE(BUTTON);
MSG_STRING_CASE(KEY);
MSG_STRING_CASE(CONFIGURE_NAME);
@ -277,6 +278,23 @@ ei_proto_send_rel(struct ei *ei, struct ei_device *device,
return ei_proto_send_msg(ei, &msg);
}
int
ei_proto_send_abs(struct ei *ei, struct ei_device *device,
double x, double y)
{
ClientMessage msg = CLIENT_MESSAGE__INIT;
PointerAbsolute abs = POINTER_ABSOLUTE__INIT;
abs.deviceid = device->id;
abs.x = x;
abs.y = y;
msg.abs = &abs;
msg.msg_case = CLIENT_MESSAGE__MSG_ABS;
return ei_proto_send_msg(ei, &msg);
}
int
ei_proto_send_button(struct ei *ei, struct ei_device *device,
uint32_t b, bool is_press)

View file

@ -109,6 +109,10 @@ int
ei_proto_send_rel(struct ei *ei, struct ei_device *device,
double x, double y);
int
ei_proto_send_abs(struct ei *ei, struct ei_device *device,
double x, double y);
int
ei_proto_send_button(struct ei *ei, struct ei_device *device,
uint32_t b, bool is_press);

View file

@ -269,6 +269,17 @@ connection_send_rel(struct ei *ei, struct ei_device *device,
return ei_proto_send_rel(ei, device, x, y);
}
static int
connection_send_abs(struct ei *ei, struct ei_device *device,
double x, double y)
{
if (ei->state == EI_STATE_NEW ||
ei->state == EI_STATE_DISCONNECTED)
return 0;
return ei_proto_send_abs(ei, device, x, y);
}
static int
connection_send_button(struct ei *ei, struct ei_device *device,
uint32_t b, bool is_press)
@ -460,6 +471,16 @@ ei_pointer_rel(struct ei_device *device, double x, double y)
return rc;
}
int
ei_pointer_abs(struct ei_device *device, double x, double y)
{
struct ei *ei = ei_device_get_context(device);
int rc = connection_send_abs(ei, device, x, y);
if (rc)
ei_disconnect(ei);
return rc;
}
int
ei_pointer_button(struct ei_device *device, uint32_t button, bool is_press)
{

View file

@ -572,6 +572,7 @@ ei_device_pointer_motion(struct ei_device *device, double x, double y);
* The required conditions are:
* - 0 <= x < width
* - 0 <= y < height
* If these conditions are not met, the event is silently discarded.
*
* @param x The x position in logical pixels
* @param y The y position in logical pixels

View file

@ -228,6 +228,20 @@ client_pointer_rel(struct eis_client *client, uint32_t deviceid,
return -EINVAL;
}
static int
client_pointer_abs(struct eis_client *client, uint32_t deviceid,
double x, double y)
{
struct eis_device *device;
list_for_each(device, &client->devices, link) {
if (device->id == deviceid) {
return eis_device_pointer_abs(device, x, y);
}
}
return -EINVAL;
}
static int
client_pointer_button(struct eis_client *client, uint32_t deviceid,
uint32_t button, bool state)
@ -312,6 +326,7 @@ client_new_handle_msg(struct eis_client *client, struct message *msg)
case MESSAGE_ADD_DEVICE:
case MESSAGE_REMOVE_DEVICE:
case MESSAGE_POINTER_REL:
case MESSAGE_POINTER_ABS:
case MESSAGE_POINTER_BUTTON:
case MESSAGE_KEYBOARD_KEY:
rc = -EPROTO;
@ -344,6 +359,7 @@ client_connecting_handle_msg(struct eis_client *client, const struct message *ms
case MESSAGE_ADD_DEVICE:
case MESSAGE_REMOVE_DEVICE:
case MESSAGE_POINTER_REL:
case MESSAGE_POINTER_ABS:
case MESSAGE_POINTER_BUTTON:
case MESSAGE_KEYBOARD_KEY:
rc = -EPROTO;
@ -391,6 +407,10 @@ client_connected_handle_msg(struct eis_client *client,
rc = client_pointer_rel(client, msg->pointer_rel.deviceid,
msg->pointer_rel.x, msg->pointer_rel.y);
break;
case MESSAGE_POINTER_ABS:
rc = client_pointer_abs(client, msg->pointer_abs.deviceid,
msg->pointer_abs.x, msg->pointer_abs.y);
break;
case MESSAGE_POINTER_BUTTON:
rc = client_pointer_button(client, msg->pointer_button.deviceid,
msg->pointer_button.button,

View file

@ -220,6 +220,25 @@ eis_device_pointer_rel(struct eis_device *device,
return 0;
}
int
eis_device_pointer_abs(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE))
return -EINVAL;
if (device->state != EIS_DEVICE_STATE_RESUMED)
return -EINVAL;
if (x < 0 || x >= device->abs.dim.width ||
y < 0 || y >= device->abs.dim.height)
return -EINVAL;
eis_queue_pointer_abs_event(device, x, y);
return 0;
}
int
eis_device_pointer_button(struct eis_device *device,
uint32_t button, bool is_press)

View file

@ -39,6 +39,7 @@ eis_event_destroy(struct eis_event *event)
case EIS_EVENT_DEVICE_ADDED:
case EIS_EVENT_POINTER_BUTTON:
case EIS_EVENT_POINTER_MOTION:
case EIS_EVENT_POINTER_MOTION_ABSOLUTE:
case EIS_EVENT_KEYBOARD_KEY:
break;
case EIS_EVENT_DEVICE_REMOVED:
@ -160,6 +161,32 @@ eis_event_pointer_get_dy(struct eis_event *event)
return event->pointer.dy;
}
_public_ double
eis_event_pointer_get_absolute_x(struct eis_event *event)
{
require_event_type(event, 0.0,
EIS_EVENT_POINTER_MOTION,
EIS_EVENT_POINTER_MOTION_ABSOLUTE,
EIS_EVENT_POINTER_BUTTON,
EIS_EVENT_POINTER_SCROLL,
EIS_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.absx;
}
_public_ double
eis_event_pointer_get_absolute_y(struct eis_event *event)
{
require_event_type(event, 0.0,
EIS_EVENT_POINTER_MOTION,
EIS_EVENT_POINTER_MOTION_ABSOLUTE,
EIS_EVENT_POINTER_BUTTON,
EIS_EVENT_POINTER_SCROLL,
EIS_EVENT_POINTER_SCROLL_DISCRETE);
return event->pointer.absy;
}
_public_ uint32_t
eis_event_pointer_get_button(struct eis_event *event)
{

View file

@ -121,6 +121,7 @@ struct eis_event {
union {
struct {
double dx, dy; /* relative motion */
double absx, absy; /* absolute motion */
uint32_t button;
bool button_is_press;
} pointer;
@ -187,6 +188,10 @@ int
eis_device_pointer_rel(struct eis_device *device,
double x, double y);
int
eis_device_pointer_abs(struct eis_device *device,
double x, double y);
int
eis_device_pointer_button(struct eis_device *device,
uint32_t button, bool state);
@ -222,6 +227,10 @@ eis_queue_removed_event(struct eis_device *device);
void
eis_queue_pointer_rel_event(struct eis_device *device, double x, double y);
void
eis_queue_pointer_abs_event(struct eis_device *device,
double x, double y);
void
eis_queue_pointer_button_event(struct eis_device *device, uint32_t button,
bool is_press);

View file

@ -271,6 +271,17 @@ eis_proto_parse_message(struct brei_message *bmsg, size_t *consumed)
};
}
break;
case CLIENT_MESSAGE__MSG_ABS:
{
PointerAbsolute *a = proto->abs;
*msg = (struct message) {
.type = MESSAGE_POINTER_ABS,
.pointer_abs.deviceid = a->deviceid,
.pointer_abs.x = a->x,
.pointer_abs.y = a->y,
};
}
break;
case CLIENT_MESSAGE__MSG_BUTTON:
{
PointerButton *b = proto->button;

View file

@ -40,6 +40,7 @@ enum message_type {
MESSAGE_ADD_DEVICE,
MESSAGE_REMOVE_DEVICE,
MESSAGE_POINTER_REL,
MESSAGE_POINTER_ABS,
MESSAGE_POINTER_BUTTON,
MESSAGE_KEYBOARD_KEY,
@ -75,6 +76,11 @@ struct message {
double x;
double y;
} pointer_rel;
struct message_pointer_abs {
uint32_t deviceid;
double x;
double y;
} pointer_abs;
struct message_pointer_button {
uint32_t deviceid;
uint32_t button;

View file

@ -175,6 +175,17 @@ eis_queue_pointer_rel_event(struct eis_device *device,
eis_queue_event(e);
}
void
eis_queue_pointer_abs_event(struct eis_device *device,
double x, double y)
{
struct eis_event *e = eis_event_new_for_device(device);
e->type = EIS_EVENT_POINTER_MOTION_ABSOLUTE;
e->pointer.absx = x;
e->pointer.absy = y;
eis_queue_event(e);
}
void
eis_queue_pointer_button_event(struct eis_device *device, uint32_t button,
bool is_press)

View file

@ -213,11 +213,13 @@ peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior)
break;
case PECK_EIS_BEHAVIOR_ACCEPT_DEVICE:
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_POINTER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_POINTER_ABSOLUTE);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_KEYBOARD);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_TOUCH);
break;
case PECK_EIS_BEHAVIOR_REJECT_DEVICE:
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER_ABSOLUTE);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_KEYBOARD);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_TOUCH);
break;
@ -272,10 +274,12 @@ peck_enable_ei_behavior(struct peck *peck, enum peck_ei_behavior behavior)
break;
case PECK_EI_BEHAVIOR_HANDLE_ADDED:
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER_ABSOLUTE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED_KEYBOARD);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED_TOUCH);
break;
case PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER:
case PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER_ABSOLUTE:
case PECK_EI_BEHAVIOR_HANDLE_ADDED_KEYBOARD:
case PECK_EI_BEHAVIOR_HANDLE_ADDED_TOUCH:
flag_set(peck->ei_behavior, behavior);
@ -427,6 +431,10 @@ peck_check_ei_added(struct peck *peck, struct ei_event *e)
flag_is_set(peck->ei_behavior, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER))
return tristate_yes;
if (ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) &&
flag_is_set(peck->ei_behavior, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER_ABSOLUTE))
return tristate_yes;
if (ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD) &&
flag_is_set(peck->ei_behavior, PECK_EI_BEHAVIOR_HANDLE_ADDED_KEYBOARD))
return tristate_yes;

View file

@ -90,6 +90,7 @@ enum peck_ei_behavior {
PECK_EI_BEHAVIOR_AUTODEVICES,
PECK_EI_BEHAVIOR_HANDLE_ADDED,
PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER,
PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER_ABSOLUTE,
PECK_EI_BEHAVIOR_HANDLE_ADDED_KEYBOARD,
PECK_EI_BEHAVIOR_HANDLE_ADDED_TOUCH,

View file

@ -663,6 +663,74 @@ MUNIT_TEST(test_ei_device_pointer_rel)
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_pointer_abs)
{
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_ei_device_ struct ei_device *device = NULL;
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES);
peck_dispatch_until_stable(peck);
with_client(peck) {
device = ei_device_new(ei);
munit_assert_not_null(device);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE);
ei_device_pointer_configure_range(device, 1920, 1200);
ei_device_add(device);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
for (int i = 0; i < 10; i++)
ei_device_pointer_motion_absolute(device, 1 * i , 2 + i);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
for (int i = 0; i < 10; i++) {
_cleanup_eis_event_ struct eis_event *e =
peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION_ABSOLUTE);
munit_assert_double_equal(eis_event_pointer_get_absolute_x(e), 1.0 * i, 2 /* precision */);
munit_assert_double_equal(eis_event_pointer_get_absolute_y(e), 2.0 + i, 2 /* precision */);
}
}
with_client(peck) {
/* outside of pointer range, expect to be discarded */
ei_device_pointer_motion_absolute(device, 1920, 1200);
ei_device_pointer_motion_absolute(device, 2000, 1400);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
}
with_client(peck) {
ei_device_remove(device);
/* absmotion after remove must not trigger an event */
ei_device_pointer_motion_absolute(device, 100, 200);
}
with_server(peck) {
/* Don't auto-handle the removed event */
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_dispatch_eis(peck);
_cleanup_eis_event_ struct eis_event *e =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED);
peck_assert_no_eis_events(eis);
}
return MUNIT_OK;
}
int
main(int argc, char **argv)
{