Skip to content

Let pointer presses reach the keyboard stage's hit targets - #1255

Open
malpern wants to merge 1 commit into
masterfrom
claude/stage-pointer-hit-testing
Open

Let pointer presses reach the keyboard stage's hit targets#1255
malpern wants to merge 1 commit into
masterfrom
claude/stage-pointer-hit-testing

Conversation

@malpern

@malpern malpern commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Clicking a key in the onboarding tour did nothing whenever Metal was active (the shipped default). KeyboardStageMTKView is a real NSView with no hitTest override, so it returned itself for every point inside the keyboard and swallowed mouse events before the semantic overlay's per-key hit targets — which sit above it and own pointer interaction — could receive them.

  • Return nil from hitTest, matching the plan's boundary that the renderer is visual output only
  • Regression test pinning the contract, verified failing without the fix

Note on how this survived

Snapshot/golden coverage renders scenes but never exercises input, so no automated test could catch a pointer-routing defect in the Metal path. Worth follow-up interaction-level coverage; see PR discussion.

Review gate

remote review gate selected — GitHub claude-review is the enforced reviewer.

Testing

  • KeyboardStageInteractionTests pass (6); the new test fails without the fix and passes with it

🤖 Generated with Claude Code

The Metal stage is a real NSView, and without a hitTest override it
returned itself for every point inside the keyboard — swallowing mouse
events before the semantic overlay's per-key hit targets stacked above
it could see them. Clicking a key worked in the SwiftUI fallback and
silently did nothing whenever Metal was active, which is the shipped
default. That contradicts the plan's own boundary: the renderer is
visual output, and the native overlay owns pointer interaction and
accessibility.

Return nil from hitTest so events fall through to the overlay, and pin
the contract with a regression test (verified failing without the fix).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review of the diff: the fix (override hitTest to always return nil on KeyboardStageMTKView) is a reasonable way to stop the Metal render view from swallowing clicks meant for the semantic overlay above it, and the new test correctly pins that behavior for a couple of sample points.

One thing worth confirming before merge: this override makes the Metal view unconditionally transparent to all pointer-driven interaction, not just clicks — that also affects mouseMoved/cursorUpdate, right-click/context-menu routing, and any drag or magnify/scroll gesture recognizers that might be attached directly to this view. If the Metal view (or a gesture recognizer on it) is ever relied on for pan/zoom, hover cursor changes, or a context menu on the keyboard stage, this change would silently break those too, since AppKit hit-tests the frontmost view first and now always skips this one. If none of that applies today, it'd be worth a one-line comment near the override stating that explicitly (the existing doc comment covers why clicks needed to pass through, but not the fact that it disables all other pointer-derived interaction as a side effect), so a future contributor adding a gesture to this view doesn't get silently defeated by it.

Test coverage is otherwise adequate for the specific regression being fixed (constructs the view directly and checks hitTest at two points); no correctness issues found in the test itself.

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