add support for touch events (WIP)
This is tested with Gtk clients. There are a number of TODO items: - hardcoded scaling for mapping the touch co-ordinate system into layout co-ordinates (works on my Pinephone :-). - we should send events to the client no matter what the Lua handler returns (I think the code to not do this is broken anyway...). Instead, if the handler returns true we should send the client a touch cancel event. - maybe there's a better way to deal with seat capabilities than adding a "touchpads" field to kiwmi_input
This commit is contained in:
parent
17814972ab
commit
e7b0bae792
6 changed files with 233 additions and 0 deletions
|
@ -39,6 +39,10 @@ struct kiwmi_cursor {
|
|||
struct wl_listener cursor_button;
|
||||
struct wl_listener cursor_axis;
|
||||
struct wl_listener cursor_frame;
|
||||
struct wl_listener cursor_touch_up;
|
||||
struct wl_listener cursor_touch_down;
|
||||
struct wl_listener cursor_touch_motion;
|
||||
struct wl_listener cursor_touch_frame;
|
||||
|
||||
struct {
|
||||
struct wl_signal button_down;
|
||||
|
@ -46,6 +50,7 @@ struct kiwmi_cursor {
|
|||
struct wl_signal destroy;
|
||||
struct wl_signal motion;
|
||||
struct wl_signal scroll;
|
||||
struct wl_signal touch;
|
||||
} events;
|
||||
};
|
||||
|
||||
|
@ -61,6 +66,14 @@ struct kiwmi_cursor_motion_event {
|
|||
double newy;
|
||||
};
|
||||
|
||||
struct kiwmi_cursor_touch_event {
|
||||
char *event;
|
||||
int id;
|
||||
double x;
|
||||
double y;
|
||||
bool handled;
|
||||
};
|
||||
|
||||
struct kiwmi_cursor_scroll_event {
|
||||
const char *device_name;
|
||||
bool is_vertical;
|
||||
|
|
|
@ -16,6 +16,7 @@ struct kiwmi_input {
|
|||
struct wl_listener new_input;
|
||||
struct kiwmi_cursor *cursor;
|
||||
struct kiwmi_seat *seat;
|
||||
int touchpads;
|
||||
|
||||
struct {
|
||||
struct wl_signal keyboard_new;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_pointer.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
@ -120,6 +122,124 @@ cursor_motion_notify(struct wl_listener *listener, void *data)
|
|||
process_cursor_motion(server, event->time_msec);
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_touch_down_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct kiwmi_cursor *cursor =
|
||||
wl_container_of(listener, cursor, cursor_touch_down);
|
||||
struct kiwmi_server *server = cursor->server;
|
||||
struct kiwmi_desktop *desktop = &server->desktop;
|
||||
struct wlr_event_touch_down *event = data;
|
||||
|
||||
struct kiwmi_input *input = &server->input;
|
||||
struct wlr_seat *seat = input->seat->seat;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
/* FIXME figure out what scaling should be done here.
|
||||
* Does the touch co-ordinate system map onto a single output
|
||||
* (e.g. phone screen) or onto the entire layout (tablet,
|
||||
* maybe?)
|
||||
*/
|
||||
double lx = 720 * event->x;
|
||||
double ly = 1440 * event->y;
|
||||
double sx, sy;
|
||||
|
||||
struct kiwmi_view *view = view_at(
|
||||
desktop,
|
||||
lx, ly,
|
||||
&surface,
|
||||
&sx, &sy);
|
||||
|
||||
/* we send the event to lua with 0..1 co-ordinates, because
|
||||
* it may not be over any surface
|
||||
*/
|
||||
struct kiwmi_cursor_touch_event new_event = {
|
||||
.event = "down",
|
||||
.id = event->touch_id,
|
||||
.x = event->x,
|
||||
.y = event->y,
|
||||
};
|
||||
|
||||
wl_signal_emit(&cursor->events.touch, &new_event);
|
||||
|
||||
if(!new_event.handled &&
|
||||
surface &&
|
||||
wlr_surface_accepts_touch(seat, surface)) {
|
||||
wlr_seat_touch_notify_down(seat, surface, event->time_msec,
|
||||
event->touch_id, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_touch_up_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct kiwmi_cursor *cursor =
|
||||
wl_container_of(listener, cursor, cursor_touch_up);
|
||||
struct kiwmi_server *server = cursor->server;
|
||||
struct wlr_event_touch_up *event = data;
|
||||
struct kiwmi_input *input = &server->input;
|
||||
struct wlr_seat *seat = input->seat->seat;
|
||||
|
||||
struct kiwmi_cursor_touch_event new_event = {
|
||||
.event = "up",
|
||||
.id = event->touch_id,
|
||||
};
|
||||
|
||||
wl_signal_emit(&cursor->events.touch, &new_event);
|
||||
if(!new_event.handled) {
|
||||
wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_touch_motion_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct kiwmi_cursor *cursor =
|
||||
wl_container_of(listener, cursor, cursor_touch_motion);
|
||||
struct kiwmi_server *server = cursor->server;
|
||||
struct wlr_event_touch_motion *event = data;
|
||||
struct kiwmi_input *input = &server->input;
|
||||
struct wlr_seat *seat = input->seat->seat;
|
||||
|
||||
struct kiwmi_cursor_touch_event new_event = {
|
||||
.event = "motion",
|
||||
.id = event->touch_id,
|
||||
.x = event->x,
|
||||
.y = event->y,
|
||||
};
|
||||
|
||||
wl_signal_emit(&cursor->events.touch, &new_event);
|
||||
|
||||
if(!new_event.handled) {
|
||||
/* UNSURE: should we still send this even if the touch_down
|
||||
* didn't get sent because the surface doesn't accept
|
||||
* touch? */
|
||||
wlr_seat_touch_notify_motion(seat, event->time_msec,
|
||||
event->touch_id, event->x, event->y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_touch_frame_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct kiwmi_cursor *cursor =
|
||||
wl_container_of(listener, cursor, cursor_touch_frame);
|
||||
struct kiwmi_server *server = cursor->server;
|
||||
struct kiwmi_input *input = &server->input;
|
||||
|
||||
struct wlr_seat *seat = input->seat->seat;
|
||||
|
||||
struct kiwmi_cursor_touch_event new_event = {
|
||||
.event = "frame",
|
||||
};
|
||||
|
||||
wl_signal_emit(&cursor->events.touch, &new_event);
|
||||
|
||||
if(!new_event.handled) {
|
||||
wlr_seat_touch_notify_frame(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_motion_absolute_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
@ -253,10 +373,23 @@ cursor_create(
|
|||
cursor->cursor_frame.notify = cursor_frame_notify;
|
||||
wl_signal_add(&cursor->cursor->events.frame, &cursor->cursor_frame);
|
||||
|
||||
cursor->cursor_touch_down.notify = cursor_touch_down_notify;
|
||||
wl_signal_add(&cursor->cursor->events.touch_down, &cursor->cursor_touch_down);
|
||||
|
||||
cursor->cursor_touch_up.notify = cursor_touch_up_notify;
|
||||
wl_signal_add(&cursor->cursor->events.touch_up, &cursor->cursor_touch_up);
|
||||
|
||||
cursor->cursor_touch_motion.notify = cursor_touch_motion_notify;
|
||||
wl_signal_add(&cursor->cursor->events.touch_motion, &cursor->cursor_touch_motion);
|
||||
|
||||
cursor->cursor_touch_frame.notify = cursor_touch_frame_notify;
|
||||
wl_signal_add(&cursor->cursor->events.touch_frame, &cursor->cursor_touch_frame);
|
||||
|
||||
wl_signal_init(&cursor->events.button_down);
|
||||
wl_signal_init(&cursor->events.button_up);
|
||||
wl_signal_init(&cursor->events.destroy);
|
||||
wl_signal_init(&cursor->events.motion);
|
||||
wl_signal_init(&cursor->events.touch);
|
||||
wl_signal_init(&cursor->events.scroll);
|
||||
|
||||
return cursor;
|
||||
|
|
|
@ -36,6 +36,13 @@ new_pointer(struct kiwmi_input *input, struct wlr_input_device *device)
|
|||
wl_list_insert(&input->pointers, &pointer->link);
|
||||
}
|
||||
|
||||
static void
|
||||
new_touch(struct kiwmi_input *input, struct wlr_input_device *device)
|
||||
{
|
||||
wlr_cursor_attach_input_device(input->cursor->cursor, device);
|
||||
input->touchpads++;
|
||||
}
|
||||
|
||||
static void
|
||||
new_keyboard(struct kiwmi_input *input, struct wlr_input_device *device)
|
||||
{
|
||||
|
@ -61,6 +68,9 @@ new_input_notify(struct wl_listener *listener, void *data)
|
|||
case WLR_INPUT_DEVICE_POINTER:
|
||||
new_pointer(input, device);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
new_touch(input, device);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
new_keyboard(input, device);
|
||||
break;
|
||||
|
@ -73,6 +83,9 @@ new_input_notify(struct wl_listener *listener, void *data)
|
|||
if (!wl_list_empty(&input->keyboards)) {
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
}
|
||||
if(input->touchpads) {
|
||||
caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
}
|
||||
|
||||
wlr_seat_set_capabilities(input->seat->seat, caps);
|
||||
}
|
||||
|
|
|
@ -153,6 +153,36 @@ kiwmi_cursor_on_motion_notify(struct wl_listener *listener, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kiwmi_cursor_on_touch_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener);
|
||||
struct kiwmi_server *server = lc->server;
|
||||
lua_State *L = server->lua->L;
|
||||
struct kiwmi_cursor_touch_event *event = data;
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref);
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushnumber(L, event->x);
|
||||
lua_setfield(L, -2, "x");
|
||||
|
||||
lua_pushnumber(L, event->y);
|
||||
lua_setfield(L, -2, "y");
|
||||
|
||||
lua_pushnumber(L, event->id);
|
||||
lua_setfield(L, -2, "id");
|
||||
|
||||
lua_pushstring(L, event->event);
|
||||
lua_setfield(L, -2, "name");
|
||||
|
||||
if (lua_pcall(L, 1, 0, 0)) {
|
||||
wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kiwmi_cursor_on_scroll_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
@ -258,6 +288,31 @@ l_kiwmi_cursor_on_motion(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
l_kiwmi_cursor_on_touch(lua_State *L)
|
||||
{
|
||||
struct kiwmi_object *obj =
|
||||
*(struct kiwmi_object **)luaL_checkudata(L, 1, "kiwmi_cursor");
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
struct kiwmi_cursor *cursor = obj->object;
|
||||
struct kiwmi_server *server = cursor->server;
|
||||
|
||||
lua_pushcfunction(L, luaK_kiwmi_lua_callback_new);
|
||||
lua_pushlightuserdata(L, server);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_pushlightuserdata(L, kiwmi_cursor_on_touch_notify);
|
||||
lua_pushlightuserdata(L, &cursor->events.touch);
|
||||
lua_pushlightuserdata(L, obj);
|
||||
|
||||
if (lua_pcall(L, 5, 0, 0)) {
|
||||
wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
l_kiwmi_cursor_on_scroll(lua_State *L)
|
||||
{
|
||||
|
@ -287,6 +342,7 @@ static const luaL_Reg kiwmi_cursor_events[] = {
|
|||
{"button_down", l_kiwmi_cursor_on_button_down},
|
||||
{"button_up", l_kiwmi_cursor_on_button_up},
|
||||
{"motion", l_kiwmi_cursor_on_motion},
|
||||
{"touch", l_kiwmi_cursor_on_touch},
|
||||
{"scroll", l_kiwmi_cursor_on_scroll},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
|
17
lua_docs.md
17
lua_docs.md
|
@ -157,6 +157,23 @@ The callback receives a table containing `device` with the device name, `vertica
|
|||
The callback is supposed to return `true` if the event was handled.
|
||||
The compositor will not forward it to the view under the cursor.
|
||||
|
||||
#### touch
|
||||
|
||||
A touchpad or toushcreen was interacted with in some way. The callback
|
||||
receives a table containing
|
||||
|
||||
* `name`: one of `down`, `up`, `motion` or `frame`
|
||||
* `id`: a number used to indicate which finger has dome something, used on devices that support "multitouch". For example, the first finger to touch the pad may be assigned id 0 and a second finger added may be assigned 1. The id may or may not be reassigned if a finger is lifted and replaced.
|
||||
* `x`, `y`: for `down` or `motion` events, the location where the screen was touched. These each range between 0.0 and 1.0
|
||||
|
||||
All touch events are sent to the same callback, because the
|
||||
appropriate mode of processing them is to collect messages until
|
||||
there's a `frame` event and group them together. For more information see [the Wayland book](https://wayland-book.com/seat/touch.html)
|
||||
|
||||
The callback is supposed to return `true` if the event was handled.
|
||||
The compositor will not forward it to the view under the cursor.
|
||||
_FIXME: should use gesture cancellation instead_
|
||||
|
||||
## kiwmi_keyboard
|
||||
|
||||
A handle to a keyboard.
|
||||
|
|
Loading…
Add table
Reference in a new issue