using EZXR.Glass.Inputs;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
namespace UnityEngine.EventSystems
{
[AddComponentMenu("Event/Hand Input Module")]
///
/// A BaseInputModule designed for mouse / keyboard / controller input.
///
///
/// Input module for working with, mouse, keyboard, or controller.
///
public class HandInputModule : PointerInputModule
{
Button curPointerHover;
Button lastPointerHover;
public static Action OnPointerHover;
public static Action OnPointerExit;
public static Touch[] touches = new Touch[2];
//public static Dictionary handInfoPairs = new Dictionary();
private static Vector2[] inputMousePosition = new Vector2[1];
private Vector2 m_MousePosition;
private GameObject m_CurrentFocusedGameObject;
private PointerEventData m_InputPointerEvent;
public static PointerEventData eventData_Left;
public static PointerEventData eventData_Right;
protected HandInputModule()
{
}
protected override void Awake()
{
base.Awake();
touches[0].fingerId = (int)HandType.Left;
touches[1].fingerId = (int)HandType.Right;
/*
if (controllerType == ControllerType.Gestures)
{
handInfoPairs.Add(finger_left, InputSystem.leftHand);
handInfoPairs.Add(finger_right, InputSystem.rightHand);
Debug.Log("HandInputModule, Init handInfoPairs with HandInfo (use Gestures)");
}
else
{
handInfoPairs.Add(finger_left, HandleControllerManager.leftHand);
handInfoPairs.Add(finger_right, HandleControllerManager.rightHand);
Debug.Log("HandInputModule, Init handInfoPairs with HandleControllerInfo (use Handles)");
}
*/
}
private void Update()
{
GetPointerData(0, out eventData_Left, false);
GetPointerData(1, out eventData_Right, false);
Button newPointerHover = null;
if (eventData_Left != null && eventData_Left.pointerEnter != null)
{
newPointerHover = eventData_Left.pointerEnter.GetComponent();
}
if (eventData_Right != null && eventData_Right.pointerEnter != null)
{
newPointerHover = eventData_Right.pointerEnter.GetComponent();
}
if (newPointerHover != null && newPointerHover != curPointerHover)
{
if (OnPointerHover != null)
{
OnPointerHover(newPointerHover);
}
if (OnPointerExit != null)
{
OnPointerExit(curPointerHover);
}
lastPointerHover = curPointerHover;
curPointerHover = newPointerHover;
}
}
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
public enum InputMode
{
Mouse,
Buttons
}
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
public InputMode inputMode
{
get { return InputMode.Mouse; }
}
[SerializeField]
[FormerlySerializedAs("m_AllowActivationOnMobileDevice")]
private bool m_ForceModuleActive;
[Obsolete("allowActivationOnMobileDevice has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")]
public bool allowActivationOnMobileDevice
{
get { return m_ForceModuleActive; }
set { m_ForceModuleActive = value; }
}
///
/// Force this module to be active.
///
///
/// If there is no module active with higher priority (ordered in the inspector) this module will be forced active even if valid enabling conditions are not met.
///
public bool forceModuleActive
{
get { return m_ForceModuleActive; }
set { m_ForceModuleActive = value; }
}
private bool m_shouldActivate;
public bool shouldActivate
{
get { return m_shouldActivate; }
set { m_shouldActivate = value; }
}
private bool ShouldIgnoreEventsOnNoFocus()
{
switch (SystemInfo.operatingSystemFamily)
{
case OperatingSystemFamily.Windows:
case OperatingSystemFamily.Linux:
case OperatingSystemFamily.MacOSX:
#if UNITY_EDITOR
if (UnityEditor.EditorApplication.isRemoteConnected)
return false;
#endif
return true;
default:
return false;
}
}
public override void UpdateModule()
{
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
{
if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
{
ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject);
}
m_InputPointerEvent = null;
return;
}
m_MousePosition = inputMousePosition[0];
}
private void ReleaseMouse(PointerEventData pointerEvent, GameObject currentOverGo)
{
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
var pointerUpHandler = ExecuteEvents.GetEventHandler(currentOverGo);
// PointerClick and Drop events
if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
{
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
}
else if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
{
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
}
pointerEvent.eligibleForClick = false;
pointerEvent.pointerPress = null;
pointerEvent.rawPointerPress = null;
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
pointerEvent.dragging = false;
pointerEvent.pointerDrag = null;
// redo pointer enter / exit to refresh state
// so that if we moused over something that ignored it before
// due to having pressed on something else
// it now gets it.
if (currentOverGo != pointerEvent.pointerEnter)
{
HandlePointerExitAndEnter(pointerEvent, null);
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
}
m_InputPointerEvent = pointerEvent;
}
public override bool IsModuleSupported()
{
return true /*|| input.mousePresent || input.touchSupported*/;
}
public override bool ShouldActivateModule()
{
if (!base.ShouldActivateModule())
return false;
var shouldActivate = m_ForceModuleActive;
//shouldActivate |= input.GetButtonDown(m_SubmitButton);
//shouldActivate |= input.GetButtonDown(m_CancelButton);
//shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_HorizontalAxis), 0.0f);
//shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_VerticalAxis), 0.0f);
//shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
//shouldActivate |= input.GetMouseButtonDown(0);
//if (input.touchCount > 0)
// shouldActivate = true;
//return shouldActivate;
return m_shouldActivate;
}
///
/// See BaseInputModule.
///
public override void ActivateModule()
{
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
return;
base.ActivateModule();
m_MousePosition = inputMousePosition[0];
var toSelect = eventSystem.currentSelectedGameObject;
if (toSelect == null)
toSelect = eventSystem.firstSelectedGameObject;
eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData());
}
///
/// See BaseInputModule.
///
public override void DeactivateModule()
{
base.DeactivateModule();
ClearSelection();
}
public override void Process()
{
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
return;
//>>>>>>>>>>>!!!!!!!!! //if (!ProcessTouchEvents() && input.mousePresent)
//ProcessMouseEvent(0);
ProcessTouchEvents();
}
private bool ProcessTouchEvents()
{
for (int i = 0; i < touches.Length; ++i)
{
Touch touch = touches[i];
if (touch.type == TouchType.Indirect)
continue;
bool released;
bool pressed;
var pointer = GetHandPointerTouchEventData(touch, out pressed, out released);
ProcessTouchPress(pointer, pressed, released, touch.fingerId == 0 ? EZXR.Glass.Inputs.InputSystem.leftHand : EZXR.Glass.Inputs.InputSystem.rightHand);
if (!released)
{
ProcessMove(pointer);
ProcessDrag(pointer);
}
else
RemovePointerData(pointer);
}
return touches.Length > 0;
}
PointerEventData GetHandPointerTouchEventData(Touch input, out bool pressed, out bool released)
{
PointerEventData pointerData;
var created = GetPointerData(input.fingerId, out pointerData, true);
pointerData.Reset();
var handInfo = input.fingerId == (int)HandType.Left ? EZXR.Glass.Inputs.InputSystem.leftHand : EZXR.Glass.Inputs.InputSystem.rightHand;
if (handInfo != null)
{
pressed = handInfo.startPinch;
released = handInfo.endPinch;
}
else
{
pressed = false;
released = false;
}
//pressed = (input.fingerId == (int)HandType.Left ? ControllerManager.leftHand : ControllerManager.rightHand).startPinch;
//released = (input.fingerId == (int)HandType.Left ? ControllerManager.leftHand : ControllerManager.rightHand).endPinch;
if (created)
pointerData.position = input.position;
if (pressed)
pointerData.delta = Vector2.zero;
else
pointerData.delta = input.position - pointerData.position;
pointerData.position = input.position;
pointerData.button = PointerEventData.InputButton.Left;
if (input.phase == TouchPhase.Canceled)
{
pointerData.pointerCurrentRaycast = new RaycastResult();
}
else
{
eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
var raycast = FindFirstRaycast(m_RaycastResultCache);
pointerData.pointerCurrentRaycast = raycast;
//if (raycast.gameObject != null)
// Debug.Log($"HandControllerSession, Raycast = {raycast.gameObject.name}, screenPosition = ({pointerData.position.x}, {pointerData.position.y})");
m_RaycastResultCache.Clear();
}
return pointerData;
}
///
/// This method is called by Unity whenever a touch event is processed. Override this method with a custom implementation to process touch events yourself.
///
/// Event data relating to the touch event, such as position and ID to be passed to the touch event destination object.
/// This is true for the first frame of a touch event, and false thereafter. This can therefore be used to determine the instant a touch event occurred.
/// This is true only for the last frame of a touch event.
///
/// This method can be overridden in derived classes to change how touch press events are handled.
///
protected void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released, InputInfoBase inputInfo)
{
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
// PointerDown notification
if (pressed)
{
pointerEvent.eligibleForClick = true;
pointerEvent.delta = Vector2.zero;
pointerEvent.dragging = false;
pointerEvent.useDragThreshold = true;
pointerEvent.pressPosition = pointerEvent.position;
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
if (pointerEvent.pointerEnter != currentOverGo)
{
// send a pointer enter to the touched element if it isn't the one to select...
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
pointerEvent.pointerEnter = currentOverGo;
}
// search for the control that will receive the press
// if we can't find a press handler set the press
// handler to be what would receive a click.
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
// didnt find a press handler... search for a click handler
if (newPressed == null)
newPressed = ExecuteEvents.GetEventHandler(currentOverGo);
// Debug.Log("Pressed: " + newPressed);
float time = Time.unscaledTime;
if (newPressed == pointerEvent.lastPress)
{
var diffTime = time - pointerEvent.clickTime;
if (diffTime < 0.3f)
++pointerEvent.clickCount;
else
pointerEvent.clickCount = 1;
pointerEvent.clickTime = time;
}
else
{
pointerEvent.clickCount = 1;
}
pointerEvent.pointerPress = newPressed;
pointerEvent.rawPointerPress = currentOverGo;
pointerEvent.clickTime = time;
// Save the drag handler as well
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler(currentOverGo);
if (pointerEvent.pointerDrag != null)
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
m_InputPointerEvent = pointerEvent;
}
// PointerUp notification
if (released)
{
#if SYSTEMUI
#region 在松开手指的时候向当前指向的物体发送press事件
if (inputInfo.isPalmFacingHead())
{
// search for the control that will receive the press
// if we can't find a press handler set the press
// handler to be what would receive a click.
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
// didnt find a press handler... search for a click handler
if (newPressed == null)
newPressed = ExecuteEvents.GetEventHandler(currentOverGo);
pointerEvent.pointerPress = newPressed;
pointerEvent.rawPointerPress = currentOverGo;
}
#endregion
#endif
// Debug.Log("Executing pressup on: " + pointer.pointerPress);
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
// Debug.Log("KeyCode: " + pointer.eventData.keyCode);
// see if we mouse up on the same element that we clicked on...
var pointerUpHandler = ExecuteEvents.GetEventHandler(currentOverGo);
#if SYSTEMUI
pointerEvent.pointerPress = pointerUpHandler;
#endif
// PointerClick and Drop events
if (/*pointerEvent.pointerPress == pointerUpHandler &&*/ pointerEvent.eligibleForClick)
{
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
}
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
{
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
}
pointerEvent.eligibleForClick = false;
pointerEvent.pointerPress = null;
pointerEvent.rawPointerPress = null;
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
pointerEvent.dragging = false;
pointerEvent.pointerDrag = null;
// send exit events as we need to simulate this on touch up on touch device
ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler);
pointerEvent.pointerEnter = null;
m_InputPointerEvent = pointerEvent;
}
}
///
/// Process all mouse events.
///
protected void ProcessMouseEvent(int id)
{
var mouseData = GetHandMousePointerEventData(id);
var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;
// Process the first mouse button fully
ProcessMousePress(leftButtonData);
ProcessMove(leftButtonData.buttonData);
ProcessDrag(leftButtonData.buttonData);
//// Now process right / middle clicks
//ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
//ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
//ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
//ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
}
protected override void ProcessMove(PointerEventData pointerEvent)
{
var targetGO = pointerEvent.pointerCurrentRaycast.gameObject;
HandlePointerExitAndEnter(pointerEvent, targetGO);
}
///
/// Return the current MouseState.
///
protected virtual MouseState GetHandMousePointerEventData(int id)
{
// Populate the left button...
PointerEventData leftData;
var created = GetPointerData(kMouseLeftId, out leftData, true);
leftData.Reset();
if (created)
leftData.position = inputMousePosition[0];
Vector2 pos = inputMousePosition[0];
leftData.delta = pos - leftData.position;
//Debug.Log(pos.ToString("#.####") + "�� " + leftData.position.ToString("#.####") + ", " + leftData.delta.y);
leftData.position = pos;
leftData.scrollDelta = Vector2.zero;// input.mouseScrollDelta;
leftData.button = PointerEventData.InputButton.Left;
eventSystem.RaycastAll(leftData, m_RaycastResultCache);
var raycast = FindFirstRaycast(m_RaycastResultCache);
leftData.pointerCurrentRaycast = raycast;
m_RaycastResultCache.Clear();
//// copy the apropriate data into right and middle slots
//PointerEventData rightData;
//GetPointerData(kMouseRightId, out rightData, true);
//CopyFromTo(leftData, rightData);
//rightData.button = PointerEventData.InputButton.Right;
//PointerEventData middleData;
//GetPointerData(kMouseMiddleId, out middleData, true);
//CopyFromTo(leftData, middleData);
//middleData.button = PointerEventData.InputButton.Middle;
MouseState m_MouseState = new MouseState();
m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForHandMouseButton(0), leftData);
//m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
//m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);
return m_MouseState;
}
///
/// Given a mouse button return the current state for the frame.
///
/// Mouse button ID
protected PointerEventData.FramePressState StateForHandMouseButton(int buttonId)
{
//#if UNITY_EDITOR
// var pressed = input.GetMouseButtonDown(buttonId);
// var released = input.GetMouseButtonUp(buttonId);
//#else
bool pressed = /*EZXR.Glass.Inputs.InputSystem.leftHand.startPinch || */EZXR.Glass.Inputs.InputSystem.leftHand.startPinch;
bool released = /*EZXR.Glass.Inputs.InputSystem.leftHand.endPinch || */EZXR.Glass.Inputs.InputSystem.leftHand.endPinch;
//#endif
if (pressed && released)
return PointerEventData.FramePressState.PressedAndReleased;
if (pressed)
return PointerEventData.FramePressState.Pressed;
if (released)
return PointerEventData.FramePressState.Released;
return PointerEventData.FramePressState.NotChanged;
}
///
/// Calculate and process any mouse button state changes.
///
protected void ProcessMousePress(MouseButtonEventData data)
{
var pointerEvent = data.buttonData;
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
// PointerDown notification
if (data.PressedThisFrame())
{
//Debug.Log("data.PressedThisFrame");
pointerEvent.eligibleForClick = true;
pointerEvent.delta = Vector2.zero;
pointerEvent.dragging = false;
pointerEvent.useDragThreshold = true;
pointerEvent.pressPosition = pointerEvent.position;
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
// search for the control that will receive the press
// if we can't find a press handler set the press
// handler to be what would receive a click.
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
// didnt find a press handler... search for a click handler
if (newPressed == null)
newPressed = ExecuteEvents.GetEventHandler(currentOverGo);
// Debug.Log("Pressed: " + newPressed);
float time = Time.unscaledTime;
if (newPressed == pointerEvent.lastPress)
{
var diffTime = time - pointerEvent.clickTime;
if (diffTime < 0.3f)
++pointerEvent.clickCount;
else
pointerEvent.clickCount = 1;
pointerEvent.clickTime = time;
}
else
{
pointerEvent.clickCount = 1;
}
pointerEvent.pointerPress = newPressed;
pointerEvent.rawPointerPress = currentOverGo;
pointerEvent.clickTime = time;
// Save the drag handler as well
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler(currentOverGo);
if (pointerEvent.pointerDrag != null)
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
m_InputPointerEvent = pointerEvent;
}
// PointerUp notification
if (data.ReleasedThisFrame())
{
ReleaseMouse(pointerEvent, currentOverGo);
}
}
protected GameObject GetCurrentFocusedGameObject()
{
return m_CurrentFocusedGameObject;
}
}
}