Remove obsolete SynthesizeScrollGesture method.
[chromium-blink-merge.git] / content / browser / devtools / protocol / input_handler.cc
blobeaa72bdd19ebe5c292c6bbe6776ffebf24c39b38
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/protocol/input_handler.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/trace_event/trace_event.h"
11 #include "cc/output/compositor_frame_metadata.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/common/input/synthetic_pinch_gesture_params.h"
14 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
15 #include "content/common/input/synthetic_tap_gesture_params.h"
16 #include "third_party/WebKit/public/web/WebInputEvent.h"
17 #include "ui/events/keycodes/dom/keycode_converter.h"
18 #include "ui/gfx/geometry/point.h"
20 namespace content {
21 namespace devtools {
22 namespace input {
24 namespace {
26 gfx::Point CssPixelsToPoint(int x, int y, float page_scale_factor) {
27 return gfx::Point(x * page_scale_factor, y * page_scale_factor);
30 gfx::Vector2d CssPixelsToVector2d(int x, int y, float page_scale_factor) {
31 return gfx::Vector2d(x * page_scale_factor, y * page_scale_factor);
34 bool StringToGestureSourceType(const std::string& in,
35 SyntheticGestureParams::GestureSourceType& out) {
36 if (in == kGestureSourceTypeDefault) {
37 out = SyntheticGestureParams::GestureSourceType::DEFAULT_INPUT;
38 return true;
39 } else if (in == kGestureSourceTypeTouch) {
40 out = SyntheticGestureParams::GestureSourceType::TOUCH_INPUT;
41 return true;
42 } else if (in == kGestureSourceTypeMouse) {
43 out = SyntheticGestureParams::GestureSourceType::MOUSE_INPUT;
44 return true;
45 } else {
46 return false;
52 typedef DevToolsProtocolClient::Response Response;
54 namespace {
56 void SetEventModifiers(blink::WebInputEvent* event, const int* modifiers) {
57 if (!modifiers)
58 return;
59 if (*modifiers & 1)
60 event->modifiers |= blink::WebInputEvent::AltKey;
61 if (*modifiers & 2)
62 event->modifiers |= blink::WebInputEvent::ControlKey;
63 if (*modifiers & 4)
64 event->modifiers |= blink::WebInputEvent::MetaKey;
65 if (*modifiers & 8)
66 event->modifiers |= blink::WebInputEvent::ShiftKey;
69 void SetEventTimestamp(blink::WebInputEvent* event, const double* timestamp) {
70 event->timeStampSeconds =
71 timestamp ? *timestamp : base::Time::Now().ToDoubleT();
74 bool SetKeyboardEventText(blink::WebUChar* to, const std::string* from) {
75 if (!from)
76 return true;
78 base::string16 text16 = base::UTF8ToUTF16(*from);
79 if (text16.size() > blink::WebKeyboardEvent::textLengthCap)
80 return false;
82 for (size_t i = 0; i < text16.size(); ++i)
83 to[i] = text16[i];
84 return true;
87 bool SetMouseEventButton(blink::WebMouseEvent* event,
88 const std::string* button) {
89 if (!button)
90 return true;
92 if (*button == dispatch_mouse_event::kButtonNone) {
93 event->button = blink::WebMouseEvent::ButtonNone;
94 } else if (*button == dispatch_mouse_event::kButtonLeft) {
95 event->button = blink::WebMouseEvent::ButtonLeft;
96 event->modifiers |= blink::WebInputEvent::LeftButtonDown;
97 } else if (*button == dispatch_mouse_event::kButtonMiddle) {
98 event->button = blink::WebMouseEvent::ButtonMiddle;
99 event->modifiers |= blink::WebInputEvent::MiddleButtonDown;
100 } else if (*button == dispatch_mouse_event::kButtonRight) {
101 event->button = blink::WebMouseEvent::ButtonRight;
102 event->modifiers |= blink::WebInputEvent::RightButtonDown;
103 } else {
104 return false;
106 return true;
109 bool SetMouseEventType(blink::WebMouseEvent* event, const std::string& type) {
110 if (type == dispatch_mouse_event::kTypeMousePressed) {
111 event->type = blink::WebInputEvent::MouseDown;
112 } else if (type == dispatch_mouse_event::kTypeMouseReleased) {
113 event->type = blink::WebInputEvent::MouseUp;
114 } else if (type == dispatch_mouse_event::kTypeMouseMoved) {
115 event->type = blink::WebInputEvent::MouseMove;
116 } else {
117 return false;
119 return true;
122 } // namespace
124 InputHandler::InputHandler()
125 : host_(NULL),
126 page_scale_factor_(1.0),
127 weak_factory_(this) {
130 InputHandler::~InputHandler() {
133 void InputHandler::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
134 host_ = host;
137 void InputHandler::SetClient(scoped_ptr<Client> client) {
138 client_.swap(client);
141 void InputHandler::OnSwapCompositorFrame(
142 const cc::CompositorFrameMetadata& frame_metadata) {
143 page_scale_factor_ = frame_metadata.page_scale_factor;
144 scrollable_viewport_size_ = frame_metadata.scrollable_viewport_size;
147 Response InputHandler::DispatchKeyEvent(
148 const std::string& type,
149 const int* modifiers,
150 const double* timestamp,
151 const std::string* text,
152 const std::string* unmodified_text,
153 const std::string* key_identifier,
154 const std::string* code,
155 const std::string* key,
156 const int* windows_virtual_key_code,
157 const int* native_virtual_key_code,
158 const bool* auto_repeat,
159 const bool* is_keypad,
160 const bool* is_system_key) {
161 NativeWebKeyboardEvent event;
163 if (type == dispatch_key_event::kTypeKeyDown) {
164 event.type = blink::WebInputEvent::KeyDown;
165 } else if (type == dispatch_key_event::kTypeKeyUp) {
166 event.type = blink::WebInputEvent::KeyUp;
167 } else if (type == dispatch_key_event::kTypeChar) {
168 event.type = blink::WebInputEvent::Char;
169 } else if (type == dispatch_key_event::kTypeRawKeyDown) {
170 event.type = blink::WebInputEvent::RawKeyDown;
171 } else {
172 return Response::InvalidParams(
173 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
176 SetEventModifiers(&event, modifiers);
177 SetEventTimestamp(&event, timestamp);
178 if (!SetKeyboardEventText(event.text, text))
179 return Response::InvalidParams("Invalid 'text' parameter");
180 if (!SetKeyboardEventText(event.unmodifiedText, unmodified_text))
181 return Response::InvalidParams("Invalid 'unmodifiedText' parameter");
183 if (windows_virtual_key_code)
184 event.windowsKeyCode = *windows_virtual_key_code;
185 if (native_virtual_key_code)
186 event.nativeKeyCode = *native_virtual_key_code;
187 if (auto_repeat && *auto_repeat)
188 event.modifiers |= blink::WebInputEvent::IsAutoRepeat;
189 if (is_keypad && *is_keypad)
190 event.modifiers |= blink::WebInputEvent::IsKeyPad;
191 if (is_system_key)
192 event.isSystemKey = *is_system_key;
194 if (key_identifier) {
195 if (key_identifier->size() >
196 blink::WebKeyboardEvent::keyIdentifierLengthCap) {
197 return Response::InvalidParams("Invalid 'keyIdentifier' parameter");
199 for (size_t i = 0; i < key_identifier->size(); ++i)
200 event.keyIdentifier[i] = (*key_identifier)[i];
201 } else if (event.type != blink::WebInputEvent::Char) {
202 event.setKeyIdentifierFromWindowsKeyCode();
205 if (code) {
206 event.domCode = static_cast<int>(
207 ui::KeycodeConverter::CodeStringToDomCode(code->c_str()));
210 if (key) {
211 event.domKey = static_cast<int>(
212 ui::KeycodeConverter::KeyStringToDomKey(key->c_str()));
215 if (!host_)
216 return Response::ServerError("Could not connect to view");
218 host_->Focus();
219 host_->ForwardKeyboardEvent(event);
220 return Response::OK();
223 Response InputHandler::DispatchMouseEvent(
224 const std::string& type,
225 int x,
226 int y,
227 const int* modifiers,
228 const double* timestamp,
229 const std::string* button,
230 const int* click_count) {
231 blink::WebMouseEvent event;
233 if (!SetMouseEventType(&event, type)) {
234 return Response::InvalidParams(
235 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
237 SetEventModifiers(&event, modifiers);
238 SetEventTimestamp(&event, timestamp);
239 if (!SetMouseEventButton(&event, button))
240 return Response::InvalidParams("Invalid mouse button");
242 event.x = x * page_scale_factor_;
243 event.y = y * page_scale_factor_;
244 event.windowX = x * page_scale_factor_;
245 event.windowY = y * page_scale_factor_;
246 event.globalX = x * page_scale_factor_;
247 event.globalY = y * page_scale_factor_;
248 event.clickCount = click_count ? *click_count : 0;
250 if (!host_)
251 return Response::ServerError("Could not connect to view");
253 host_->Focus();
254 host_->ForwardMouseEvent(event);
255 return Response::OK();
258 Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
259 int x,
260 int y,
261 double timestamp,
262 const std::string& button,
263 double* delta_x,
264 double* delta_y,
265 int* modifiers,
266 int* click_count) {
267 blink::WebMouseWheelEvent wheel_event;
268 blink::WebMouseEvent mouse_event;
269 blink::WebMouseEvent* event = &mouse_event;
271 if (type == emulate_touch_from_mouse_event::kTypeMouseWheel) {
272 if (!delta_x || !delta_y) {
273 return Response::InvalidParams(
274 "'deltaX' and 'deltaY' are expected for mouseWheel event");
276 wheel_event.deltaX = static_cast<float>(*delta_x);
277 wheel_event.deltaY = static_cast<float>(*delta_y);
278 event = &wheel_event;
279 event->type = blink::WebInputEvent::MouseWheel;
280 } else if (!SetMouseEventType(event, type)) {
281 return Response::InvalidParams(
282 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
285 SetEventModifiers(event, modifiers);
286 SetEventTimestamp(event, &timestamp);
287 if (!SetMouseEventButton(event, &button))
288 return Response::InvalidParams("Invalid mouse button");
290 event->x = x;
291 event->y = y;
292 event->windowX = x;
293 event->windowY = y;
294 event->globalX = x;
295 event->globalY = y;
296 event->clickCount = click_count ? *click_count : 0;
298 if (!host_)
299 return Response::ServerError("Could not connect to view");
301 if (event->type == blink::WebInputEvent::MouseWheel)
302 host_->ForwardWheelEvent(wheel_event);
303 else
304 host_->ForwardMouseEvent(mouse_event);
305 return Response::OK();
308 Response InputHandler::SynthesizePinchGesture(
309 DevToolsCommandId command_id,
310 int x,
311 int y,
312 double scale_factor,
313 const int* relative_speed,
314 const std::string* gesture_source_type) {
315 if (!host_)
316 return Response::ServerError("Could not connect to view");
318 SyntheticPinchGestureParams gesture_params;
319 const int kDefaultRelativeSpeed = 800;
321 gesture_params.scale_factor = scale_factor;
322 gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
323 gesture_params.relative_pointer_speed_in_pixels_s =
324 relative_speed ? *relative_speed : kDefaultRelativeSpeed;
326 if (!StringToGestureSourceType(
327 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
328 gesture_params.gesture_source_type)) {
329 return Response::InvalidParams("gestureSourceType");
332 host_->QueueSyntheticGesture(
333 SyntheticGesture::Create(gesture_params),
334 base::Bind(&InputHandler::SendSynthesizePinchGestureResponse,
335 weak_factory_.GetWeakPtr(), command_id));
337 return Response::OK();
340 Response InputHandler::SynthesizeScrollGesture(
341 DevToolsCommandId command_id,
342 int x,
343 int y,
344 const int* x_distance,
345 const int* y_distance,
346 const int* x_overscroll,
347 const int* y_overscroll,
348 const bool* prevent_fling,
349 const int* speed,
350 const std::string* gesture_source_type,
351 const int* repeat_count,
352 const int* repeat_delay_ms,
353 const std::string* interaction_marker_name) {
354 if (!host_)
355 return Response::ServerError("Could not connect to view");
357 SyntheticSmoothScrollGestureParams gesture_params;
358 const bool kDefaultPreventFling = true;
359 const int kDefaultSpeed = 800;
361 gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
362 gesture_params.prevent_fling =
363 prevent_fling ? *prevent_fling : kDefaultPreventFling;
364 gesture_params.speed_in_pixels_s = speed ? *speed : kDefaultSpeed;
366 if (x_distance || y_distance) {
367 gesture_params.distances.push_back(
368 CssPixelsToVector2d(x_distance ? *x_distance : 0,
369 y_distance ? *y_distance : 0,
370 page_scale_factor_));
373 if (x_overscroll || y_overscroll) {
374 gesture_params.distances.push_back(
375 CssPixelsToVector2d(x_overscroll ? -*x_overscroll : 0,
376 y_overscroll ? -*y_overscroll : 0,
377 page_scale_factor_));
380 if (!StringToGestureSourceType(
381 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
382 gesture_params.gesture_source_type)) {
383 return Response::InvalidParams("gestureSourceType");
386 SynthesizeRepeatingScroll(
387 gesture_params, repeat_count ? *repeat_count : 0,
388 base::TimeDelta::FromMilliseconds(repeat_delay_ms ? *repeat_delay_ms
389 : 250),
390 interaction_marker_name ? *interaction_marker_name : "", command_id);
392 return Response::OK();
395 void InputHandler::SynthesizeRepeatingScroll(
396 SyntheticSmoothScrollGestureParams gesture_params,
397 int repeat_count,
398 base::TimeDelta repeat_delay,
399 std::string interaction_marker_name,
400 DevToolsCommandId command_id) {
401 if (!interaction_marker_name.empty()) {
402 // TODO(alexclarke): Can we move this elsewhere? It doesn't really fit here.
403 TRACE_EVENT_COPY_ASYNC_BEGIN0("benchmark",
404 interaction_marker_name.c_str(), command_id);
407 host_->QueueSyntheticGesture(
408 SyntheticGesture::Create(gesture_params),
409 base::Bind(&InputHandler::OnScrollFinished, weak_factory_.GetWeakPtr(),
410 gesture_params, repeat_count, repeat_delay,
411 interaction_marker_name, command_id));
414 void InputHandler::OnScrollFinished(
415 SyntheticSmoothScrollGestureParams gesture_params,
416 int repeat_count,
417 base::TimeDelta repeat_delay,
418 std::string interaction_marker_name,
419 DevToolsCommandId command_id,
420 SyntheticGesture::Result result) {
421 if (!interaction_marker_name.empty()) {
422 TRACE_EVENT_COPY_ASYNC_END0("benchmark",
423 interaction_marker_name.c_str(), command_id);
426 if (repeat_count > 0) {
427 base::MessageLoop::current()->task_runner()->PostDelayedTask(
428 FROM_HERE,
429 base::Bind(&InputHandler::SynthesizeRepeatingScroll,
430 weak_factory_.GetWeakPtr(), gesture_params, repeat_count - 1,
431 repeat_delay, interaction_marker_name, command_id),
432 repeat_delay);
433 } else {
434 SendSynthesizeScrollGestureResponse(command_id, result);
438 Response InputHandler::SynthesizeTapGesture(
439 DevToolsCommandId command_id,
440 int x,
441 int y,
442 const int* duration,
443 const int* tap_count,
444 const std::string* gesture_source_type) {
445 if (!host_)
446 return Response::ServerError("Could not connect to view");
448 SyntheticTapGestureParams gesture_params;
449 const int kDefaultDuration = 50;
450 const int kDefaultTapCount = 1;
452 gesture_params.position = CssPixelsToPoint(x, y, page_scale_factor_);
453 gesture_params.duration_ms = duration ? *duration : kDefaultDuration;
455 if (!StringToGestureSourceType(
456 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
457 gesture_params.gesture_source_type)) {
458 return Response::InvalidParams("gestureSourceType");
461 if (!tap_count)
462 tap_count = &kDefaultTapCount;
464 for (int i = 0; i < *tap_count; i++) {
465 // If we're doing more than one tap, don't send the response to the client
466 // until we've completed the last tap.
467 bool is_last_tap = i == *tap_count - 1;
468 host_->QueueSyntheticGesture(
469 SyntheticGesture::Create(gesture_params),
470 base::Bind(&InputHandler::SendSynthesizeTapGestureResponse,
471 weak_factory_.GetWeakPtr(), command_id, is_last_tap));
474 return Response::OK();
477 void InputHandler::SendSynthesizePinchGestureResponse(
478 DevToolsCommandId command_id,
479 SyntheticGesture::Result result) {
480 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
481 client_->SendSynthesizePinchGestureResponse(
482 command_id, SynthesizePinchGestureResponse::Create());
483 } else {
484 client_->SendError(command_id,
485 Response::InternalError(base::StringPrintf(
486 "Synthetic pinch failed, result was %d", result)));
490 void InputHandler::SendSynthesizeScrollGestureResponse(
491 DevToolsCommandId command_id,
492 SyntheticGesture::Result result) {
493 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
494 client_->SendSynthesizeScrollGestureResponse(
495 command_id, SynthesizeScrollGestureResponse::Create());
496 } else {
497 client_->SendError(command_id,
498 Response::InternalError(base::StringPrintf(
499 "Synthetic scroll failed, result was %d", result)));
503 void InputHandler::SendSynthesizeTapGestureResponse(
504 DevToolsCommandId command_id,
505 bool send_success,
506 SyntheticGesture::Result result) {
507 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
508 if (send_success) {
509 client_->SendSynthesizeTapGestureResponse(
510 command_id, SynthesizeTapGestureResponse::Create());
512 } else {
513 client_->SendError(command_id,
514 Response::InternalError(base::StringPrintf(
515 "Synthetic tap failed, result was %d", result)));
519 } // namespace input
520 } // namespace devtools
521 } // namespace content