文档手册

模拟鼠标操作 按钮点击, 文本输入, 滚动条

2024-05-14 09:24:27


模拟: 按钮点击, 文本输入, 滚动条


    1. 仅在主进程中使用ipc监听renderLoadEnd事件

    2. 在渲染进程中的app.SetOnRenderLoadEnd监听渲染进程页面加载结束事件,在这个事件里获取页面html元素位置和大小

    3. html元素位置和大小获取之后触发主进程监听事件, 把要获取到的html元素位置和大小发送到主进程renderLoadEnd事件

    4. 主进程renderLoadEnd事件被触发后使用渲染进程传递的元素数据模拟事件操作

            模拟事件使用当前窗口chromium或者browser提供的函数

            chromium.SendXXX 只能在主进程中使用

            browser.SendXXX  可在主进程或渲染进程中直接使用

    5. 最后主进程回复ipc消息给渲染进程


    该示例在windows下表现较好,linux和mac输入事件键盘码需要转换以及中文问题



代码如下:


首先给渲染进程定义一个事件,让他渲染完页面后通知我们主进程:


//【渲染进程】渲染结束
app.SetOnRenderLoadEnd(func(browser *cef.ICefBrowser, frame *cef.ICefFrame, httpStatusCode int32) {
   // 浏览器ID和通道ID, 用于回复给渲染进程使用
   var (
      browserId = browser.Identifier()
      channelId = frame.Identifier()
   )
   if browserId != 1 {
      return
   }
   fmt.Println("渲染完成", browserId, channelId)
   // 创建 dom visitor
   visitor := cef.DomVisitorRef.New()
   // 通过VisitDom获取html元素的位置和大小 , SetOnVisit 函数只能在渲染进程中执行
   visitor.SetOnVisit(func(document *cef.ICefDomDocument) {
      // html > body
      body := document.GetBody()
      //获取输入框的位置
      kw := body.GetDocument().GetElementById("kw")
      // dom元素Rect集合数据发送到主进程
      var doms = make(map[string]cef.TCefRect)
      doms["kw"] = kw.GetElementBounds()
      // 触发主进程ipc监听事件
      ipc.EmitTarget("renderLoadEnd", target.NewTargetMain(), browserId, channelId, doms)
   })
   // 调用该函数后, 执行SetOnVisit回调函数
   frame.VisitDom(visitor)
})

   


//然后主进程收到通知以后,我们做一些事情


//渲染进程发过来的消息,我们拿到了搜索框开始做事情
ipc.On("renderLoadEnd", func(browserId int32, channelId int64, doms map[string]cef.TCefRect) {
   fmt.Println("渲染进程发过来大消息", doms)
   inputTextEvent("国产最棒", doms["kw"]) //中文
   jj.Sleep(1000)
   inputEnterEvent(doms["kw"])
   textareaWheelEvent(doms["kw"])
   me := &cef.TCefMouseEvent{
      Modifiers: consts.EVENTFLAG_MIDDLE_MOUSE_BUTTON, //鼠标中键按下
   }
   for i := 0; i < 3; i++ {
      var y int32 = int32(i * 100)
      me.Y = y
      fmt.Println("滚轮滚动")
      newllqChromium.SendMouseWheelEvent(me, 1, y)
      jj.Sleep(2000)
   }

   // 回复到渲染进程执行成功, 触发是Go的事件.
   ipc.EmitTarget("replyMockIsSuccess", target.NewTarget(nil, browserId, channelId, target.TgGoSub))
})




下面是模拟鼠标键盘的一些函数:


var domXYCenter = func(bound cef.TCefRect) (int32, int32) {
   return bound.X + bound.Width/2, bound.Y + bound.Height/2
}
// 模拟button点击事件
var buttonClickEvent = func(domRect cef.TCefRect) {
   // 鼠标事件
   me := &cef.TCefMouseEvent{}
   // 设置元素坐标,元素坐标相对于窗口,这里取元素中间位置
   me.X, me.Y = domXYCenter(domRect)
   // 模拟鼠标到指定位置
   newllqChromium.SendMouseMoveEvent(me, false)
   // 模拟鼠标双击事件
   //   左键点击按下1次
   newllqChromium.SendMouseClickEvent(me, consts.MBT_LEFT, false, 1)
   //   左键点击抬起1次
   newllqChromium.SendMouseClickEvent(me, consts.MBT_LEFT, true, 1)
}
// 模拟input输入
var inputTextEvent = func(value string, domRect cef.TCefRect) {
   // 点击, 获取焦点
   buttonClickEvent(domRect)
   // 一个一个字符设置
   for _, v := range value {
      newllqChromium.SendKeyEvent(keyPress(string(v)))
   }
}
//模拟输入回车键
var inputEnterEvent = func(domRect cef.TCefRect) {
   event := &cef.TCefKeyEvent{}
   var asciiCode int = 13
   event.Kind = consts.KEYEVENT_CHAR
   event.WindowsKeyCode = t.Int32(asciiCode)
   event.FocusOnEditableField = 1 // 0=false, 1=true
   newllqChromium.SendKeyEvent(event)
}

// 模拟textarea滚动
var textareaWheelEvent = func(domRect cef.TCefRect) {
   // 点击, 获取焦点
   buttonClickEvent(domRect)
   // 鼠标事件
   me := &cef.TCefMouseEvent{
      Modifiers: consts.EVENTFLAG_MIDDLE_MOUSE_BUTTON, //鼠标中键按下
   }
   // 设置元素坐标,元素坐标相对于窗口,这里取元素中间位置
   me.X, me.Y = domXYCenter(domRect)
   newllqChromium.SendMouseWheelEvent(me, -100, -100)
}

// 模拟按键输入
func keyPress(key string) *cef.TCefKeyEvent {
   utf8Key := &lcltypes.TUTF8Char{}
   utf8Key.SetString(key)
   event := &cef.TCefKeyEvent{}
   var asciiCode int
   fmt.Sscanf(utf8Key.ToString(), "%c", &asciiCode)
   fmt.Println("输入", key, asciiCode)
   event.Kind = consts.KEYEVENT_CHAR
   event.WindowsKeyCode = t.Int32(asciiCode)
   event.FocusOnEditableField = 1 // 0=false, 1=true
   return event
}