diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 3453304eb6..e80a381a8b 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- Fixed the Input Actions editor requiring two clicks to move focus between processor or interaction parameter fields, because committing a parameter value rebuilt the parameter field UI mid-click [UUM-144339](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-144339) - Fixed `InputSystemProvider` disabling project-wide actions on shutdown when UI Toolkit destroys its objects mid-play. The provider now scopes its lifecycle to the UI action map only and does not disable project-wide actions [UUM-134130](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-134130) - Fixed `InputActionRebindingExtensions.GetBindingDisplayString(InputAction, InputBinding, ...)` returning an empty string for composite bindings when the binding mask filters by group [UUM-141423](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-141423) - Fixed `InputEventPtr.handled` not preventing actions from triggering when switching devices. The default event handled policy has been changed from `SuppressStateUpdates` (now deprecated) to `SuppressActionEventNotifications`, which keeps device state synchronized while suppressing action callbacks for handled events. [ISXB-1097](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1097) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/StateContainer.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/StateContainer.cs index 4a2af93675..d7dd16559f 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/StateContainer.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/StateContainer.cs @@ -22,6 +22,12 @@ internal class StateContainer private InputActionsEditorState m_State; public readonly string assetGUID; + // When set, the next change detected by the TrackSerializedObjectValue callback below does not rebuild + // the editor UI. Used to commit value-only edits (e.g. an interaction/processor parameter) without + // tearing down and recreating the field the user is interacting with (UUM-144339). It is a one-shot: + // the very next change notification consumes it, so unrelated changes still rebuild as normal. + private bool m_IgnoreNextSerializedObjectChange; + public StateContainer(InputActionsEditorState initialState, string assetGUID) { m_State = initialState; @@ -52,6 +58,15 @@ public void Dispatch(Command command, UIRebuildMode editorRebuildMode = UIRebuil }); } + // Request that the editor UI is not rebuilt in response to the next change of the tracked serialized + // object. Call this immediately before committing a value-only edit (ApplyModifiedProperties) that must + // not tear down the VisualElement the user is interacting with. The request is consumed by the next + // change notification, so any subsequent change still rebuilds normally. + public void IgnoreNextSerializedObjectChange() + { + m_IgnoreNextSerializedObjectChange = true; + } + public void Initialize(VisualElement rootVisualElement) { // We need to use a root element for the TrackSerializedObjectValue that is destroyed with the view. @@ -62,6 +77,14 @@ public void Initialize(VisualElement rootVisualElement) m_RootVisualElement.Unbind(); m_RootVisualElement.TrackSerializedObjectValue(m_State.serializedObject, so => { + // A value-only edit asked us not to rebuild the UI for this change (see + // IgnoreNextSerializedObjectChange). Consume the request and skip the rebuild. + if (m_IgnoreNextSerializedObjectChange) + { + m_IgnoreNextSerializedObjectChange = false; + return; + } + StateChanged?.Invoke(m_State, UIRebuildMode.Rebuild); }); StateChanged?.Invoke(m_State, UIRebuildMode.Rebuild); diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs index c0f0bade83..cba44ac0e3 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs @@ -77,7 +77,22 @@ private void OnParametersChanged(ParameterListView listView, int index) { var interactionsOrProcessorsList = NameAndParameters.ParseMultiple(m_ListProperty.stringValue).ToList(); interactionsOrProcessorsList[index] = new NameAndParameters { name = interactionsOrProcessorsList[index].name, parameters = listView.GetParameters() }; - m_ListProperty.stringValue = NameAndParameters.ToSerializableString(interactionsOrProcessorsList); + var newValue = NameAndParameters.ToSerializableString(interactionsOrProcessorsList); + + // onChange also fires on a plain blur with no edit, leaving the serialized string unchanged. Bail before + // arming the ignore flag below: ApplyModifiedProperties would be a no-op that never fires the + // TrackSerializedObjectValue callback, so the flag would stay armed and wrongly swallow the next real rebuild. + if (m_ListProperty.stringValue == newValue) + return; + + m_ListProperty.stringValue = newValue; + + // This is a value-only edit of an existing interaction/processor: the parameter fields are already + // showing the new value. A full UI rebuild here would tear down and recreate the field the user is + // moving focus into, forcing a second click (UUM-144339). Suppress the rebuild that committing the + // value would otherwise trigger via StateContainer's TrackSerializedObjectValue callback. Structural + // edits (add/move/delete) intentionally do not call this and still rebuild. + stateContainer.IgnoreNextSerializedObjectChange(); m_ListProperty.serializedObject.ApplyModifiedProperties(); }