Process Alt-Svc headers.
[chromium-blink-merge.git] / content / browser / devtools / protocol / input_handler.cc
blobfb24b021b3c44b0ca26a3568fbf91c8304c9edbb
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/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "cc/output/compositor_frame_metadata.h"
10 #include "content/browser/renderer_host/render_widget_host_impl.h"
11 #include "content/common/input/synthetic_pinch_gesture_params.h"
12 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
13 #include "content/common/input/synthetic_tap_gesture_params.h"
14 #include "third_party/WebKit/public/web/WebInputEvent.h"
15 #include "ui/events/keycodes/dom/keycode_converter.h"
16 #include "ui/gfx/geometry/point.h"
18 namespace content {
19 namespace devtools {
20 namespace input {
22 namespace {
24 gfx::Point CssPixelsToPoint(int x, int y, float page_scale_factor) {
25 return gfx::Point(x * page_scale_factor, y * page_scale_factor);
28 gfx::Vector2d CssPixelsToVector2d(int x, int y, float page_scale_factor) {
29 return gfx::Vector2d(x * page_scale_factor, y * page_scale_factor);
32 bool StringToGestureSourceType(const std::string& in,
33 SyntheticGestureParams::GestureSourceType& out) {
34 if (in == kGestureSourceTypeDefault) {
35 out = SyntheticGestureParams::GestureSourceType::DEFAULT_INPUT;
36 return true;
37 } else if (in == kGestureSourceTypeTouch) {
38 out = SyntheticGestureParams::GestureSourceType::TOUCH_INPUT;
39 return true;
40 } else if (in == kGestureSourceTypeMouse) {
41 out = SyntheticGestureParams::GestureSourceType::MOUSE_INPUT;
42 return true;
43 } else {
44 return false;
50 typedef DevToolsProtocolClient::Response Response;
52 namespace {
54 void SetEventModifiers(blink::WebInputEvent* event, const int* modifiers) {
55 if (!modifiers)
56 return;
57 if (*modifiers & 1)
58 event->modifiers |= blink::WebInputEvent::AltKey;
59 if (*modifiers & 2)
60 event->modifiers |= blink::WebInputEvent::ControlKey;
61 if (*modifiers & 4)
62 event->modifiers |= blink::WebInputEvent::MetaKey;
63 if (*modifiers & 8)
64 event->modifiers |= blink::WebInputEvent::ShiftKey;
67 void SetEventTimestamp(blink::WebInputEvent* event, const double* timestamp) {
68 event->timeStampSeconds =
69 timestamp ? *timestamp : base::Time::Now().ToDoubleT();
72 bool SetKeyboardEventText(blink::WebUChar* to, const std::string* from) {
73 if (!from)
74 return true;
76 base::string16 text16 = base::UTF8ToUTF16(*from);
77 if (text16.size() > blink::WebKeyboardEvent::textLengthCap)
78 return false;
80 for (size_t i = 0; i < text16.size(); ++i)
81 to[i] = text16[i];
82 return true;
85 bool SetMouseEventButton(blink::WebMouseEvent* event,
86 const std::string* button) {
87 if (!button)
88 return true;
90 if (*button == dispatch_mouse_event::kButtonNone) {
91 event->button = blink::WebMouseEvent::ButtonNone;
92 } else if (*button == dispatch_mouse_event::kButtonLeft) {
93 event->button = blink::WebMouseEvent::ButtonLeft;
94 event->modifiers |= blink::WebInputEvent::LeftButtonDown;
95 } else if (*button == dispatch_mouse_event::kButtonMiddle) {
96 event->button = blink::WebMouseEvent::ButtonMiddle;
97 event->modifiers |= blink::WebInputEvent::MiddleButtonDown;
98 } else if (*button == dispatch_mouse_event::kButtonRight) {
99 event->button = blink::WebMouseEvent::ButtonRight;
100 event->modifiers |= blink::WebInputEvent::RightButtonDown;
101 } else {
102 return false;
104 return true;
107 bool SetMouseEventType(blink::WebMouseEvent* event, const std::string& type) {
108 if (type == dispatch_mouse_event::kTypeMousePressed) {
109 event->type = blink::WebInputEvent::MouseDown;
110 } else if (type == dispatch_mouse_event::kTypeMouseReleased) {
111 event->type = blink::WebInputEvent::MouseUp;
112 } else if (type == dispatch_mouse_event::kTypeMouseMoved) {
113 event->type = blink::WebInputEvent::MouseMove;
114 } else {
115 return false;
117 return true;
120 } // namespace
122 InputHandler::InputHandler()
123 : host_(NULL),
124 page_scale_factor_(1.0),
125 weak_factory_(this) {
128 InputHandler::~InputHandler() {
131 void InputHandler::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
132 host_ = host;
135 void InputHandler::SetClient(scoped_ptr<Client> client) {
136 client_.swap(client);
139 void InputHandler::OnSwapCompositorFrame(
140 const cc::CompositorFrameMetadata& frame_metadata) {
141 page_scale_factor_ = frame_metadata.page_scale_factor;
142 scrollable_viewport_size_ = frame_metadata.scrollable_viewport_size;
145 Response InputHandler::DispatchKeyEvent(
146 const std::string& type,
147 const int* modifiers,
148 const double* timestamp,
149 const std::string* text,
150 const std::string* unmodified_text,
151 const std::string* key_identifier,
152 const std::string* code,
153 const std::string* key,
154 const int* windows_virtual_key_code,
155 const int* native_virtual_key_code,
156 const bool* auto_repeat,
157 const bool* is_keypad,
158 const bool* is_system_key) {
159 NativeWebKeyboardEvent event;
161 if (type == dispatch_key_event::kTypeKeyDown) {
162 event.type = blink::WebInputEvent::KeyDown;
163 } else if (type == dispatch_key_event::kTypeKeyUp) {
164 event.type = blink::WebInputEvent::KeyUp;
165 } else if (type == dispatch_key_event::kTypeChar) {
166 event.type = blink::WebInputEvent::Char;
167 } else if (type == dispatch_key_event::kTypeRawKeyDown) {
168 event.type = blink::WebInputEvent::RawKeyDown;
169 } else {
170 return Response::InvalidParams(
171 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
174 SetEventModifiers(&event, modifiers);
175 SetEventTimestamp(&event, timestamp);
176 if (!SetKeyboardEventText(event.text, text))
177 return Response::InvalidParams("Invalid 'text' parameter");
178 if (!SetKeyboardEventText(event.unmodifiedText, unmodified_text))
179 return Response::InvalidParams("Invalid 'unmodifiedText' parameter");
181 if (windows_virtual_key_code)
182 event.windowsKeyCode = *windows_virtual_key_code;
183 if (native_virtual_key_code)
184 event.nativeKeyCode = *native_virtual_key_code;
185 if (auto_repeat && *auto_repeat)
186 event.modifiers |= blink::WebInputEvent::IsAutoRepeat;
187 if (is_keypad && *is_keypad)
188 event.modifiers |= blink::WebInputEvent::IsKeyPad;
189 if (is_system_key)
190 event.isSystemKey = *is_system_key;
192 if (key_identifier) {
193 if (key_identifier->size() >
194 blink::WebKeyboardEvent::keyIdentifierLengthCap) {
195 return Response::InvalidParams("Invalid 'keyIdentifier' parameter");
197 for (size_t i = 0; i < key_identifier->size(); ++i)
198 event.keyIdentifier[i] = (*key_identifier)[i];
199 } else if (event.type != blink::WebInputEvent::Char) {
200 event.setKeyIdentifierFromWindowsKeyCode();
203 if (code) {
204 event.domCode = static_cast<int>(
205 ui::KeycodeConverter::CodeStringToDomCode(code->c_str()));
208 if (key) {
209 event.domKey = static_cast<int>(
210 ui::KeycodeConverter::KeyStringToDomKey(key->c_str()));
213 if (!host_)
214 return Response::ServerError("Could not connect to view");
216 host_->Focus();
217 host_->ForwardKeyboardEvent(event);
218 return Response::OK();
221 Response InputHandler::DispatchMouseEvent(
222 const std::string& type,
223 int x,
224 int y,
225 const int* modifiers,
226 const double* timestamp,
227 const std::string* button,
228 const int* click_count) {
229 blink::WebMouseEvent event;
231 if (!SetMouseEventType(&event, type)) {
232 return Response::InvalidParams(
233 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
235 SetEventModifiers(&event, modifiers);
236 SetEventTimestamp(&event, timestamp);
237 if (!SetMouseEventButton(&event, button))
238 return Response::InvalidParams("Invalid mouse button");
240 event.x = x * page_scale_factor_;
241 event.y = y * page_scale_factor_;
242 event.windowX = x * page_scale_factor_;
243 event.windowY = y * page_scale_factor_;
244 event.globalX = x * page_scale_factor_;
245 event.globalY = y * page_scale_factor_;
246 event.clickCount = click_count ? *click_count : 0;
248 if (!host_)
249 return Response::ServerError("Could not connect to view");
251 host_->Focus();
252 host_->ForwardMouseEvent(event);
253 return Response::OK();
256 Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
257 int x,
258 int y,
259 double timestamp,
260 const std::string& button,
261 double* delta_x,
262 double* delta_y,
263 int* modifiers,
264 int* click_count) {
265 blink::WebMouseWheelEvent wheel_event;
266 blink::WebMouseEvent mouse_event;
267 blink::WebMouseEvent* event = &mouse_event;
269 if (type == emulate_touch_from_mouse_event::kTypeMouseWheel) {
270 if (!delta_x || !delta_y) {
271 return Response::InvalidParams(
272 "'deltaX' and 'deltaY' are expected for mouseWheel event");
274 wheel_event.deltaX = static_cast<float>(*delta_x);
275 wheel_event.deltaY = static_cast<float>(*delta_y);
276 event = &wheel_event;
277 event->type = blink::WebInputEvent::MouseWheel;
278 } else if (!SetMouseEventType(event, type)) {
279 return Response::InvalidParams(
280 base::StringPrintf("Unexpected event type '%s'", type.c_str()));
283 SetEventModifiers(event, modifiers);
284 SetEventTimestamp(event, &timestamp);
285 if (!SetMouseEventButton(event, &button))
286 return Response::InvalidParams("Invalid mouse button");
288 event->x = x;
289 event->y = y;
290 event->windowX = x;
291 event->windowY = y;
292 event->globalX = x;
293 event->globalY = y;
294 event->clickCount = click_count ? *click_count : 0;
296 if (!host_)
297 return Response::ServerError("Could not connect to view");
299 if (event->type == blink::WebInputEvent::MouseWheel)
300 host_->ForwardWheelEvent(wheel_event);
301 else
302 host_->ForwardMouseEvent(mouse_event);
303 return Response::OK();
306 Response InputHandler::SynthesizePinchGesture(
307 DevToolsCommandId command_id,
308 int x,
309 int y,
310 double scale_factor,
311 const int* relative_speed,
312 const std::string* gesture_source_type) {
313 if (!host_)
314 return Response::ServerError("Could not connect to view");
316 SyntheticPinchGestureParams gesture_params;
317 const int kDefaultRelativeSpeed = 800;
319 gesture_params.scale_factor = scale_factor;
320 gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
321 gesture_params.relative_pointer_speed_in_pixels_s =
322 relative_speed ? *relative_speed : kDefaultRelativeSpeed;
324 if (!StringToGestureSourceType(
325 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
326 gesture_params.gesture_source_type)) {
327 return Response::InvalidParams("gestureSourceType");
330 host_->QueueSyntheticGesture(
331 SyntheticGesture::Create(gesture_params),
332 base::Bind(&InputHandler::SendSynthesizePinchGestureResponse,
333 weak_factory_.GetWeakPtr(), command_id));
335 return Response::OK();
338 Response InputHandler::SynthesizeScrollGesture(
339 DevToolsCommandId command_id,
340 int x,
341 int y,
342 const int* x_distance,
343 const int* y_distance,
344 const int* x_overscroll,
345 const int* y_overscroll,
346 const bool* prevent_fling,
347 const int* speed,
348 const std::string* gesture_source_type) {
349 if (!host_)
350 return Response::ServerError("Could not connect to view");
352 SyntheticSmoothScrollGestureParams gesture_params;
353 const bool kDefaultPreventFling = true;
354 const int kDefaultSpeed = 800;
356 gesture_params.anchor = CssPixelsToPoint(x, y, page_scale_factor_);
357 gesture_params.prevent_fling =
358 prevent_fling ? *prevent_fling : kDefaultPreventFling;
359 gesture_params.speed_in_pixels_s = speed ? *speed : kDefaultSpeed;
361 if (x_distance || y_distance) {
362 gesture_params.distances.push_back(
363 CssPixelsToVector2d(x_distance ? *x_distance : 0,
364 y_distance ? *y_distance : 0,
365 page_scale_factor_));
368 if (x_overscroll || y_overscroll) {
369 gesture_params.distances.push_back(
370 CssPixelsToVector2d(x_overscroll ? -*x_overscroll : 0,
371 y_overscroll ? -*y_overscroll : 0,
372 page_scale_factor_));
375 if (!StringToGestureSourceType(
376 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
377 gesture_params.gesture_source_type)) {
378 return Response::InvalidParams("gestureSourceType");
381 host_->QueueSyntheticGesture(
382 SyntheticGesture::Create(gesture_params),
383 base::Bind(&InputHandler::SendSynthesizeScrollGestureResponse,
384 weak_factory_.GetWeakPtr(), command_id));
386 return Response::OK();
389 Response InputHandler::SynthesizeTapGesture(
390 DevToolsCommandId command_id,
391 int x,
392 int y,
393 const int* duration,
394 const int* tap_count,
395 const std::string* gesture_source_type) {
396 if (!host_)
397 return Response::ServerError("Could not connect to view");
399 SyntheticTapGestureParams gesture_params;
400 const int kDefaultDuration = 50;
401 const int kDefaultTapCount = 1;
403 gesture_params.position = CssPixelsToPoint(x, y, page_scale_factor_);
404 gesture_params.duration_ms = duration ? *duration : kDefaultDuration;
406 if (!StringToGestureSourceType(
407 gesture_source_type ? *gesture_source_type : kGestureSourceTypeDefault,
408 gesture_params.gesture_source_type)) {
409 return Response::InvalidParams("gestureSourceType");
412 if (!tap_count)
413 tap_count = &kDefaultTapCount;
415 for (int i = 0; i < *tap_count; i++) {
416 // If we're doing more than one tap, don't send the response to the client
417 // until we've completed the last tap.
418 bool is_last_tap = i == *tap_count - 1;
419 host_->QueueSyntheticGesture(
420 SyntheticGesture::Create(gesture_params),
421 base::Bind(&InputHandler::SendSynthesizeTapGestureResponse,
422 weak_factory_.GetWeakPtr(), command_id, is_last_tap));
425 return Response::OK();
428 void InputHandler::SendSynthesizePinchGestureResponse(
429 DevToolsCommandId command_id,
430 SyntheticGesture::Result result) {
431 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
432 client_->SendSynthesizePinchGestureResponse(
433 command_id, SynthesizePinchGestureResponse::Create());
434 } else {
435 client_->SendError(command_id,
436 Response::InternalError(base::StringPrintf(
437 "Synthetic pinch failed, result was %d", result)));
441 void InputHandler::SendSynthesizeScrollGestureResponse(
442 DevToolsCommandId command_id,
443 SyntheticGesture::Result result) {
444 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
445 client_->SendSynthesizeScrollGestureResponse(
446 command_id, SynthesizeScrollGestureResponse::Create());
447 } else {
448 client_->SendError(command_id,
449 Response::InternalError(base::StringPrintf(
450 "Synthetic scroll failed, result was %d", result)));
454 void InputHandler::SendSynthesizeTapGestureResponse(
455 DevToolsCommandId command_id,
456 bool send_success,
457 SyntheticGesture::Result result) {
458 if (result == SyntheticGesture::Result::GESTURE_FINISHED) {
459 if (send_success) {
460 client_->SendSynthesizeTapGestureResponse(
461 command_id, SynthesizeTapGestureResponse::Create());
463 } else {
464 client_->SendError(command_id,
465 Response::InternalError(base::StringPrintf(
466 "Synthetic tap failed, result was %d", result)));
470 } // namespace input
471 } // namespace devtools
472 } // namespace content