From e2ba7017ea66c92e6385171943b780e37050a2df Mon Sep 17 00:00:00 2001 From: 6z7y Date: Fri, 19 Jun 2026 23:59:06 +0300 Subject: [PATCH] touch-input: Support osu! and fix touch motion issue --- patches/touch-input/README.md | 50 ++-- .../touch-input/touch-input-0.8-osu-ver.patch | 279 ++++++++++++++++++ 2 files changed, 307 insertions(+), 22 deletions(-) create mode 100755 patches/touch-input/touch-input-0.8-osu-ver.patch diff --git a/patches/touch-input/README.md b/patches/touch-input/README.md index 6b348ee..1dde5a9 100644 --- a/patches/touch-input/README.md +++ b/patches/touch-input/README.md @@ -1,22 +1,28 @@ -### Description -Adds touchscreen functionality. - -KNOWN BUGS: -- Sometimes, the pointer moves to where the screen is pressed, but the button press doesn't occur until the screen is touched AGAIN. This means that if you touch to click button 'Q' on the screen (for instance), nothing happens; then you touch elsewhere on the screen and THEN button 'Q' registers a click. This is annoying, doesn't always happen, and I don't yet know how to fix it. - -### Download -- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/touch-input) -- [touch-input-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-wlroots-next-f4249db.patch) -- [touch-input-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-0.8.patch) - -### Authors -- [fauxmight](https://codeberg.org/fauxmight) -- [minego](https://codeberg.org/minego) -- [Unprex](https://github.com/Unprex) - -### Changelog -- 2026-02-26 Update patch for dwl v0.8 and dwl wlroots-next branch commit f4249db -- 2025-01-01 @fauxmight took over maintenance. Previous maintainer @minego notes [lack of available time](https://codeberg.org/dwl/dwl-patches/pulls/102#issuecomment-2557944) -- 2024-02-11 Corrected issue where motion events where not sending notifications for unfocused clients such as an on screen keyboard -- 2024-03-26 Rebased, and removed #ifdef's for the pointer constraints patch which has been merged into upstream -- 2024-03-28 Removed debug +### Description +Adds touchscreen functionality. + +KNOWN BUGS: +- Sometimes, the pointer moves to where the screen is pressed, but the button press doesn't occur until the screen is touched AGAIN. This means that if you touch to click button 'Q' on the screen (for instance), nothing happens; then you touch elsewhere on the screen and THEN button 'Q' registers a click. This is annoying, doesn't always happen, and I don't yet know how to fix it. + +### Download +- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/touch-input) +- [touch-input-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-wlroots-next-f4249db.patch) +- [touch-input-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-0.8.patch) +- [touch-input-0.8-osu-ver.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input-0.8-osu-ver.patch) + +### Authors +#### Current +- [fauxmight](https://codeberg.org/fauxmight) +- [6z7y](https://codeberg.org/6z7y) -- maintaining `osu!` version of the `touch-input` patch +#### Historic +- [minego](https://codeberg.org/minego) +- [Unprex](https://github.com/Unprex) + + +### Changelog +- 2026-06-15 Add support for osu! fullscreen touch input (fix cursor stuck issue) +- 2026-02-26 Update patch for dwl v0.8 and dwl wlroots-next branch commit f4249db +- 2025-01-01 @fauxmight took over maintenance. Previous maintainer @minego notes [lack of available time](https://codeberg.org/dwl/dwl-patches/pulls/102#issuecomment-2557944) +- 2024-02-11 Corrected issue where motion events where not sending notifications for unfocused clients such as an on screen keyboard +- 2024-03-26 Rebased, and removed #ifdef's for the pointer constraints patch which has been merged into upstream +- 2024-03-28 Removed debug diff --git a/patches/touch-input/touch-input-0.8-osu-ver.patch b/patches/touch-input/touch-input-0.8-osu-ver.patch new file mode 100755 index 0000000..9d527f0 --- /dev/null +++ b/patches/touch-input/touch-input-0.8-osu-ver.patch @@ -0,0 +1,279 @@ +diff --git a/dwl.c b/dwl.c +index 44f3ad9..977f2c8 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,6 +52,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -161,6 +163,12 @@ typedef struct { + struct wl_listener destroy; + } KeyboardGroup; + ++typedef struct TouchGroup { ++ struct wl_list link; ++ struct wlr_touch *touch; ++ Monitor *m; ++} TouchGroup; ++ + typedef struct { + /* Must keep this field first */ + unsigned int type; /* LayerShell */ +@@ -269,6 +277,7 @@ static void createpointer(struct wlr_pointer *pointer); + static void createpointerconstraint(struct wl_listener *listener, void *data); + static void createpopup(struct wl_listener *listener, void *data); + static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); ++static void createtouch(struct wlr_touch *touch); + static void cursorframe(struct wl_listener *listener, void *data); + static void cursorwarptohint(void); + static void destroydecoration(struct wl_listener *listener, void *data); +@@ -338,6 +347,10 @@ static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); ++static void touchdown(struct wl_listener *listener, void *data); ++static void touchup(struct wl_listener *listener, void *data); ++static void touchframe(struct wl_listener *listener, void *data); ++static void touchmotion(struct wl_listener *listener, void *data); + static void unlocksession(struct wl_listener *listener, void *data); + static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); + static void unmapnotify(struct wl_listener *listener, void *data); +@@ -405,6 +418,7 @@ static struct wlr_output_layout *output_layout; + static struct wlr_box sgeom; + static struct wl_list mons; + static Monitor *selmon; ++static struct wl_list touches; + + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; +@@ -434,6 +448,10 @@ static struct wl_listener request_set_sel = {.notify = setsel}; + static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; + static struct wl_listener request_start_drag = {.notify = requeststartdrag}; + static struct wl_listener start_drag = {.notify = startdrag}; ++static struct wl_listener touch_down = {.notify = touchdown}; ++static struct wl_listener touch_frame = {.notify = touchframe}; ++static struct wl_listener touch_motion = {.notify = touchmotion}; ++static struct wl_listener touch_up = {.notify = touchup}; + static struct wl_listener new_session_lock = {.notify = locksession}; + + #ifdef XWAYLAND +@@ -585,7 +603,7 @@ arrangelayers(Monitor *m) + arrange(m); + } + +- /* Arrange non-exlusive surfaces from top->bottom */ ++ /* Arrange non-exclusive surfaces from top->bottom */ + for (i = 3; i >= 0; i--) + arrangelayer(m, &m->layers[i], &usable_area, 0); + +@@ -781,6 +799,10 @@ cleanuplisteners(void) + wl_list_remove(&request_set_cursor_shape.link); + wl_list_remove(&request_start_drag.link); + wl_list_remove(&start_drag.link); ++ wl_list_remove(&touch_down.link); ++ wl_list_remove(&touch_frame.link); ++ wl_list_remove(&touch_motion.link); ++ wl_list_remove(&touch_up.link); + wl_list_remove(&new_session_lock.link); + #ifdef XWAYLAND + wl_list_remove(&new_xwayland_surface.link); +@@ -1199,6 +1221,16 @@ createpopup(struct wl_listener *listener, void *data) + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); + } + ++void ++createtouch(struct wlr_touch *wlr_touch) ++{ ++ TouchGroup *touch = ecalloc(1, sizeof(TouchGroup)); ++ ++ touch->touch = wlr_touch; ++ wl_list_insert(&touches, &touch->link); ++ wlr_cursor_attach_input_device(cursor, &wlr_touch->base); ++} ++ + void + cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) + { +@@ -1590,6 +1622,9 @@ inputdevice(struct wl_listener *listener, void *data) + case WLR_INPUT_DEVICE_POINTER: + createpointer(wlr_pointer_from_input_device(device)); + break; ++ case WLR_INPUT_DEVICE_TOUCH: ++ createtouch(wlr_touch_from_input_device(device)); ++ break; + default: + /* TODO handle other input device types */ + break; +@@ -1602,6 +1637,8 @@ inputdevice(struct wl_listener *listener, void *data) + caps = WL_SEAT_CAPABILITY_POINTER; + if (!wl_list_empty(&kb_group->wlr_group->devices)) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; ++ if (!wl_list_empty(&touches)) ++ caps |= WL_SEAT_CAPABILITY_TOUCH; + wlr_seat_set_capabilities(seat, caps); + } + +@@ -2133,7 +2170,7 @@ powermgrsetmode(struct wl_listener *listener, void *data) + if (!m) + return; + +- m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ ++ m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */ + wlr_output_state_set_enabled(&state, event->mode); + wlr_output_commit_state(m->wlr_output, &state); + +@@ -2455,7 +2492,7 @@ setup(void) + wlr_log_init(log_level, NULL); + + /* The Wayland display is managed by libwayland. It handles accepting +- * clients from the Unix socket, manging Wayland globals, and so on. */ ++ * clients from the Unix socket, managing Wayland globals, and so on. */ + dpy = wl_display_create(); + event_loop = wl_display_get_event_loop(dpy); + +@@ -2518,6 +2555,7 @@ setup(void) + wlr_export_dmabuf_manager_v1_create(dpy); + wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); ++ wlr_ext_data_control_manager_v1_create(dpy, 1); + wlr_primary_selection_v1_device_manager_create(dpy); + wlr_viewporter_create(dpy); + wlr_single_pixel_buffer_manager_v1_create(dpy); +@@ -2615,6 +2653,13 @@ setup(void) + wl_signal_add(&cursor->events.axis, &cursor_axis); + wl_signal_add(&cursor->events.frame, &cursor_frame); + ++ wl_list_init(&touches); ++ ++ wl_signal_add(&cursor->events.touch_down, &touch_down); ++ wl_signal_add(&cursor->events.touch_frame, &touch_frame); ++ wl_signal_add(&cursor->events.touch_motion, &touch_motion); ++ wl_signal_add(&cursor->events.touch_up, &touch_up); ++ + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); + +@@ -2787,6 +2832,111 @@ toggleview(const Arg *arg) + printstatus(); + } + ++void ++touchdown(struct wl_listener *listener, void *data) ++{ ++ struct wlr_touch_down_event *event = data; ++ double lx, ly; ++ double sx, sy; ++ struct wlr_surface *surface; ++ Client *c = NULL; ++ Monitor *m; ++ ++ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ ++ // Map the input to the appropriate output ++ wl_list_for_each(m, &mons, link) { ++ if (m == NULL || m->wlr_output == NULL) ++ continue; ++ if (event->touch->output_name != NULL && ++ 0 != strcmp(event->touch->output_name, m->wlr_output->name)) ++ continue; ++ wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output); ++ } ++ ++ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, ++ event->x, event->y, &lx, &ly); ++ ++ /* Find the client under the touch point */ ++ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy); ++ if (sloppyfocus && c) ++ focusclient(c, 0); ++ ++ // Send touch event to client (if any) ++ if (surface != NULL) { ++ wlr_seat_touch_notify_down(seat, surface, event->time_msec, ++ event->touch_id, sx, sy); ++ } ++ ++ // ALWAYS move cursor and send click - no conditions! ++ wlr_cursor_warp_closest(cursor, NULL, lx, ly); ++ motionnotify(0, NULL, 0, 0, 0, 0); ++ ++ wlr_seat_pointer_notify_button(seat, event->time_msec, ++ BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); ++ wlr_seat_pointer_notify_frame(seat); ++} ++ ++void ++touchup(struct wl_listener *listener, void *data) ++{ ++ struct wlr_touch_up_event *event = data; ++ ++ if (!wlr_seat_touch_get_point(seat, event->touch_id)) ++ return; ++ ++ wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id); ++ ++ // Always send click release ++ wlr_seat_pointer_notify_button(seat, event->time_msec, ++ BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); ++ wlr_seat_pointer_notify_frame(seat); ++ ++ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++} ++ ++void ++touchframe(struct wl_listener *listener, void *data) ++{ ++ wlr_seat_touch_notify_frame(seat); ++ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++} ++ ++void ++touchmotion(struct wl_listener *listener, void *data) ++{ ++ struct wlr_touch_motion_event *event = data; ++ double lx, ly; ++ double sx, sy; ++ struct wlr_surface *surface; ++ Client *c = NULL; ++ ++ if (!wlr_seat_touch_get_point(seat, event->touch_id)) { ++ return; ++ } ++ ++ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly); ++ wlr_cursor_warp_closest(cursor, NULL, lx, ly); ++ motionnotify(0, NULL, 0, 0, 0, 0); ++ wlr_seat_pointer_notify_frame(seat); ++ ++ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy); ++ ++ if (c != NULL && surface != NULL) { ++ if (sloppyfocus) ++ focusclient(c, 0); ++ wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy); ++ } else { ++ if (sloppyfocus) ++ focusclient(NULL, 0); ++ wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id); ++ } ++ wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy); ++ ++ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++} ++ ++ + void + unlocksession(struct wl_listener *listener, void *data) + {