diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/InputActionsTreeViewItem.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/InputActionsTreeViewItem.cs index c5acb6794d..bf492130f5 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/InputActionsTreeViewItem.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/InputActionsTreeViewItem.cs @@ -61,7 +61,7 @@ private void OnKeyDownEventForRename(KeyDownEvent e) return; FocusOnRenameTextField(); - e.PreventDefault(); + e.StopPropagation(); } private void OnMouseDownEventForRename(MouseDownEvent e) @@ -70,7 +70,6 @@ private void OnMouseDownEventForRename(MouseDownEvent e) return; FocusOnRenameTextField(); - e.StopPropagation(); } diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI.meta new file mode 100644 index 0000000000..7fc981398a --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96500a17645c67442a0ccdca007e6d28 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs new file mode 100644 index 0000000000..ea35c04c30 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.CompilerServices; +using UnityEngine.Scripting; + +[assembly: InternalsVisibleTo("UnityEngine.InputForUIVisualizer")] +[assembly: AlwaysLinkAssembly] diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs.meta new file mode 100644 index 0000000000..fc5bea2c78 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65c861c7ef9bee2479c728694e87ea45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef new file mode 100644 index 0000000000..b1326b2bfa --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef @@ -0,0 +1,15 @@ +{ + "name": "Unity.InputSystem.ForUI", + "references": [ + "Unity.InputSystem" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef.meta new file mode 100644 index 0000000000..2a814154e4 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemForUI.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 09dcc9c0126b6b34ab2a877b8f2277f5 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs new file mode 100644 index 0000000000..e385373951 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs @@ -0,0 +1,682 @@ +#if UNITY_2023_2_OR_NEWER // UnityEngine.InputForUI Module unavailable in earlier releases +using System.Collections.Generic; +using Unity.IntegerTime; +using UnityEngine.InputSystem.Controls; +using UnityEngine.InputForUI; + +namespace UnityEngine.InputSystem.Plugins.InputForUI +{ + using Event = UnityEngine.InputForUI.Event; + using EventModifiers = UnityEngine.InputForUI.EventModifiers; + using EventProvider = UnityEngine.InputForUI.EventProvider; + + internal class InputSystemProvider : IEventProviderImpl + { + InputEventPartialProvider m_InputEventPartialProvider; + + Configuration m_Cfg; + + InputActionAsset m_InputActionAsset; + InputActionReference m_PointAction; + InputActionReference m_MoveAction; + InputActionReference m_SubmitAction; + InputActionReference m_CancelAction; + InputActionReference m_LeftClickAction; + InputActionReference m_MiddleClickAction; + InputActionReference m_RightClickAction; + InputActionReference m_ScrollWheelAction; + + InputAction m_NextPreviousAction; + + List m_Events = new List(); + + PointerState m_MouseState; + + PointerState m_PenState; + bool m_SeenPenEvents; + + PointerState m_TouchState; + bool m_SeenTouchEvents; + + const float k_SmallestReportedMovementSqrDist = 0.01f; + + NavigationEventRepeatHelper m_RepeatHelper = new(); + bool m_ResetSeenEventsOnUpdate; + + static InputSystemProvider() + { + // Only if InputSystem is enabled in the PlayerSettings do we set it as the provider. + // This includes situations where both InputManager and InputSystem are enabled. +#if ENABLE_INPUT_SYSTEM + EventProvider.SetInputSystemProvider(new InputSystemProvider()); +#endif + } + + [RuntimeInitializeOnLoadMethod(loadType: RuntimeInitializeLoadType.SubsystemRegistration)] + static void Bootstrap() {} // Empty function. Exists only to invoke the static class constructor in Runtime Players + + EventModifiers m_EventModifiers => m_InputEventPartialProvider._eventModifiers; + + DiscreteTime m_CurrentTime => (DiscreteTime)Time.timeAsRational; + + const uint k_DefaultPlayerId = 0u; + + public void Initialize() + { + m_InputEventPartialProvider ??= new InputEventPartialProvider(); + m_InputEventPartialProvider.Initialize(); + + m_Events.Clear(); + + m_MouseState.Reset(); + + m_PenState.Reset(); + m_SeenPenEvents = false; + + m_TouchState.Reset(); + m_SeenTouchEvents = false; + + // TODO should UITK somehow override this? + m_Cfg = Configuration.GetDefaultConfiguration(); + RegisterActions(m_Cfg); + } + + public void Shutdown() + { + UnregisterActions(m_Cfg); + + m_InputEventPartialProvider.Shutdown(); + m_InputEventPartialProvider = null; + } + + public void Update() + { +#if UNITY_EDITOR + // Ensure we are in a good (initialized) state before running updates. + // This could be in a bad state for a duration while the build pipeline is running + // when building tests to run in the Standalone Player. + if (m_InputActionAsset == null) + return; +#endif + + m_InputEventPartialProvider.Update(); + + // Sort events added by input actions callbacks, based on type. + // This is necessary to ensure that events are dispatched in the correct order. + // If all events are of the PointerEvents type, sorting is based on reverse order of the EventSource enum. + // Touch -> Pen -> Mouse. + m_Events.Sort(SortEvents); + + var currentTime = (DiscreteTime)Time.timeAsRational; + + DirectionNavigation(currentTime); + + foreach (var ev in m_Events) + { + // We need to ignore some pointer events based on priority (Touch->Pen->Mouse) + // This is mostly used to filter out simulated input, e.g. when pen is active it also generates mouse input + if (m_SeenTouchEvents && ev.type == Event.Type.PointerEvent && ev.eventSource == EventSource.Pen) + m_PenState.Reset(); + else if ((m_SeenTouchEvents || m_SeenPenEvents) && + ev.type == Event.Type.PointerEvent && (ev.eventSource == EventSource.Mouse || ev.eventSource == EventSource.Unspecified)) + m_MouseState.Reset(); + else + EventProvider.Dispatch(ev); + } + + // Sometimes single lower priority events can be received when using Touch or Pen, on a different frame. + // To avoid dispatching them, the seen event flags aren't reset in between calls to OnPointerPerformed. + // Essentially, if we're moving with Touch or Pen, lower priority events aren't dispatch as well. + // Once OnClickPerformed is called, the seen flags are reset + if (m_ResetSeenEventsOnUpdate) + { + ResetSeenEvents(); + m_ResetSeenEventsOnUpdate = false; + } + + m_Events.Clear(); + } + + void ResetSeenEvents() + { + m_SeenTouchEvents = false; + m_SeenPenEvents = false; + } + + //TODO: Refactor as there is no need for having almost the same implementation in the IM and ISX? + void DirectionNavigation(DiscreteTime currentTime) + { + var(move, axesButtonWerePressed) = ReadCurrentNavigationMoveVector(); + var direction = NavigationEvent.DetermineMoveDirection(move); + + // Checks for next/previous directions if no movement was detected + if (direction == NavigationEvent.Direction.None) + { + direction = ReadNextPreviousDirection(); + axesButtonWerePressed = m_NextPreviousAction.WasPressedThisFrame(); + } + + if (direction == NavigationEvent.Direction.None) + { + m_RepeatHelper.Reset(); + } + else + { + if (m_RepeatHelper.ShouldSendMoveEvent(currentTime, direction, axesButtonWerePressed)) + { + EventProvider.Dispatch(Event.From(new NavigationEvent + { + type = NavigationEvent.Type.Move, + direction = direction, + timestamp = currentTime, + eventSource = GetEventSource(GetActiveDeviceFromDirection(direction)), + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + } + } + } + + InputDevice GetActiveDeviceFromDirection(NavigationEvent.Direction direction) + { + switch (direction) + { + case NavigationEvent.Direction.Left: + case NavigationEvent.Direction.Up: + case NavigationEvent.Direction.Right: + case NavigationEvent.Direction.Down: + return m_MoveAction.action.activeControl.device; + case NavigationEvent.Direction.Next: + case NavigationEvent.Direction.Previous: + return m_NextPreviousAction.activeControl.device; + case NavigationEvent.Direction.None: + default: + return Keyboard.current; + } + } + + (Vector2, bool) ReadCurrentNavigationMoveVector() + { + var move = m_MoveAction.action.ReadValue(); + // Check if the action was "pressed" this frame to deal with repeating events + var axisWasPressed = m_MoveAction.action.WasPressedThisFrame(); + return (move, axisWasPressed); + } + + NavigationEvent.Direction ReadNextPreviousDirection() + { + if (m_NextPreviousAction.IsPressed()) + { + //TODO: For now it only deals with Keyboard, needs to deal with other devices if we can add bindings + // for Gamepad, etc + //TODO: An alternative could be to have an action for next and for previous since shortcut support does + // not work properly + if (m_NextPreviousAction.activeControl.device is Keyboard) + { + var keyboard = m_NextPreviousAction.activeControl.device as Keyboard; + // Return direction based on whether shift is pressed or not + return keyboard.shiftKey.isPressed ? NavigationEvent.Direction.Previous : NavigationEvent.Direction.Next; + } + } + + return NavigationEvent.Direction.None; + } + + static int SortEvents(Event a, Event b) + { + return Event.CompareType(a, b); + } + + public void OnFocusChanged(bool focus) + { + m_InputEventPartialProvider.OnFocusChanged(focus); + } + + public bool RequestCurrentState(Event.Type type) + { + if (m_InputEventPartialProvider.RequestCurrentState(type)) + return true; + + switch (type) + { + case Event.Type.PointerEvent: + { + if (m_TouchState.LastPositionValid) + EventProvider.Dispatch(Event.From(ToPointerStateEvent(m_CurrentTime, m_TouchState, EventSource.Touch))); + if (m_PenState.LastPositionValid) + EventProvider.Dispatch(Event.From(ToPointerStateEvent(m_CurrentTime, m_PenState, EventSource.Pen))); + if (m_MouseState.LastPositionValid) + EventProvider.Dispatch(Event.From(ToPointerStateEvent(m_CurrentTime, m_MouseState, EventSource.Mouse))); + else + { + // TODO maybe it's reasonable to poll and dispatch mouse state here anyway? + } + + return m_TouchState.LastPositionValid || + m_PenState.LastPositionValid || + m_MouseState.LastPositionValid; + } + // TODO + case Event.Type.IMECompositionEvent: + default: + return false; + } + } + + public uint playerCount => 1; // TODO + + // copied from UIElementsRuntimeUtility.cs + static Vector2 ScreenBottomLeftToPanelPosition(Vector2 position, int targetDisplay) + { + // Flip positions Y axis between input and UITK + var screenHeight = Screen.height; + if (targetDisplay > 0 && targetDisplay < Display.displays.Length) + screenHeight = Display.displays[targetDisplay].systemHeight; + position.y = screenHeight - position.y; + return position; + } + + PointerEvent ToPointerStateEvent(DiscreteTime currentTime, in PointerState state, EventSource eventSource) + { + return new PointerEvent + { + type = PointerEvent.Type.State, + pointerIndex = 0, + position = state.LastPosition, + deltaPosition = Vector2.zero, + scroll = Vector2.zero, + displayIndex = state.LastDisplayIndex, + // TODO + // tilt = eventSource == EventSource.Pen ? _lastPenData.tilt : Vector2.zero, + // twist = eventSource == EventSource.Pen ? _lastPenData.twist : 0.0f, + // pressure = eventSource == EventSource.Pen ? _lastPenData.pressure : 0.0f, + // isInverted = eventSource == EventSource.Pen && ((_lastPenData.penStatus & PenStatus.Inverted) != 0), + button = 0, + buttonsState = state.ButtonsState, + clickCount = 0, + timestamp = currentTime, + eventSource = eventSource, + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + }; + } + + EventSource GetEventSource(InputAction.CallbackContext ctx) + { + var device = ctx.control.device; + return GetEventSource(device); + } + + EventSource GetEventSource(InputDevice device) + { + if (device is Touchscreen) + return EventSource.Touch; + if (device is Pen) + return EventSource.Pen; + if (device is Mouse) + return EventSource.Mouse; + if (device is Keyboard) + return EventSource.Keyboard; + if (device is Gamepad) + return EventSource.Gamepad; + + return EventSource.Unspecified; + } + + ref PointerState GetPointerStateForSource(EventSource eventSource) + { + switch (eventSource) + { + case EventSource.Touch: + return ref m_TouchState; + case EventSource.Pen: + return ref m_PenState; + default: + return ref m_MouseState; + } + } + + void DispatchFromCallback(in Event ev) + { + m_Events.Add(ev); + } + + static int FindTouchFingerIndex(Touchscreen touchscreen, InputAction.CallbackContext ctx) + { + if (touchscreen == null) + return 0; + + var asVector2Control = ctx.control is Vector2Control ? (Vector2Control)ctx.control : null; + var asTouchPressControl = ctx.control is TouchPressControl ? (TouchPressControl)ctx.control : null; + var asTouchControl = ctx.control is TouchControl ? (TouchControl)ctx.control : null; + + // Finds the index of the matching control type in the Touchscreen device lost of touch controls (touches) + for (var i = 0; i < touchscreen.touches.Count; ++i) + { + if (asVector2Control != null && asVector2Control == touchscreen.touches[i].position) + return i; + if (asTouchPressControl != null && asTouchPressControl == touchscreen.touches[i].press) + return i; + if (asTouchControl != null && asTouchControl == touchscreen.touches[i]) + return i; + } + return 0; + } + + void OnPointerPerformed(InputAction.CallbackContext ctx) + { + var eventSource = GetEventSource(ctx); + ref var pointerState = ref GetPointerStateForSource(eventSource); + + // Overall I'm not happy how leaky this is, we're using input actions to have flexibility to bind to different controls, + // but instead we just kinda abuse it to bind to different devices ... + var asPointerDevice = ctx.control.device is Pointer ? (Pointer)ctx.control.device : null; + var asPenDevice = ctx.control.device is Pen ? (Pen)ctx.control.device : null; + var asTouchscreenDevice = ctx.control.device is Touchscreen ? (Touchscreen)ctx.control.device : null; + var asTouchControl = ctx.control is TouchControl ? (TouchControl)ctx.control : null; + var pointerIndex = FindTouchFingerIndex(asTouchscreenDevice, ctx); + + m_ResetSeenEventsOnUpdate = false; + if (asTouchControl != null || asTouchscreenDevice != null) + m_SeenTouchEvents = true; + else if (asPenDevice != null) + m_SeenPenEvents = true; + + var positionISX = ctx.ReadValue(); + var targetDisplay = asPointerDevice != null ? asPointerDevice.displayIndex.ReadValue() : (asTouchscreenDevice != null ? asTouchscreenDevice.displayIndex.ReadValue() : 0); + var position = ScreenBottomLeftToPanelPosition(positionISX, targetDisplay); + var delta = pointerState.LastPositionValid ? position - pointerState.LastPosition : Vector2.zero; + + var tilt = asPenDevice != null ? asPenDevice.tilt.ReadValue() : Vector2.zero; + var twist = asPenDevice != null ? asPenDevice.twist.ReadValue() : 0.0f; + var pressure = asPenDevice != null + ? asPenDevice.pressure.ReadValue() + : (asTouchControl != null ? asTouchControl.pressure.ReadValue() : 0.0f); + var isInverted = asPenDevice != null + ? asPenDevice.eraser.isPressed + : false; // TODO any way to detect that pen is inverted but not touching? + + if (delta.sqrMagnitude >= k_SmallestReportedMovementSqrDist) + { + DispatchFromCallback(Event.From(new PointerEvent + { + type = PointerEvent.Type.PointerMoved, + pointerIndex = pointerIndex, + position = position, + deltaPosition = delta, + scroll = Vector2.zero, + displayIndex = targetDisplay, + tilt = tilt, + twist = twist, + pressure = pressure, + isInverted = isInverted, + button = 0, + buttonsState = pointerState.ButtonsState, + clickCount = 0, + timestamp = m_CurrentTime, + eventSource = eventSource, + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + + // only record if we send an event + pointerState.OnMove(m_CurrentTime, position, targetDisplay); + } + else if (!pointerState.LastPositionValid) + pointerState.OnMove(m_CurrentTime, position, targetDisplay); + } + + void OnSubmitPerformed(InputAction.CallbackContext ctx) + { + DispatchFromCallback(Event.From(new NavigationEvent + { + type = NavigationEvent.Type.Submit, + direction = NavigationEvent.Direction.None, + timestamp = m_CurrentTime, + eventSource = GetEventSource(ctx), + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + } + + void OnCancelPerformed(InputAction.CallbackContext ctx) + { + DispatchFromCallback(Event.From(new NavigationEvent + { + type = NavigationEvent.Type.Cancel, + direction = NavigationEvent.Direction.None, + timestamp = m_CurrentTime, + eventSource = GetEventSource(ctx), + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + } + + void OnClickPerformed(InputAction.CallbackContext ctx, EventSource eventSource, PointerEvent.Button button) + { + ref var state = ref GetPointerStateForSource(eventSource); + + var asTouchscreenDevice = ctx.control.device is Touchscreen ? (Touchscreen)ctx.control.device : null; + var asTouchControl = ctx.control is TouchControl ? (TouchControl)ctx.control : null; + var pointerIndex = FindTouchFingerIndex(asTouchscreenDevice, ctx); + + m_ResetSeenEventsOnUpdate = true; + if (asTouchControl != null || asTouchscreenDevice != null) + m_SeenTouchEvents = true; + + var wasPressed = state.ButtonsState.Get(button); + var isPressed = ctx.ReadValueAsButton(); + state.OnButtonChange(m_CurrentTime, button, wasPressed, isPressed); + + DispatchFromCallback(Event.From(new PointerEvent + { + type = isPressed ? PointerEvent.Type.ButtonPressed : PointerEvent.Type.ButtonReleased, + pointerIndex = pointerIndex, + position = state.LastPosition, + deltaPosition = Vector2.zero, + scroll = Vector2.zero, + displayIndex = state.LastDisplayIndex, + tilt = Vector2.zero, + twist = 0.0f, + pressure = 0.0f, + isInverted = false, + button = button, + buttonsState = state.ButtonsState, + clickCount = state.ClickCount, + timestamp = m_CurrentTime, + eventSource = eventSource, + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + } + + void OnLeftClickPerformed(InputAction.CallbackContext ctx) => OnClickPerformed(ctx, GetEventSource(ctx), PointerEvent.Button.MouseLeft); + void OnMiddleClickPerformed(InputAction.CallbackContext ctx) => OnClickPerformed(ctx, GetEventSource(ctx), PointerEvent.Button.MouseMiddle); + void OnRightClickPerformed(InputAction.CallbackContext ctx) => OnClickPerformed(ctx, GetEventSource(ctx), PointerEvent.Button.MouseRight); + + void OnScrollWheelPerformed(InputAction.CallbackContext ctx) + { + var scrollDelta = ctx.ReadValue(); + if (scrollDelta.sqrMagnitude < k_SmallestReportedMovementSqrDist) + return; + + var eventSource = GetEventSource(ctx); + ref var state = ref GetPointerStateForSource(eventSource); + + var position = Vector2.zero; + var targetDisplay = 0; + + if (state.LastPositionValid) + { + position = state.LastPosition; + targetDisplay = state.LastDisplayIndex; + } + else if (eventSource == EventSource.Mouse && Mouse.current != null) + { + position = Mouse.current.position.ReadValue(); + targetDisplay = Mouse.current.displayIndex.ReadValue(); + } + + // Make it look similar to IMGUI event scroll values. + // TODO check how it behaves on macOS + scrollDelta.x /= 40.0f; + scrollDelta.y /= -40.0f; + + DispatchFromCallback(Event.From(new PointerEvent + { + type = PointerEvent.Type.Scroll, + pointerIndex = 0, + position = position, + deltaPosition = Vector2.zero, + scroll = scrollDelta, + displayIndex = targetDisplay, + tilt = Vector2.zero, + twist = 0.0f, + pressure = 0.0f, + isInverted = false, + button = 0, + buttonsState = state.ButtonsState, + clickCount = 0, + timestamp = m_CurrentTime, + eventSource = EventSource.Mouse, + playerId = k_DefaultPlayerId, + eventModifiers = m_EventModifiers + })); + } + + void RegisterNextPreviousAction() + { + m_NextPreviousAction = new InputAction(name: "nextPreviousAction", type: InputActionType.Button); + // TODO add more default bindings, or make them configurable + m_NextPreviousAction.AddBinding("/tab"); + m_NextPreviousAction.Enable(); + } + + void UnregisterNextPreviousAction() + { + if (m_NextPreviousAction != null) + { + m_NextPreviousAction.Disable(); + m_NextPreviousAction = null; + } + } + + void RegisterActions(Configuration cfg) + { + m_InputActionAsset = InputActionAsset.FromJson(cfg.InputActionAssetAsJson); + + m_PointAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.PointAction)); + m_MoveAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.MoveAction)); + m_SubmitAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.SubmitAction)); + m_CancelAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.CancelAction)); + m_LeftClickAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.LeftClickAction)); + m_MiddleClickAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.MiddleClickAction)); + m_RightClickAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.RightClickAction)); + m_ScrollWheelAction = InputActionReference.Create(m_InputActionAsset.FindAction(m_Cfg.ScrollWheelAction)); + + if (m_PointAction.action != null) + m_PointAction.action.performed += OnPointerPerformed; + + if (m_SubmitAction.action != null) + m_SubmitAction.action.performed += OnSubmitPerformed; + + if (m_CancelAction.action != null) + m_CancelAction.action.performed += OnCancelPerformed; + + if (m_LeftClickAction.action != null) + m_LeftClickAction.action.performed += OnLeftClickPerformed; + + if (m_MiddleClickAction.action != null) + m_MiddleClickAction.action.performed += OnMiddleClickPerformed; + + if (m_RightClickAction.action != null) + m_RightClickAction.action.performed += OnRightClickPerformed; + + if (m_ScrollWheelAction.action != null) + m_ScrollWheelAction.action.performed += OnScrollWheelPerformed; + + // When adding new one's don't forget to add them to UnregisterActions + + m_InputActionAsset.Enable(); + + // TODO make it configurable as it is not part of default config + // The Next/Previous action is not part of the input actions asset + RegisterNextPreviousAction(); + } + + void UnregisterActions(Configuration cfg) + { + if (m_PointAction.action != null) + m_PointAction.action.performed -= OnPointerPerformed; + + if (m_SubmitAction.action != null) + m_SubmitAction.action.performed -= OnSubmitPerformed; + + if (m_CancelAction.action != null) + m_CancelAction.action.performed -= OnCancelPerformed; + + if (m_LeftClickAction.action != null) + m_LeftClickAction.action.performed -= OnLeftClickPerformed; + + if (m_MiddleClickAction.action != null) + m_MiddleClickAction.action.performed -= OnMiddleClickPerformed; + + if (m_RightClickAction.action != null) + m_RightClickAction.action.performed -= OnRightClickPerformed; + + if (m_ScrollWheelAction.action != null) + m_ScrollWheelAction.action.performed -= OnScrollWheelPerformed; + + m_PointAction = null; + m_MoveAction = null; + m_SubmitAction = null; + m_CancelAction = null; + m_LeftClickAction = null; + m_MiddleClickAction = null; + m_RightClickAction = null; + m_ScrollWheelAction = null; + + m_InputActionAsset.Disable(); + + // The Next/Previous action is not part of the input actions asset + UnregisterNextPreviousAction(); + + UnityEngine.Object.Destroy(m_InputActionAsset); // TODO check if this is ok + } + + public struct Configuration + { + public string InputActionAssetAsJson; + public string PointAction; + public string MoveAction; + public string SubmitAction; + public string CancelAction; + public string LeftClickAction; + public string MiddleClickAction; + public string RightClickAction; + public string ScrollWheelAction; + + public static Configuration GetDefaultConfiguration() + { + // TODO this is a weird way of doing that, is there an easier way? + var asset = new DefaultInputActions(); + var json = asset.asset.ToJson(); + UnityEngine.Object.DestroyImmediate(asset.asset); // TODO just Dispose doesn't work in edit mode + + return new Configuration + { + InputActionAssetAsJson = json, + PointAction = "UI/Point", + MoveAction = "UI/Navigate", + SubmitAction = "UI/Submit", + CancelAction = "UI/Cancel", + LeftClickAction = "UI/Click", + MiddleClickAction = "UI/MiddleClick", + RightClickAction = "UI/RightClick", + ScrollWheelAction = "UI/ScrollWheel", + }; + } + } + } +} +#endif // UNITY_2023_2_OR_NEWER diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs.meta new file mode 100644 index 0000000000..227d101fac --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/InputForUI/InputSystemProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6965b068653ebe45986cb10b38854d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: