247 lines
6.9 KiB
C#
247 lines
6.9 KiB
C#
#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]);
|
|
}
|
|
}
|
|
|
|
} |