-
-
Save Urethramancer/65cb7e16a489fdd11c01 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Replacement module for Standalone Input Module | |
// Up to date for Unity 4.6 beta 19 | |
// | |
// Usage: | |
// -Remove the standalone module from your event system | |
// -Add this instead | |
// -Include ExtraMouseEvents.cs and IExtraMouseEventsHandler.cs | |
// -Implement IRightPointerClickHandler, IRightPointerDownHandler, IRightPointerUpHandler, IMiddlePointerClickHandler, | |
// IMiddlePointerDownHandler and/or IMiddlePointerUpHandler. | |
// | |
// Example right-click script: | |
// using UnityEngine; | |
// using UnityEngine.EventSystems; | |
// | |
// public class ButtonDelegates : MonoBehaviour, IRightPointerClickHandler | |
// { | |
// public void OnRightPointerClick(PointerEventData data) | |
// { | |
// Debug.Log("Right-click"); | |
// } | |
// } | |
namespace UnityEngine.EventSystems | |
{ | |
[AddComponentMenu("Event/Mouse Input Module")] | |
public class MouseInputModule : PointerInputModule | |
{ | |
enum MouseButtons | |
{ | |
Left = 0, | |
Right, | |
Middle | |
}; | |
private float m_NextAction; | |
private InputMode m_CurrentInputMode = InputMode.Buttons; | |
private Vector2 m_LastMousePosition; | |
private Vector2 m_MousePosition; | |
protected MouseInputModule() | |
{} | |
private enum InputMode | |
{ | |
Mouse, | |
Buttons | |
} | |
[SerializeField] | |
private string m_HorizontalAxis = "Horizontal"; | |
/// <summary> | |
/// Name of the vertical axis for movement (if axis events are used). | |
/// </summary> | |
[SerializeField] | |
private string m_VerticalAxis = "Vertical"; | |
/// <summary> | |
/// Name of the submit button. | |
/// </summary> | |
[SerializeField] | |
private string m_SubmitButton = "Submit"; | |
/// <summary> | |
/// Name of the submit button. | |
/// </summary> | |
[SerializeField] | |
private string m_CancelButton = "Cancel"; | |
[SerializeField] | |
private float m_InputActionsPerSecond = 10; | |
[SerializeField] | |
private bool _allowRMBDrag; | |
public bool allowRMBDrag | |
{ | |
get {return _allowRMBDrag;} | |
set {_allowRMBDrag = value;} | |
} | |
[SerializeField] | |
private bool _allowMMBDrag; | |
public bool allowMMBDrag | |
{ | |
get {return _allowMMBDrag;} | |
set {_allowMMBDrag = value;} | |
} | |
[SerializeField] | |
private bool m_AllowActivationOnMobileDevice; | |
public bool allowActivationOnMobileDevice | |
{ | |
get { return m_AllowActivationOnMobileDevice; } | |
set { m_AllowActivationOnMobileDevice = value; } | |
} | |
public float inputActionsPerSecond | |
{ | |
get { return m_InputActionsPerSecond; } | |
set { m_InputActionsPerSecond = value; } | |
} | |
/// <summary> | |
/// Name of the horizontal axis for movement (if axis events are used). | |
/// </summary> | |
public string horizontalAxis | |
{ | |
get { return m_HorizontalAxis; } | |
set { m_HorizontalAxis = value; } | |
} | |
/// <summary> | |
/// Name of the vertical axis for movement (if axis events are used). | |
/// </summary> | |
public string verticalAxis | |
{ | |
get { return m_VerticalAxis; } | |
set { m_VerticalAxis = value; } | |
} | |
public string submitButton | |
{ | |
get { return m_SubmitButton; } | |
set { m_SubmitButton = value; } | |
} | |
public string cancelButton | |
{ | |
get { return m_CancelButton; } | |
set { m_CancelButton = value; } | |
} | |
public override void UpdateModule() | |
{ | |
m_LastMousePosition = m_MousePosition; | |
m_MousePosition = Input.mousePosition; | |
} | |
public override bool IsModuleSupported() | |
{ | |
return m_AllowActivationOnMobileDevice || !Application.isMobilePlatform; | |
} | |
public override bool ShouldActivateModule() | |
{ | |
if (!base.ShouldActivateModule ()) | |
return false; | |
var shouldActivate = Input.GetButtonDown (m_SubmitButton); | |
shouldActivate |= Input.GetButtonDown (m_CancelButton); | |
shouldActivate |= !Mathf.Approximately (Input.GetAxis (m_HorizontalAxis), 0.0f); | |
shouldActivate |= !Mathf.Approximately (Input.GetAxis (m_VerticalAxis), 0.0f); | |
shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f; | |
shouldActivate |= Input.GetMouseButtonDown (0); | |
return shouldActivate; | |
} | |
public override void ActivateModule() | |
{ | |
base.ActivateModule (); | |
m_MousePosition = Input.mousePosition; | |
m_LastMousePosition = Input.mousePosition; | |
var toSelect = eventSystem.currentSelectedGameObject; | |
if (toSelect == null) | |
toSelect = eventSystem.lastSelectedGameObject; | |
if (toSelect == null) | |
toSelect = eventSystem.firstSelectedGameObject; | |
eventSystem.SetSelectedGameObject (null, GetBaseEventData ()); | |
eventSystem.SetSelectedGameObject (toSelect, GetBaseEventData ()); | |
} | |
public override void DeactivateModule() | |
{ | |
base.DeactivateModule (); | |
ClearSelection (); | |
} | |
public override void Process() | |
{ | |
bool usedEvent = SendUpdateEventToSelectedObject (); | |
if (!usedEvent) | |
usedEvent |= SendMoveEventToSelectedObject (); | |
if (!usedEvent) | |
SendSubmitEventToSelectedObject (); | |
ProcessMouseEvent (); | |
} | |
/// <summary> | |
/// Process submit keys. | |
/// </summary> | |
private bool SendSubmitEventToSelectedObject() | |
{ | |
if (eventSystem.currentSelectedGameObject == null || m_CurrentInputMode != InputMode.Buttons) | |
return false; | |
var data = GetBaseEventData (); | |
if (Input.GetButtonDown (m_SubmitButton)) | |
ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler); | |
if (Input.GetButtonDown (m_CancelButton)) | |
ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); | |
return data.used; | |
} | |
private bool AllowMoveEventProcessing(float time) | |
{ | |
bool allow = Input.GetButtonDown (m_HorizontalAxis); | |
allow |= Input.GetButtonDown (m_VerticalAxis); | |
allow |= (time > m_NextAction); | |
return allow; | |
} | |
private Vector2 GetRawMoveVector() | |
{ | |
Vector2 move = Vector2.zero; | |
move.x = Input.GetAxis (m_HorizontalAxis); | |
move.y = Input.GetAxis (m_VerticalAxis); | |
if (Input.GetButtonDown (m_HorizontalAxis)) | |
{ | |
if (move.x < 0) | |
move.x = -1f; | |
if (move.x > 0) | |
move.x = 1f; | |
} | |
if (Input.GetButtonDown (m_VerticalAxis)) | |
{ | |
if (move.y < 0) | |
move.y = -1f; | |
if (move.y > 0) | |
move.y = 1f; | |
} | |
return move; | |
} | |
/// <summary> | |
/// Process keyboard events. | |
/// </summary> | |
private bool SendMoveEventToSelectedObject() | |
{ | |
float time = Time.unscaledTime; | |
if (!AllowMoveEventProcessing (time)) | |
return false; | |
Vector2 movement = GetRawMoveVector (); | |
//Debug.Log(m_ProcessingEvent.rawType + " axis:" + m_AllowAxisEvents + " value:" + "(" + x + "," + y + ")"); | |
var axisEventData = GetAxisEventData (movement.x, movement.y, 0.6f); | |
if (!Mathf.Approximately (axisEventData.moveVector.x, 0f) | |
|| !Mathf.Approximately (axisEventData.moveVector.y, 0f)) | |
{ | |
if (m_CurrentInputMode != InputMode.Buttons) | |
{ | |
// so if we are chaning to keyboard | |
m_CurrentInputMode = InputMode.Buttons; | |
// if we are doing a 'fresh selection' | |
// return as we don't want to do a move. | |
if (ResetSelection ()) | |
{ | |
m_NextAction = time + 1f / m_InputActionsPerSecond; | |
return true; | |
} | |
} | |
ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler); | |
} | |
m_NextAction = time + 1f / m_InputActionsPerSecond; | |
return axisEventData.used; | |
} | |
private bool ResetSelection() | |
{ | |
var baseEventData = GetBaseEventData (); | |
// clear all selection | |
// & figure out what the mouse is over | |
var lastMousePointer = GetLastPointerEventData (kMouseId); | |
var hoveredObject = lastMousePointer == null ? null : lastMousePointer.pointerEnter; | |
HandlePointerExitAndEnter (lastMousePointer, null); | |
eventSystem.SetSelectedGameObject (null, baseEventData); | |
// if we were hovering something... | |
// use this as the basis for the selection | |
bool resetSelection = false; | |
GameObject toSelect = ExecuteEvents.GetEventHandler<ISelectHandler> (hoveredObject); | |
if (toSelect == null) | |
{ | |
// if there was no hover | |
// then use the last selected | |
toSelect = eventSystem.lastSelectedGameObject; | |
resetSelection = true; | |
} | |
eventSystem.SetSelectedGameObject (toSelect, baseEventData); | |
return resetSelection; | |
} | |
/// <summary> | |
/// Process all mouse events. | |
/// </summary> | |
private void ProcessMouseEvent() | |
{ | |
bool leftPressed = Input.GetMouseButtonDown(0); | |
bool leftReleased = Input.GetMouseButtonUp(0); | |
bool rightPressed = Input.GetMouseButtonDown(1); | |
bool rightReleased = Input.GetMouseButtonUp(1); | |
bool middlePressed = Input.GetMouseButtonDown(2); | |
bool middleReleased = Input.GetMouseButtonUp(2); | |
var pointerData = GetMousePointerEventData(); | |
// Take care of the scroll wheel | |
float scroll = Input.GetAxis ("Mouse ScrollWheel"); | |
pointerData.scrollDelta.x = 0f; | |
pointerData.scrollDelta.y = scroll; | |
bool useLeft = UseMouse (leftPressed, leftReleased, pointerData); | |
bool useRight = UseMouse (rightPressed, rightReleased, pointerData); | |
bool useMiddle = UseMouse (middlePressed, middleReleased, pointerData); | |
bool mouse = useLeft | useRight | useMiddle; | |
if (!mouse) return; | |
// Process the mouse buttons fully | |
if(useLeft) ProcessMousePress(pointerData, leftPressed, leftReleased, MouseButtons.Left); | |
if(useRight) ProcessMousePress(pointerData, rightPressed, rightReleased, MouseButtons.Right); | |
if(useMiddle) ProcessMousePress(pointerData, middlePressed, middleReleased, MouseButtons.Middle); | |
ProcessMove(pointerData); | |
if (!Mathf.Approximately(scroll, 0.0f)) | |
{ | |
var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(pointerData.pointerCurrentRaycast.go); | |
ExecuteEvents.ExecuteHierarchy(scrollHandler, pointerData, ExecuteEvents.scrollHandler); | |
} | |
} | |
protected override void ProcessMove(PointerEventData pointerEvent) | |
{ | |
base.ProcessMove (pointerEvent); | |
var targetGO = pointerEvent.pointerCurrentRaycast.go; | |
HandlePointerExitAndEnter (pointerEvent, targetGO); | |
} | |
private bool UseMouse(bool pressed, bool released, PointerEventData pointerData) | |
{ | |
if (m_CurrentInputMode == InputMode.Mouse) return true; | |
// On mouse action switch back to mouse control scheme | |
if (pressed || released || pointerData.IsPointerMoving() || pointerData.IsScrolling()) | |
{ | |
m_CurrentInputMode = InputMode.Mouse; | |
eventSystem.SetSelectedGameObject(null, pointerData); | |
} | |
return m_CurrentInputMode == InputMode.Mouse; | |
} | |
private bool SendUpdateEventToSelectedObject() | |
{ | |
if (eventSystem.currentSelectedGameObject == null) | |
return false; | |
var data = GetBaseEventData (); | |
ExecuteEvents.Execute (eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler); | |
return data.used; | |
} | |
/// <summary> | |
/// Process the current mouse press. | |
/// </summary> | |
private void ProcessMousePress(PointerEventData pointerEvent, bool pressed, bool released, MouseButtons button) | |
{ | |
var currentOverGo = pointerEvent.pointerCurrentRaycast.go; | |
// Limit drag events to allowed buttons | |
bool allowDrag = true; | |
switch(button) | |
{ | |
// We skip LMB, because we're just looking for exceptions | |
case MouseButtons.Right: | |
allowDrag = allowRMBDrag; | |
break; | |
case MouseButtons.Middle: | |
allowDrag = allowMMBDrag; | |
break; | |
} | |
// PointerDown notification | |
if(pressed) | |
{ | |
pointerEvent.eligibleForClick = true; | |
pointerEvent.delta = Vector2.zero; | |
pointerEvent.pressPosition = pointerEvent.position; | |
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast; | |
// Search for the relevant handler on the control to receive a press, | |
// based on which button was pressed | |
GameObject newPressed = null; | |
switch(button) | |
{ | |
case MouseButtons.Left: | |
newPressed = ExecuteEvents.ExecuteHierarchy (currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler); | |
// Didn't find a press handler - search for a click handler | |
if(newPressed == null) newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); | |
break; | |
case MouseButtons.Right: | |
newPressed = ExecuteEvents.ExecuteHierarchy (currentOverGo, pointerEvent, ExtraMouseEvents.rightDownHandler); | |
// Didn't find a press handler - search for a click handler | |
if(newPressed == null) newPressed = ExecuteEvents.GetEventHandler<IRightPointerClickHandler>(currentOverGo); | |
break; | |
case MouseButtons.Middle: | |
newPressed = ExecuteEvents.ExecuteHierarchy (currentOverGo, pointerEvent, ExtraMouseEvents.middleDownHandler); | |
// Didn't find a press handler - search for a click handler | |
if(newPressed == null) newPressed = ExecuteEvents.GetEventHandler<IMiddlePointerClickHandler>(currentOverGo); | |
break; | |
} | |
if (newPressed != pointerEvent.pointerPress) | |
{ | |
pointerEvent.pointerPress = newPressed; | |
pointerEvent.rawPointerPress = currentOverGo; | |
pointerEvent.clickCount = 0; | |
} | |
// Save the drag handler as well | |
if(allowDrag) | |
{ | |
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo); | |
if(pointerEvent.pointerDrag != null) ExecuteEvents.Execute (pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler); | |
} | |
// Selection tracking | |
var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo); | |
eventSystem.SetSelectedGameObject (selectHandlerGO, pointerEvent); | |
} | |
// PointerUp notification | |
if(released) | |
{ | |
GameObject pointerUpHandler = null; | |
switch(button) | |
{ | |
case MouseButtons.Left: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); | |
// see if we mouse up on the same element that we clicked on... | |
pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); | |
break; | |
case MouseButtons.Right: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExtraMouseEvents.rightUpHandler); | |
// see if we mouse up on the same element that we clicked on... | |
pointerUpHandler = ExecuteEvents.GetEventHandler<IRightPointerClickHandler>(currentOverGo); | |
break; | |
case MouseButtons.Middle: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExtraMouseEvents.middleUpHandler); | |
// see if we mouse up on the same element that we clicked on... | |
pointerUpHandler = ExecuteEvents.GetEventHandler<IMiddlePointerClickHandler>(currentOverGo); | |
break; | |
} | |
// PointerClick and Drop events | |
if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick) | |
{ | |
float time = Time.unscaledTime; | |
if (time - pointerEvent.clickTime < 0.3f) | |
++pointerEvent.clickCount; | |
else | |
pointerEvent.clickCount = 1; | |
pointerEvent.clickTime = time; | |
switch(button) | |
{ | |
case MouseButtons.Left: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler); | |
break; | |
case MouseButtons.Right: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExtraMouseEvents.rightClickHandler); | |
break; | |
case MouseButtons.Middle: | |
ExecuteEvents.Execute (pointerEvent.pointerPress, pointerEvent, ExtraMouseEvents.middleClickHandler); | |
break; | |
} | |
} | |
else if(pointerEvent.pointerDrag != null && allowDrag) | |
{ | |
ExecuteEvents.ExecuteHierarchy (currentOverGo, pointerEvent, ExecuteEvents.dropHandler); | |
} | |
pointerEvent.eligibleForClick = false; | |
pointerEvent.pointerPress = null; | |
pointerEvent.rawPointerPress = null; | |
if (pointerEvent.pointerDrag != null && allowDrag) ExecuteEvents.Execute (pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler); | |
pointerEvent.pointerDrag = null; | |
// redo pointer enter / exit to refresh state | |
// so that if we moused over somethign that ignored it before | |
// due to having pressed on something else | |
// it now gets it. | |
HandlePointerExitAndEnter(pointerEvent, null); | |
HandlePointerExitAndEnter(pointerEvent, currentOverGo); | |
} | |
} | |
} | |
} |
I've updated the source for beta 19 and included some brief instructions.
Remember to include https://gist.github.com/Urethramancer/77a2df0658373d81aa5c and https://gist.github.com/Urethramancer/a35bdbdd7de030f6f487 to make it all work.
Broken again (and not necessary!) in beta 20.
I've encountered this page somewhat randomly (I want to implement my own InputModule as well, so thanks for the example).
In your comments you don't say what advantage your implementation gives, why should anyone use it over the standard MouseInputModule?
This WAS useful before the main version had full support for all buttons. Now it's probably not of interest to anyone but archaeologists.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I tried this but it does not seem to be picking up my right and middle clicks. Are there some other settings I need to change?