• Unity EmbeddedBrowser浏览器插件事件通讯


    Unity EmbeddedBrowser浏览器插件事件通讯


    Embedded Browser浏览器插件是一款基于Chrome内核的内嵌浏览器,被许多开发语言和框架内嵌,为开发者提供方便的浏览网页支持。
    Embedded Browser浏览器的工作方式是在后台运行浏览器进程,通过后台浏览器通讯解析网址,合成Texture贴图帧,传递给Unity,同时Unity可以调用接口,与浏览器进程进行交互。

    在这里插入图片描述
    Embedded这种集成方式区别于移动端的WebView集成方式(WebView是将一块屏幕空间开辟出来给WebView使用,调用者和WebView之间没有太多关联),提供更自由的整合渠道,可以在三维空间和实体表面显示网页,使用更灵活。

    模拟鼠标输入

    通常,无论是Screen Canvas还是三维Mesh表面的Embedded页面,插件已经提供了无缝的输入方式,内部提供的MapPointerToBrowser已经帮助用户将三维坐标转换到Browser平面坐标。
    如果我们要自定义输入,如远程控制,通过远程主机发送控制坐标和鼠标按键通讯,驱动非用户硬件输入,通常做法是引入Windows DLL,通过模拟鼠标可以达到要求

      #region DLLs
      [DllImport("user32.dll")]
      private static extern int SetCursorPos(int x, int y); //设置光标位置
      [DllImport("user32.dll")]
      private static extern bool GetCursorPos(ref int x, ref int y); //获取光标位置
      [DllImport("user32.dll")]
      static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, System.UIntPtr extraInfo); // 鼠标事件
                                                                                                          // 方法参数说明
                                                                                                          // VOID mouse_event(
                                                                                                          //     DWORD dwFlags,         // motion and click options
                                                                                                          //     DWORD dx,              // horizontal position or change
                                                                                                          //     DWORD dy,              // vertical position or change
                                                                                                          //     DWORD dwData,          // wheel movement
                                                                                                          //     ULONG_PTR dwExtraInfo  // application-defined information
                                                                                                          // );
    
      public enum MouseEventFlag : uint
      {
        Move = 0x0001,
        LeftDown = 0x0002,
        LeftUp = 0x0004,
        RightDown = 0x0008,
        RightUp = 0x0010,
        MiddleDown = 0x0020,
        MiddleUp = 0x0040,
        XDown = 0x0080,
        XUp = 0x0100,
        Wheel = 0x0800,
        VirtualDesk = 0x4000,
        Absolute = 0x8000
      }
      #endregion
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    调用代码

      IEnumerator MouseClick(int x, int y)
      {
        SetCursorPos(x, y);
        mouse_event(MouseEventFlag.LeftDown, 0, 0, 0, System.UIntPtr.Zero);
        yield return new WaitForSeconds(0.1f);
        mouse_event(MouseEventFlag.LeftUp, 0, 0, 0, System.UIntPtr.Zero);
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这种方法在调试和使用时,由于窗口分辨率不是1:1全屏导致坐标映射错误、窗口不在前台、干扰正常鼠操作等等问题,使用非常不友好。

    调用Embedded接口直接输入

    查看源代码BrowserInput.cs,可以看到插件处理输入事件代码

    	private void HandleMouseInput() {
    		var handler = browser.UIHandler;
    		var mousePos = handler.MousePosition;
    		var currentButtons = handler.MouseButtons;
    		var mouseScroll = handler.MouseScroll;
    		if (mousePos != prevPos) {
    			BrowserNative.zfb_mouseMove(browser.browserId, mousePos.x, 1 - mousePos.y);
    		}
    		// ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    核心代码

    BrowserNative.zfb_mouseMove(browser.browserId, mousePos.x, 1 - mousePos.y);
    
    • 1

    EmbeddedBrowser.Browser是虚拟给Unity使用的Browser对象,实际的浏览器对象是BrowserNative定义的一系列DLL接口。
    browserId是一个数组索引,标记所有实际浏览器实例的列表
    EmbeddedBrowser.Browser创建时加入allBrowsers列表

          unsafeBrowserId = newId;
          allBrowsers[unsafeBrowserId] = this;
    
    • 1
    • 2

    按图索骥,BrowserNative包含了一系列浏览器接口,直接调用这些接口就可以扩展插件给我们定义的功能。
    代码节选

    	/**
    	 * Reports the mouse's current location.
    	 * x and y are in the range [0,1]. (0, 0) is top-left, (1, 1) is bottom-right
    	 */
    	public delegate void Calltype_zfb_mouseMove(int id, float x, float y);
    	public static Calltype_zfb_mouseMove zfb_mouseMove;
    
    
    	public delegate void Calltype_zfb_mouseButton(int id, MouseButton button, bool down, int clickCount);
    	public static Calltype_zfb_mouseButton zfb_mouseButton;
    
    
    	/** Reports a mouse scroll. One "tick" of a scroll wheel is generally around 120 units. */
    	public delegate void Calltype_zfb_mouseScroll(int id, int deltaX, int deltaY);
    	public static Calltype_zfb_mouseScroll zfb_mouseScroll;
    
    
    	/**
    	 * Report a key down/up event. Repeated "virtual" keystrokes are simulated by repeating the down event without
    	 * an interveneing up event.
    	 */
    	public delegate void Calltype_zfb_keyEvent(int id, bool down, int windowsKeyCode);
    	public static Calltype_zfb_keyEvent zfb_keyEvent;
    
    
    	/**
    	 * Report a typed character. This typically interleaves with calls to zfb_keyEvent
    	 */
    	public delegate void Calltype_zfb_characterEvent(int id, int character, int windowsKeyCode);
    	public static Calltype_zfb_characterEvent zfb_characterEvent;
    
    
    	/** Register a function to call when console.log etc. is called in the browser. */
    	public delegate void Calltype_zfb_registerConsoleCallback(int id, ConsoleFunc callback);
    	public static Calltype_zfb_registerConsoleCallback zfb_registerConsoleCallback;
    
    
    	public delegate void Calltype_zfb_evalJS(int id, string script, string scriptURL);
    	public static Calltype_zfb_evalJS zfb_evalJS;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    调用BrowserNative接口,唯一需要标记是browserId,这个在EmbeddedBrowser.Browser中是一个保护变量

        /** Handle to the native browser. */
        [NonSerialized]
        internal protected int browserId;
    
    • 1
    • 2
    • 3

    我们给他增加一个公有属性

        /** Handle to the native browser. */
        [NonSerialized]
        internal protected int browserId;
        public int BrowserId { get { return browserId; } } // 增加公有属性暴露browserId
    
    • 1
    • 2
    • 3
    • 4

    之后,我们就可以直接调用BrowserNative接口模拟鼠标输入了

      public void UpdateMouseEvent(EventType eventType, ViewRect rect)
      {
        float x = rect.x / rect.width;
        float y = rect.y / rect.height;
        Vector2 pos = MapPointerToBrowser(x, y, viewRect);
        if (eventType == EventType.MouseDown)
        {
          ZenFulcrum.EmbeddedBrowser.BrowserNative.zfb_mouseMove(browser.BrowserId, pos.x, pos.y); // 注意:x,y坐标为0-1范围
          ZenFulcrum.EmbeddedBrowser.BrowserNative.zfb_mouseButton(browser.BrowserId, ZenFulcrum.EmbeddedBrowser.BrowserNative.MouseButton.MBT_LEFT, true, 1);
        }
        else if (eventType == EventType.MouseUp)
        {
          ZenFulcrum.EmbeddedBrowser.BrowserNative.zfb_mouseButton(browser.BrowserId, ZenFulcrum.EmbeddedBrowser.BrowserNative.MouseButton.MBT_LEFT, false, 1);
        }
        else if (eventType == EventType.MouseMove)
        {
          ZenFulcrum.EmbeddedBrowser.BrowserNative.zfb_mouseMove(browser.BrowserId, pos.x, pos.y); // 注意:x,y坐标为0-1范围
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    基于ghOSt用户调度器的环境搭建
    PY32F003F18之RTC
    7-58 修理牧场——优先队列
    R语言使用nnet包的multinom函数构建无序多分类logistic回归模型、使用summary函数获取模型汇总统计信息
    怎样吃透一个java项目?
    基于SSM(SpringBoot+Mybatis+MySql+Layui)实现的健身房管理系统
    R语言的各种统计分布函数
    matlab 基操~
    【MySQL】数据库操作指南:数据类型篇
    【K8S 八】使用containerd作为CRI
  • 原文地址:https://blog.csdn.net/qq_31042143/article/details/125551279