#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX #define ZF_OSX #endif using System; using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.EventSystems; using UnityEngine.UI; namespace ZenFulcrum.EmbeddedBrowser { /** * This class will handle input to a browser based on the mouse position and a mesh collider on the browser. * Mouse positions are looked up according to the UVs on the *collider* mesh. Generally, you will want to use * the same or a visually similar (including UVs) mesh for the renderer. */ [Obsolete("Use PointerUIMesh instead.")] public class ClickMeshBrowserUI : MonoBehaviour, IBrowserUI { /** * Creates a new UI handler. * We will attach to {parent}, which must have the mesh we are interacting with. * In most cases, this will also be the same object that has the Browser we will be fed to. (a la browser.UIHandler) */ public static ClickMeshBrowserUI Create(MeshCollider meshCollider) { var ui = meshCollider.gameObject.AddComponent(); ui.meshCollider = meshCollider; return ui; } public void Awake() { BrowserCursor = new BrowserCursor(); BrowserCursor.cursorChange += CursorUpdated; InputSettings = new BrowserInputSettings(); } protected MeshCollider meshCollider; /** * How far can we reach to touch a browser? * * HideInInspector: * Showing it in the inspector would imply that changing the value would be used, but in most practical cases * with FPSBrowserUI, the value will be overridden by the FPSCursorRenderer. */ [HideInInspector] public float maxDistance = float.PositiveInfinity; /** Fills up with key events as they happen. */ protected List keyEvents = new List(); /** Swaps with keyEvents on InputUpdate and is returned in the main getter. */ protected List keyEventsLast = new List(); /** Returns the user's interacting ray, usually the mouse pointer in some form. */ protected virtual Ray LookRay { get { return Camera.main.ScreenPointToRay(Input.mousePosition); } } /** List of keys Unity won't give us events for. So we have to poll. */ static readonly KeyCode[] keysToCheck = { #if ZF_OSX //On windows you get GUI events for ctrl, super, alt. On mac...you don't! KeyCode.LeftCommand, KeyCode.RightCommand, KeyCode.LeftControl, KeyCode.RightControl, KeyCode.LeftAlt, KeyCode.RightAlt, //KeyCode.CapsLock, unity refuses to inform us of this, so there's not much we can do #endif //Unity consistently doesn't send events for shift across all platforms. KeyCode.LeftShift, KeyCode.RightShift, }; public virtual void InputUpdate() { //Note: keyEvents gets filled in OnGUI as things happen. InputUpdate get called just before it's read. //To get the right events to the right place at the right time, swap the "double buffer" of key events. var tmp = keyEvents; keyEvents = keyEventsLast; keyEventsLast = tmp; keyEvents.Clear(); //Trace mouse from the main camera var mouseRay = LookRay; RaycastHit hit; Physics.Raycast(mouseRay, out hit, maxDistance); if (hit.transform != meshCollider.transform) { //not looking at it. MousePosition = new Vector3(0, 0); MouseButtons = 0; MouseScroll = new Vector2(0, 0); MouseHasFocus = false; KeyboardHasFocus = false; LookOff(); return; } LookOn(); MouseHasFocus = true; KeyboardHasFocus = true; //convert ray hit to useful mouse position on page var localPoint = hit.textureCoord; MousePosition = localPoint; var buttons = (MouseButton)0; if (Input.GetMouseButton(0)) buttons |= MouseButton.Left; if (Input.GetMouseButton(1)) buttons |= MouseButton.Right; if (Input.GetMouseButton(2)) buttons |= MouseButton.Middle; MouseButtons = buttons; MouseScroll = Input.mouseScrollDelta; //Unity doesn't include events for some keys, so fake it by checking each frame. for (int i = 0; i < keysToCheck.Length; i++) { if (Input.GetKeyDown(keysToCheck[i])) { //Prepend down, postpend up. We don't know which happened first, but pressing //modifiers usually precedes other key presses and releasing tends to follow. keyEventsLast.Insert(0, new Event() {type = EventType.KeyDown, keyCode = keysToCheck[i]}); } else if (Input.GetKeyUp(keysToCheck[i])) { keyEventsLast.Add(new Event() {type = EventType.KeyUp, keyCode = keysToCheck[i]}); } } } public void OnGUI() { var ev = Event.current; if (ev.type != EventType.KeyDown && ev.type != EventType.KeyUp) return; // if (ev.character != 0) Debug.Log("ev >>> " + ev.character); // else if (ev.type == EventType.KeyUp) Debug.Log("ev ^^^ " + ev.keyCode); // else if (ev.type == EventType.KeyDown) Debug.Log("ev vvv " + ev.keyCode); keyEvents.Add(new Event(ev)); } protected bool mouseWasOver = false; protected void LookOn() { if (BrowserCursor != null) { CursorUpdated(); } mouseWasOver = true; } protected void LookOff() { if (BrowserCursor != null && mouseWasOver) { SetCursor(null); } mouseWasOver = false; } protected void CursorUpdated() { SetCursor(BrowserCursor); } /** * Sets the current mouse cursor. * If the cursor is null we are not looking at this browser. * * This base implementation changes the mouse cursor, but you could change an in-game reticle, etc. */ protected virtual void SetCursor(BrowserCursor newCursor) { //note that HandleKeyInputBrowserCursor can change while we don't have focus. //In such a case, don't do anything if (!MouseHasFocus && newCursor != null) return; if (newCursor == null) { Cursor.visible = true; Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto); } else { if (newCursor.Texture != null) { Cursor.visible = true; Cursor.SetCursor(newCursor.Texture, newCursor.Hotspot, CursorMode.Auto); } else { Cursor.visible = false; Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto); } } } public bool MouseHasFocus { get; protected set; } public Vector2 MousePosition { get; protected set; } public MouseButton MouseButtons { get; protected set; } public Vector2 MouseScroll { get; protected set; } public bool KeyboardHasFocus { get; protected set; } public List KeyEvents { get { return keyEventsLast; } } public BrowserCursor BrowserCursor { get; protected set; } public BrowserInputSettings InputSettings { get; protected set; } } }