You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
6.9 KiB
247 lines
6.9 KiB
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX |
|
#define ZF_OSX |
|
#endif |
|
using System; |
|
using System.Collections; |
|
using UnityEngine; |
|
using UnityEngine.UI; |
|
|
|
namespace ZenFulcrum.EmbeddedBrowser { |
|
|
|
/// <summary> |
|
/// Helper/worker class for displaying an external keyboard and |
|
/// sending the input to a browser. |
|
/// |
|
/// Don't put this script on your target browser directly, add a separate browser |
|
/// to the scene and attach it to that instead. |
|
/// |
|
/// </summary> |
|
[RequireComponent(typeof(Browser))] |
|
[RequireComponent(typeof(PointerUIBase))] |
|
public class ExternalKeyboard : MonoBehaviour { |
|
|
|
[Tooltip("Set to true before startup to have the keyboard automatically hook to the browser with the most recently focused text field.")] |
|
public bool automaticFocus; |
|
|
|
[Tooltip("Browser to start as the focused browser for this keyboard. Not really needed if automaticFocus is on.")] |
|
public Browser initialBrowser; |
|
|
|
[Tooltip(@"Set to true to have the keyboard automatically hide when we don't have a text entry box to type into.")] |
|
public bool hideWhenUnneeded = true; |
|
|
|
protected PointerUIBase activeBrowserUI; |
|
protected Browser keyboardBrowser; |
|
protected bool forcingFocus; |
|
|
|
protected Browser _activeBrowser; |
|
/// <summary> |
|
/// Browser that gets input if we press keys on the keyboard. |
|
/// </summary> |
|
protected virtual Browser ActiveBrowser { |
|
get { return _activeBrowser; } |
|
set { |
|
_SetActiveBrowser(value); |
|
DoFocus(_activeBrowser); |
|
} |
|
} |
|
|
|
protected void _SetActiveBrowser(Browser browser) { |
|
if (ActiveBrowser) { |
|
if (activeBrowserUI && forcingFocus) { |
|
activeBrowserUI.ForceKeyboardHasFocus(false); |
|
forcingFocus = false; |
|
} |
|
} |
|
|
|
_activeBrowser = browser; |
|
activeBrowserUI = ActiveBrowser.GetComponent<PointerUIBase>(); |
|
if (!activeBrowserUI) { |
|
//We can't focus the browser when we type, so the typed letters won't appear as we type. |
|
Debug.LogWarning("Browser does not have a PointerUI, external keyboard may not work properly."); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Called when the focus of the keyboard changes. |
|
/// The browser is the browser we are focused on (may or may not be different), editable will be true if we |
|
/// are expected to type in the new focus, false if not. |
|
/// </summary> |
|
public event Action<Browser, bool> onFocusChange = (browser, editable) => {}; |
|
|
|
public void Awake() { |
|
var keyboardPage = Resources.Load<TextAsset>("Browser/Keyboard").text; |
|
|
|
keyboardBrowser = GetComponent<Browser>(); |
|
|
|
keyboardBrowser.onBrowserFocus += OnKeyboardFocus; |
|
keyboardBrowser.LoadHTML(keyboardPage); |
|
keyboardBrowser.RegisterFunction("textTyped", TextTyped); |
|
keyboardBrowser.RegisterFunction("commandEntered", CommandEntered); |
|
|
|
if (initialBrowser) ActiveBrowser = initialBrowser; |
|
|
|
if (automaticFocus) { |
|
foreach (var browser in FindObjectsOfType<Browser>()) { |
|
ObserveBrowser(browser); |
|
} |
|
Browser.onAnyBrowserCreated += ObserveBrowser; |
|
} |
|
|
|
if (hideWhenUnneeded) SetVisible(false); |
|
} |
|
|
|
public void OnDisable() { |
|
Browser.onAnyBrowserCreated -= ObserveBrowser; |
|
} |
|
|
|
protected void ObserveBrowser(Browser browser) { |
|
if (browser == keyboardBrowser) return;//don't want to know about ourself |
|
|
|
browser.onNodeFocus += (tagName, editable, value) => { |
|
if (!this) return; |
|
if (browser != ActiveBrowser && !browser.focusState.hasMouseFocus) { |
|
return; |
|
} |
|
|
|
DoFocus(browser); |
|
}; |
|
|
|
var pointerUI = browser.GetComponent<PointerUIBase>(); |
|
if (pointerUI) { |
|
pointerUI.onClick += () => { |
|
DoFocus(browser); |
|
}; |
|
} |
|
} |
|
|
|
protected void DoFocus(Browser browser) { |
|
if (browser != ActiveBrowser) { |
|
_SetActiveBrowser(browser); |
|
} |
|
|
|
bool visible; |
|
if (browser) visible = browser.focusState.focusedNodeEditable; |
|
else visible = false; |
|
|
|
if (hideWhenUnneeded) SetVisible(visible); |
|
|
|
onFocusChange(_activeBrowser, visible); |
|
} |
|
|
|
protected void SetVisible(bool visible) { |
|
var renderer = GetComponent<Renderer>(); |
|
if (renderer) renderer.enabled = visible; |
|
var collider = GetComponent<Collider>(); |
|
if (collider) collider.enabled = visible; |
|
|
|
var image = GetComponent<RawImage>(); |
|
if (image) image.enabled = visible; |
|
var keyboardInput = GetComponent<PointerUIGUI>(); |
|
if (keyboardInput) keyboardInput.enableInput = visible; |
|
} |
|
|
|
protected void OnKeyboardFocus(bool mouseFocused, bool kbFocused) { |
|
//when our keyboard is focused, focus the browser we will be typing into. |
|
if (!activeBrowserUI) return; |
|
|
|
if ((mouseFocused || kbFocused) && !forcingFocus) { |
|
activeBrowserUI.ForceKeyboardHasFocus(true); |
|
forcingFocus = true; |
|
} |
|
|
|
if (!(mouseFocused || kbFocused) && forcingFocus) { |
|
activeBrowserUI.ForceKeyboardHasFocus(false); |
|
forcingFocus = false; |
|
} |
|
} |
|
|
|
protected void CommandEntered(JSONNode args) { |
|
if (!ActiveBrowser) return; |
|
|
|
string command = args[0]; |
|
bool shiftPressed = args[1]; |
|
|
|
if (shiftPressed) ActiveBrowser.PressKey(KeyCode.LeftShift, KeyAction.Press); |
|
|
|
|
|
#if ZF_OSX |
|
const KeyCode wordShifter = KeyCode.LeftAlt; |
|
#else |
|
const KeyCode wordShifter = KeyCode.LeftControl; |
|
#endif |
|
|
|
switch (command) { |
|
case "backspace": |
|
ActiveBrowser.PressKey(KeyCode.Backspace); |
|
break; |
|
case "copy": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.Copy); |
|
break; |
|
case "cut": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.Cut); |
|
break; |
|
case "delete": |
|
ActiveBrowser.PressKey(KeyCode.Delete); |
|
break; |
|
case "down": |
|
ActiveBrowser.PressKey(KeyCode.DownArrow); |
|
break; |
|
case "end": |
|
ActiveBrowser.PressKey(KeyCode.End); |
|
break; |
|
case "home": |
|
ActiveBrowser.PressKey(KeyCode.Home); |
|
break; |
|
case "insert": |
|
ActiveBrowser.PressKey(KeyCode.Insert); |
|
break; |
|
case "left": |
|
ActiveBrowser.PressKey(KeyCode.LeftArrow); |
|
break; |
|
case "pageDown": |
|
ActiveBrowser.PressKey(KeyCode.PageDown); |
|
break; |
|
case "pageUp": |
|
ActiveBrowser.PressKey(KeyCode.PageUp); |
|
break; |
|
case "paste": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.Paste); |
|
break; |
|
case "redo": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.Redo); |
|
break; |
|
case "right": |
|
ActiveBrowser.PressKey(KeyCode.RightArrow); |
|
break; |
|
case "selectAll": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.SelectAll); |
|
break; |
|
case "undo": |
|
ActiveBrowser.SendFrameCommand(BrowserNative.FrameCommand.Undo); |
|
break; |
|
case "up": |
|
ActiveBrowser.PressKey(KeyCode.UpArrow); |
|
break; |
|
case "wordLeft": |
|
ActiveBrowser.PressKey(wordShifter, KeyAction.Press); |
|
ActiveBrowser.PressKey(KeyCode.LeftArrow); |
|
ActiveBrowser.PressKey(wordShifter, KeyAction.Release); |
|
break; |
|
case "wordRight": |
|
ActiveBrowser.PressKey(wordShifter, KeyAction.Press); |
|
ActiveBrowser.PressKey(KeyCode.RightArrow); |
|
ActiveBrowser.PressKey(wordShifter, KeyAction.Release); |
|
break; |
|
} |
|
|
|
if (shiftPressed) ActiveBrowser.PressKey(KeyCode.LeftShift, KeyAction.Release); |
|
} |
|
|
|
protected void TextTyped(JSONNode args) { |
|
if (!ActiveBrowser) return; |
|
|
|
ActiveBrowser.TypeText(args[0]); |
|
} |
|
} |
|
|
|
} |