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 {
kPressedMouseEventType = 0,
kReleasedMouseEventType,
kMovedMouseEventType,
kWheelMouseEventType,
kPauseMouseEventType
};
......@@ -54,6 +55,8 @@ struct MouseEvent {
int buttons;
// |click_count| should not be negative.
int click_count;
int delta_x;
int delta_y;
PointerType pointer_type;
};
......
......@@ -72,6 +72,8 @@ const char* GetAsString(MouseEventType type) {
return "mouseReleased";
case kMovedMouseEventType:
return "mouseMoved";
case kWheelMouseEventType:
return "mouseWheel";
default:
return "";
}
......@@ -561,7 +563,8 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events,
Status status(kOk);
for (auto it = events.begin(); it != events.end(); ++it) {
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("y", it->y);
params.SetInteger("modifiers", it->modifiers);
......@@ -569,6 +572,10 @@ Status WebViewImpl::DispatchMouseEvents(const std::vector<MouseEvent>& events,
params.SetInteger("buttons", it->buttons);
params.SetInteger("clickCount", it->click_count);
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);
if (async_dispatch_events || !last_event) {
......
......@@ -956,6 +956,29 @@ class ChromeDriverTest(ChromeDriverBaseTestWithWebServer):
self.assertAlmostEqual(115, rect['x'], 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):
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
self._driver.ExecuteScript(
......
......@@ -114,6 +114,8 @@ MouseEventType StringToMouseEventType(std::string action_type) {
return kReleasedMouseEventType;
else if (action_type == "pointerMove")
return kMovedMouseEventType;
else if (action_type == "scroll")
return kWheelMouseEventType;
else if (action_type == "pause")
return kPauseMouseEventType;
else
......@@ -1211,10 +1213,11 @@ Status ProcessInputActionSequence(
const base::DictionaryValue* parameters;
std::string pointer_type;
if (!action_sequence->GetString("type", &type) ||
((type != "key") && (type != "pointer") && (type != "none"))) {
return Status(
kInvalidArgument,
"'type' must be one of the strings 'key', 'pointer' or 'none'");
((type != "key") && (type != "pointer") && (type != "wheel") &&
(type != "none"))) {
return Status(kInvalidArgument,
"'type' must be one of the strings 'key', 'pointer', 'wheel' "
"or 'none'");
}
if (!action_sequence->GetString("id", &id))
......@@ -1356,18 +1359,29 @@ Status ProcessInputActionSequence(
"'value' must be a single Unicode code point");
action->SetString("value", key);
}
} else if (type == "pointer") {
action->SetString("pointerType", pointer_type);
} else if (type == "pointer" || type == "wheel") {
std::string subtype;
if (!action_item->GetString("type", &subtype) ||
(subtype != "pointerUp" && subtype != "pointerDown" &&
subtype != "pointerMove" && subtype != "pointerCancel" &&
subtype != "pause"))
return Status(kInvalidArgument,
"type of action must be the string 'pointerUp', "
"'pointerDown', 'pointerMove' or 'pause'");
if (type == "pointer") {
if (!action_item->GetString("type", &subtype) ||
(subtype != "pointerUp" && subtype != "pointerDown" &&
subtype != "pointerMove" && subtype != "pointerCancel" &&
subtype != "pause")) {
return Status(kInvalidArgument,
"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("pointerType", pointer_type);
if (subtype == "pointerDown" || subtype == "pointerUp") {
if (pointer_type == "mouse" || pointer_type == "pen") {
......@@ -1384,7 +1398,7 @@ Status ProcessInputActionSequence(
return status;
action->SetString("button", button_str);
}
} else if (subtype == "pointerMove") {
} else if (subtype == "pointerMove" || subtype == "scroll") {
int x;
if (!action_item->GetInteger("x", &x))
return Status(kInvalidArgument, "'x' must be an int");
......@@ -1422,6 +1436,17 @@ Status ProcessInputActionSequence(
Status status = ProcessPauseAction(action_item, action.get());
if (status.IsError())
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") {
Status status = ProcessPauseAction(action_item, action.get());
if (status.IsError())
......@@ -1523,7 +1548,7 @@ Status ExecutePerformActions(Session* session,
pointer_id_set.insert(id);
action_input_states.push_back(input_state);
if (type == "pointer") {
if (type == "pointer" || type == "wheel") {
Status status = WindowViewportSize(
session, web_view, &viewport_width, &viewport_height);
if (status.IsError())
......@@ -1583,13 +1608,11 @@ Status ExecutePerformActions(Session* session,
return status;
}
}
} else if (type == "pointer") {
std::string pointer_type;
action->GetString("pointerType", &pointer_type);
} else if (type == "pointer" || type == "wheel") {
double x = 0, y = 0;
OriginType origin = kViewPort;
std::string element_id;
if (action_type == "pointerMove") {
if (action_type == "pointerMove" || action_type == "scroll") {
action->GetDouble("x", &x);
action->GetDouble("y", &y);
const base::DictionaryValue* origin_dict;
......@@ -1624,8 +1647,34 @@ Status ExecutePerformActions(Session* session,
duration = 0;
GetOptionalInt(action, "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 (action_type != "pause") {
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