diff --git a/Assets/Tests/InputSystem/Plugins/UITests.cs b/Assets/Tests/InputSystem/Plugins/UITests.cs index 1b94f75ab8..2928db8c8a 100644 --- a/Assets/Tests/InputSystem/Plugins/UITests.cs +++ b/Assets/Tests/InputSystem/Plugins/UITests.cs @@ -2911,10 +2911,16 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Right), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); Assert.That(scene.rightChildReceiver.events, Is.Empty); +#if UNITY_INPUT_SYSTEM_INPUT_MODULE_NAVIGATION_DEVICE_TYPE + Assert.That(scene.uiModule.GetNavigationEventDeviceType(scene.leftChildReceiver.events[0].data), + Is.EqualTo(NavigationDeviceType.NonKeyboard)); +#endif + scene.leftChildReceiver.events.Clear(); // Move left. @@ -2924,6 +2930,7 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Left), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); Assert.That(scene.rightChildReceiver.events, Is.Empty); @@ -2937,6 +2944,7 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Up), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); Assert.That(scene.rightChildReceiver.events, Is.Empty); @@ -2950,6 +2958,7 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Down), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); Assert.That(scene.rightChildReceiver.events, Is.Empty); @@ -2964,6 +2973,7 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Down), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); @@ -2977,6 +2987,7 @@ public IEnumerator UI_CanDriveUIFromGamepad() Assert.That(scene.leftChildReceiver.events, EventSequence( OneEvent("type", EventType.Move), + OneEvent("device", gamepad), OneEvent("moveDir", MoveDirection.Down), OneEvent("moveVector", gamepad.leftStick.ReadValue()))); @@ -2986,7 +2997,12 @@ public IEnumerator UI_CanDriveUIFromGamepad() PressAndRelease(gamepad.buttonSouth); yield return null; - Assert.That(scene.leftChildReceiver.events, EventSequence(OneEvent("type", EventType.Submit))); + Assert.That(scene.leftChildReceiver.events, + EventSequence( + OneEvent("type", EventType.Submit), + OneEvent("device", gamepad) + ) + ); Assert.That(scene.rightChildReceiver.events, Is.Empty); scene.leftChildReceiver.events.Clear(); @@ -2995,7 +3011,12 @@ public IEnumerator UI_CanDriveUIFromGamepad() PressAndRelease(gamepad.buttonEast); yield return null; - Assert.That(scene.leftChildReceiver.events, EventSequence(OneEvent("type", EventType.Cancel))); + Assert.That(scene.leftChildReceiver.events, + EventSequence( + OneEvent("type", EventType.Cancel), + OneEvent("device", gamepad) + ) + ); Assert.That(scene.rightChildReceiver.events, Is.Empty); scene.leftChildReceiver.events.Clear(); @@ -4463,6 +4484,7 @@ public struct Event public BaseEventData data { get; } public AxisEventData axisData => (AxisEventData)data; public ExtendedPointerEventData pointerData => (ExtendedPointerEventData)data; + public INavigationEventData navigationData => (INavigationEventData)data; public Event(EventType type, BaseEventData data) { @@ -4521,12 +4543,12 @@ public void OnMove(AxisEventData eventData) public void OnSubmit(BaseEventData eventData) { - events.Add(new Event(EventType.Submit, null)); + events.Add(new Event(EventType.Submit, CloneSubmitCancelEventData(eventData))); } public void OnCancel(BaseEventData eventData) { - events.Add(new Event(EventType.Cancel, null)); + events.Add(new Event(EventType.Cancel, CloneSubmitCancelEventData(eventData))); } public void OnSelect(BaseEventData eventData) @@ -4579,11 +4601,20 @@ private static AxisEventData CloneAxisEventData(AxisEventData eventData) { return new ExtendedAxisEventData(EventSystem.current) { + device = (eventData as ExtendedAxisEventData)?.device, moveVector = eventData.moveVector, moveDir = eventData.moveDir }; } + private static ExtendedSubmitCancelEventData CloneSubmitCancelEventData(BaseEventData eventData) + { + return new ExtendedSubmitCancelEventData(EventSystem.current) + { + device = (eventData as ExtendedSubmitCancelEventData)?.device + }; + } + private static ExtendedPointerEventData ClonePointerEventData(PointerEventData eventData) { // InputSystemUIInputModule should only be sending ExtendedPointEventData. diff --git a/Assets/Tests/InputSystem/Unity.InputSystem.Tests.asmdef b/Assets/Tests/InputSystem/Unity.InputSystem.Tests.asmdef index 260e6e8b89..e10c74f1cc 100644 --- a/Assets/Tests/InputSystem/Unity.InputSystem.Tests.asmdef +++ b/Assets/Tests/InputSystem/Unity.InputSystem.Tests.asmdef @@ -51,6 +51,11 @@ "expression": "6000.0.11", "define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_SCROLL_DELTA" }, + { + "name": "Unity", + "expression": "6000.2.0a4", + "define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_NAVIGATION_DEVICE_TYPE" + }, { "name": "Unity", "expression": "6000.0.15", diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 0450a277f8..600d71c5f3 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -13,6 +13,7 @@ however, it has to be formatted properly to pass verification tests. ### Fixed - Fixed an issue where removing a newly created action in the Asset Editor would cause an exception. [UUM-95693](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-95693) - Fixed arrow key navigation of Input Actions after Action rename. [ISXB-1024](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1024) +- Fixed gamepad navigation in UI Toolkit TextField when using InputSystemUIInputModule. [UUM-77364](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-77364) ## [1.13.0] - 2025-02-05 diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedAxisEventData.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedAxisEventData.cs index cce60e74c0..d916fcb174 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedAxisEventData.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedAxisEventData.cs @@ -3,10 +3,17 @@ namespace UnityEngine.InputSystem.UI { - // AxisEventData has no ToString. But that's the only thing we add so keeping - // it internal. - internal class ExtendedAxisEventData : AxisEventData + // AxisEventData has no ToString. Also added device info. Keeping + // it internal for now. + internal class ExtendedAxisEventData : AxisEventData, INavigationEventData { + /// + /// The that generated the axis input. + /// + /// + /// + public InputDevice device { get; set; } + public ExtendedAxisEventData(EventSystem eventSystem) : base(eventSystem) { diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs new file mode 100644 index 0000000000..8541d613d5 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs @@ -0,0 +1,20 @@ +#if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI +using UnityEngine.EventSystems; + +namespace UnityEngine.InputSystem.UI +{ + // A BaseEventData with added device info. + internal class ExtendedSubmitCancelEventData : BaseEventData, INavigationEventData + { + /// + /// The that generated the axis input. + /// + public InputDevice device { get; set; } + + public ExtendedSubmitCancelEventData(EventSystem eventSystem) + : base(eventSystem) + { + } + } +} +#endif diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs.meta new file mode 100644 index 0000000000..872b268403 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/ExtendedSubmitCancelEventData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b7430542eee4694469709e804d36cbbb \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs new file mode 100644 index 0000000000..e839fc6fd0 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs @@ -0,0 +1,13 @@ +#if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI + +namespace UnityEngine.InputSystem.UI +{ + internal interface INavigationEventData + { + /// + /// The that generated the axis input. + /// + public InputDevice device { get; } + } +} +#endif diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs.meta new file mode 100644 index 0000000000..6e973b1c0d --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/INavigationEventData.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4ee65784bb8ce434a947aea199821419 \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs index d0c03ad6f0..b4b9202b18 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs @@ -861,7 +861,7 @@ internal void ProcessNavigation(ref NavigationModel navigationState) if (allow) { - var eventData = m_NavigationState.eventData; + var eventData = m_NavigationState.eventData as ExtendedAxisEventData; if (eventData == null) { eventData = new ExtendedAxisEventData(eventSystem); @@ -871,6 +871,7 @@ internal void ProcessNavigation(ref NavigationModel navigationState) eventData.moveVector = moveVector; eventData.moveDir = moveDirection; + eventData.device = navigationState.device; if (IsMoveAllowed(eventData)) { @@ -903,7 +904,16 @@ internal void ProcessNavigation(ref NavigationModel navigationState) var submitAction = m_SubmitAction?.action; var cancelAction = m_CancelAction?.action; - var data = GetBaseEventData(); + var data = m_SubmitCancelState.eventData as ExtendedSubmitCancelEventData; + if (data == null) + { + data = new ExtendedSubmitCancelEventData(eventSystem); + m_SubmitCancelState.eventData = data; + } + data.Reset(); + + data.device = m_SubmitCancelState.device; + if (cancelAction != null && cancelAction.WasPerformedThisFrame()) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); if (!data.used && submitAction != null && submitAction.WasPerformedThisFrame()) @@ -1393,7 +1403,7 @@ public InputActionReference move public InputActionReference submit { get => m_SubmitAction; - set => SwapAction(ref m_SubmitAction, value, m_ActionsHooked, null); + set => SwapAction(ref m_SubmitAction, value, m_ActionsHooked, m_OnSubmitCancelDelegate); } /// @@ -1433,7 +1443,7 @@ public InputActionReference submit public InputActionReference cancel { get => m_CancelAction; - set => SwapAction(ref m_CancelAction, value, m_ActionsHooked, null); + set => SwapAction(ref m_CancelAction, value, m_ActionsHooked, m_OnSubmitCancelDelegate); } /// @@ -2252,6 +2262,12 @@ private void OnMoveCallback(InputAction.CallbackContext context) { ////REVIEW: should we poll this? or set the action to not be pass-through? (ps4 controller is spamming this action) m_NavigationState.move = context.ReadValue(); + m_NavigationState.device = context.control.device; + } + + private void OnSubmitCancelCallback(InputAction.CallbackContext context) + { + m_SubmitCancelState.device = context.control.device; } private void OnTrackedDeviceOrientationCallback(InputAction.CallbackContext context) @@ -2446,6 +2462,18 @@ public override Vector2 ConvertPointerEventScrollDeltaToTicks(Vector2 scrollDelt return scrollDelta / scrollDeltaPerTick; } +#endif + +#if UNITY_INPUT_SYSTEM_INPUT_MODULE_NAVIGATION_DEVICE_TYPE + public override NavigationDeviceType GetNavigationEventDeviceType(BaseEventData eventData) + { + if (eventData is not INavigationEventData eed) + return NavigationDeviceType.Unknown; + if (eed.device is Keyboard) + return NavigationDeviceType.Keyboard; + return NavigationDeviceType.NonKeyboard; + } + #endif private void HookActions() @@ -2465,6 +2493,8 @@ private void HookActions() m_OnScrollWheelDelegate = OnScrollCallback; if (m_OnMoveDelegate == null) m_OnMoveDelegate = OnMoveCallback; + if (m_OnSubmitCancelDelegate == null) + m_OnSubmitCancelDelegate = OnSubmitCancelCallback; if (m_OnTrackedDeviceOrientationDelegate == null) m_OnTrackedDeviceOrientationDelegate = OnTrackedDeviceOrientationCallback; if (m_OnTrackedDevicePositionDelegate == null) @@ -2486,6 +2516,8 @@ private void SetActionCallbacks(bool install) m_ActionsHooked = install; SetActionCallback(m_PointAction, m_OnPointDelegate, install); SetActionCallback(m_MoveAction, m_OnMoveDelegate, install); + SetActionCallback(m_SubmitAction, m_OnSubmitCancelDelegate, install); + SetActionCallback(m_CancelAction, m_OnSubmitCancelDelegate, install); SetActionCallback(m_LeftClickAction, m_OnLeftClickDelegate, install); SetActionCallback(m_RightClickAction, m_OnRightClickDelegate, install); SetActionCallback(m_MiddleClickAction, m_OnMiddleClickDelegate, install); @@ -2601,6 +2633,7 @@ private struct InputActionReferenceState private Action m_OnPointDelegate; private Action m_OnMoveDelegate; + private Action m_OnSubmitCancelDelegate; private Action m_OnLeftClickDelegate; private Action m_OnRightClickDelegate; private Action m_OnMiddleClickDelegate; @@ -2618,6 +2651,7 @@ private struct InputActionReferenceState // Navigation-type input. private NavigationModel m_NavigationState; + private SubmitCancelModel m_SubmitCancelState; [NonSerialized] private GameObject m_LocalMultiPlayerRoot; diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/NavigationModel.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/NavigationModel.cs index a6e493047e..5fb6d80c79 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/NavigationModel.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/UI/NavigationModel.cs @@ -10,11 +10,18 @@ internal struct NavigationModel public MoveDirection lastMoveDirection; public float lastMoveTime; public AxisEventData eventData; + public InputDevice device; public void Reset() { move = Vector2.zero; } } + + internal struct SubmitCancelModel + { + public BaseEventData eventData; + public InputDevice device; + } } #endif diff --git a/Packages/com.unity.inputsystem/InputSystem/Unity.InputSystem.asmdef b/Packages/com.unity.inputsystem/InputSystem/Unity.InputSystem.asmdef index 6bc8cc3e6a..f60bf6a10b 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Unity.InputSystem.asmdef +++ b/Packages/com.unity.inputsystem/InputSystem/Unity.InputSystem.asmdef @@ -92,6 +92,11 @@ "expression": "6000.0.11", "define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_SCROLL_DELTA" }, + { + "name": "Unity", + "expression": "6000.2.0a4", + "define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_NAVIGATION_DEVICE_TYPE" + }, { "name": "Unity", "expression": "6000.0.15", diff --git a/Packages/manifest.json b/Packages/manifest.json index 7890b741b0..47deea3119 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -11,7 +11,7 @@ "com.unity.test-framework.performance": "3.0.3", "com.unity.test-framework.utp-reporter": "1.1.0-preview", "com.unity.textmeshpro": "3.0.6", - "com.unity.ugui": "1.0.0", + "com.unity.ugui": "2.0.0", "nuget.mono-cecil": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0",