feat: block handle interaction start when pointer is over uGUI#42
Conversation
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.
There was a problem hiding this comment.
💡 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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ 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.
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.

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_UGUIversion define, mirroring the existing Input System integration. Projects withoutcom.unity.uguicompile cleanly and the guard is a no-op (IsPointerOverUIreturns false). Theci/floor-2021project gainscom.unity.uguiso the guarded path is compiled on the 2021.3 floor leg.Verification
Local batch (Unity 6000.3.16f1, uGUI present →
TH_UGUIpath): EditMode 62/62, PlayMode 35/35, zero compiler warnings. Interaction suite confirms drag-start still works when noEventSystemis 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 blocksMouseInputfrom beginning a drag; active drags are unchanged.uGUI is optional via the
TH_UGUIversion define (asmdef reference +versionDefines); without uGUI the guard is a no-op.protected virtual IsPointerOverUI()supports custom UI stacks.InputWrapper.PrimaryTouchPointerIdlets touch useEventSystem.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-2021addscom.unity.uguiso 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.