Skip to content

feat(input): add tablet and touch support for release/1.4 - #692

Open
shuber2 wants to merge 6 commits into
trip-zip:release/1.4from
shuber2:feat/tablet-support
Open

feat(input): add tablet and touch support for release/1.4#692
shuber2 wants to merge 6 commits into
trip-zip:release/1.4from
shuber2:feat/tablet-support

Conversation

@shuber2

@shuber2 shuber2 commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Description

It adds tablet support as described in feature issue #663 and touch support as described in feature issue #707.

The following developments could naturally follow up on this PR:

  • Adding support for input rule management of somewem-client.

Test Plan

Only little test code coverage. Mainly manual tests.

Checklist

  • Lua libraries (lua/awful/, lua/gears/, lua/wibox/, lua/naughty/) are not modified — if a bug surfaces in Lua, the fix belongs in C
  • Tests pass (make test-unit && make test-integration)

@JimmyCozza

Copy link
Copy Markdown
Contributor

This is one that's going to be hard for me to test since I don't have a tablet. Did this end up having any overlap with PR #612?

Or are they completely separate?

@shuber2

shuber2 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Yes, that is a little bit uncomfortable, indeed. Maybe Wacom should sponsor you with a tablet :-)

Concerning #612 I discussed this there, too. To me it feels that this PR also adds infrastructure on top of which touch support can be implemented. See also the last comment by @zharsing.

I may actually give touch support a try, too. Have some Thinkpad Yoga with Debian nearby.

@shuber2

shuber2 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

@JimmyCozza I did an attempt to streamline the touch discussion in #707.

@shuber2

shuber2 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Well, I now added a commit to this branch that also adds touch support as described in #707. I have tested it on a Lenovo Yoga, which has both, a touch display and a tablet pen. Tested in krita and firefox, e.g., drawing, pinch to zoom, and scrolling.

It intends to replace or integrate #612.

@shuber2 shuber2 changed the title Add tablet support for release/1.4 Add tablet and touch support for release/1.4 Aug 19, 2026
@shuber2 shuber2 changed the title Add tablet and touch support for release/1.4 feat(input): add tablet and touch support for release/1.4 Aug 19, 2026
@shuber2 shuber2 mentioned this pull request Aug 19, 2026
2 tasks
@shuber2

shuber2 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

And mouse tap-to-click added. I think this is a reasonable feature set for now. Let's leave it there.

Next steps:

  • More testing
  • Review the code
  • Peer reviewing would be advisable

@shuber2
shuber2 force-pushed the feat/tablet-support branch from 01620e0 to 586461d Compare August 19, 2026 20:50
@shuber2

shuber2 commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Fixed a few smaller bugs and inconsistencies in behavior.

@shuber2
shuber2 force-pushed the feat/tablet-support branch 2 times, most recently from 03cce34 to c6447c6 Compare August 20, 2026 18:29
shuber2 and others added 6 commits August 27, 2026 20:00
Looks up a Monitor by its wlr_output connector name (e.g. "DP-8").
Used by the tablet map_to_output resolution added in a following
commit.
DRM connector names (DP-8, DP-9, ...) are assigned by enumeration order
and can shift across replug/redock even for the same physical monitor,
which breaks anything matching an output by connector name. Fall back to
the make/model/serial identifier - the same "make model serial" ("Unknown"
for missing fields) convention used by sway and wlr-randr - which stays
stable regardless of which port the monitor ends up on.

some_monitor_by_name() has a single caller today (tablet map_to_output
resolution), so this is low-risk; sets up list-valued map_to_output
(fallback preference list) as a following commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implements the tablet-v2 Wayland protocol for drawing tablets (e.g.
Wacom), in the two stages proposed in trip-zip#663:

- Stage 1 (MVP): a pen in proximity moves the pointer; a tip emulates
  a left click. Works for any client via wl_pointer emulation.
- Stage 2 (full): wlr_tablet_v2_tablet_{tool,pad}_notify_*() forward
  pressure, distance, tilt, rotation, slider, and wheel to
  tablet-aware clients (tested against Krita, Xournal++, Okular).
  motionnotify() suppresses the wl_pointer emulation for surfaces
  that accept tablet-v2, so clients don't see both protocols firing
  for the same motion.

Tip events route through buttonpress() rather than calling
wlr_seat_pointer_notify_button() directly: buttonpress() is also
where Lua button-binding dispatch happens (click-to-focus/raise), so
tapping an unfocused window with the stylus focuses/raises it the
same way a mouse click does. The tool already drives a real, hovering
cursor via tablet_apply_motion() -> motionnotify(), so tip down/up
map straight onto buttonpress() press/release - no atomic
press+release synthesis needed the way touch requires.

wlr_tablet_tool_axis_event only reports the axes that actually
changed (updated_axes is a bitmask), not a full x/y or tilt_x/tilt_y
pair every time - a tool dragged along a single axis near the
tablet's edge is a normal, frequent case. Each tool's last known
position is cached (find_or_create_tracked_tablet_tool(), split out
of get_or_create_tablet_v2_tool() so it also works without
tablet_v2_mgr) and used to fill in whichever axis wasn't part of a
given event.

Tablet pad support (buttons, ring, strip) sends proper enter/leave
focus based on cursor position, since pad events carry no surface of
their own. Pad-to-tablet pairing is done authoritatively via libinput
device groups at device-creation time (mirrors sway), which is
backend-independent and correctly handles multiple simultaneous
tablets; the wlr_tablet_pad attach_tablet event is also wired up for
the nested-Wayland-backend testing path, where libinput groups aren't
available.

Config surface, via awful.input.rules (inspired by man sway-input):
- tool_mode = "absolute" | "relative" per tool type (tablet-tool-pen,
  -eraser, ...; tablet-tool wildcard). Mouse/lens tools are always
  relative, matching sway's hardcoded behavior - they have no fixed
  position on the tablet surface.
- map_to_output: output name, "make model serial" identifier (stable
  across DRM connector renumbering, e.g. DP-8 -> DP-9 on replug), or
  an ordered list of candidates tried in turn (useful for docked
  laptops with different monitors per location). "*" or no match
  falls back to the full output layout.
- map_to_region / map_from_region: explicit absolute-layout or
  tablet-space rectangles; map_to_region takes precedence over
  map_to_output when both are set, mirroring sway's mutually-
  exclusive output/region mapping.

Not yet verified on real hardware: pad ring/strip and pen
tilt/rotation (available test hardware doesn't have them).

No live reconfiguration: changing map_to_output/map_to_region/
tool_mode requires editing rc.lua and reloading, or `somewm-client
eval`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Forwards touch down/motion/up/cancel/frame events to clients via the
core wl_touch protocol, reusing the tablet-v2 output-mapping mechanism
(generalized tablet_map_coords() into input_map_coords()) instead of
duplicating it, and adds a single-enabled-output auto-default so an
unconfigured device maps onto the one screen present instead of
spanning the whole layout. rule = { type = "touch" } in
awful.input.rules works via the existing generic rule matcher, no Lua
changes required. No compositor-side pointer/click emulation is
included; that's deliberately out of scope for this first pass.

wlr_seat_touch_notify_motion() takes no surface argument - it always
delivers to the client of the touch point's original down surface, so
touchnotifymotion() stays pinned to that surface and projects the
current layout coordinates onto its own origin, rather than
re-resolving whatever surface is currently under the finger (which
would compute coordinates relative to the wrong surface once the
finger drags across a window boundary, and drop the event outright
once it drags off any surface at all). Same approach motionnotify()
uses to keep a held mouse button pinned to its focused surface while
the cursor roams elsewhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Raw wl_touch forwarding leaves clients that never bind wl_touch (wibar,
GTK3/Qt-widgets apps) with no way to be clicked by touch.

Gate emulation per-client on whether it bound wl_touch
(wlr_seat_client->touches, same idiom pointerfocus() uses for
->pointers) so touch-aware clients keep receiving only real touch.
XWayland is excluded the same way: it always binds wl_touch once the
seat advertises it, deferring to its own built-in emulation.

touchnotifydown() fires one atomic press+release, routed through
buttonpress() rather than wlr_seat_pointer_notify_button() directly -
buttonpress() is where Lua button-binding dispatch (and therefore
click-to-focus/raise) happens, which a raw notify_button() call would
skip. Raw touch forwarding is now also skipped for clients with no
touch binding, avoiding a wlroots "could not create touch point" error
on every such tap.

Touch-aware clients (Krita, GIMP, ...) still deserve focus/raise on a
tap, the same as a mouse click gets it, without a synthetic
wl_pointer click on top of their real touch input (that would be
double input). touchnotifydown() runs the same rc.lua button-binding
dispatch (luaA_client_button_check()) for them too, just without the
final wl_pointer delivery - unless some other surface already has an
active touch point, since that means concurrent touch use across
different windows (e.g. touch-drawing on an unfocused canvas on one
screen while touch-scrolling a document on another) that a stolen
focus would disrupt. Concurrent touches on the same surface (a
two-finger gesture) don't count as "elsewhere".

New awful.input.rules property: emulate_pointer (touch rule type),
defaults on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@shuber2
shuber2 force-pushed the feat/tablet-support branch 2 times, most recently from 1d25c78 to 6ce4a6e Compare August 27, 2026 18:03
@JimmyCozza

JimmyCozza commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@shuber2 I don't want to stall this too long.

I'm tempted to merge this and watch for bug reports after the fact just because I really do not have a way to test this out myself.

Have you been running this yourself lately? Have you noticed any bugs or concerns with it?

What I can say definitively, is that it is at least inert when I run this branch as my daily driver, so my vote is merge and monitor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants