Commit c44000bc authored by Lan Wei's avatar Lan Wei Committed by Commit Bot

Reland "Support Wheel input source in Action API"

We will add a new input source type to simulate the mouse wheel scroll
to the Webdriver Action API, https://github.com/w3c/webdriver/pull/1522.

In this CL, we are adding the wheel input source in the ChromeDriver's
ExecutePerformActions function, which implements the Webdriver Action
API in Chrome and we will use Devtool's input protocol,
Input.dispatchMouseEvent with a type of "mouseWheel".

I added some waiting time to wait for the action to be executed to fix
the failure on Mac 14 test.

TBR=johnchen@chromium.org

Bug: 1040611
Change-Id: I348c71bacc32b403ba995c1c736b6bfb230b65aa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2337255Reviewed-by: default avatarLan Wei <lanwei@chromium.org>
Commit-Queue: Lan Wei <lanwei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#794706}
parent be55ab80
...@@ -16,6 +16,7 @@ enum MouseEventType { ...@@ -16,6 +16,7 @@ enum MouseEventType {
kPressedMouseEventType = 0, kPressedMouseEventType = 0,
kReleasedMouseEventType, kReleasedMouseEventType,
kMovedMouseEventType, kMovedMouseEventType,
kWheelMouseEventType,
kPauseMouseEventType kPauseMouseEventType
}; };
...@@ -54,6 +55,8 @@ struct MouseEvent { ...@@ -54,6 +55,8 @@ struct MouseEvent {
int buttons; int buttons;
// |click_count| should not be negative. // |click_count| should not be negative.
int click_count; int click_count;
int delta_x;
int delta_y;
PointerType pointer_type; PointerType pointer_type;
}; };
......
...@@ -72,6 +72,8 @@ const char* GetAsString(MouseEventType type) { ...@@ -72,6 +72,8 @@ const char* GetAsString(MouseEventType type) {
return "mouseReleased"; return "mouseReleased";
case kMovedMouseEventType: case kMovedMouseEventType:
return "mouseMoved"; return "mouseMoved";
case kWheelMouseEventType:
return "mouseWheel";
default: default:
return ""; return "";
} }
...@@ -561,7 +563,8 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events, ...@@ -561,7 +563,8 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events,
Status status(kOk); Status status(kOk);
for (auto it = events.begin(); it != events.end(); ++it) { for (auto it = events.begin(); it != events.end(); ++it) {
base::DictionaryValue params; base::DictionaryValue params;
params.SetString("type", GetAsString(it->type)); std::string type = GetAsString(it->type);
params.SetString("type", type);
params.SetInteger("x", it->x); params.SetInteger("x", it->x);
params.SetInteger("y", it->y); params.SetInteger("y", it->y);
params.SetInteger("modifiers", it->modifiers); params.SetInteger("modifiers", it->modifiers);
...@@ -569,6 +572,10 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events, ...@@ -569,6 +572,10 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events,
params.SetInteger("buttons", it->buttons); params.SetInteger("buttons", it->buttons);
params.SetInteger("clickCount", it->click_count); params.SetInteger("clickCount", it->click_count);
params.SetString("pointerType", GetAsString(it->pointer_type)); params.SetString("pointerType", GetAsString(it->pointer_type));
if (type == "mouseWheel") {
params.SetInteger("deltaX", it->delta_x);
params.SetInteger("deltaY", it->delta_y);
}
const bool last_event = (it == events.end() - 1); const bool last_event = (it == events.end() - 1);
if (async_dispatch_events || !last_event) { if (async_dispatch_events || !last_event) {
......
...@@ -956,6 +956,29 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer): ...@@ -956,6 +956,29 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer):
self.assertAlmostEqual(115, rect['x'], delta=1) self.assertAlmostEqual(115, rect['x'], delta=1)
self.assertAlmostEqual(145, rect['y'], delta=1) self.assertAlmostEqual(145, rect['y'], delta=1)
def testActionsWheelScroll(self):
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
self._driver.ExecuteScript(
'document.body.innerHTML = "<div>old</div>";'
'var div = document.getElementsByTagName("div")[0];'
'div.style["width"] = "100px";'
'div.style["height"] = "1000px";'
'div.addEventListener("wheel", function() {'
' var div = document.getElementsByTagName("div")[0];'
' div.innerHTML="new<br>";'
'});'
'return div;')
time.sleep(1)
actions = ({"actions": [{
"type":"wheel",
"actions":[{"type": "scroll", "x": 10, "y": 10, "deltaX": 5,
"deltaY": 15}],
"id": "wheel1"}]})
time.sleep(1)
self._driver.PerformActions(actions)
time.sleep(1)
self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
def testActionsTouchTap(self): def testActionsTouchTap(self):
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html')) self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
self._driver.ExecuteScript( self._driver.ExecuteScript(
......
...@@ -114,6 +114,8 @@ MouseEventType StringToMouseEventType(std::string action_type) { ...@@ -114,6 +114,8 @@ MouseEventType StringToMouseEventType(std::string action_type) {
return kReleasedMouseEventType; return kReleasedMouseEventType;
else if (action_type == "pointerMove") else if (action_type == "pointerMove")
return kMovedMouseEventType; return kMovedMouseEventType;
else if (action_type == "scroll")
return kWheelMouseEventType;
else if (action_type == "pause") else if (action_type == "pause")
return kPauseMouseEventType; return kPauseMouseEventType;
else else
...@@ -1211,10 +1213,11 @@ Status ProcessInputActionSequence( ...@@ -1211,10 +1213,11 @@ Status ProcessInputActionSequence(
const base::DictionaryValue* parameters; const base::DictionaryValue* parameters;
std::string pointer_type; std::string pointer_type;
if (!action_sequence->GetString("type", &type) || if (!action_sequence->GetString("type", &type) ||
((type != "key") && (type != "pointer") && (type != "none"))) { ((type != "key") && (type != "pointer") && (type != "wheel") &&
return Status( (type != "none"))) {
kInvalidArgument, return Status(kInvalidArgument,
"'type' must be one of the strings 'key', 'pointer' or 'none'"); "'type' must be one of the strings 'key', 'pointer', 'wheel' "
"or 'none'");
} }
if (!action_sequence->GetString("id", &id)) if (!action_sequence->GetString("id", &id))
...@@ -1356,18 +1359,29 @@ Status ProcessInputActionSequence( ...@@ -1356,18 +1359,29 @@ Status ProcessInputActionSequence(
"'value' must be a single Unicode code point"); "'value' must be a single Unicode code point");
action->SetString("value", key); action->SetString("value", key);
} }
} else if (type == "pointer") { } else if (type == "pointer" || type == "wheel") {
action->SetString("pointerType", pointer_type);
std::string subtype; std::string subtype;
if (!action_item->GetString("type", &subtype) || if (type == "pointer") {
(subtype != "pointerUp" && subtype != "pointerDown" && if (!action_item->GetString("type", &subtype) ||
subtype != "pointerMove" && subtype != "pointerCancel" && (subtype != "pointerUp" && subtype != "pointerDown" &&
subtype != "pause")) subtype != "pointerMove" && subtype != "pointerCancel" &&
return Status(kInvalidArgument, subtype != "pause")) {
"type of action must be the string 'pointerUp', " return Status(kInvalidArgument,
"'pointerDown', 'pointerMove' or 'pause'"); "type of pointer action must be the string "
"'pointerUp', 'pointerDown', 'pointerMove' or "
"'pause'");
}
} else {
if (!action_item->GetString("type", &subtype) ||
(subtype != "scroll" && subtype != "pause")) {
return Status(
kInvalidArgument,
"type of action must be the string 'scroll' or 'pause'");
}
}
action->SetString("subtype", subtype); action->SetString("subtype", subtype);
action->SetString("pointerType", pointer_type);
if (subtype == "pointerDown" || subtype == "pointerUp") { if (subtype == "pointerDown" || subtype == "pointerUp") {
if (pointer_type == "mouse" || pointer_type == "pen") { if (pointer_type == "mouse" || pointer_type == "pen") {
...@@ -1384,7 +1398,7 @@ Status ProcessInputActionSequence( ...@@ -1384,7 +1398,7 @@ Status ProcessInputActionSequence(
return status; return status;
action->SetString("button", button_str); action->SetString("button", button_str);
} }
} else if (subtype == "pointerMove") { } else if (subtype == "pointerMove" || subtype == "scroll") {
int x; int x;
if (!action_item->GetInteger("x", &x)) if (!action_item->GetInteger("x", &x))
return Status(kInvalidArgument, "'x' must be an int"); return Status(kInvalidArgument, "'x' must be an int");
...@@ -1422,6 +1436,17 @@ Status ProcessInputActionSequence( ...@@ -1422,6 +1436,17 @@ Status ProcessInputActionSequence(
Status status = ProcessPauseAction(action_item, action.get()); Status status = ProcessPauseAction(action_item, action.get());
if (status.IsError()) if (status.IsError())
return status; return status;
if (subtype == "scroll") {
int delta_x;
if (!action_item->GetInteger("deltaX", &delta_x))
return Status(kInvalidArgument, "'delta x' must be an int");
int delta_y;
if (!action_item->GetInteger("deltaY", &delta_y))
return Status(kInvalidArgument, "'delta y' must be an int");
action->SetInteger("deltaX", delta_x);
action->SetInteger("deltaY", delta_y);
}
} else if (subtype == "pause") { } else if (subtype == "pause") {
Status status = ProcessPauseAction(action_item, action.get()); Status status = ProcessPauseAction(action_item, action.get());
if (status.IsError()) if (status.IsError())
...@@ -1523,7 +1548,7 @@ Status ExecutePerformActions(Session* session, ...@@ -1523,7 +1548,7 @@ Status ExecutePerformActions(Session* session,
pointer_id_set.insert(id); pointer_id_set.insert(id);
action_input_states.push_back(input_state); action_input_states.push_back(input_state);
if (type == "pointer") { if (type == "pointer" || type == "wheel") {
Status status = WindowViewportSize( Status status = WindowViewportSize(
session, web_view, &viewport_width, &viewport_height); session, web_view, &viewport_width, &viewport_height);
if (status.IsError()) if (status.IsError())
...@@ -1583,13 +1608,11 @@ Status ExecutePerformActions(Session* session, ...@@ -1583,13 +1608,11 @@ Status ExecutePerformActions(Session* session,
return status; return status;
} }
} }
} else if (type == "pointer") { } else if (type == "pointer" || type == "wheel") {
std::string pointer_type;
action->GetString("pointerType", &pointer_type);
double x = 0, y = 0; double x = 0, y = 0;
OriginType origin = kViewPort; OriginType origin = kViewPort;
std::string element_id; std::string element_id;
if (action_type == "pointerMove") { if (action_type == "pointerMove" || action_type == "scroll") {
action->GetDouble("x", &x); action->GetDouble("x", &x);
action->GetDouble("y", &y); action->GetDouble("y", &y);
const base::DictionaryValue* origin_dict; const base::DictionaryValue* origin_dict;
...@@ -1624,8 +1647,34 @@ Status ExecutePerformActions(Session* session, ...@@ -1624,8 +1647,34 @@ Status ExecutePerformActions(Session* session,
duration = 0; duration = 0;
GetOptionalInt(action, "duration", &duration); GetOptionalInt(action, "duration", &duration);
tick_duration = std::max(tick_duration, duration); tick_duration = std::max(tick_duration, duration);
if (action_type == "scroll") {
int delta_x = 0, delta_y = 0;
action->GetInteger("deltaX", &delta_x);
action->GetInteger("deltaY", &delta_y);
std::vector<MouseEvent> dispatch_wheel_events;
MouseEvent event(StringToMouseEventType(action_type),
StringToMouseButton(button_type[id]),
action_locations[id].x(),
action_locations[id].y(), 0, buttons[id], 0);
event.modifiers = session->sticky_modifiers;
event.delta_x = delta_x;
event.delta_y = delta_y;
buttons[id] |= StringToModifierMouseButton(button_type[id]);
session->mouse_position = WebPoint(event.x, event.y);
session->input_cancel_list.emplace_back(
action_input_states[j], &event, nullptr, nullptr);
dispatch_wheel_events.push_back(event);
Status status = web_view->DispatchMouseEvents(
dispatch_wheel_events, session->GetCurrentFrameId(),
async_dispatch_event);
if (status.IsError())
return status;
}
} }
std::string pointer_type;
action->GetString("pointerType", &pointer_type);
if (pointer_type == "mouse" || pointer_type == "pen") { if (pointer_type == "mouse" || pointer_type == "pen") {
if (action_type != "pause") { if (action_type != "pause") {
std::vector<MouseEvent> dispatch_mouse_events; std::vector<MouseEvent> dispatch_mouse_events;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment