diff --git a/Runtime/BrowserView.cs b/Runtime/BrowserView.cs deleted file mode 100644 index f76c66b00adb6bfcd1f99aeffb67ee60ef76ed7f..0000000000000000000000000000000000000000 --- a/Runtime/BrowserView.cs +++ /dev/null @@ -1,213 +0,0 @@ -using ChromeDevTools; -using ChromeDevTools.Protocol.Input; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; - -[RequireComponent(typeof(RawImage))] -public class BrowserView : MonoBehaviour, IPointerDownHandler, IPointerMoveHandler, IPointerUpHandler, IPointerEnterHandler, IDropHandler, IPointerExitHandler -{ - #region json serializer - - /// <summary> - /// Json serializer settings for the user space objects (e.g. transfering objects that have been droped on the BrowserView) - /// Users are allowed to change serializer settings to their liking. - /// </summary> - public static JsonSerializerSettings serializerSettings = new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Converters = new List<JsonConverter>() - { - new ColorConverter(), - new Vector2Converter(), - new Vector3Converter(), - new Vector4Converter() - } - }; - /// <summary> - /// JsonSerializer for the user space objects (e.g. transfering objects that have been droped on the BrowserView) - /// Users are allowed to change serializer settings to their liking. - /// </summary> - public static JsonSerializer serializer = JsonSerializer.Create(serializerSettings); - - #endregion json serializer - - private Browser browser; - private BrowserTab tab; - - private RawImage rawImage; - private RectTransform rectTransform; - - public bool headlessBrowser = true; - //TODO: handle changed targetUrl - public string targetUrl = "https://google.de"; - - // Start is called before the first frame update - private void Start() - { - rawImage = this.gameObject.GetComponent<RawImage>(); - rectTransform = this.gameObject.GetComponent<RectTransform>(); - } - - private void OnEnable() - { - Browser.headless = headlessBrowser; - browser = Browser.getInstance(); - - //StartCoroutine(GetOpenTabs()); - var c = StartCoroutine(browser.OpenNewTab(targetUrl, (BrowserTab bt) => - { - tab = bt; - StartCoroutine(tab.Update()); - //StartCoroutine(createScreenshots()); - StartCoroutine(tab.StartStream(900, 560, (frame) => - { - rawImage.texture = frame; - rawImage.SetNativeSize(); - })); - })); - - } - - public IEnumerator createScreenshots () - { - yield return tab.CreateScreenshot(900, 560, (screenshot) => - { - rawImage.texture = screenshot; - StartCoroutine(createScreenshots()); - }); - } - - // Update is called once per frame - private void Update() - { - - } - - #region pointer event handlers - - public void OnPointerDown(PointerEventData eventData) - { - Vector2Int pos = toBrowserCoordinates(eventData.position); - tab.OnPointerDown(pos, eventData); - } - - public void OnPointerMove(PointerEventData eventData) - { - // TODO: transform eventData delta vector to browser coordinates - Vector2Int pos = toBrowserCoordinates(eventData.position); - tab.OnPointerMove(pos, eventData); - - // On drag over - if (eventData.dragging) - { - Debug.LogWarning($"OnDragOver: {eventData.position}"); - createDragEvent(DragEventType.dragOver, eventData); - } - } - - public void OnPointerUp(PointerEventData eventData) - { - Vector2Int pos = toBrowserCoordinates(eventData.position); - tab.OnPointerUp(pos, eventData); - } - #endregion pointer event handlers - - #region drag event handlers - public void OnPointerEnter(PointerEventData eventData) - { - if (eventData.dragging) - { - Debug.LogWarning($"OnDragEnter: {eventData.position}"); - createDragEvent(DragEventType.dragEnter, eventData); - } - } - - // TODO: OnDragMove -> PointerMove - - public void OnDrop(PointerEventData eventData) - { - Debug.LogWarning($"OnDrop: {eventData.position}"); - createDragEvent(DragEventType.drop, eventData); - } - - public void OnPointerExit(PointerEventData eventData) - { - if (eventData.dragging) - { - Debug.LogWarning($"OnDragLeave: {eventData.position}"); - //createDragEvent(DragEventType.dragCancel, eventData); - tab.CancelDragging(); - // TODO: drag cancel seems to be ignored by the browser - } - } - - private void createDragEvent(DragEventType dragEventType, PointerEventData eventData) - { - if (eventData.pointerDrag.TryGetComponent(out BrowserDropable dropable)) - { - var position = toBrowserCoordinates(eventData.position); - var dragEvent = new dispatchDragEvent - { - type = dragEventType, - data = new DragData - { - items = new DragDataItem[] - { - new DragDataItem - { - mimeType = "application/json", - data = JsonConvert.SerializeObject(dropable, serializerSettings) - } - }, - dragOperationsMask = DragOperationsMask.Copy - }, - x = position.x, - y = position.y, - }; - Debug.LogWarning($"DragEvent: {dragEvent.type}, {eventData.position}, '{dragEvent.data.items[0].data}'"); - // send the DragEvent as drag event to the browser - tab.OnDragNDrop(dragEvent); - } - } - #endregion drag event handlers - - private Vector2Int toBrowserCoordinates(Vector2 eventPos) - { - Vector2 localPoint; - RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventPos, null, out localPoint); - - // invert y because the browser has y=0 on the top - Vector2 invertedLocalPos = new Vector2(localPoint.x, rectTransform.rect.size.y - localPoint.y); - Vector2 browserCoorinate = tab.size / rectTransform.rect.size * invertedLocalPos; - Debug.Log($"eventPos: {eventPos}, invertedLocalPos: {invertedLocalPos}, browserCoordinate: {browserCoorinate}"); - return new Vector2Int((int) browserCoorinate.x, (int) browserCoorinate.y); - } - - private void OnDisable() - { - // TODO: do we want to close the browser when not in use? - // close browser when recompiling - tab.Close(); - browser.Close(); - } - private void OnDestroy() - { - tab.Close(); - browser.Close(); - } - /** - * Close all browser windows. - */ - private void OnApplicationQuit() - { - tab.Close(); - browser.Close(); - } -} - -public interface BrowserDropable { } diff --git a/Runtime/ChromeDevtools/Browser.cs b/Runtime/ChromeDevtools/Browser.cs index 3d2e56319724b23901b4789ceeacfb224b4455f7..ca1bbaf81f56b0492cfaa361d12af2d5179a0606 100644 --- a/Runtime/ChromeDevtools/Browser.cs +++ b/Runtime/ChromeDevtools/Browser.cs @@ -8,7 +8,7 @@ using System.Threading; using UnityEngine; using UnityEngine.Networking; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools { public class Browser { diff --git a/Runtime/ChromeDevtools/BrowserTab.cs b/Runtime/ChromeDevtools/BrowserTab.cs index b2787f8926ba52e897a68d16a1ac1a6e291ece72..74b8ce03cb956f0cec38af16b1ac6ba3a7143693 100644 --- a/Runtime/ChromeDevtools/BrowserTab.cs +++ b/Runtime/ChromeDevtools/BrowserTab.cs @@ -1,12 +1,12 @@ -using ChromeDevTools.Protocol.Input; -using ChromeDevTools.Protocol.Page; -using ChromeDevTools.Protocol.Target; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Input; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Page; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Target; using System; using System.Collections; using UnityEngine; using UnityEngine.EventSystems; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools { public class BrowserTab diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsProtocolHandler.cs b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs similarity index 98% rename from Runtime/ChromeDevtools/Protocol/DevtoolsProtocolHandler.cs rename to Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs index ef7f3f7085ea0c2fc886a540611aafbae7a7400d..aed39162b4422e9b2c1ded8ffa35485af7b10bad 100644 --- a/Runtime/ChromeDevtools/Protocol/DevtoolsProtocolHandler.cs +++ b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs @@ -1,5 +1,5 @@ -using ChromeDevTools.Protocol; -using ChromeDevTools.Protocol.Page; +using bessw.Unity.WebView.ChromeDevTools.Protocol; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Page; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -8,7 +8,7 @@ using System.Collections.Concurrent; using System.Threading.Tasks; using UnityEngine; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools { /// <summary> /// Manages a chrome devtools websocket connection and parses the messages to C# objects diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsProtocolHandler.cs.meta b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs.meta similarity index 100% rename from Runtime/ChromeDevtools/Protocol/DevtoolsProtocolHandler.cs.meta rename to Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs.meta diff --git a/Runtime/ChromeDevtools/DevtoolsWebsocket.cs b/Runtime/ChromeDevtools/DevtoolsWebsocket.cs index f0f6183582c8f99fb0f284396aaf0e68a7854a9a..c4e05260e2963b8caac3a1cdd91937503ed2ee7d 100644 --- a/Runtime/ChromeDevtools/DevtoolsWebsocket.cs +++ b/Runtime/ChromeDevtools/DevtoolsWebsocket.cs @@ -1,4 +1,4 @@ -using ChromeDevTools.Protocol; +using bessw.Unity.WebView.ChromeDevTools; using System; using System.IO; using System.Net.WebSockets; @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using UnityEngine; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools { /// <summary> /// Manages a chrome devtools websocket connection and parses the messages to C# objects diff --git a/Runtime/ChromeDevtools/IDevtoolsConnection.cs b/Runtime/ChromeDevtools/IDevtoolsConnection.cs new file mode 100644 index 0000000000000000000000000000000000000000..c75221f2a75ca326900b877d1253dde7baa5c049 --- /dev/null +++ b/Runtime/ChromeDevtools/IDevtoolsConnection.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; + +namespace bessw.Unity.WebView.ChromeDevTools +{ + public interface IDevtoolsConnection + { + public event Action<string> receivedMessage; + + /// <summary> + /// Opens the devtools connection. + /// </summary> + /// <returns>Returns a Task that is resolved when the connection is established.</returns> + public Task OpenAsync(); + + /// <summary> + /// Reads one message from the devtools connection. + /// </summary> + /// <returns>Returns a Task that is resolved with the message that has been read.</returns> + public Task<string> ReadAsync(); + + /// <summary> + /// experimential + /// </summary> + /// <returns></returns> + [Obsolete] + public Task AsyncReadLoop(); + + public Task SendCommandAsync(string command); + public void Dispose(); + } + + public class DevtoolsConnectionException : Exception + { + public DevtoolsConnectionException(string msg) : base(msg) { } + } + + public class DevtoolsConnectionClosedException : DevtoolsConnectionException + { + public DevtoolsConnectionClosedException() : base("Devtools connection closed") { } + } +} diff --git a/Runtime/ChromeDevtools/Protocol/IDevtoolsConnection.cs.meta b/Runtime/ChromeDevtools/IDevtoolsConnection.cs.meta similarity index 100% rename from Runtime/ChromeDevtools/Protocol/IDevtoolsConnection.cs.meta rename to Runtime/ChromeDevtools/IDevtoolsConnection.cs.meta diff --git a/Runtime/ChromeDevtools/PageTargetInfo.cs b/Runtime/ChromeDevtools/PageTargetInfo.cs index 70911eda1f625dd8e9a0ed22bea7e73eec79737c..be365cf940910b274436584fc20f6ba0dea85166 100644 --- a/Runtime/ChromeDevtools/PageTargetInfo.cs +++ b/Runtime/ChromeDevtools/PageTargetInfo.cs @@ -1,7 +1,7 @@ /** * Json structs used in the chrome devtools protocol */ -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools { public class PageTargetInfo { diff --git a/Runtime/ChromeDevtools/Protocol/Cast/Cast.cs b/Runtime/ChromeDevtools/Protocol/Cast/Cast.cs index 4a67cb36e0666c850736f8ce156eb7b49b93f28f..05c06c6655ecbd078814ab6fcd64cd7ea6813fbf 100644 --- a/Runtime/ChromeDevtools/Protocol/Cast/Cast.cs +++ b/Runtime/ChromeDevtools/Protocol/Cast/Cast.cs @@ -1,124 +1,113 @@ -using Newtonsoft.Json; - -namespace ChromeDevTools -{ - namespace Protocol +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Cast { + /* + Devtools protocol.json: { - namespace Cast - { - } - } -} - - -/* -Devtools protocol.json: -{ - "domain": "Cast", - "description": "A domain for interacting with Cast, Presentation API, and Remote Playback API\nfunctionalities.", - "experimental": true, - "types": [ - { - "id": "Sink", - "type": "object", - "properties": [ - { - "name": "name", - "type": "string" - }, - { - "name": "id", - "type": "string" - }, - { - "name": "session", - "description": "Text describing the current session. Present only if there is an active\nsession on the sink.", - "optional": true, - "type": "string" - } - ] - } - ], - "commands": [ - { - "name": "enable", - "description": "Starts observing for sinks that can be used for tab mirroring, and if set,\nsinks compatible with |presentationUrl| as well. When sinks are found, a\n|sinksUpdated| event is fired.\nAlso starts observing for issue messages. When an issue is added or removed,\nan |issueUpdated| event is fired.", - "parameters": [ - { - "name": "presentationUrl", - "optional": true, - "type": "string" - } - ] - }, - { - "name": "disable", - "description": "Stops observing for sinks and issues." - }, - { - "name": "setSinkToUse", - "description": "Sets a sink to be used when the web page requests the browser to choose a\nsink via Presentation API, Remote Playback API, or Cast SDK.", - "parameters": [ - { - "name": "sinkName", - "type": "string" - } - ] - }, - { - "name": "startDesktopMirroring", - "description": "Starts mirroring the desktop to the sink.", - "parameters": [ - { - "name": "sinkName", - "type": "string" - } - ] - }, - { - "name": "startTabMirroring", - "description": "Starts mirroring the tab to the sink.", - "parameters": [ - { - "name": "sinkName", - "type": "string" - } - ] - }, - { - "name": "stopCasting", - "description": "Stops the active Cast session on the sink.", - "parameters": [ - { - "name": "sinkName", - "type": "string" - } - ] - } - ], - "events": [ - { - "name": "sinksUpdated", - "description": "This is fired whenever the list of available sinks changes. A sink is a\ndevice or a software surface that you can cast to.", - "parameters": [ - { - "name": "sinks", - "type": "array", - "items": { - "$ref": "Sink" + "domain": "Cast", + "description": "A domain for interacting with Cast, Presentation API, and Remote Playback API\nfunctionalities.", + "experimental": true, + "types": [ + { + "id": "Sink", + "type": "object", + "properties": [ + { + "name": "name", + "type": "string" + }, + { + "name": "id", + "type": "string" + }, + { + "name": "session", + "description": "Text describing the current session. Present only if there is an active\nsession on the sink.", + "optional": true, + "type": "string" + } + ] + } + ], + "commands": [ + { + "name": "enable", + "description": "Starts observing for sinks that can be used for tab mirroring, and if set,\nsinks compatible with |presentationUrl| as well. When sinks are found, a\n|sinksUpdated| event is fired.\nAlso starts observing for issue messages. When an issue is added or removed,\nan |issueUpdated| event is fired.", + "parameters": [ + { + "name": "presentationUrl", + "optional": true, + "type": "string" + } + ] + }, + { + "name": "disable", + "description": "Stops observing for sinks and issues." + }, + { + "name": "setSinkToUse", + "description": "Sets a sink to be used when the web page requests the browser to choose a\nsink via Presentation API, Remote Playback API, or Cast SDK.", + "parameters": [ + { + "name": "sinkName", + "type": "string" + } + ] + }, + { + "name": "startDesktopMirroring", + "description": "Starts mirroring the desktop to the sink.", + "parameters": [ + { + "name": "sinkName", + "type": "string" + } + ] + }, + { + "name": "startTabMirroring", + "description": "Starts mirroring the tab to the sink.", + "parameters": [ + { + "name": "sinkName", + "type": "string" } - } - ] - }, - { - "name": "issueUpdated", - "description": "This is fired whenever the outstanding issue/error message changes.\n|issueMessage| is empty if there is no issue.", - "parameters": [ - { - "name": "issueMessage", - "type": "string" - } - ] - } - ] -}*/ \ No newline at end of file + ] + }, + { + "name": "stopCasting", + "description": "Stops the active Cast session on the sink.", + "parameters": [ + { + "name": "sinkName", + "type": "string" + } + ] + } + ], + "events": [ + { + "name": "sinksUpdated", + "description": "This is fired whenever the list of available sinks changes. A sink is a\ndevice or a software surface that you can cast to.", + "parameters": [ + { + "name": "sinks", + "type": "array", + "items": { + "$ref": "Sink" + } + } + ] + }, + { + "name": "issueUpdated", + "description": "This is fired whenever the outstanding issue/error message changes.\n|issueMessage| is empty if there is no issue.", + "parameters": [ + { + "name": "issueMessage", + "type": "string" + } + ] + } + ] + }*/ +} diff --git a/Runtime/ChromeDevtools/Protocol/CommandResponseAttribute.cs b/Runtime/ChromeDevtools/Protocol/CommandResponseAttribute.cs index 2e60417de5fdbf933647b1705d7b602dfd0474d4..d4753af95b338afe4f07cc6fad072642f49e1924 100644 --- a/Runtime/ChromeDevtools/Protocol/CommandResponseAttribute.cs +++ b/Runtime/ChromeDevtools/Protocol/CommandResponseAttribute.cs @@ -1,15 +1,12 @@ using System; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol { - namespace Protocol + [AttributeUsage(AttributeTargets.Class)] + public class CommandResponseAttribute : Attribute { - [AttributeUsage(AttributeTargets.Class)] - public class CommandResponseAttribute : Attribute - { - public Type responseType { get; } - public CommandResponseAttribute(Type responseType) => this.responseType = responseType; + public Type responseType { get; } + public CommandResponseAttribute(Type responseType) => this.responseType = responseType; - } } -} \ No newline at end of file +} diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsCommand.cs b/Runtime/ChromeDevtools/Protocol/DevtoolsCommand.cs index 47a25d8a65371859e0f084bf98d87aa9cfdbef92..cbd8af1306fdd3582f28d778af1d197070c82662 100644 --- a/Runtime/ChromeDevtools/Protocol/DevtoolsCommand.cs +++ b/Runtime/ChromeDevtools/Protocol/DevtoolsCommand.cs @@ -1,27 +1,24 @@ -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol { - namespace Protocol + /// + /// Every devtools command has an id and a method + /// + public class DevtoolsCommandWrapper<T> where T: IDevtoolsCommand { - /// - /// Every devtools command has an id and a method - /// - public class DevtoolsCommandWrapper<T> where T: IDevtoolsCommand - { - //private static long LAST_ID = 0; - public long Id { get; set; } // = ++LAST_ID; - public string Method - { - get - { - // Remove the namespace prefix 'ChromeDevTools.Protocol.' - return Params.GetType().FullName.Substring("ChromeDevTools.Protocol.".Length); - } + //private static long LAST_ID = 0; + public long Id { get; set; } // = ++LAST_ID; + public string Method + { + get + { + // Remove the namespace prefix 'ChromeDevTools.Protocol.' + return Params.GetType().FullName.Substring("bessw.Unity.WebView.ChromeDevTools.Protocol.".Length); } - - public T Params { get; set; } - public DevtoolsCommandWrapper(T command) => Params = command; } - public interface IDevtoolsCommand { } - public interface IDevtoolsCommandWithResponse: IDevtoolsCommand { } + + public T Params { get; set; } + public DevtoolsCommandWrapper(T command) => Params = command; } -} \ No newline at end of file + public interface IDevtoolsCommand { } + public interface IDevtoolsCommandWithResponse: IDevtoolsCommand { } +} diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsEvent.cs b/Runtime/ChromeDevtools/Protocol/DevtoolsEvent.cs index a4c124e444c8e03978b01247792e0c674ae6c206..5c254125b7855e978862f296ddb21b9667c7a529 100644 --- a/Runtime/ChromeDevtools/Protocol/DevtoolsEvent.cs +++ b/Runtime/ChromeDevtools/Protocol/DevtoolsEvent.cs @@ -1,23 +1,19 @@ using Newtonsoft.Json.Linq; -using System; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol { - namespace Protocol + public class DevtoolsEventWrapper { - public class DevtoolsEventWrapper - { - public string Method { get; set; } - public JObject Params { get; set; } - } - /// - /// Every devtools command response has the same id and a method as the corresponding command - /// - public class DevtoolsEventWrapper<T> : DevtoolsEventWrapper where T : IDevtoolsEvent - { - public new T Params { get; set; } - } - - public interface IDevtoolsEvent { } + public string Method { get; set; } + public JObject Params { get; set; } + } + /// + /// Every devtools command response has the same id and a method as the corresponding command + /// + public class DevtoolsEventWrapper<T> : DevtoolsEventWrapper where T : IDevtoolsEvent + { + public new T Params { get; set; } } -} \ No newline at end of file + + public interface IDevtoolsEvent { } +} diff --git a/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs b/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs index 8d4f55cf2cef9ebb6b43123141da6b9c4bdea180..ac790ad3a74926196da35ae926d11960b914d595 100644 --- a/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs +++ b/Runtime/ChromeDevtools/Protocol/DevtoolsResponse.cs @@ -1,23 +1,20 @@ using Newtonsoft.Json.Linq; using System; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol { - namespace Protocol + public class DevtoolsResponseWrapper { - public class DevtoolsResponseWrapper - { - public long Id { get; set; } - public JObject Result { get; set; } - } - /// - /// Every devtools command response has the same id and a method as the corresponding command - /// - public class DevtoolsResponseWrapper<T> : DevtoolsResponseWrapper where T : IDevtoolsResponse - { - public new T Result { get; set; } - } - - public interface IDevtoolsResponse { } + public long Id { get; set; } + public JObject Result { get; set; } + } + /// + /// Every devtools command response has the same id and a method as the corresponding command + /// + public class DevtoolsResponseWrapper<T> : DevtoolsResponseWrapper where T : IDevtoolsResponse + { + public new T Result { get; set; } } -} \ No newline at end of file + + public interface IDevtoolsResponse { } +} diff --git a/Runtime/ChromeDevtools/Protocol/IDevtoolsConnection.cs b/Runtime/ChromeDevtools/Protocol/IDevtoolsConnection.cs deleted file mode 100644 index 81f27aa49406e61aee941475b8ef857c4a9613d2..0000000000000000000000000000000000000000 --- a/Runtime/ChromeDevtools/Protocol/IDevtoolsConnection.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace ChromeDevTools -{ - namespace Protocol - { - public interface IDevtoolsConnection - { - public event Action<string> receivedMessage; - - /// <summary> - /// Opens the devtools connection. - /// </summary> - /// <returns>Returns a Task that is resolved when the connection is established.</returns> - public Task OpenAsync(); - - /// <summary> - /// Reads one message from the devtools connection. - /// </summary> - /// <returns>Returns a Task that is resolved with the message that has been read.</returns> - public Task<string> ReadAsync(); - - /// <summary> - /// experimential - /// </summary> - /// <returns></returns> - [Obsolete] - public Task AsyncReadLoop(); - - public Task SendCommandAsync(string command); - public void Dispose(); - } - - public class DevtoolsConnectionException : Exception - { - public DevtoolsConnectionException(string msg) : base(msg) { } - } - - public class DevtoolsConnectionClosedException : DevtoolsConnectionException - { - public DevtoolsConnectionClosedException() : base("Devtools connection closed") { } - } - } -} \ No newline at end of file diff --git a/Runtime/ChromeDevtools/Protocol/Input/Input.cs b/Runtime/ChromeDevtools/Protocol/Input/Input.cs index 08d5ec101147ec6dbd178718128a66427dbc15bb..c15cfcd846025913b5efde647d1b18c9122a41d9 100644 --- a/Runtime/ChromeDevtools/Protocol/Input/Input.cs +++ b/Runtime/ChromeDevtools/Protocol/Input/Input.cs @@ -5,232 +5,226 @@ using Newtonsoft.Json.Serialization; using UnityEngine.EventSystems; using static UnityEngine.EventSystems.PointerEventData; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Input { - namespace Protocol + #region dispatchMouseEvent + /// <summary> + /// Dispatches a mouse event to the page. + /// </summary> + public class dispatchMouseEvent: IDevtoolsCommand { - namespace Input + public dispatchMouseEvent(MouseEventType type, int x, int y) { - #region dispatchMouseEvent - /// <summary> - /// Dispatches a mouse event to the page. - /// </summary> - public class dispatchMouseEvent: IDevtoolsCommand + this.type = type; + this.x = x; + this.y = y; + } + public dispatchMouseEvent(MouseEventType type, int x, int y, PointerEventData eventData) : this(type, x, y) + { + switch (eventData.button) { - public dispatchMouseEvent(MouseEventType type, int x, int y) - { - this.type = type; - this.x = x; - this.y = y; - } - public dispatchMouseEvent(MouseEventType type, int x, int y, PointerEventData eventData) : this(type, x, y) - { - switch (eventData.button) - { - case InputButton.Left: - button = MouseButton.Left; break; - case InputButton.Right: - button = MouseButton.Right; break; - case InputButton.Middle: - button = MouseButton.Middle; break; - } - clickCount = eventData.clickCount; - // TODO: delta compensate stream and texture scaling - deltaX = (int?)eventData.delta.x; - deltaY = (int?)eventData.delta.y; - } - - /// <summary> - /// Type of the mouse event. - /// Allowed Values: mousePressed, mouseReleased, mouseMoved, mouseWheel - /// </summary> - [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] - public MouseEventType type { get; set; } - /// <summary> - /// X coordinate of the event relative to the main frame's viewport in CSS pixels. - /// </summary> - public int x { get; set; } - /// <summary> - /// Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport. - /// </summary> - public int y { get; set; } - /// <summary> - /// Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public ModifierKeyFlags? modifiers { get; set; } - /// <summary> - /// Time at which the event occurred. - /// TimeSinceEpoch UTC time in seconds, counted from January 1, 1970. - /// </summary> - [JsonConverter(typeof(UnixDateTimeConverter))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public DateTime? timestamp { get; set; } - /// <summary> - /// Allowed Values: none, left, middle, right, back, forward - /// Mouse button (default: "none"). - /// </summary> - [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public MouseButton? button { get; set; } - /// <summary> - /// A number indicating which buttons are pressed on the mouse when a mouse event is triggered. Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public MouseButtonFlags? buttons { get; set; } - /// <summary> - /// Number of times the mouse button was clicked (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? clickCount { get; set; } - /// <summary> - /// The normalized pressure, which has a range of [0,1] (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? force { get; set; } - /// <summary> - /// The normalized tangential pressure, which has a range of [-1,1] (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? tangentialPressure { get; set; } - /// <summary> - /// The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? tiltX { get; set; } - /// <summary> - /// The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? tiltY { get; set; } - /// <summary> - /// The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? twist { get; set; } - /// <summary> - /// X delta in CSS pixels for mouse wheel event (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? deltaX { get; set; } - /// <summary> - /// Y delta in CSS pixels for mouse wheel event (default: 0). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? deltaY { get; set; } - /// <summary> - /// Pointer type (default: "mouse"). - /// Allowed Values: mouse, pen - /// </summary> - [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public PointerType? pointerType { get; set; } + case InputButton.Left: + button = MouseButton.Left; break; + case InputButton.Right: + button = MouseButton.Right; break; + case InputButton.Middle: + button = MouseButton.Middle; break; } + clickCount = eventData.clickCount; + // TODO: delta compensate stream and texture scaling + deltaX = (int?)eventData.delta.x; + deltaY = (int?)eventData.delta.y; + } - public enum MouseEventType - { - MousePressed, MouseReleased, MouseMoved, MouseWheel - } + /// <summary> + /// Type of the mouse event. + /// Allowed Values: mousePressed, mouseReleased, mouseMoved, mouseWheel + /// </summary> + [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] + public MouseEventType type { get; set; } + /// <summary> + /// X coordinate of the event relative to the main frame's viewport in CSS pixels. + /// </summary> + public int x { get; set; } + /// <summary> + /// Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport. + /// </summary> + public int y { get; set; } + /// <summary> + /// Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public ModifierKeyFlags? modifiers { get; set; } + /// <summary> + /// Time at which the event occurred. + /// TimeSinceEpoch UTC time in seconds, counted from January 1, 1970. + /// </summary> + [JsonConverter(typeof(UnixDateTimeConverter))] + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public DateTime? timestamp { get; set; } + /// <summary> + /// Allowed Values: none, left, middle, right, back, forward + /// Mouse button (default: "none"). + /// </summary> + [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public MouseButton? button { get; set; } + /// <summary> + /// A number indicating which buttons are pressed on the mouse when a mouse event is triggered. Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public MouseButtonFlags? buttons { get; set; } + /// <summary> + /// Number of times the mouse button was clicked (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? clickCount { get; set; } + /// <summary> + /// The normalized pressure, which has a range of [0,1] (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? force { get; set; } + /// <summary> + /// The normalized tangential pressure, which has a range of [-1,1] (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? tangentialPressure { get; set; } + /// <summary> + /// The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? tiltX { get; set; } + /// <summary> + /// The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? tiltY { get; set; } + /// <summary> + /// The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? twist { get; set; } + /// <summary> + /// X delta in CSS pixels for mouse wheel event (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? deltaX { get; set; } + /// <summary> + /// Y delta in CSS pixels for mouse wheel event (default: 0). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? deltaY { get; set; } + /// <summary> + /// Pointer type (default: "mouse"). + /// Allowed Values: mouse, pen + /// </summary> + [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public PointerType? pointerType { get; set; } + } - public enum MouseButton - { - None, Left, Middle, Right, Back, Forward - } + public enum MouseEventType + { + MousePressed, MouseReleased, MouseMoved, MouseWheel + } - [Flags] - public enum MouseButtonFlags - { - None = 0, Left = 1, Right = 2, Middle = 4, Back = 8, Forward = 16 - } + public enum MouseButton + { + None, Left, Middle, Right, Back, Forward + } - public enum PointerType - { - Mouse, Pen - } - #endregion dispatchMouseEvent + [Flags] + public enum MouseButtonFlags + { + None = 0, Left = 1, Right = 2, Middle = 4, Back = 8, Forward = 16 + } - #region dispatchDragEvent + public enum PointerType + { + Mouse, Pen + } + #endregion dispatchMouseEvent - /// <summary> - /// Cancels any active dragging in the page. - /// </summary> - public class cancelDragging : IDevtoolsCommand - { + #region dispatchDragEvent - } + /// <summary> + /// Cancels any active dragging in the page. + /// </summary> + public class cancelDragging : IDevtoolsCommand + { - /// <summary> - /// Dispatches a drag event into the page. - /// </summary> - public class dispatchDragEvent : IDevtoolsCommand - { - /// <summary> - /// Type of the drag event. - /// Allowed Values: dragEnter, dragOver, drop, dragCancel - /// </summary> - [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] - public DragEventType type { get; set; } - public int x { get; set; } - public int y { get; set; } - public DragData data { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public ModifierKeyFlags? modifiers { get; set; } + } - } + /// <summary> + /// Dispatches a drag event into the page. + /// </summary> + public class dispatchDragEvent : IDevtoolsCommand + { + /// <summary> + /// Type of the drag event. + /// Allowed Values: dragEnter, dragOver, drop, dragCancel + /// </summary> + [JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))] + public DragEventType type { get; set; } + public int x { get; set; } + public int y { get; set; } + public DragData data { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public ModifierKeyFlags? modifiers { get; set; } - public enum DragEventType - { - dragEnter, dragOver, drop, dragCancel - } + } - public class DragData - { - public DragDataItem[] items { get; set; } - /// <summary> - /// List of filenames that should be included when dropping - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string[]? files { get; set; } - public DragOperationsMask dragOperationsMask { get; set; } - } + public enum DragEventType + { + dragEnter, dragOver, drop, dragCancel + } - [Flags] - public enum DragOperationsMask - { - Copy = 1, Link = 2, Move = 16 - } + public class DragData + { + public DragDataItem[] items { get; set; } + /// <summary> + /// List of filenames that should be included when dropping + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string[]? files { get; set; } + public DragOperationsMask dragOperationsMask { get; set; } + } - public class DragDataItem - { - /// <summary> - /// Mime type of the dragged data. - /// </summary> - public string mimeType { get; set; } = ""; - /// <summary> - /// Depending of the value of mimeType, it contains the dragged link, text, HTML markup or any other data. - /// </summary> - public string data { get; set; } = ""; - /// <summary> - /// Title associated with a link. Only valid when mimeType == "text/uri-list". - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string? title { get; set; } = null; - /// <summary> - /// Stores the base URL for the contained markup. Only valid when mimeType == "text/html". - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string? baseURL { get; set; } = null; - } - #endregion dispatchDragEvent + [Flags] + public enum DragOperationsMask + { + Copy = 1, Link = 2, Move = 16 + } - /// <summary> - /// Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). - /// </summary> - [Flags] - public enum ModifierKeyFlags - { - None = 0, Alt = 1, Ctrl = 2, Meta_Command = 4, Shift = 8 - } - } + public class DragDataItem + { + /// <summary> + /// Mime type of the dragged data. + /// </summary> + public string mimeType { get; set; } = ""; + /// <summary> + /// Depending of the value of mimeType, it contains the dragged link, text, HTML markup or any other data. + /// </summary> + public string data { get; set; } = ""; + /// <summary> + /// Title associated with a link. Only valid when mimeType == "text/uri-list". + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string? title { get; set; } = null; + /// <summary> + /// Stores the base URL for the contained markup. Only valid when mimeType == "text/html". + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string? baseURL { get; set; } = null; + } + #endregion dispatchDragEvent + + /// <summary> + /// Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). + /// </summary> + [Flags] + public enum ModifierKeyFlags + { + None = 0, Alt = 1, Ctrl = 2, Meta_Command = 4, Shift = 8 } -} \ No newline at end of file +} diff --git a/Runtime/ChromeDevtools/Protocol/Page/CaptureScreenshot.cs b/Runtime/ChromeDevtools/Protocol/Page/CaptureScreenshot.cs index 09e1b1af574b90bcb16c7b274ee19ce82e1d62ef..3ec97765b501ad3d4c8a3d4178a6d4fcd0e978dc 100644 --- a/Runtime/ChromeDevtools/Protocol/Page/CaptureScreenshot.cs +++ b/Runtime/ChromeDevtools/Protocol/Page/CaptureScreenshot.cs @@ -1,50 +1,44 @@ using Newtonsoft.Json; -using ChromeDevTools.Protocol.Types; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Types; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Page { - namespace Protocol + /// <summary> + /// Capture page screenshot. + /// </summary> + [CommandResponseAttribute(typeof(CaptureScreenshotCommandResponse))] + public class captureScreenshot : IDevtoolsCommandWithResponse { - namespace Page - { - /// <summary> - /// Capture page screenshot. - /// </summary> - [CommandResponseAttribute(typeof(CaptureScreenshotCommandResponse))] - public class captureScreenshot : IDevtoolsCommandWithResponse - { - /// <summary> - /// Gets or sets Image compression format (defaults to png). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string Format { get; set; } - /// <summary> - /// Gets or sets Compression quality from range [0..100] (jpeg only). - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public long? Quality { get; set; } - /// <summary> - /// Gets or sets Capture the screenshot of a given region only. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public Viewport Clip { get; set; } - /// <summary> - /// Gets or sets Capture the screenshot from the surface, rather than the view. Defaults to true. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public bool? FromSurface { get; set; } - } + /// <summary> + /// Gets or sets Image compression format (defaults to png). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string Format { get; set; } + /// <summary> + /// Gets or sets Compression quality from range [0..100] (jpeg only). + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public long? Quality { get; set; } + /// <summary> + /// Gets or sets Capture the screenshot of a given region only. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public Viewport Clip { get; set; } + /// <summary> + /// Gets or sets Capture the screenshot from the surface, rather than the view. Defaults to true. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool? FromSurface { get; set; } + } - /// <summary> - /// Capture page screenshot response. - /// </summary> - public class CaptureScreenshotCommandResponse : IDevtoolsResponse - { - /// <summary> - /// Gets or sets Base64-encoded image data. - /// </summary> - public string Data { get; set; } - } - } + /// <summary> + /// Capture page screenshot response. + /// </summary> + public class CaptureScreenshotCommandResponse : IDevtoolsResponse + { + /// <summary> + /// Gets or sets Base64-encoded image data. + /// </summary> + public string Data { get; set; } } -} \ No newline at end of file +} diff --git a/Runtime/ChromeDevtools/Protocol/Page/Screencast.cs b/Runtime/ChromeDevtools/Protocol/Page/Screencast.cs index a8ccbd7f71ee246d4b1599f8bc2a7588450b2ecb..7ed0cfdfafadfdf66fe70200ea9fd89cc79a3c3f 100644 --- a/Runtime/ChromeDevtools/Protocol/Page/Screencast.cs +++ b/Runtime/ChromeDevtools/Protocol/Page/Screencast.cs @@ -1,137 +1,131 @@ using Newtonsoft.Json; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Page { - namespace Protocol + /// <summary> + /// Starts sending each frame using the `screencastFrame` event. + /// "experimental": true + /// + /// No Response + /// </summary> + //[CommandResponseAttribute(typeof(StartScreencastCommandResponse))] + public class startScreencast : IDevtoolsCommand { - namespace Page + /// <summary> + /// Gets or sets Image compression format (defaults to png). + /// Can be "jpeg" or "png" + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string Format { get; set; } + /// <summary> + /// Gets or sets Compression quality from range [0..100]. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? Quality { get; set; } + /// <summary> + /// Maximum screenshot width. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int MaxWidth { get; set; } + /// <summary> + /// Maximum screenshot height. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int maxHeight { get; set; } + /// <summary> + /// Send every n-th frame. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? everyNthFrame { get; set; } + } + + + /// <summary> + /// Acknowledges that a screencast frame has been received by the frontend. + /// "experimental": true + /// </summary> + public class screencastFrameAck : IDevtoolsCommand + { + /// <summary> + /// Frame number. + /// </summary> + public int sessionId { get; set; } + } + + /// <summary> + /// Stops sending each frame in the `screencastFrame`. + /// "experimental": true + /// </summary> + public class stopScreencast : IDevtoolsCommand + { } + + /// <summary> + /// Compressed image data requested by the `startScreencast`. + /// </summary> + public class screencastFrameEvent : IDevtoolsEvent + { + /// <summary> + /// Gets or sets Base64-encoded image data. + /// </summary> + public string Data { get; set; } + /// <summary> + /// Screencast frame metadata. + /// </summary> + public Types.ScreencastFrameMetadata metadata { get; set; } + /// <summary> + /// Frame number. + /// </summary> + public int sessionId { get; set; } + } + + /// <summary> + /// Fired when the page with currently enabled screencast was shown or hidden `. + /// </summary> + public class screencastVisibilityChangedEvent : IDevtoolsEvent + { + /// <summary> + /// True if the page is visible. + /// </summary> + public bool visible { get; set; } + } + + namespace Types + { + /// <summary> + /// Screencast frame metadata. + /// </summary> + public class ScreencastFrameMetadata { /// <summary> - /// Starts sending each frame using the `screencastFrame` event. - /// "experimental": true - /// - /// No Response + /// Top offset in DIP. /// </summary> - //[CommandResponseAttribute(typeof(StartScreencastCommandResponse))] - public class startScreencast : IDevtoolsCommand - { - /// <summary> - /// Gets or sets Image compression format (defaults to png). - /// Can be "jpeg" or "png" - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string Format { get; set; } - /// <summary> - /// Gets or sets Compression quality from range [0..100]. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? Quality { get; set; } - /// <summary> - /// Maximum screenshot width. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int MaxWidth { get; set; } - /// <summary> - /// Maximum screenshot height. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int maxHeight { get; set; } - /// <summary> - /// Send every n-th frame. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public int? everyNthFrame { get; set; } - } - - + public int offsetTop { get; set; } /// <summary> - /// Acknowledges that a screencast frame has been received by the frontend. - /// "experimental": true + /// Page scale factor. /// </summary> - public class screencastFrameAck : IDevtoolsCommand - { - /// <summary> - /// Frame number. - /// </summary> - public int sessionId { get; set; } - } - + public int pageScaleFactor { get; set; } /// <summary> - /// Stops sending each frame in the `screencastFrame`. - /// "experimental": true + /// Device screen width in DIP. /// </summary> - public class stopScreencast : IDevtoolsCommand - { } - + public int deviceWidth { get; set; } /// <summary> - /// Compressed image data requested by the `startScreencast`. + /// Device screen height in DIP. /// </summary> - public class screencastFrameEvent : IDevtoolsEvent - { - /// <summary> - /// Gets or sets Base64-encoded image data. - /// </summary> - public string Data { get; set; } - /// <summary> - /// Screencast frame metadata. - /// </summary> - public Types.ScreencastFrameMetadata metadata { get; set; } - /// <summary> - /// Frame number. - /// </summary> - public int sessionId { get; set; } - } - + public int deviceHeight { get; set; } /// <summary> - /// Fired when the page with currently enabled screencast was shown or hidden `. + /// Position of horizontal scroll in CSS pixels. /// </summary> - public class screencastVisibilityChangedEvent : IDevtoolsEvent - { - /// <summary> - /// True if the page is visible. - /// </summary> - public bool visible { get; set; } - } - - namespace Types - { - /// <summary> - /// Screencast frame metadata. - /// </summary> - public class ScreencastFrameMetadata - { - /// <summary> - /// Top offset in DIP. - /// </summary> - public int offsetTop { get; set; } - /// <summary> - /// Page scale factor. - /// </summary> - public int pageScaleFactor { get; set; } - /// <summary> - /// Device screen width in DIP. - /// </summary> - public int deviceWidth { get; set; } - /// <summary> - /// Device screen height in DIP. - /// </summary> - public int deviceHeight { get; set; } - /// <summary> - /// Position of horizontal scroll in CSS pixels. - /// </summary> - public int scrollOffsetX { get; set; } - /// <summary> - /// Position of vertical scroll in CSS pixels. - /// </summary> - public int scrollOffsetY { get; set; } - /// <summary> - /// Frame swap timestamp. - /// UTC time in seconds, counted from January 1, 1970. - /// </summary> - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public long? timestamp { get; set; } - } - } + public int scrollOffsetX { get; set; } + /// <summary> + /// Position of vertical scroll in CSS pixels. + /// </summary> + public int scrollOffsetY { get; set; } + /// <summary> + /// Frame swap timestamp. + /// UTC time in seconds, counted from January 1, 1970. + /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public long? timestamp { get; set; } } } -} \ No newline at end of file +} diff --git a/Runtime/ChromeDevtools/Protocol/Target/CloseTarget.cs b/Runtime/ChromeDevtools/Protocol/Target/CloseTarget.cs index 9a129828c8b0802a02ace71060293c644a40c42e..353a4806173ae9b45cfb771ad644e2dd37465ca5 100644 --- a/Runtime/ChromeDevtools/Protocol/Target/CloseTarget.cs +++ b/Runtime/ChromeDevtools/Protocol/Target/CloseTarget.cs @@ -1,38 +1,32 @@ using Newtonsoft.Json; -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Target { - namespace Protocol + /// <summary> + /// Closes the target. If the target is a page that gets closed too. + /// </summary> + [CommandResponseAttribute(typeof(CloseTargetCommandResponse))] + public class closeTarget : IDevtoolsCommandWithResponse { - namespace Target - { - /// <summary> - /// Closes the target. If the target is a page that gets closed too. - /// </summary> - [CommandResponseAttribute(typeof(CloseTargetCommandResponse))] - public class closeTarget : IDevtoolsCommandWithResponse - { - [JsonIgnore] - public string Method { get; } = "Target.closeTarget"; + [JsonIgnore] + public string Method { get; } = "Target.closeTarget"; - public closeTarget(string targetId) => TargetId = targetId; + public closeTarget(string targetId) => TargetId = targetId; - /// <summary> - /// Gets or sets TargetId - /// </summary> - public string TargetId { get; set; } - } + /// <summary> + /// Gets or sets TargetId + /// </summary> + public string TargetId { get; set; } + } - /// <summary> - /// Closes the target. If the target is a page that gets closed too. - /// </summary> - public class CloseTargetCommandResponse - { - /// <summary> - /// Always set to true. If an error occurs, the response indicates protocol error. - /// </summary> - public bool Success { get; } - } - } + /// <summary> + /// Closes the target. If the target is a page that gets closed too. + /// </summary> + public class CloseTargetCommandResponse + { + /// <summary> + /// Always set to true. If an error occurs, the response indicates protocol error. + /// </summary> + public bool Success { get; } } -} \ No newline at end of file +} diff --git a/Runtime/ChromeDevtools/Protocol/Types/Viewport.cs b/Runtime/ChromeDevtools/Protocol/Types/Viewport.cs index 474f0432aa8b711880e7a100ed274a56eab341c8..7b2e8974a5454438ff915cc444a6a5c6d0bc510a 100644 --- a/Runtime/ChromeDevtools/Protocol/Types/Viewport.cs +++ b/Runtime/ChromeDevtools/Protocol/Types/Viewport.cs @@ -1,35 +1,29 @@ -namespace ChromeDevTools +namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Types { - namespace Protocol + /// <summary> + /// Viewport for capturing screenshot. + /// </summary> + public class Viewport { - namespace Types - { - /// <summary> - /// Viewport for capturing screenshot. - /// </summary> - public class Viewport - { - /// <summary> - /// Gets or sets X offset in CSS pixels. - /// </summary> - public double X { get; set; } = 0; - /// <summary> - /// Gets or sets Y offset in CSS pixels - /// </summary> - public double Y { get; set; } = 0; - /// <summary> - /// Gets or sets Rectangle width in CSS pixels - /// </summary> - public double Width { get; set; } = 1920; - /// <summary> - /// Gets or sets Rectangle height in CSS pixels - /// </summary> - public double Height { get; set; } = 1080; - /// <summary> - /// Gets or sets Page scale factor. - /// </summary> - public double Scale { get; set; } = 1; - } - } + /// <summary> + /// Gets or sets X offset in CSS pixels. + /// </summary> + public double X { get; set; } = 0; + /// <summary> + /// Gets or sets Y offset in CSS pixels + /// </summary> + public double Y { get; set; } = 0; + /// <summary> + /// Gets or sets Rectangle width in CSS pixels + /// </summary> + public double Width { get; set; } = 1920; + /// <summary> + /// Gets or sets Rectangle height in CSS pixels + /// </summary> + public double Height { get; set; } = 1080; + /// <summary> + /// Gets or sets Page scale factor. + /// </summary> + public double Scale { get; set; } = 1; } } diff --git a/Runtime/WebViewComponent.cs b/Runtime/WebViewComponent.cs new file mode 100644 index 0000000000000000000000000000000000000000..fa94db7f2cac7188bc05cb44471306c61509c253 --- /dev/null +++ b/Runtime/WebViewComponent.cs @@ -0,0 +1,220 @@ +using bessw.Unity.WebView.ChromeDevTools; +using bessw.Unity.WebView.ChromeDevTools.Protocol.Input; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace bessw.Unity.WebView +{ + [RequireComponent(typeof(RawImage))] + public class WebViewComponent : MonoBehaviour, IPointerDownHandler, IPointerMoveHandler, IPointerUpHandler, IPointerEnterHandler, IDropHandler, IPointerExitHandler + { + #region json serializer + + /// <summary> + /// Json serializer settings for the user space objects (e.g. transfering objects that have been droped on the BrowserView) + /// Users are allowed to change serializer settings to their liking. + /// </summary> + public static JsonSerializerSettings serializerSettings = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Converters = new List<JsonConverter>() + { + new ColorConverter(), + new Vector2Converter(), + new Vector3Converter(), + new Vector4Converter() + } + }; + /// <summary> + /// JsonSerializer for the user space objects (e.g. transfering objects that have been droped on the BrowserView) + /// Users are allowed to change serializer settings to their liking. + /// </summary> + public static JsonSerializer serializer = JsonSerializer.Create(serializerSettings); + + #endregion json serializer + + private Browser browser; + private BrowserTab tab; + + private RawImage rawImage; + private RectTransform rectTransform; + + public bool headlessBrowser = true; + //TODO: handle changed targetUrl + public string targetUrl = "https://google.de"; + + // Start is called before the first frame update + private void Start() + { + Debug.LogWarning("start Webview"); + rawImage = this.gameObject.GetComponent<RawImage>(); + rectTransform = this.gameObject.GetComponent<RectTransform>(); + } + + private void OnEnable() + { + Debug.LogWarning("enable Webview"); + Browser.headless = headlessBrowser; + browser = Browser.getInstance(); + + //StartCoroutine(GetOpenTabs()); + var c = StartCoroutine(browser.OpenNewTab(targetUrl, (BrowserTab bt) => + { + tab = bt; + StartCoroutine(tab.Update()); + //StartCoroutine(createScreenshots()); + StartCoroutine(tab.StartStream(900, 560, (frame) => + { + Debug.LogWarning("stream"); + rawImage.texture = frame; + rawImage.SetNativeSize(); + })); + })); + + } + + public IEnumerator createScreenshots () + { + yield return tab.CreateScreenshot(900, 560, (screenshot) => + { + rawImage.texture = screenshot; + StartCoroutine(createScreenshots()); + }); + } + + // Update is called once per frame + private void Update() + { + + } + + #region pointer event handlers + + public void OnPointerDown(PointerEventData eventData) + { + Vector2Int pos = toBrowserCoordinates(eventData.position); + tab.OnPointerDown(pos, eventData); + } + + public void OnPointerMove(PointerEventData eventData) + { + // TODO: transform eventData delta vector to browser coordinates + Vector2Int pos = toBrowserCoordinates(eventData.position); + tab.OnPointerMove(pos, eventData); + + // On drag over + if (eventData.dragging) + { + Debug.LogWarning($"OnDragOver: {eventData.position}"); + createDragEvent(DragEventType.dragOver, eventData); + } + } + + public void OnPointerUp(PointerEventData eventData) + { + Vector2Int pos = toBrowserCoordinates(eventData.position); + tab.OnPointerUp(pos, eventData); + } + #endregion pointer event handlers + + #region drag event handlers + public void OnPointerEnter(PointerEventData eventData) + { + if (eventData.dragging) + { + Debug.LogWarning($"OnDragEnter: {eventData.position}"); + createDragEvent(DragEventType.dragEnter, eventData); + } + } + + // TODO: OnDragMove -> PointerMove + + public void OnDrop(PointerEventData eventData) + { + Debug.LogWarning($"OnDrop: {eventData.position}"); + createDragEvent(DragEventType.drop, eventData); + } + + public void OnPointerExit(PointerEventData eventData) + { + if (eventData.dragging) + { + Debug.LogWarning($"OnDragLeave: {eventData.position}"); + //createDragEvent(DragEventType.dragCancel, eventData); + tab.CancelDragging(); + // TODO: drag cancel seems to be ignored by the browser + } + } + + private void createDragEvent(DragEventType dragEventType, PointerEventData eventData) + { + if (eventData.pointerDrag.TryGetComponent(out BrowserDropable dropable)) + { + var position = toBrowserCoordinates(eventData.position); + var dragEvent = new dispatchDragEvent + { + type = dragEventType, + data = new DragData + { + items = new DragDataItem[] + { + new DragDataItem + { + mimeType = "application/json", + data = JsonConvert.SerializeObject(dropable, serializerSettings) + } + }, + dragOperationsMask = DragOperationsMask.Copy + }, + x = position.x, + y = position.y, + }; + Debug.LogWarning($"DragEvent: {dragEvent.type}, {eventData.position}, '{dragEvent.data.items[0].data}'"); + // send the DragEvent as drag event to the browser + tab.OnDragNDrop(dragEvent); + } + } + #endregion drag event handlers + + private Vector2Int toBrowserCoordinates(Vector2 eventPos) + { + Vector2 localPoint; + RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventPos, null, out localPoint); + + // invert y because the browser has y=0 on the top + Vector2 invertedLocalPos = new Vector2(localPoint.x, rectTransform.rect.size.y - localPoint.y); + Vector2 browserCoorinate = tab.size / rectTransform.rect.size * invertedLocalPos; + Debug.Log($"eventPos: {eventPos}, invertedLocalPos: {invertedLocalPos}, browserCoordinate: {browserCoorinate}"); + return new Vector2Int((int) browserCoorinate.x, (int) browserCoorinate.y); + } + + private void OnDisable() + { + // TODO: do we want to close the browser when not in use? + // close browser when recompiling + tab.Close(); + browser.Close(); + } + private void OnDestroy() + { + tab.Close(); + browser.Close(); + } + /** + * Close all browser windows. + */ + private void OnApplicationQuit() + { + tab.Close(); + browser.Close(); + } + } + + public interface BrowserDropable { } + +} \ No newline at end of file diff --git a/Runtime/BrowserView.cs.meta b/Runtime/WebViewComponent.cs.meta similarity index 100% rename from Runtime/BrowserView.cs.meta rename to Runtime/WebViewComponent.cs.meta diff --git a/Runtime/in.esswe.browserview.asmdef b/Runtime/bessw.Unity.WebView.asmdef similarity index 89% rename from Runtime/in.esswe.browserview.asmdef rename to Runtime/bessw.Unity.WebView.asmdef index 9e6168cee46fa592aefd183d8aaa7d23f2731010..6aa252a2d055924cccfe5a3cb1d4e350e5821363 100644 --- a/Runtime/in.esswe.browserview.asmdef +++ b/Runtime/bessw.Unity.WebView.asmdef @@ -1,5 +1,5 @@ { - "name": "in.esswe.browserview", + "name": "bessw.Unity.WebView", "rootNamespace": "", "references": [], "includePlatforms": [], diff --git a/Runtime/in.esswe.browserview.asmdef.meta b/Runtime/bessw.Unity.WebView.asmdef.meta similarity index 100% rename from Runtime/in.esswe.browserview.asmdef.meta rename to Runtime/bessw.Unity.WebView.asmdef.meta diff --git a/BrowserView.prefab b/WebViewComponent.prefab similarity index 98% rename from BrowserView.prefab rename to WebViewComponent.prefab index 732b376306d20147774431dae831fa093bb693ab..4b9baec086607a73417a9ba579b51fa31a96f159 100644 --- a/BrowserView.prefab +++ b/WebViewComponent.prefab @@ -13,7 +13,7 @@ GameObject: - component: {fileID: 3767983593885104582} - component: {fileID: 2459857651630437765} m_Layer: 5 - m_Name: BrowserView + m_Name: WebViewComponent m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 diff --git a/BrowserView.prefab.meta b/WebViewComponent.prefab.meta similarity index 100% rename from BrowserView.prefab.meta rename to WebViewComponent.prefab.meta diff --git a/package.json b/package.json index 7c95cdcd4e95cf27a7a7c6ed643abb5e9ac69eb0..5241995a44bea297fd7f4665d36e0130aed3df44 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,16 @@ { - "name": "in.esswe.browserview", - "version": "0.0.1", - "description": "An interactive browser for unity running the systems browser in headless mode and rendering it to a texture instead.", - "displayName": "BrowserView", - "author": "Björn Eßwein", - "keywords": ["browser", "web", "webbrowser", "internet", "chrome", "chromium", "firefox"] + "name": "bessw.unity.webview", + "version": "0.0.2", + "description": "An interactive browser for unity running the systems browser in headless mode and rendering it to a texture instead.", + "displayName": "WebView", + "author": "Bj\u00f6rn E\u00dfwein", + "keywords": [ + "browser", + "web", + "webbrowser", + "internet", + "chrome", + "chromium", + "firefox" + ] } \ No newline at end of file