Skip to content

feat: block handle interaction start when pointer is over uGUI#42

Merged
manaporkun merged 5 commits into
mainfrom
feat/ui-occlusion-guard
Jun 11, 2026
Merged

feat: block handle interaction start when pointer is over uGUI#42
manaporkun merged 5 commits into
mainfrom
feat/ui-occlusion-guard

Conversation

@manaporkun

@manaporkun manaporkun commented Jun 11, 2026

Copy link
Copy Markdown
Owner

What

Clicking a uGUI element rendered above the scene no longer starts a handle drag — the most common integration papercut. An interaction already in progress is never interrupted (the guard only gates starting one).

  • TransformHandleManager.BlockWhenPointerOverUI — serialized, default on, runtime-settable.
  • protected virtual bool IsPointerOverUI() — override seam for non-uGUI UI stacks.

Optional dependency, non-breaking

uGUI is wired as an optional dependency via the TH_UGUI version define, mirroring the existing Input System integration. Projects without com.unity.ugui compile cleanly and the guard is a no-op (IsPointerOverUI returns false). The ci/floor-2021 project gains com.unity.ugui so the guarded path is compiled on the 2021.3 floor leg.

Verification

Local batch (Unity 6000.3.16f1, uGUI present → TH_UGUI path): EditMode 62/62, PlayMode 35/35, zero compiler warnings. Interaction suite confirms drag-start still works when no EventSystem is present (guard inert). The occlusion itself depends on live pointer state, which Unity cannot reproduce headless — manual verification: a fullscreen Canvas button over the scene must not start a drag.

🤖 Generated with Claude Code


Note

Low Risk
Default-off behavior preserves existing input; risk is limited to projects that enable the flag and rely on EventSystem/uGUI pointer hits (including touch pointer id).

Overview
Adds an opt-in guard so transform-handle drags do not start while the pointer is over uGUI (TransformHandleManager.BlockWhenPointerOverUI, off by default). When enabled and not dragging, hover raycasts are skipped over UI, which clears highlight and blocks MouseInput from beginning a drag; active drags are unchanged.

uGUI is optional via the TH_UGUI version define (asmdef reference + versionDefines); without uGUI the guard is a no-op. protected virtual IsPointerOverUI() supports custom UI stacks. InputWrapper.PrimaryTouchPointerId lets touch use EventSystem.IsPointerOverGameObject(int).

The Demo sample spawns an overlay panel, ensures an EventSystem, mirrors the guard for target picking, and adds a HUD toggle. README/changelog document the feature; ci/floor-2021 adds com.unity.ugui so the guarded code path compiles on the 2021.3 floor job.

Reviewed by Cursor Bugbot for commit 6159cbd. Bugbot is set up for automated code reviews on this repo. Configure here.

A handle interaction no longer starts while the pointer is over a uGUI
element, so clicking a button or panel above the scene does not begin a
drag. An interaction already in progress is never interrupted. Exposed as
TransformHandleManager.BlockWhenPointerOverUI (serialized, default on) and
the overridable IsPointerOverUI() seam.

uGUI is an optional dependency via the TH_UGUI version define (mirrors the
Input System integration): projects without com.unity.ugui compile cleanly
and the guard is a no-op. The 2021.3 floor CI project gains com.unity.ugui
so the guarded path is exercised on the floor leg too.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 600681c3e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!blockWhenPointerOverUI) return false;
#if TH_UGUI
var eventSystem = UnityEngine.EventSystems.EventSystem.current;
return eventSystem != null && eventSystem.IsPointerOverGameObject();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass the active touch id to the UI hit test

In touch builds this guard still allows starting a drag through uGUI, because the package treats the first touch as the primary pointer (InputWrapper.GetMouseButtonDown(0) returns true for TouchPhase.Began and MousePosition uses Input.GetTouch(0).position), but EventSystem.IsPointerOverGameObject() without an id queries the mouse pointer rather than the active finger. When a user taps a UI button over a handle on mobile/tablet, IsPointerOverUI() returns false and MouseInput() can start the handle interaction anyway; use the current touch/finger pointer id for the uGUI check.

Useful? React with 👍 / 👎.

The Demo now spawns a uGUI Canvas + panel (and an EventSystem with the input
module matching the active backend) and adds a HUD toggle for
BlockWhenPointerOverUI, so the guard is directly testable: clicking the panel
must not move objects behind it while the guard is on. The sample's own target
picking now also respects UI occlusion. uGUI/Input System are referenced by
the sample asmdef and gated behind TH_UGUI/TH_INPUTSYSTEM.
EventSystem.IsPointerOverGameObject() with no argument only queries the mouse
pointer, but the package treats the first active touch as the primary pointer
(InputWrapper), so a tap over uGUI on mobile bypassed the guard and started a
drag. IsPointerOverUI now also tests the active finger's pointer id via the new
InputWrapper.PrimaryTouchPointerId; the demo's own picking guard mirrors it.

Reported independently by Cursor Bugbot and Codex on PR #42.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0e7365c. Configure here.

Comment thread Packages/com.orkunmanap.runtime-transform-handles/Samples~/Demo/HandleDemo.cs Outdated
HandleSelectionInput bailed unconditionally when the pointer was over UI, so
toggling the guard off in the HUD still blocked target picking over the panel
while handle drags passed through — contradicting the on-screen hint. Gate the
demo's own picking on the same flag the manager uses.

Reported by Cursor Bugbot on PR #42.
Changing interaction behavior on by default in a minor release could surprise
existing users, so BlockWhenPointerOverUI now defaults to false — enabling the
package never silently alters input. The Demo sample enables it at startup so
it still showcases the feature out of the box.
@manaporkun manaporkun merged commit fde271a into main Jun 11, 2026
11 checks passed
@manaporkun manaporkun deleted the feat/ui-occlusion-guard branch June 11, 2026 14:02
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