Skip to content

fix(hook): report Windows pointer motion by differencing the cursor point - #473

Open
Stanley5249 wants to merge 1 commit into
AprilNEA:masterfrom
Stanley5249:fix/windows-gesture-motion-hook
Open

fix(hook): report Windows pointer motion by differencing the cursor point#473
Stanley5249 wants to merge 1 commit into
AprilNEA:masterfrom
Stanley5249:fix/windows-gesture-motion-hook

Conversation

@Stanley5249

Copy link
Copy Markdown

Summary

WH_MOUSE_LL never emitted MouseEvent::Moved, so SwipeAccumulator saw no
travel during a gesture hold and a swipe could never commit on Windows — only the
plain click on release fired. This differences the cursor position each
WM_MOUSEMOVE against the previous one, giving the accumulator the relative delta
it expects, the same shape as macOS MOUSE_EVENT_DELTA_X and Linux REL_X.

Changes

openlogi-hook

  • windows.rs: motion_delta() differences MSLLHOOKSTRUCT.pt against a
    Cell<Option<POINT>> thread-local; WM_MOUSEMOVE translates to
    MouseEvent::Moved. No synchronization — WH_MOUSE_LL callbacks run on the
    installing thread.
  • Injected moves stay filtered from the event stream but do advance the baseline,
    so a cursor jump made by another process can't be reported as the user's travel.
  • Tests: successive differencing (no-baseline first move, zero-delta repeat) and
    the injected-baseline case.

Known limitation

The OS clamps MSLLHOOKSTRUCT.pt to the desktop bounds, so a swipe running into a
screen edge stops producing deltas and may not reach the threshold. Documented on
motion_delta. #472 is the alternative that avoids it, at the cost of ~350 lines
of raw-input FFI; these two are alternatives, not a sequence.

Testing

  • cargo clippy -p openlogi-hook --all-targets — clean
  • cargo test -p openlogi-hook — 11 passed
  • Not runtime-tested on hardware.

Note: the Windows CI job fails until #458 lands — openlogi-hid does not build
without the Win32_System_IO feature.

Fixes #471

…oint

WH_MOUSE_LL never emitted MouseEvent::Moved, so the gesture accumulator
saw no travel on Windows and a hold+swipe could never commit — only the
plain click on release ever fired. Differencing the cursor position each
WM_MOUSEMOVE against the previous one turns the hook's absolute point
into the relative delta the accumulator expects, matching macOS
MOUSE_EVENT_DELTA_X and Linux REL_X.

The baseline lives in a thread-local: WH_MOUSE_LL callbacks run on the
installing thread, so no synchronization is needed on the callback path.
Injected moves are still filtered from the event stream but do advance
the baseline, so a cursor jump can't be reported as the user's travel.

Known limitation: the OS clamps the cursor point to the desktop bounds,
so a swipe that runs into a screen edge stops producing deltas and may
not reach the threshold. Reading the device's own relative counts needs
raw input (WM_INPUT) and a second message pump.
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

Adds Windows pointer-motion translation for gesture swipes.

  • Differences consecutive WH_MOUSE_LL cursor positions into MouseEvent::Moved deltas.
  • Advances the cursor baseline for filtered injected movement.
  • Documents edge-clamped motion and adds unit tests for differencing and injected movement.

Confidence Score: 3/5

The first-movement handling should be fixed before merging because it can still turn a valid Windows swipe into a click.

A gesture can begin while the thread-local cursor baseline is empty, causing the first and potentially only threshold-crossing movement to be discarded before it reaches the swipe accumulator.

Files Needing Attention: crates/openlogi-hook/src/windows.rs

Important Files Changed

Filename Overview
crates/openlogi-hook/src/windows.rs Adds Windows motion differencing and injected-event baseline handling, but drops the first movement even when it occurs during an active gesture.
crates/openlogi-hook/src/lib.rs Documents that Windows pointer motion is edge-clamped.

Sequence Diagram

sequenceDiagram
  participant OS as Windows WH_MOUSE_LL
  participant Hook as translate_event
  participant Delta as motion_delta
  participant Swipe as SwipeAccumulator
  OS->>Hook: WM_MOUSEMOVE with cursor point
  Hook->>Delta: Difference from LAST_POINT
  alt Baseline exists and position changed
    Delta-->>Hook: delta_x, delta_y
    Hook->>Swipe: MouseEvent::Moved
  else First observed point
    Delta-->>Hook: None
    Note over Swipe: Movement is not accumulated
  end
Loading

Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(hook): report Windows pointer motion..." | Re-trigger Greptile

@@ -268,10 +287,30 @@ fn translate_event(wparam: WPARAM, data: MSLLHOOKSTRUCT) -> Option<MouseEvent> {
from_trackpad: false,
device: None,
}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 First gesture movement is dropped

When a gesture button is pressed before the hook has observed any pointer movement, motion_delta uses the following WM_MOUSEMOVE only to initialize LAST_POINT, causing that movement to be omitted from the swipe accumulator and a valid swipe to resolve as the fallback click.

Knowledge Base Used: openlogi-hook: OS-level input hooking

Fix in Codex Fix in Claude Code

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.

Gesture swipes never commit on Windows

1 participant