Skip to content

fix(cua-driver/windows): route DoubleClick/RightClick on Chromium targets via SendInput (#1984) - #1995

Merged
f-trycua merged 3 commits into
mainfrom
fix/windows-chromium-doubleclick-1984
Jun 24, 2026
Merged

fix(cua-driver/windows): route DoubleClick/RightClick on Chromium targets via SendInput (#1984)#1995
f-trycua merged 3 commits into
mainfrom
fix/windows-chromium-doubleclick-1984

Conversation

@f-trycua

@f-trycua f-trycua commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

double_click and right_click against an element_index (or pixel) on a Chromium/Electron window (Obsidian, VS Code, Slack, …) report success but do nothing — the DOM never sees the click. Addresses #1984, candidate B.

Root cause

Chromium's input thread only honors SendInput-origin events; it silently drops PostMessage(WM_*BUTTON*) (#1623). ClickTool already auto-detects a Chromium target HWND and routes through SendInput — but DoubleClickTool and RightClickTool had no such check (verified: ClickTool has 3 is_chromium_target_window calls, these tools had 0). Their default (Auto) dispatch fell straight to post_click_screen (PostMessage) and no-op'd.

Fix

  • New chromium_click_short_circuit() helper mirrors the ClickTool branch: detect a Chromium HWND, deliver count clicks of button at screen (sx, sy) via send_click_synthesized with async foreground restore, and return Some(result); return None for non-Chromium targets so the normal PostMessage path is unchanged.
  • Wired into both dispatch paths (element_index + x/y) of DoubleClickTool and RightClickTool, before the default PostMessage call. Explicit dispatch:foreground / dispatch:background paths are untouched.

Scope notes

  • DragTool has the same gap on its default path, but its press-move-release SendInput path (send_drag_synthesized) needs separate handling — left as a fast-follow rather than bundled here.
  • Candidate A (stale element_cache.get_element_center after a window move) is a deeper cache-lifetime audit and is not addressed in this PR.

Verification

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved mouse click handling in Chromium and Electron-based applications with proper window focus restoration after clicking.

…gets via SendInput (#1984)

ClickTool auto-detects Chromium/Electron target HWNDs and routes clicks through
SendInput because Chromium's input thread silently drops PostMessage mouse
events (#1623). DoubleClickTool and RightClickTool lacked this short-circuit, so
element_index/pixel double- and right-clicks on Electron apps (Obsidian, VS
Code, Slack, …) fell through to post_click_screen (PostMessage) and no-op'd —
matching the #1984 candidate B audit hypothesis.

- Add chromium_click_short_circuit() helper (mirrors the ClickTool branch:
  detect Chromium HWND, deliver via send_click_synthesized with async
  foreground restore, else return None to keep the PostMessage path).
- Wire it into both dispatch paths (element_index + x/y) of DoubleClickTool and
  RightClickTool, before the default PostMessage call.

DragTool has the same gap on its default path; left as a fast-follow since its
press-move-release SendInput path (send_drag_synthesized) needs separate
handling. Candidate A (stale element-cache center) is a deeper audit, tracked
separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jun 24, 2026 1:48am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d53960ae-3dd8-4299-9211-2294ec3fb734

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new private async helper chromium_click_short_circuit in impl_.rs that detects Chromium/Electron window targets and dispatches clicks via SendInput (send_click_synthesized) with subsequent foreground restoration. This helper is wired into four call sites: both addressing modes (element_index and (x, y) pixel) in DoubleClickTool and RightClickTool, replacing the existing PostMessage-based paths for Chromium/Electron targets.

Changes

Chromium/Electron SendInput short-circuit for DoubleClick and RightClick

Layer / File(s) Summary
chromium_click_short_circuit helper
libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs
New async helper function (lines 3514–3560) that runs Chromium/Electron detection in a blocking task, captures the pre-click foreground HWND, dispatches the click gesture via send_click_synthesized (SendInput), spawns restore_foreground_polling_best_effort for focus restoration, and returns Some(ToolResult) on match or None to fall through to PostMessage logic.
Integration into DoubleClickTool and RightClickTool
libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs
Four early-return guards added: DoubleClickTool element_index path (3702–3705), DoubleClickTool (x,y) pixel path (3761–3764), RightClickTool element_index path (3920–3923), and RightClickTool (x,y) pixel path (3978–3981). Each calls chromium_click_short_circuit and returns immediately for Chromium/Electron targets instead of proceeding with the prior PostMessage paths.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

  • trycua/cua#1625: Introduced the original Chromium detection + send_click_synthesized short-circuit pattern for coordinate clicks that this PR extends to DoubleClickTool and RightClickTool.
  • trycua/cua#1669: Applied the same SendInput + restore_foreground_polling_best_effort pattern to ClickTool in the same impl_.rs file — the direct predecessor to this PR's expansion.
  • trycua/cua#1980: Modified coordinate normalization inside send_click_synthesized itself, directly affecting the SendInput path this PR routes double/right clicks through.

Poem

🐇 Hop, hop — no PostMessage today,
SendInput carries the click on its way!
Chromium detected, the shortcut is clear,
Foreground restored with a poll and a cheer.
DoubleClick, RightClick — both get the fix,
A rabbit's own trick in the Windows toolbox mix! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: routing DoubleClick/RightClick operations on Chromium targets via SendInput instead of PostMessage, which directly addresses the core issue documented in the PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/windows-chromium-doubleclick-1984

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs (1)

3514-3560: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Helper logic is sound; consider consolidating the repeated SendInput pattern.

The detection-then-SendInput-then-restore flow correctly mirrors the existing dispatch:foreground branches, and returning Some(ToolResult::error(...)) on a failed send_click_synthesized is the right call — it surfaces the diagnostic instead of silently falling through to the PostMessage no-op.

The prev_fg capture → spawn_blocking(send_click_synthesized)tokio::spawn(restore_foreground_polling_best_effort) → result-match sequence is now duplicated across this helper plus the four dispatch:foreground branches (Lines 3686-3700, 3744-3758, 3904-3918, 3961-3975). Extracting a single send_click_via_sendinput(...) core that both this helper and those branches delegate to would remove the repetition; the only delta is the success-message text.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs` around lines
3514 - 3560, The SendInput pattern used in chromium_click_short_circuit
(capturing prev_fg_addr, calling spawn_blocking on send_click_synthesized,
spawning restore_foreground_polling_best_effort, and matching on the result) is
duplicated across four dispatch:foreground branches. Extract this repeated logic
into a new helper function (e.g., send_click_via_sendinput) that accepts the
hwnd, screen coordinates, click count, button, pid, and a success message
template as parameters, then refactor both chromium_click_short_circuit and the
four duplicate dispatch:foreground branch implementations to call this single
helper instead, eliminating the repetition while preserving each branch's custom
success message text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs`:
- Around line 3514-3560: The SendInput pattern used in
chromium_click_short_circuit (capturing prev_fg_addr, calling spawn_blocking on
send_click_synthesized, spawning restore_foreground_polling_best_effort, and
matching on the result) is duplicated across four dispatch:foreground branches.
Extract this repeated logic into a new helper function (e.g.,
send_click_via_sendinput) that accepts the hwnd, screen coordinates, click
count, button, pid, and a success message template as parameters, then refactor
both chromium_click_short_circuit and the four duplicate dispatch:foreground
branch implementations to call this single helper instead, eliminating the
repetition while preserving each branch's custom success message text.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 02d74cf0-c473-4b5c-ac74-fc09665ed7b0

📥 Commits

Reviewing files that changed from the base of the PR and between c898d7b and c308990.

📒 Files selected for processing (1)
  • libs/cua-driver/rust/crates/platform-windows/src/tools/impl_.rs

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Linux visual regression artifacts

Matrix jobs now run independently. Download visual artifacts from this workflow run.
Each background-GUI job uploads a .gif of the interaction plus two annotated PNGs (<app>.png raw, <app>-atspi.png with AT-SPI element boxes); the cua-driver-linux-som-overlays artifact adds <app>-som.png cua Set-of-Marks overlays:

  • cua-driver-linux-cursor-click-gif
  • cua-driver-linux-background-terminal-gif
  • cua-driver-linux-parallel-drag-xserver
  • cua-driver-linux-background-gui-chromium
  • cua-driver-linux-background-gui-tk
  • cua-driver-linux-background-gui-gtk3-gedit
  • cua-driver-linux-background-gui-gtk3-mousepad
  • cua-driver-linux-background-gui-gtk3-scite
  • cua-driver-linux-background-gui-gtk4-characters
  • cua-driver-linux-background-gui-qt5-manuskript
  • cua-driver-linux-background-gui-qt5-klog
  • cua-driver-linux-background-gui-qt5-openambit
  • cua-driver-linux-background-gui-qt6-kate
  • cua-driver-linux-background-gui-qt6-kcalc
  • cua-driver-linux-background-gui-qt6-okular
  • cua-driver-linux-background-gui-qt6-qownnotes
  • cua-driver-linux-background-gui-electron-zettlr
  • cua-driver-linux-background-gui-electron-joplin
  • cua-driver-linux-background-gui-electron-logseq
  • cua-driver-linux-som-overlays

Open workflow run and download artifacts

f-trycua and others added 2 commits June 23, 2026 18:40
…nd dispatch, not just auto (#1984)

Runtime testing on a real desktop (Edge) revealed the first cut was ineffective
in the DEFAULT path: double_click/right_click default to dispatch:background,
where the pre-existing 'would_be_silently_dropped' guard returned
background_unavailable_error for Chromium BEFORE the auto-only SendInput
short-circuit could run — so a Chromium double-click just errored.

Mirror ClickTool exactly: in the background branch, route Chromium/GTK targets
through inject_click_screen (coordinate injection into the system input queue,
NO foreground swap) and only fall back to background_unavailable_error if the
actuator can't express the click (e.g. right/middle). The auto-path SendInput
short-circuit is retained for dispatch:auto.

Covers both addressing modes (element_index + x/y) of DoubleClickTool and
RightClickTool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
…etic pen device (#1984)

Runtime testing showed single click injected fine in background but double_click
errored: inject_click_screen looped pen_tap, which creates AND destroys a
synthetic pen device per tap. The second CreateSyntheticPointerDevice in quick
succession fails, so the second tap (and thus every double/triple click)
returned Err -> background_unavailable_error.

Rename pen_tap -> pen_taps(count): create ONE device and emit count down/up
cycles (70ms apart) on it, then destroy once. A real double-click is two taps
from one digitizer, so this is also more correct. inject_click_screen now calls
it once. Fixes background double_click / right-double scenarios for
Chromium/Electron/GTK targets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KMXCW4M5uK1HRGjjH4wueZ
@f-trycua

Copy link
Copy Markdown
Collaborator Author

Runtime-verified on a real desktop ✅

Validated this branch (7ef67c1b) end-to-end against Microsoft Edge (Chromium, window class Chrome_WidgetWin_1) in an interactive Windows session, default dispatch (background):

double_click → ✅ Injected double-click to pid … at screen (321,261) (background, no foreground swap).
right_click  → ✅ Injected right-click  to pid … at screen (321,261) (background, no foreground swap).

Both now deliver via the coordinate actuator (system input queue, no foreground swap) instead of failing. Before this branch, a default double_click / right_click on a Chromium target hit would_be_silently_dropped and returned background_unavailable_error.

Notes:

  • The fix evolved during runtime testing: the original cut routed Chromium only on dispatch:auto, but the default is background — so the real fix injects in the background branch (mirroring ClickTool), and a second commit made inject_click_screen use one synthetic pen device for all taps (the per-tap create/destroy failed the 2nd CreateSyntheticPointerDevice, which is why double-click specifically errored).
  • The dispatch:foreground path on Chromium still needs the UIAccess worker (cua-driver-uia.exe) — SetForegroundWindow is foreground-locked for a non-UIAccess process. That's the pre-existing requirement tracked in cua-driver Windows: UIA Invoke / ValuePattern.SetValue steal foreground on WPF — needs UIAccess worker #1706, unrelated to this change.
  • Candidate A (stale element-cache center) and the Drag Chromium short-circuit remain follow-ups.

@f-trycua
f-trycua merged commit 26d9298 into main Jun 24, 2026
67 of 71 checks passed
@f-trycua
f-trycua deleted the fix/windows-chromium-doubleclick-1984 branch June 24, 2026 02:13
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.

1 participant