1 // Copyright 2013 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/renderer_host/input/input_router_impl.h"
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/browser/renderer_host/input/gesture_event_queue.h"
12 #include "content/browser/renderer_host/input/input_ack_handler.h"
13 #include "content/browser/renderer_host/input/input_router_client.h"
14 #include "content/browser/renderer_host/input/touch_event_queue.h"
15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
16 #include "content/browser/renderer_host/overscroll_controller.h"
17 #include "content/common/content_constants_internal.h"
18 #include "content/common/edit_command.h"
19 #include "content/common/input/touch_action.h"
20 #include "content/common/input/web_input_event_traits.h"
21 #include "content/common/input_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/port/common/input_event_ack_state.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/common/content_switches.h"
28 #include "ipc/ipc_sender.h"
29 #include "ui/events/event.h"
30 #include "ui/events/keycodes/keyboard_codes.h"
32 #if defined(OS_ANDROID)
33 #include "ui/gfx/android/view_configuration.h"
34 #include "ui/gfx/screen.h"
36 #include "ui/events/gestures/gesture_configuration.h"
40 using base::TimeDelta;
41 using base::TimeTicks;
42 using blink::WebGestureEvent;
43 using blink::WebInputEvent;
44 using blink::WebKeyboardEvent;
45 using blink::WebMouseEvent;
46 using blink::WebMouseWheelEvent;
51 // TODO(jdduke): Instead of relying on command line flags or conditional
52 // conditional compilation here, we should instead use an InputRouter::Settings
53 // construct, supplied and customized by the RenderWidgetHostView. See
55 bool GetTouchAckTimeoutDelayMs(size_t* touch_ack_timeout_delay_ms) {
56 CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
57 if (!parsed_command_line->HasSwitch(switches::kTouchAckTimeoutDelayMs))
60 std::string timeout_string = parsed_command_line->GetSwitchValueASCII(
61 switches::kTouchAckTimeoutDelayMs);
63 if (!base::StringToSizeT(timeout_string, &timeout_value))
66 *touch_ack_timeout_delay_ms = timeout_value;
70 #if defined(OS_ANDROID)
71 double GetTouchMoveSlopSuppressionLengthDips() {
72 const double touch_slop_length_pixels =
73 static_cast<double>(gfx::ViewConfiguration::GetTouchSlopInPixels());
74 const double device_scale_factor =
75 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
76 return touch_slop_length_pixels / device_scale_factor;
78 #elif defined(USE_AURA)
79 double GetTouchMoveSlopSuppressionLengthDips() {
80 return ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
83 double GetTouchMoveSlopSuppressionLengthDips() {
88 TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
89 std::string modeString = CommandLine::ForCurrentProcess()->
90 GetSwitchValueASCII(switches::kTouchScrollingMode);
91 if (modeString == switches::kTouchScrollingModeSyncTouchmove)
92 return TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE;
93 if (modeString == switches::kTouchScrollingModeAbsorbTouchmove)
94 return TouchEventQueue::TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE;
95 if (modeString != "" &&
96 modeString != switches::kTouchScrollingModeTouchcancel)
97 LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString;
98 return TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT;
101 GestureEventWithLatencyInfo MakeGestureEvent(WebInputEvent::Type type,
102 double timestamp_seconds,
106 const ui::LatencyInfo latency) {
107 WebGestureEvent result;
112 result.sourceDevice = WebGestureEvent::Touchscreen;
113 result.timeStampSeconds = timestamp_seconds;
114 result.modifiers = modifiers;
116 return GestureEventWithLatencyInfo(result, latency);
119 const char* GetEventAckName(InputEventAckState ack_result) {
121 case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
122 case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED";
123 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
124 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
125 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
127 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
133 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
134 InputRouterClient* client,
135 InputAckHandler* ack_handler,
139 ack_handler_(ack_handler),
140 routing_id_(routing_id),
141 select_range_pending_(false),
142 move_caret_pending_(false),
143 mouse_move_pending_(false),
144 mouse_wheel_pending_(false),
145 touch_ack_timeout_enabled_(false),
146 touch_ack_timeout_delay_ms_(std::numeric_limits<size_t>::max()),
147 current_ack_source_(ACK_SOURCE_NONE),
148 gesture_event_queue_(new GestureEventQueue(this, this)) {
152 touch_event_queue_.reset(new TouchEventQueue(
153 this, GetTouchScrollingMode(), GetTouchMoveSlopSuppressionLengthDips()));
154 touch_ack_timeout_enabled_ =
155 GetTouchAckTimeoutDelayMs(&touch_ack_timeout_delay_ms_);
156 touch_event_queue_->SetAckTimeoutEnabled(touch_ack_timeout_enabled_,
157 touch_ack_timeout_delay_ms_);
160 InputRouterImpl::~InputRouterImpl() {}
162 void InputRouterImpl::Flush() {}
164 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
165 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
166 switch (message->type()) {
167 // Check for types that require an ACK.
168 case InputMsg_SelectRange::ID:
169 return SendSelectRange(message.Pass());
170 case InputMsg_MoveCaret::ID:
171 return SendMoveCaret(message.Pass());
172 case InputMsg_HandleInputEvent::ID:
173 NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
176 return Send(message.release());
180 void InputRouterImpl::SendMouseEvent(
181 const MouseEventWithLatencyInfo& mouse_event) {
182 // Order is important here; we need to convert all MouseEvents before they
183 // propagate further, e.g., to the tap suppression controller.
184 if (CommandLine::ForCurrentProcess()->HasSwitch(
185 switches::kSimulateTouchScreenWithMouse)) {
186 SimulateTouchGestureWithMouse(mouse_event);
190 if (mouse_event.event.type == WebInputEvent::MouseDown &&
191 gesture_event_queue_->GetTouchpadTapSuppressionController()->
192 ShouldDeferMouseDown(mouse_event))
194 if (mouse_event.event.type == WebInputEvent::MouseUp &&
195 gesture_event_queue_->GetTouchpadTapSuppressionController()->
196 ShouldSuppressMouseUp())
199 SendMouseEventImmediately(mouse_event);
202 void InputRouterImpl::SendWheelEvent(
203 const MouseWheelEventWithLatencyInfo& wheel_event) {
204 // If there's already a mouse wheel event waiting to be sent to the renderer,
205 // add the new deltas to that event. Not doing so (e.g., by dropping the old
206 // event, as for mouse moves) results in very slow scrolling on the Mac (on
207 // which many, very small wheel events are sent).
208 if (mouse_wheel_pending_) {
209 if (coalesced_mouse_wheel_events_.empty() ||
210 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) {
211 coalesced_mouse_wheel_events_.push_back(wheel_event);
213 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
217 mouse_wheel_pending_ = true;
218 current_wheel_event_ = wheel_event;
220 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
221 coalesced_mouse_wheel_events_.size());
223 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
226 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
227 const ui::LatencyInfo& latency_info,
228 bool is_keyboard_shortcut) {
229 // Put all WebKeyboardEvent objects in a queue since we can't trust the
230 // renderer and we need to give something to the HandleKeyboardEvent
232 key_queue_.push_back(key_event);
233 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
235 gesture_event_queue_->FlingHasBeenHalted();
237 // Only forward the non-native portions of our event.
238 FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut);
241 void InputRouterImpl::SendGestureEvent(
242 const GestureEventWithLatencyInfo& original_gesture_event) {
243 GestureEventWithLatencyInfo gesture_event(original_gesture_event);
244 if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
247 touch_event_queue_->OnGestureScrollEvent(gesture_event);
249 if (!IsInOverscrollGesture() &&
250 !gesture_event_queue_->ShouldForward(gesture_event)) {
251 OverscrollController* controller = client_->GetOverscrollController();
253 controller->DiscardingGestureEvent(gesture_event.event);
257 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
260 void InputRouterImpl::SendTouchEvent(
261 const TouchEventWithLatencyInfo& touch_event) {
262 touch_event_queue_->QueueEvent(touch_event);
265 // Forwards MouseEvent without passing it through
266 // TouchpadTapSuppressionController.
267 void InputRouterImpl::SendMouseEventImmediately(
268 const MouseEventWithLatencyInfo& mouse_event) {
269 // Avoid spamming the renderer with mouse move events. It is important
270 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
271 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
272 // more WM_MOUSEMOVE events than we wish to send to the renderer.
273 if (mouse_event.event.type == WebInputEvent::MouseMove) {
274 if (mouse_move_pending_) {
275 if (!next_mouse_move_)
276 next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event));
278 next_mouse_move_->CoalesceWith(mouse_event);
281 mouse_move_pending_ = true;
284 FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false);
287 void InputRouterImpl::SendTouchEventImmediately(
288 const TouchEventWithLatencyInfo& touch_event) {
289 FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
292 void InputRouterImpl::SendGestureEventImmediately(
293 const GestureEventWithLatencyInfo& gesture_event) {
294 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
297 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
298 if (key_queue_.empty())
300 return &key_queue_.front();
303 bool InputRouterImpl::ShouldForwardTouchEvent() const {
304 // Always send a touch event if the renderer has a touch-event handler.
305 return touch_event_queue_->has_handlers();
308 void InputRouterImpl::OnViewUpdated(int view_flags) {
309 bool fixed_page_scale = (view_flags & FIXED_PAGE_SCALE) != 0;
310 bool mobile_viewport = (view_flags & MOBILE_VIEWPORT) != 0;
311 touch_event_queue_->SetAckTimeoutEnabled(
312 touch_ack_timeout_enabled_ && !(fixed_page_scale || mobile_viewport),
313 touch_ack_timeout_delay_ms_);
316 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
318 bool message_is_ok = true;
319 IPC_BEGIN_MESSAGE_MAP_EX(InputRouterImpl, message, message_is_ok)
320 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
321 IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
322 IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck)
323 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
324 OnHasTouchEventHandlers)
325 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
327 IPC_MESSAGE_UNHANDLED(handled = false)
328 IPC_END_MESSAGE_MAP()
331 ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
336 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
337 InputEventAckState ack_result) {
338 ack_handler_->OnTouchEventAck(event, ack_result);
341 void InputRouterImpl::OnGestureEventAck(
342 const GestureEventWithLatencyInfo& event,
343 InputEventAckState ack_result) {
344 touch_event_queue_->OnGestureEventAck(event, ack_result);
345 ProcessAckForOverscroll(event.event, ack_result);
346 ack_handler_->OnGestureEventAck(event, ack_result);
349 bool InputRouterImpl::SendSelectRange(scoped_ptr<IPC::Message> message) {
350 DCHECK(message->type() == InputMsg_SelectRange::ID);
351 if (select_range_pending_) {
352 next_selection_range_ = message.Pass();
356 select_range_pending_ = true;
357 return Send(message.release());
360 bool InputRouterImpl::SendMoveCaret(scoped_ptr<IPC::Message> message) {
361 DCHECK(message->type() == InputMsg_MoveCaret::ID);
362 if (move_caret_pending_) {
363 next_move_caret_ = message.Pass();
367 move_caret_pending_ = true;
368 return Send(message.release());
371 bool InputRouterImpl::Send(IPC::Message* message) {
372 return sender_->Send(message);
375 void InputRouterImpl::FilterAndSendWebInputEvent(
376 const WebInputEvent& input_event,
377 const ui::LatencyInfo& latency_info,
378 bool is_keyboard_shortcut) {
379 TRACE_EVENT1("input",
380 "InputRouterImpl::FilterAndSendWebInputEvent",
382 WebInputEventTraits::GetName(input_event.type));
384 // Transmit any pending wheel events on a non-wheel event. This ensures that
385 // final PhaseEnded wheel event is received, which is necessary to terminate
386 // rubber-banding, for example.
387 if (input_event.type != WebInputEvent::MouseWheel) {
388 WheelEventQueue mouse_wheel_events;
389 mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
390 for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
391 OfferToHandlers(mouse_wheel_events[i].event,
392 mouse_wheel_events[i].latency,
397 // Any input event cancels a pending mouse move event.
398 next_mouse_move_.reset();
400 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
403 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
404 const ui::LatencyInfo& latency_info,
405 bool is_keyboard_shortcut) {
406 if (OfferToOverscrollController(input_event, latency_info))
409 if (OfferToClient(input_event, latency_info))
412 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
414 // If we don't care about the ack disposition, send the ack immediately.
415 if (WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
416 ProcessInputEventAck(input_event.type,
417 INPUT_EVENT_ACK_STATE_IGNORED,
419 IGNORING_DISPOSITION);
423 bool InputRouterImpl::OfferToOverscrollController(
424 const WebInputEvent& input_event,
425 const ui::LatencyInfo& latency_info) {
426 OverscrollController* controller = client_->GetOverscrollController();
430 OverscrollController::Disposition disposition =
431 controller->DispatchEvent(input_event, latency_info);
433 bool consumed = disposition == OverscrollController::CONSUMED;
435 if (disposition == OverscrollController::SHOULD_FORWARD_TO_GESTURE_QUEUE) {
436 DCHECK(WebInputEvent::isGestureEventType(input_event.type));
437 const blink::WebGestureEvent& gesture_event =
438 static_cast<const blink::WebGestureEvent&>(input_event);
439 // An ACK is expected for the event, so mark it as consumed.
440 consumed = !gesture_event_queue_->ShouldForward(
441 GestureEventWithLatencyInfo(gesture_event, latency_info));
445 InputEventAckState overscroll_ack =
446 WebInputEvent::isTouchEventType(input_event.type) ?
447 INPUT_EVENT_ACK_STATE_NOT_CONSUMED : INPUT_EVENT_ACK_STATE_CONSUMED;
448 ProcessInputEventAck(input_event.type,
451 OVERSCROLL_CONTROLLER);
452 // WARNING: |this| may be deleted at this point.
458 bool InputRouterImpl::OfferToClient(const WebInputEvent& input_event,
459 const ui::LatencyInfo& latency_info) {
460 bool consumed = false;
462 InputEventAckState filter_ack =
463 client_->FilterInputEvent(input_event, latency_info);
464 switch (filter_ack) {
465 case INPUT_EVENT_ACK_STATE_CONSUMED:
466 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
467 // Send the ACK and early exit.
468 next_mouse_move_.reset();
469 ProcessInputEventAck(input_event.type, filter_ack, latency_info, CLIENT);
470 // WARNING: |this| may be deleted at this point.
473 case INPUT_EVENT_ACK_STATE_UNKNOWN:
474 // Simply drop the event.
484 bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
485 const ui::LatencyInfo& latency_info,
486 bool is_keyboard_shortcut) {
487 if (Send(new InputMsg_HandleInputEvent(
488 routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
489 // Ack messages for ignored ack event types are not required, and might
490 // never be sent by the renderer. Consequently, such event types should not
491 // affect event timing or in-flight event count metrics.
492 if (!WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
493 input_event_start_time_ = TimeTicks::Now();
494 client_->IncrementInFlightEventCount();
501 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type,
502 InputEventAckState ack_result,
503 const ui::LatencyInfo& latency_info) {
504 // A synthetic ack will already have been sent for this event, and it should
505 // not affect event timing or in-flight count metrics.
506 if (WebInputEventTraits::IgnoresAckDisposition(event_type))
509 client_->DecrementInFlightEventCount();
511 // Log the time delta for processing an input event.
512 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
513 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta);
515 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER);
516 // WARNING: |this| may be deleted at this point.
518 // This is used only for testing, and the other end does not use the
519 // source object. On linux, specifying
520 // Source<RenderWidgetHost> results in a very strange
521 // runtime error in the epilogue of the enclosing
522 // (ProcessInputEventAck) method, but not on other platforms; using
523 // 'void' instead is just as safe (since NotificationSource
524 // is not actually typesafe) and avoids this error.
525 int type = static_cast<int>(event_type);
526 NotificationService::current()->Notify(
527 NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
529 Details<int>(&type));
532 void InputRouterImpl::OnMsgMoveCaretAck() {
533 move_caret_pending_ = false;
534 if (next_move_caret_)
535 SendMoveCaret(next_move_caret_.Pass());
538 void InputRouterImpl::OnSelectRangeAck() {
539 select_range_pending_ = false;
540 if (next_selection_range_)
541 SendSelectRange(next_selection_range_.Pass());
544 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
545 TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
546 "has_handlers", has_handlers);
548 touch_event_queue_->OnHasTouchEventHandlers(has_handlers);
549 client_->OnHasTouchEventHandlers(has_handlers);
552 void InputRouterImpl::OnSetTouchAction(
553 content::TouchAction touch_action) {
554 // Synthetic touchstart events should get filtered out in RenderWidget.
555 DCHECK(touch_event_queue_->IsPendingAckTouchStart());
557 touch_action_filter_.OnSetTouchAction(touch_action);
560 void InputRouterImpl::ProcessInputEventAck(
561 WebInputEvent::Type event_type,
562 InputEventAckState ack_result,
563 const ui::LatencyInfo& latency_info,
564 AckSource ack_source) {
565 TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
566 "type", WebInputEventTraits::GetName(event_type),
567 "ack", GetEventAckName(ack_result));
569 // Note: The keyboard ack must be treated carefully, as it may result in
570 // synchronous destruction of |this|. Handling immediately guards against
571 // future references to |this|, as with |auto_reset_current_ack_source| below.
572 if (WebInputEvent::isKeyboardEventType(event_type)) {
573 ProcessKeyboardAck(event_type, ack_result);
574 // WARNING: |this| may be deleted at this point.
578 base::AutoReset<AckSource> auto_reset_current_ack_source(
579 ¤t_ack_source_, ack_source);
581 if (WebInputEvent::isMouseEventType(event_type)) {
582 ProcessMouseAck(event_type, ack_result);
583 } else if (event_type == WebInputEvent::MouseWheel) {
584 ProcessWheelAck(ack_result, latency_info);
585 } else if (WebInputEvent::isTouchEventType(event_type)) {
586 ProcessTouchAck(ack_result, latency_info);
587 } else if (WebInputEvent::isGestureEventType(event_type)) {
588 ProcessGestureAck(event_type, ack_result, latency_info);
589 } else if (event_type != WebInputEvent::Undefined) {
590 ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
594 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
595 InputEventAckState ack_result) {
596 if (key_queue_.empty()) {
597 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK);
598 } else if (key_queue_.front().type != type) {
599 // Something must be wrong. Clear the |key_queue_| and char event
600 // suppression so that we can resume from the error.
602 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
604 NativeWebKeyboardEvent front_item = key_queue_.front();
605 key_queue_.pop_front();
607 ack_handler_->OnKeyboardEventAck(front_item, ack_result);
608 // WARNING: This InputRouterImpl can be deallocated at this point
609 // (i.e. in the case of Ctrl+W, where the call to
610 // HandleKeyboardEvent destroys this InputRouterImpl).
611 // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
615 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
616 InputEventAckState ack_result) {
617 if (type != WebInputEvent::MouseMove)
620 mouse_move_pending_ = false;
622 if (next_mouse_move_) {
623 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove);
624 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move
625 = next_mouse_move_.Pass();
626 SendMouseEvent(*next_mouse_move);
630 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
631 const ui::LatencyInfo& latency) {
632 ProcessAckForOverscroll(current_wheel_event_.event, ack_result);
634 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
635 // wheel event and add terminal component to each of them.
636 current_wheel_event_.latency.AddNewLatencyFrom(latency);
637 // Process the unhandled wheel event here before calling SendWheelEvent()
638 // since it will mutate current_wheel_event_.
639 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
640 mouse_wheel_pending_ = false;
642 // Now send the next (coalesced) mouse wheel event.
643 if (!coalesced_mouse_wheel_events_.empty()) {
644 MouseWheelEventWithLatencyInfo next_wheel_event =
645 coalesced_mouse_wheel_events_.front();
646 coalesced_mouse_wheel_events_.pop_front();
647 SendWheelEvent(next_wheel_event);
651 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
652 InputEventAckState ack_result,
653 const ui::LatencyInfo& latency) {
654 // If |ack_result| originated from the overscroll controller, only
655 // feed |gesture_event_queue_| the ack if it was expecting one.
656 if (current_ack_source_ == OVERSCROLL_CONTROLLER &&
657 !gesture_event_queue_->HasQueuedGestureEvents()) {
661 // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
662 gesture_event_queue_->ProcessGestureAck(ack_result, type, latency);
665 void InputRouterImpl::ProcessTouchAck(
666 InputEventAckState ack_result,
667 const ui::LatencyInfo& latency) {
668 // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
669 touch_event_queue_->ProcessTouchAck(ack_result, latency);
672 void InputRouterImpl::ProcessAckForOverscroll(const WebInputEvent& event,
673 InputEventAckState ack_result) {
674 // Acks sent from the overscroll controller need not be fed back into the
675 // overscroll controller.
676 if (current_ack_source_ == OVERSCROLL_CONTROLLER)
679 OverscrollController* controller = client_->GetOverscrollController();
683 controller->ReceivedEventACK(
684 event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
687 void InputRouterImpl::SimulateTouchGestureWithMouse(
688 const MouseEventWithLatencyInfo& event) {
689 const WebMouseEvent& mouse_event = event.event;
690 int x = mouse_event.x, y = mouse_event.y;
691 float dx = mouse_event.movementX, dy = mouse_event.movementY;
692 static int startX = 0, startY = 0;
694 switch (mouse_event.button) {
695 case WebMouseEvent::ButtonLeft:
696 if (mouse_event.type == WebInputEvent::MouseDown) {
699 SendGestureEvent(MakeGestureEvent(
700 WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
701 x, y, 0, event.latency));
703 if (dx != 0 || dy != 0) {
704 GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
705 WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds,
706 x, y, 0, event.latency);
707 gesture_event.event.data.scrollUpdate.deltaX = dx;
708 gesture_event.event.data.scrollUpdate.deltaY = dy;
709 SendGestureEvent(gesture_event);
711 if (mouse_event.type == WebInputEvent::MouseUp) {
712 SendGestureEvent(MakeGestureEvent(
713 WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
714 x, y, 0, event.latency));
717 case WebMouseEvent::ButtonMiddle:
718 if (mouse_event.type == WebInputEvent::MouseDown) {
721 SendGestureEvent(MakeGestureEvent(
722 WebInputEvent::GestureShowPress, mouse_event.timeStampSeconds,
723 x, y, 0, event.latency));
724 SendGestureEvent(MakeGestureEvent(
725 WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
726 x, y, 0, event.latency));
728 if (mouse_event.type == WebInputEvent::MouseUp) {
729 SendGestureEvent(MakeGestureEvent(
730 WebInputEvent::GestureTap, mouse_event.timeStampSeconds,
731 x, y, 0, event.latency));
734 case WebMouseEvent::ButtonRight:
735 if (mouse_event.type == WebInputEvent::MouseDown) {
738 SendGestureEvent(MakeGestureEvent(
739 WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
740 x, y, 0, event.latency));
741 SendGestureEvent(MakeGestureEvent(
742 WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds,
743 x, y, 0, event.latency));
745 if (dx != 0 || dy != 0) {
746 dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy));
747 GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
748 WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds,
749 startX, startY, 0, event.latency);
750 gesture_event.event.data.pinchUpdate.scale = dx;
751 SendGestureEvent(gesture_event);
753 if (mouse_event.type == WebInputEvent::MouseUp) {
754 SendGestureEvent(MakeGestureEvent(
755 WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds,
756 x, y, 0, event.latency));
757 SendGestureEvent(MakeGestureEvent(
758 WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
759 x, y, 0, event.latency));
762 case WebMouseEvent::ButtonNone:
767 bool InputRouterImpl::IsInOverscrollGesture() const {
768 OverscrollController* controller = client_->GetOverscrollController();
769 return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
772 } // namespace content