screenshots via keyboard only nvim motions - #118
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
It adds a new threaded Wayland pointer component and reworks the editor's core input path, which warrants human verification against live compositor behavior beyond the headless smoke coverage.
Pull request overview
This PR adds full keyboard control to the capture overlay so a region or window can be selected without a mouse. It reuses the existing output-bound zwlr_virtual_pointer_v1 (previously used only by scroll capture) to warp the real pointer, and drives selection through the editor's existing mouse-event path via synthetic events. The pointer starts at the focused monitor's center; hjkl glides with acceleration (Shift for fine motion), Enter captures the window under the pointer, and Ctrl+hjkl draws a region committed on Ctrl release. This fits Omasnap's "fast capture" principle and keeps the main thread non-blocking by running the Wayland pointer on a worker thread.
Changes:
- New
CapturePointer(declared incapture-pointer.hpp, implemented inscroll-inject.cpp) drives an output-bound virtual pointer on a dedicated worker thread with a mutex/condition-variable handoff. - Editor gains keyboard motion (timer-driven glide + acceleration), window-under-pointer Enter capture, and
Ctrl+hjklfixed-anchor region drawing, with cancellation on Esc/focus loss and guards against auto-repeat and zero-size regions. - Documentation (README) and a comprehensive headless smoke test (
runKeyboardCaptureSmoke) cover the new behavior.
File summaries
| File | Description |
|---|---|
src/capture-pointer.hpp |
New RAII interface wrapping an output-bound Wayland virtual pointer. |
src/scroll-inject.cpp |
Implements CapturePointer worker thread and thread-safe moveTo/shutdown. |
src/editor.hpp |
New members, timers, and overrides (showEvent/hideEvent/focusOutEvent) for keyboard capture. |
src/editor.cpp |
Key/motion handling, pointer centering, region/window selection, cancellation, and hotkey legend. |
tests/editor-smoke.cpp |
Adds runKeyboardCaptureSmoke covering glide, window capture, region draw, and edge cases. |
README.md |
Documents the new keyboard capture controls. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| update(); | ||
| } | ||
| pointerKeys_.insert(event->key()); | ||
| keyboardFineMotion_ = event->modifiers().testFlag(Qt::ShiftModifier); |
|
so atm, it blocks my mouse, but you get the idea likely this stuff will feel rather different on each machine:
currently it feels good on my machine, but this thing is likely the case where "feels good on my machine" will require some fine tuning I very much like the feature, bc. I would want to get rid of the damn mouse fully, and for screenshots I cant |
There was a problem hiding this comment.
🔵 Needs a closer look
It is a substantial new input-handling feature that spawns a Wayland pointer thread, synthesizes mouse events, warps the physical cursor on every launch, and changes existing Enter/window-capture semantics, which warrants human review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
tests/editor-smoke.cpp:7703
- This is the only smoke check in
main()that logs its failure withqCritical(); every other check (e.g.runAreaLastRegionSmokeat line 7707,runChromeFontCheckat line 7727, and ~50 others) usesqWarning().noquote(). For consistency with the surrounding harness, preferqWarning()here.
- Files reviewed: 6/6 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces a threaded Wayland input path with a concurrency concern (UI thread can block on the worker's mutex during wl_display_flush) that needs human judgment on the intended locking model.
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 1
- Review effort level: Balanced
| const QPointF position = state->position; | ||
| state->pending = false; | ||
| // Fractions map to the bound output, including its scale and rotation. | ||
| constexpr uint32_t extent = 1000000; | ||
| zwlr_virtual_pointer_v1_motion_absolute( | ||
| pointer->pointer, pointer->timeMs(), | ||
| static_cast<uint32_t>(std::clamp(position.x(), 0.0, 1.0) * extent), | ||
| static_cast<uint32_t>(std::clamp(position.y(), 0.0, 1.0) * extent), | ||
| extent, extent); | ||
| zwlr_virtual_pointer_v1_frame(pointer->pointer); | ||
| if (wl_display_flush(pointer->display) < 0) { | ||
| qWarning() << "capture pointer: Wayland motion failed"; | ||
| return; | ||
| } | ||
| } |
|
@tobi @jondkinney whoever reads the code here the clanker is hallucinating bs. as far as I can tell https://wayland.freedesktop.org/docs/html/apb.html says explicitly says if it cannot send everything immediately, it returns releasing the shared lock before sending the pointer movement is correct tho, see 671b53c |
There was a problem hiding this comment.
🔵 Needs a closer look
It combines worker-thread Wayland pointer injection, a nontrivial keyboard input state machine, and a broad behavioral change (warping the physical cursor to monitor center on every capture) that warrants human verification on real Hyprland hardware.
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 0 new
- Review effort level: Balanced
hey guys thank you for the tool
given a feasability check, I'd like to work on this feature; the annoyance is that I have to leave my fingers from the keyboard and take the mouse to do screenshots, and I dont think this is necessary
this adds keyboard control to the capture overlay, using the existing Wayland virtual pointer and output path.
Esc cancels the rectangle. Focus loss cancels keyboard movement and selection. Auto-repeat, a lone ctrl release, and zero-width or zero-height regions do not trigger a capture.
--copy --saveexports immediately; normal launches openthe editor after selection.
Validation:
make check, plus live Hyprland checks on landscape and rotatedportrait monitors for pointer centering, movement, window capture, and region
capture. Saved PNGs were compared byte-for-byte with the clipboard output.