欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

为 CDP 协议添加新的事件通知

最编程 2024-06-09 19:24:23
...

增加一个page事件回调协议

1. 在接口中添加协议:

E:\dev\chromium\src\third_party\blink\public\devtools_protocol\browser_protocol.pdl

  # Fired when a user input state changed
  # zhibin:cdp
  event javascriptDialogClosed1
    parameters
      # Whether dialog was confirmed.
      boolean result
      # User input in case of prompt.
      string userInput

自动生成的代码在:
E:\dev\chromium\src\out\Default\gen\content\browser\devtools\protocol\page.cc

2. 在page handler中实现

E:\dev\chromium\src\content\browser\devtools\protocol\page_handler.cc

#if 1//zhibin:cdp
void PageHandler::DidCloseJavaScriptDialog1(bool success,
                                           const base::string16& user_input) {
  if (!enabled_)
    return;
  
  frontend_->JavascriptDialogClosed1(success, base::UTF16ToUTF8(user_input));
}
#endif

头文件加入:
E:\dev\chromium\src\content\browser\devtools\protocol\page_handler.h

#if 1//zhibin:cdp
  void DidCloseJavaScriptDialog1(bool success, const base::string16& user_input);
#endif

3. 配置文件中添加事件 javascriptDialogClosed1

E:\dev\chromium\src\content\browser\devtools\protocol_config.json

{
                "domain": "Page",
                "include": ["enable", "disable", "reload", "navigate", "stopLoading", "getNavigationHistory", "navigateToHistoryEntry", "resetNavigationHistory", "captureScreenshot",
                    "startScreencast", "stopScreencast", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled",
                    "printToPDF", "bringToFront", "setDownloadBehavior", "getAppManifest", "crash", "close", "setWebLifecycleState", "captureSnapshot", "getInstallabilityErrors", "getManifestIcons"],
              "include_events": [ "colorPicked", "interstitialShown", "interstitialHidden", "javascriptDialogOpening", "javascriptDialogClosed", "javascriptDialogClosed1", "downloadWillBegin", "downloadProgress", "screencastVisibilityChanged", "screencastFrame" ],
                "async": ["captureScreenshot", "printToPDF", "navigate", "getAppManifest", "reload", "captureSnapshot", "getInstallabilityErrors", "getManifestIcons"]
            },

4. 提供前端实现

E:\dev\chromium\src\third_party\devtools-frontend\src\third_party\blink\public\devtools_protocol\browser_protocol.pdl

  # Fired when a user input text state changed
  # zhibin:cdp frontend.
  event javascriptDialogClosed1
    parameters
      # Whether dialog was confirmed.
      boolean result
      # User input in case of prompt.
      string userInput

写入content调用辅助类

  1. /content/browser/devtools/devtools_instrumentation.cc
    这是个全局函数
#if 1  // zhibin:cdp
void WillBeginDownload1(FrameTreeNode* frame_tree_node) {
  if (!frame_tree_node)
      return;

  base::string16 sss = base::ASCIIToUTF16("===WebView zhibin's Browser===");
  LOG(INFO) << "== TEST DidCloseJavaScriptDialog";
  DispatchToAgents(frame_tree_node,
                   &protocol::PageHandler::DidCloseJavaScriptDialog1, true, sss);
  // DispatchToAgents(ftn, &protocol::PageHandler::DownloadWillBegin, ftn,
  // item);
}
#endif

头文件中加入:
/content/browser/devtools/devtools_instrumentation.h

#if 1//zhibin:cdp
void WillBeginDownload1(FrameTreeNode* frame_tree_node);
#endif

外围调用

/content/browser/renderer_host/render_widget_host_impl.cc

#if 1//zhibin:cdp
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/renderer_host/frame_tree.h"
#endif

void RenderWidgetHostImpl::TextInputStateChanged(
    ui::mojom::TextInputStatePtr state) {
#if 1  // zhibin:cdp
  content::devtools_instrumentation::WillBeginDownload1(
      frame_tree_->GetFocusedFrame());
#endif
  if (view_)
    view_->TextInputStateChanged(*state);
}

用nodejs连接cdp示例

var Chrome = require('chrome-remote-interface');

console.log("start");
Chrome(function (chrome) {
    with (chrome) {       
        on('Page.javascriptDialogClosed1', function (time,value) {
            console.log(time);
            console.log(value);            
        });

        Page.enable();
        DOM.enable();
        console.log("nav.");
        Page.navigate({'url': 'http://192.168.30.236:8080'});
        console.log(Browser.getVersion(
            function (err, res) {
                console.log(res);
            }
        ));

    }
    console.log("call baidu end.");
}

);
console.log("end.");

新增对 text_input_state 的事件输出

  1. text_input_state的结构体

E:\dev\chromium\src\ui\base\ime\mojom\text_input_state.mojom
接口定义

// This structure represents the current editing state.
struct TextInputState {
  // Type of the input field.
  ui.mojom.TextInputType type = ui.mojom.TextInputType.NONE;

  // The mode of input field.
  ui.mojom.TextInputMode mode = ui.mojom.TextInputMode.kDefault;

  // The action of the input field.
  ui.mojom.TextInputAction action = ui.mojom.TextInputAction.kDefault;

  // The flags of input field (autocorrect, autocomplete, etc.)
  // See ui/base/ime/text_input_flags.h for definitions.
  uint32 flags;

  // The value of input field.
  mojo_base.mojom.BigString16? value;

  // The current selection range, or the caret position if nothing is selected.
  gfx.mojom.Range selection;

  // The current composition range if there is one.
  gfx.mojom.Range? composition;

  // Whether or not inline composition can be performed for the current input.
  bool can_compose_inline = true;

  // Whether or not the IME should be shown as a result of this update. Even if
  // true, the IME will only be shown if the input is appropriate (e.g. not
  // TEXT_INPUT_TYPE_NONE).
  bool show_ime_if_needed;

  // Whether or not the IME should always be hidden as a result of this update.
  bool always_hide_ime;

  // Whether or not this is a reply to a request from IME.
  bool reply_to_request;

  // Store control and selection bounds of EditContext.
  // These optionals will be nullopts if there isn't any active EditContext.
  // For non EditContext scenarios, the bounds are returned via
  // |GetCompositionCharacterBounds|
  gfx.mojom.Rect? edit_context_control_bounds;
  gfx.mojom.Rect? edit_context_selection_bounds;

  // The virtualkeyboardpolicy of the input field.
  ui.mojom.VirtualKeyboardPolicy vk_policy =
    ui.mojom.VirtualKeyboardPolicy.AUTO;

  // Whether or not show()/hide() API is called from VirtualKeyboard by web
  // authors when the virtualkeyboardpolicy is manual.
  ui.mojom.VirtualKeyboardVisibilityRequest last_vk_visibility_request =
    ui.mojom.VirtualKeyboardVisibilityRequest.NONE;

  // Information of ime text spans at the cursor position.
  array<ImeTextSpanInfo> ime_text_spans_info;
};

生成的头文件:
E:\dev\chromium\src\out\Default\gen\ui\base\ime\mojom\text_input_state.mojom.h

TextInputState(
      ::ui::TextInputType type,
      ::ui::TextInputMode mode,
      ::ui::TextInputAction action,
      uint32_t flags,
      const base::Optional<::base::string16>& value,
      const ::gfx::Range& selection,
      const base::Optional<::gfx::Range>& composition,
      bool can_compose_inline,
      bool show_ime_if_needed,
      bool always_hide_ime,
      bool reply_to_request,
      const base::Optional<::gfx::Rect>& edit_context_control_bounds,
      const base::Optional<::gfx::Rect>& edit_context_selection_bounds,
      ::ui::mojom::VirtualKeyboardPolicy vk_policy,
      ::ui::mojom::VirtualKeyboardVisibilityRequest last_vk_visibility_request,
      std::vector<ImeTextSpanInfoPtr> ime_text_spans_info);

其中ui::TextInputType定义
E:\dev\chromium\src\ui\base\ime\text_input_type.h

enum TextInputType {
  // Input caret is not in an editable node, no input method shall be used.
  TEXT_INPUT_TYPE_NONE,

  // Input caret is in a normal editable node, any input method can be used.
  TEXT_INPUT_TYPE_TEXT,

  // Input caret is in a password box, an input method may be used only if
  // it's suitable for password input.
  TEXT_INPUT_TYPE_PASSWORD,

  TEXT_INPUT_TYPE_SEARCH,
  TEXT_INPUT_TYPE_EMAIL,
  TEXT_INPUT_TYPE_NUMBER,
  TEXT_INPUT_TYPE_TELEPHONE,
  TEXT_INPUT_TYPE_URL,
  TEXT_INPUT_TYPE_DATE,
  TEXT_INPUT_TYPE_DATE_TIME,
  TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
  TEXT_INPUT_TYPE_MONTH,
  TEXT_INPUT_TYPE_TIME,
  TEXT_INPUT_TYPE_WEEK,
  TEXT_INPUT_TYPE_TEXT_AREA,

  // Input caret is in a contenteditable node (not an INPUT field).
  TEXT_INPUT_TYPE_CONTENT_EDITABLE,

  // The focused node is date time field. The date time field does not have
  // input caret but it is necessary to distinguish from TEXT_INPUT_TYPE_NONE
  // for on-screen keyboard.
  TEXT_INPUT_TYPE_DATE_TIME_FIELD,

  // Input caret is in an editable node which doesn't support rich editing.
  // It means that the editable node cannot support the features like candidate
  // texts and retrieving text around cursor.
  // However, it still can process raw key events and needs the on-screen
  // keyboard if it wants.
  TEXT_INPUT_TYPE_NULL,

  TEXT_INPUT_TYPE_MAX = TEXT_INPUT_TYPE_NULL,
};
  • text_input_state对象生成
    ui::mojom::blink::TextInputStatePtr params =
        ui::mojom::blink::TextInputState::New();
    params->type = new_type;
    params->mode = new_mode;
    params->action = new_info.action;
    params->flags = new_info.flags;
    params->vk_policy = new_vk_policy;
    params->last_vk_visibility_request = last_vk_visibility_request;
    params->edit_context_control_bounds = control_bounds;
    params->edit_context_selection_bounds = selection_bounds;

    if (!new_info.ime_text_spans.empty()) {
      params->ime_text_spans_info =
          frame_widget->GetImeTextSpansInfo(new_info.ime_text_spans);
    }
#if defined(OS_ANDROID)
    if (next_previous_flags_ == kInvalidNextPreviousFlagsValue) {
      // Due to a focus change, values will be reset by the frame.
      // That case we only need fresh NEXT/PREVIOUS information.
      // Also we won't send WidgetHostMsg_TextInputStateChanged if next/previous
      // focusable status is changed.
      if (frame_widget) {
        next_previous_flags_ =
            frame_widget->ComputeWebTextInputNextPreviousFlags();
      } else {
        // For safety in case GetInputMethodController() is null, because -1 is
        // invalid value to send to browser process.
        next_previous_flags_ = 0;
      }
    }
#else
    next_previous_flags_ = 0;
#endif
    params->flags |= next_previous_flags_;
    params->value = new_info.value;
    params->selection =
        gfx::Range(new_info.selection_start, new_info.selection_end);
    if (new_info.composition_start != -1) {
      params->composition =
          gfx::Range(new_info.composition_start, new_info.composition_end);
    }
    params->can_compose_inline = new_can_compose_inline;
    // TODO(changwan): change instances of show_ime_if_needed to
    // show_virtual_keyboard.
    params->show_ime_if_needed = show_virtual_keyboard;
    params->always_hide_ime = always_hide_ime;
    params->reply_to_request = reply_to_request;
    widget_host_->TextInputStateChanged(std::move(params));
  • 在 browser_protocol.pdl 协议中定义的 DOM.rect.

在domain的DOM中定义了Rect,如下

  # Rectangle.
  type Rect extends object
    properties
      # X coordinate
      number x
      # Y coordinate
      number y
      # Rectangle width
      number width
      # Rectangle height
      number height

在DOM domain中可以直接引用,如

  experimental command scrollIntoViewIfNeeded
    parameters
      # Identifier of the node.
      optional NodeId nodeId
      # Identifier of the backend node.
      optional BackendNodeId backendNodeId
      # JavaScript object id of the node wrapper.
      optional Runtime.RemoteObjectId objectId
      # The rect to be scrolled into view, relative to the node's border box, in CSS pixels.
      # When omitted, center of the node will be used, similar to Element.scrollIntoView.
      optional Rect rect

在domain DOM外,需要指定域名DOM, 如

    parameters
      # type.
      number type
      # show_ime_if_needed.
      boolean show_ime_if_needed
      # always_hide_ime.
      boolean always_hide_ime
      #edit_context_control_bounds.
      #Rect edit_context_control_bounds
      optional DOM.Rect rect
  • 编译后会生成protocol::DOM::Rect,头文件存放在:
    gen\content/browser/devtools/protocol/dom.h

转换成DOM.Rect 函数


static std::unique_ptr<protocol::DOM::Rect> BuildObjectForRect(
    const gfx::Rect& rect) {
  return protocol::DOM::Rect::create()
      .setX(rect.x())
      .setY(rect.y())
      .setHeight(rect.height())
      .setWidth(rect.width())
      .build();
}

//构造number
String::Number("")

原文地址:https://www.cnblogs.com/bigben0123/p/14736141.html

推荐阅读