PopUpBrowser.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. namespace ZenFulcrum.EmbeddedBrowser {
  7. /// <summary>
  8. /// Manages a browser that's been opened in an OS-native window outside the game's main window.
  9. /// (Presently only used for OS X.)
  10. /// </summary>
  11. public class PopUpBrowser : MonoBehaviour, IBrowserUI {
  12. private int windowId;
  13. private int browserId;
  14. private List<string> messages = new List<string>();
  15. private Browser browser;
  16. private BrowserNative.WindowCallbackFunc callbackRef;//don't let this get GC'd
  17. private Vector2 delayedResize;
  18. public static void Create(int possibleBrowserId) {
  19. var go = new GameObject("Pop up browser");
  20. var browser = go.AddComponent<Browser>();
  21. browser.RequestNativeBrowser(possibleBrowserId);
  22. var pop = go.AddComponent<PopUpBrowser>();
  23. pop.callbackRef = pop.HandleWindowMessage;
  24. pop.windowId = BrowserNative.zfb_windowCreate("", pop.callbackRef);
  25. pop.browserId = possibleBrowserId;
  26. pop.BrowserCursor = new BrowserCursor();
  27. pop.KeyEvents = new List<Event>();
  28. pop.browser = browser;
  29. pop.StartCoroutine(pop.FixFocus());
  30. pop.InputSettings = new BrowserInputSettings();
  31. browser.UIHandler = pop;
  32. browser.EnableRendering = false;//rendering is done differently, so don't run the usual code
  33. }
  34. private void HandleWindowMessage(int windowId, IntPtr data) {
  35. var msgJSON = Util.PtrToStringUTF8(data);
  36. //if (!msgJSON.Contains("mouseMove")) Debug.Log("Window message: " + msgJSON);
  37. lock (messages) messages.Add(msgJSON);
  38. }
  39. public void OnDestroy() {
  40. if (!BrowserNative.SymbolsLoaded) return;
  41. BrowserNative.zfb_windowClose(windowId);
  42. }
  43. private IEnumerator FixFocus() {
  44. //OS X: Magically, new browser windows that are focused don't think they are focused, even though we told them so.
  45. //Hack workaround.
  46. yield return null;
  47. BrowserNative.zfb_setFocused(browserId, false);
  48. yield return null;
  49. BrowserNative.zfb_setFocused(browserId, true);
  50. yield return null;
  51. BrowserNative.zfb_setFocused(browserId, KeyboardHasFocus);
  52. }
  53. public void InputUpdate() {
  54. MouseScroll = Vector2.zero;
  55. KeyEvents.Clear();
  56. delayedResize = new Vector2(float.NaN, float.NaN);
  57. lock (messages) {
  58. for (int i = 0; i < messages.Count; i++) {
  59. HandleMessage(messages[i]);
  60. }
  61. messages.Clear();
  62. }
  63. if (!float.IsNaN(delayedResize.x)) {
  64. browser.Resize((int)delayedResize.x, (int)delayedResize.y);
  65. }
  66. }
  67. private void HandleMessage(string message) {
  68. var msg = JSONNode.Parse(message);
  69. switch ((string)msg["type"]) {
  70. case "mouseDown":
  71. case "mouseUp": {
  72. int button = msg["button"];
  73. MouseButton flag = 0;
  74. if (button == 0) flag = MouseButton.Left;
  75. else if (button == 1) flag = MouseButton.Right;
  76. else if (button == 2) flag = MouseButton.Middle;
  77. if (msg["type"] == "mouseDown") MouseButtons |= flag;
  78. else MouseButtons &= ~flag;
  79. break;
  80. }
  81. case "mouseMove": {
  82. var screenPos = new Vector2(msg["x"], msg["y"]);
  83. screenPos.x = screenPos.x / browser.Size.x;
  84. screenPos.y = screenPos.y / browser.Size.y;
  85. MousePosition = screenPos;
  86. //Debug.Log("mouse now at " + screenPos);
  87. break;
  88. }
  89. case "mouseFocus":
  90. MouseHasFocus = msg["focus"];
  91. break;
  92. case "keyboardFocus":
  93. KeyboardHasFocus = msg["focus"];
  94. break;
  95. case "mouseScroll": {
  96. const float mult = 1 / 3f;
  97. MouseScroll += new Vector2(msg["x"], msg["y"]) * mult;
  98. break;
  99. }
  100. case "keyDown":
  101. case "keyUp": {
  102. var ev = new Event();
  103. ev.type = msg["type"] == "keyDown" ? EventType.KeyDown : EventType.KeyUp;
  104. ev.character = (char)0;
  105. ev.keyCode = KeyMappings.GetUnityKeyCode(msg["code"]);
  106. SetMods(ev);
  107. //Debug.Log("Convert wkc " + (int)msg["code"] + " to ukc " + ev.keyCode);
  108. KeyEvents.Add(ev);
  109. break;
  110. }
  111. case "keyPress": {
  112. string characters = msg["characters"];
  113. foreach (char c in characters) {
  114. var ev = new Event();
  115. ev.type = EventType.KeyDown;
  116. SetMods(ev);
  117. ev.character = c;
  118. ev.keyCode = 0;
  119. KeyEvents.Add(ev);
  120. }
  121. break;
  122. }
  123. case "resize":
  124. //on OS X (editor at least), resizing hangs the update loop, so we suddenly end up with a bajillion resize
  125. //messages we were unable to process. Just record it here and when we've processed everything we'll resize
  126. delayedResize.x = msg["w"];
  127. delayedResize.y = msg["h"];
  128. break;
  129. case "close":
  130. Destroy(gameObject);
  131. break;
  132. default:
  133. Debug.LogWarning("Unknown window event: " + msg.AsJSON);
  134. break;
  135. }
  136. }
  137. private bool shiftDown, controlDown, altDown, commandDown;
  138. private void SetMods(Event ev) {
  139. switch (ev.keyCode) {
  140. case KeyCode.LeftShift: case KeyCode.RightShift:
  141. shiftDown = ev.type == EventType.KeyDown;
  142. break;
  143. case KeyCode.LeftControl: case KeyCode.RightControl:
  144. controlDown = ev.type == EventType.KeyDown;
  145. break;
  146. case KeyCode.LeftAlt: case KeyCode.RightAlt:
  147. altDown = ev.type == EventType.KeyDown;
  148. break;
  149. case KeyCode.LeftCommand: case KeyCode.RightCommand:
  150. case KeyCode.LeftWindows: case KeyCode.RightWindows:
  151. commandDown = ev.type == EventType.KeyDown;
  152. break;
  153. }
  154. ev.shift = shiftDown;
  155. ev.control = controlDown;
  156. ev.alt = altDown;
  157. ev.command = commandDown;
  158. }
  159. public void Update() {
  160. if (!BrowserNative.SymbolsLoaded) return;
  161. BrowserNative.zfb_windowRender(windowId, browserId);
  162. }
  163. public bool MouseHasFocus { get; private set; }
  164. public Vector2 MousePosition { get; private set; }
  165. public MouseButton MouseButtons { get; private set; }
  166. public Vector2 MouseScroll { get; private set; }
  167. public bool KeyboardHasFocus { get; private set; }
  168. public List<Event> KeyEvents { get; private set; }
  169. public BrowserCursor BrowserCursor { get; private set; }
  170. public BrowserInputSettings InputSettings { get; private set; }
  171. }
  172. }
  173. #endif