mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-05-09 03:58:03 +02:00
Add support for absolute pointer motion events
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
09ad65d5c6
commit
90d2b1b980
17 changed files with 262 additions and 4 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
21
src/libei.c
21
src/libei.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
11
src/libeis.c
11
src/libeis.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue