Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: fixed gamepad navigation in UI Toolkit TextField #2103

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions Assets/Tests/InputSystem/Plugins/UITests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2911,10 +2911,14 @@ 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);

Assert.That(scene.uiModule.GetNavigationEventDeviceType(scene.leftChildReceiver.events[0].data),
Is.EqualTo(NavigationDeviceType.NonKeyboard));

scene.leftChildReceiver.events.Clear();

// Move left.
Expand All @@ -2924,6 +2928,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);
Expand All @@ -2937,6 +2942,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);
Expand All @@ -2950,6 +2956,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);
Expand All @@ -2964,6 +2971,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())));

Expand All @@ -2977,6 +2985,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())));

Expand All @@ -2986,7 +2995,11 @@ 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();
Expand All @@ -2995,7 +3008,11 @@ 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();
Expand Down Expand Up @@ -4463,6 +4480,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)
{
Expand Down Expand Up @@ -4521,12 +4539,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)
Expand Down Expand Up @@ -4579,11 +4597,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.
Expand Down
1 change: 1 addition & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ however, it has to be formatted properly to pass verification tests.
- Fixed an issue where batch jobs would fail with "Error: Error building Player because scripts are compiling" if a source generated .inputactions asset is out of sync with its generated source code (ISXB-1300).
- Fixed multiple `OnScreenStick` Components that does not work together when using them simultaneously in isolation mode. [ISXB-813](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-813)
- Fixed an issue in input actions editor window that caused certain fields in custom input composite bindings to require multiple clicks to action / focus. [ISXB-1171](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1171)
- Fixed gamepad navigation in UI Toolkit TextField when using InputSystemUIInputModule.

### Changed
- Changed location of the link xml file (code stripping rules), from a temporary directory to the project Library folder (ISX-2140).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/// <summary>
/// The <see cref="InputDevice"/> that generated the axis input.
/// </summary>
/// <seealso cref="Keyboard"/>
/// <seealso cref="Gamepad"/>
public InputDevice device { get; set; }

public ExtendedAxisEventData(EventSystem eventSystem)
: base(eventSystem)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// The <see cref="InputDevice"/> that generated the axis input.
/// </summary>
public InputDevice device { get; set; }

public ExtendedSubmitCancelEventData(EventSystem eventSystem)
: base(eventSystem)
{
}
}
}
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#if PACKAGE_DOCS_GENERATION || UNITY_INPUT_SYSTEM_ENABLE_UI

namespace UnityEngine.InputSystem.UI
{
internal interface INavigationEventData
{
/// <summary>
/// The <see cref="InputDevice"/> that generated the axis input.
/// </summary>
public InputDevice device { get; }
}
}
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -871,6 +871,7 @@ internal void ProcessNavigation(ref NavigationModel navigationState)

eventData.moveVector = moveVector;
eventData.moveDir = moveDirection;
eventData.device = navigationState.device;

if (IsMoveAllowed(eventData))
{
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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);
}

/// <summary>
Expand Down Expand Up @@ -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);
}

/// <summary>
Expand Down Expand Up @@ -2245,6 +2255,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<Vector2>();
m_NavigationState.device = context.control.device;
}

private void OnSubmitCancelCallback(InputAction.CallbackContext context)
{
m_SubmitCancelState.device = context.control.device;
}

private void OnTrackedDeviceOrientationCallback(InputAction.CallbackContext context)
Expand Down Expand Up @@ -2441,6 +2457,17 @@ public override Vector2 ConvertPointerEventScrollDeltaToTicks(Vector2 scrollDelt

#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()
{
if (m_ActionsHooked)
Expand All @@ -2458,6 +2485,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)
Expand All @@ -2479,6 +2508,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);
Expand Down Expand Up @@ -2594,6 +2625,7 @@ private struct InputActionReferenceState

private Action<InputAction.CallbackContext> m_OnPointDelegate;
private Action<InputAction.CallbackContext> m_OnMoveDelegate;
private Action<InputAction.CallbackContext> m_OnSubmitCancelDelegate;
private Action<InputAction.CallbackContext> m_OnLeftClickDelegate;
private Action<InputAction.CallbackContext> m_OnRightClickDelegate;
private Action<InputAction.CallbackContext> m_OnMiddleClickDelegate;
Expand All @@ -2611,6 +2643,7 @@ private struct InputActionReferenceState

// Navigation-type input.
private NavigationModel m_NavigationState;
private SubmitCancelModel m_SubmitCancelState;

[NonSerialized] private GameObject m_LocalMultiPlayerRoot;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@
"expression": "6000.0.11",
"define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_SCROLL_DELTA"
},
{
"name": "Unity",
"expression": "6000.1.0b2",
"define": "UNITY_INPUT_SYSTEM_INPUT_MODULE_NAVIGATION_DEVICE_TYPE"
},
{
"name": "Unity",
"expression": "6000.0.15",
Expand Down
Loading