Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(485)

Side by Side Diff: content/browser/renderer_host/render_widget_host_view_event_handler.cc

Issue 2317333002: Refactor EventHandler out of RenderWidgetHostViewAura (Closed)
Patch Set: Fix Windows Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/browser/renderer_host/render_widget_host_view_event_handler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "content/browser/renderer_host/render_widget_host_view_event_handler.h"
6
7 #include "base/metrics/user_metrics_action.h"
8 #include "content/browser/renderer_host/input/touch_selection_controller_client_ aura.h"
9 #include "content/browser/renderer_host/overscroll_controller.h"
10 #include "content/browser/renderer_host/render_view_host_delegate.h"
11 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
12 #include "content/browser/renderer_host/render_widget_host_impl.h"
13 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
14 #include "content/browser/renderer_host/render_widget_host_view_base.h"
15 #include "content/browser/renderer_host/text_input_manager.h"
16 #include "content/common/content_switches_internal.h"
17 #include "content/common/site_isolation_policy.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/render_widget_host.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "ui/aura/client/cursor_client.h"
22 #include "ui/aura/client/focus_client.h"
23 #include "ui/aura/client/screen_position_client.h"
24 #include "ui/aura/window.h"
25 #include "ui/aura/window_delegate.h"
26 #include "ui/base/ime/text_input_client.h"
27 #include "ui/events/blink/blink_event_util.h"
28 #include "ui/events/blink/web_input_event.h"
29 #include "ui/touch_selection/touch_selection_controller.h"
30
31 #if defined(OS_WIN)
32 #include "content/browser/frame_host/render_frame_host_impl.h"
33 #include "content/public/common/context_menu_params.h"
34 #include "ui/aura/window_tree_host.h"
35 #include "ui/display/screen.h"
36 #endif // defined(OS_WIN)
37
38 namespace {
39
40 // In mouse lock mode, we need to prevent the (invisible) cursor from hitting
41 // the border of the view, in order to get valid movement information. However,
42 // forcing the cursor back to the center of the view after each mouse move
43 // doesn't work well. It reduces the frequency of useful mouse move messages
44 // significantly. Therefore, we move the cursor to the center of the view only
45 // if it approaches the border. |kMouseLockBorderPercentage| specifies the width
46 // of the border area, in percentage of the corresponding dimension.
47 const int kMouseLockBorderPercentage = 15;
48
49 #if defined(OS_WIN)
50 // A callback function for EnumThreadWindows to enumerate and dismiss
51 // any owned popup windows.
52 BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
53 const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg);
54
55 if (::IsWindowVisible(window)) {
56 const HWND owner = ::GetWindow(window, GW_OWNER);
57 if (toplevel_hwnd == owner) {
58 ::PostMessage(window, WM_CANCELMODE, 0, 0);
59 }
60 }
61
62 return TRUE;
63 }
64 #endif // defined(OS_WIN)
65
66 gfx::Point GetScreenLocationFromEvent(const ui::LocatedEvent& event) {
67 aura::Window* root =
68 static_cast<aura::Window*>(event.target())->GetRootWindow();
69 aura::client::ScreenPositionClient* spc =
70 aura::client::GetScreenPositionClient(root);
71 if (!spc)
72 return event.root_location();
73
74 gfx::Point screen_location(event.root_location());
75 spc->ConvertPointToScreen(root, &screen_location);
76 return screen_location;
77 }
78
79 bool IsFractionalScaleFactor(float scale_factor) {
80 return (scale_factor - static_cast<int>(scale_factor)) > 0;
81 }
82
83 // We don't mark these as handled so that they're sent back to the
84 // DefWindowProc so it can generate WM_APPCOMMAND as necessary.
85 bool IsXButtonUpEvent(const ui::MouseEvent* event) {
86 #if defined(OS_WIN)
87 switch (event->native_event().message) {
88 case WM_XBUTTONUP:
89 case WM_NCXBUTTONUP:
90 return true;
91 }
92 #endif
93 return false;
94 }
95
96 // Reset unchanged touch points to StateStationary for touchmove and
97 // touchcancel.
98 void MarkUnchangedTouchPointsAsStationary(blink::WebTouchEvent* event,
99 int changed_touch_id) {
100 if (event->type == blink::WebInputEvent::TouchMove ||
101 event->type == blink::WebInputEvent::TouchCancel) {
102 for (size_t i = 0; i < event->touchesLength; ++i) {
103 if (event->touches[i].id != changed_touch_id)
104 event->touches[i].state = blink::WebTouchPoint::StateStationary;
105 }
106 }
107 }
108
109 bool NeedsInputGrab(content::RenderWidgetHostViewBase* view) {
110 if (!view)
111 return false;
112 return view->GetPopupType() == blink::WebPopupTypePage;
113 }
114
115 } // namespace
116
117 namespace content {
118
119 RenderWidgetHostViewEventHandler::Delegate::Delegate()
120 : selection_controller_client_(nullptr),
121 selection_controller_(nullptr),
122 overscroll_controller_(nullptr) {}
123
124 RenderWidgetHostViewEventHandler::Delegate::~Delegate() {}
125
126 RenderWidgetHostViewEventHandler::RenderWidgetHostViewEventHandler(
127 RenderWidgetHostImpl* host,
128 RenderWidgetHostViewBase* host_view,
129 Delegate* delegate)
130 : accept_return_character_(false),
131 disable_input_event_router_for_testing_(false),
132 mouse_locked_(false),
133 pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
134 set_focus_on_mouse_down_or_key_event_(false),
135 synthetic_move_sent_(false),
136 host_(RenderWidgetHostImpl::From(host)),
137 host_view_(host_view),
138 popup_child_host_view_(nullptr),
139 popup_child_event_handler_(nullptr),
140 delegate_(delegate),
141 window_(nullptr) {}
142
143 RenderWidgetHostViewEventHandler::~RenderWidgetHostViewEventHandler() {}
144
145 void RenderWidgetHostViewEventHandler::SetPopupChild(
146 RenderWidgetHostViewBase* popup_child_host_view,
147 ui::EventHandler* popup_child_event_handler) {
148 popup_child_host_view_ = popup_child_host_view;
149 popup_child_event_handler_ = popup_child_event_handler;
150 }
151
152 void RenderWidgetHostViewEventHandler::TrackHost(
153 aura::Window* reference_window) {
154 if (!reference_window)
155 return;
156 DCHECK(!host_tracker_);
157 host_tracker_.reset(new aura::WindowTracker);
158 host_tracker_->Add(reference_window);
159 }
160
161 #if defined(OS_WIN)
162 void RenderWidgetHostViewEventHandler::SetContextMenuParams(
163 const ContextMenuParams& params) {
164 last_context_menu_params_.reset();
165 if (params.source_type == ui::MENU_SOURCE_LONG_PRESS) {
166 last_context_menu_params_.reset(new ContextMenuParams);
167 *last_context_menu_params_ = params;
168 }
169 }
170
171 void RenderWidgetHostViewEventHandler::UpdateMouseLockRegion() {
172 RECT window_rect =
173 display::Screen::GetScreen()
174 ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen())
175 .ToRECT();
176 ::ClipCursor(&window_rect);
177 }
178 #endif
179
180 bool RenderWidgetHostViewEventHandler::LockMouse() {
181 aura::Window* root_window = window_->GetRootWindow();
182 if (!root_window)
183 return false;
184
185 if (mouse_locked_)
186 return true;
187
188 mouse_locked_ = true;
189 #if !defined(OS_WIN)
190 window_->SetCapture();
191 #else
192 UpdateMouseLockRegion();
193 #endif
194 aura::client::CursorClient* cursor_client =
195 aura::client::GetCursorClient(root_window);
196 if (cursor_client) {
197 cursor_client->HideCursor();
198 cursor_client->LockCursor();
199 }
200
201 if (ShouldMoveToCenter()) {
202 synthetic_move_sent_ = true;
203 window_->MoveCursorTo(gfx::Rect(window_->bounds().size()).CenterPoint());
204 }
205 delegate_->SetTooltipsEnabled(false);
206 return true;
207 }
208
209 void RenderWidgetHostViewEventHandler::UnlockMouse() {
210 delegate_->SetTooltipsEnabled(true);
211
212 aura::Window* root_window = window_->GetRootWindow();
213 if (!mouse_locked_ || !root_window)
214 return;
215
216 mouse_locked_ = false;
217
218 if (window_->HasCapture())
219 window_->ReleaseCapture();
220
221 #if defined(OS_WIN)
222 ::ClipCursor(NULL);
223 #endif
224
225 // Ensure that the global mouse position is updated here to its original
226 // value. If we don't do this then the synthesized mouse move which is posted
227 // after the cursor is moved ends up getting a large movement delta which is
228 // not what sites expect. The delta is computed in the
229 // ModifyEventMovementAndCoords function.
230 global_mouse_position_ = unlocked_global_mouse_position_;
231 window_->MoveCursorTo(unlocked_mouse_position_);
232
233 aura::client::CursorClient* cursor_client =
234 aura::client::GetCursorClient(root_window);
235 if (cursor_client) {
236 cursor_client->UnlockCursor();
237 cursor_client->ShowCursor();
238 }
239 host_->LostMouseLock();
240 }
241
242 void RenderWidgetHostViewEventHandler::OnKeyEvent(ui::KeyEvent* event) {
243 TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnKeyEvent");
244
245 if (NeedsInputGrab(popup_child_host_view_)) {
246 popup_child_event_handler_->OnKeyEvent(event);
247 if (event->handled())
248 return;
249 }
250
251 // We need to handle the Escape key for Pepper Flash.
252 if (host_view_->is_fullscreen() && event->key_code() == ui::VKEY_ESCAPE) {
253 // Focus the window we were created from.
254 if (host_tracker_.get() && !host_tracker_->windows().empty()) {
255 aura::Window* host = *(host_tracker_->windows().begin());
256 aura::client::FocusClient* client = aura::client::GetFocusClient(host);
257 if (client) {
258 // Calling host->Focus() may delete |this|. We create a local observer
259 // for that. In that case we exit without further access to any members.
260 auto local_tracker = std::move(host_tracker_);
261 local_tracker->Add(window_);
262 host->Focus();
263 if (!local_tracker->Contains(window_)) {
264 event->SetHandled();
265 return;
266 }
267 }
268 }
269 delegate_->Shutdown();
270 host_tracker_.reset();
271 } else {
272 if (event->key_code() == ui::VKEY_RETURN) {
273 // Do not forward return key release events if no press event was handled.
274 if (event->type() == ui::ET_KEY_RELEASED && !accept_return_character_)
275 return;
276 // Accept return key character events between press and release events.
277 accept_return_character_ = event->type() == ui::ET_KEY_PRESSED;
278 }
279
280 // Call SetKeyboardFocus() for not only ET_KEY_PRESSED but also
281 // ET_KEY_RELEASED. If a user closed the hotdog menu with ESC key press,
282 // we need to notify focus to Blink on ET_KEY_RELEASED for ESC key.
283 SetKeyboardFocus();
284 // We don't have to communicate with an input method here.
285 NativeWebKeyboardEvent webkit_event(*event);
286 delegate_->ForwardKeyboardEvent(webkit_event);
287 }
288 event->SetHandled();
289 }
290
291 void RenderWidgetHostViewEventHandler::OnMouseEvent(ui::MouseEvent* event) {
292 TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnMouseEvent");
293 ForwardMouseEventToParent(event);
294 // TODO(mgiuca): Return if event->handled() returns true. This currently
295 // breaks drop-down lists which means something is incorrectly setting
296 // event->handled to true (http://crbug.com/577983).
297
298 if (mouse_locked_) {
299 HandleMouseEventWhileLocked(event);
300 return;
301 }
302
303 // As the overscroll is handled during scroll events from the trackpad, the
304 // RWHVA window is transformed by the overscroll controller. This transform
305 // triggers a synthetic mouse-move event to be generated (by the aura
306 // RootWindow). But this event interferes with the overscroll gesture. So,
307 // ignore such synthetic mouse-move events if an overscroll gesture is in
308 // progress.
309 OverscrollController* overscroll_controller =
310 delegate_->overscroll_controller();
311 if (overscroll_controller &&
312 overscroll_controller->overscroll_mode() != OVERSCROLL_NONE &&
313 event->flags() & ui::EF_IS_SYNTHESIZED &&
314 (event->type() == ui::ET_MOUSE_ENTERED ||
315 event->type() == ui::ET_MOUSE_EXITED ||
316 event->type() == ui::ET_MOUSE_MOVED)) {
317 event->StopPropagation();
318 return;
319 }
320
321 if (event->type() == ui::ET_MOUSEWHEEL) {
322 #if defined(OS_WIN)
323 // We get mouse wheel/scroll messages even if we are not in the foreground.
324 // So here we check if we have any owned popup windows in the foreground and
325 // dismiss them.
326 aura::WindowTreeHost* host = window_->GetHost();
327 if (host) {
328 HWND parent = host->GetAcceleratedWidget();
329 HWND toplevel_hwnd = ::GetAncestor(parent, GA_ROOT);
330 EnumThreadWindows(GetCurrentThreadId(), DismissOwnedPopups,
331 reinterpret_cast<LPARAM>(toplevel_hwnd));
332 }
333 #endif
334 blink::WebMouseWheelEvent mouse_wheel_event =
335 ui::MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent&>(*event),
336 base::Bind(&GetScreenLocationFromEvent));
337 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) {
338 if (ShouldRouteEvent(event)) {
339 host_->delegate()->GetInputEventRouter()->RouteMouseWheelEvent(
340 host_view_, &mouse_wheel_event, *event->latency());
341 } else {
342 ProcessMouseWheelEvent(mouse_wheel_event, *event->latency());
343 }
344 }
345 } else {
346 bool is_selection_popup = NeedsInputGrab(popup_child_host_view_);
347 if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
348 !(event->flags() & ui::EF_FROM_TOUCH)) {
349 // Confirm existing composition text on mouse press, to make sure
350 // the input caret won't be moved with an ongoing composition text.
351 if (event->type() == ui::ET_MOUSE_PRESSED)
352 FinishImeCompositionSession();
353
354 blink::WebMouseEvent mouse_event = ui::MakeWebMouseEvent(
355 *event, base::Bind(&GetScreenLocationFromEvent));
356 ModifyEventMovementAndCoords(*event, &mouse_event);
357 if (ShouldRouteEvent(event)) {
358 host_->delegate()->GetInputEventRouter()->RouteMouseEvent(
359 host_view_, &mouse_event, *event->latency());
360 } else {
361 ProcessMouseEvent(mouse_event, *event->latency());
362 }
363
364 // Ensure that we get keyboard focus on mouse down as a plugin window may
365 // have grabbed keyboard focus.
366 if (event->type() == ui::ET_MOUSE_PRESSED)
367 SetKeyboardFocus();
368 }
369 }
370
371 switch (event->type()) {
372 case ui::ET_MOUSE_PRESSED:
373 window_->SetCapture();
374 break;
375 case ui::ET_MOUSE_RELEASED:
376 if (!delegate_->NeedsMouseCapture())
377 window_->ReleaseCapture();
378 break;
379 default:
380 break;
381 }
382
383 if (!IsXButtonUpEvent(event))
384 event->SetHandled();
385 }
386
387 void RenderWidgetHostViewEventHandler::OnScrollEvent(ui::ScrollEvent* event) {
388 TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnScrollEvent");
389
390 if (event->type() == ui::ET_SCROLL) {
391 #if !defined(OS_WIN)
392 // TODO(ananta)
393 // Investigate if this is true for Windows 8 Metro ASH as well.
394 if (event->finger_count() != 2)
395 return;
396 #endif
397 blink::WebGestureEvent gesture_event = ui::MakeWebGestureEventFlingCancel();
398 // Coordinates need to be transferred to the fling cancel gesture only
399 // for Surface-targeting to ensure that it is targeted to the correct
400 // RenderWidgetHost.
401 gesture_event.x = event->x();
402 gesture_event.y = event->y();
403 blink::WebMouseWheelEvent mouse_wheel_event = ui::MakeWebMouseWheelEvent(
404 *event, base::Bind(&GetScreenLocationFromEvent));
405 if (ShouldRouteEvent(event)) {
406 host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
407 host_view_, &gesture_event,
408 ui::LatencyInfo(ui::SourceEventType::WHEEL));
409 host_->delegate()->GetInputEventRouter()->RouteMouseWheelEvent(
410 host_view_, &mouse_wheel_event, *event->latency());
411 } else {
412 host_->ForwardGestureEvent(gesture_event);
413 host_->ForwardWheelEventWithLatencyInfo(mouse_wheel_event,
414 *event->latency());
415 }
416 RecordAction(base::UserMetricsAction("TrackpadScroll"));
417 } else if (event->type() == ui::ET_SCROLL_FLING_START ||
418 event->type() == ui::ET_SCROLL_FLING_CANCEL) {
419 blink::WebGestureEvent gesture_event = ui::MakeWebGestureEvent(
420 *event, base::Bind(&GetScreenLocationFromEvent));
421 if (ShouldRouteEvent(event)) {
422 host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
423 host_view_, &gesture_event,
424 ui::LatencyInfo(ui::SourceEventType::WHEEL));
425 } else {
426 host_->ForwardGestureEvent(gesture_event);
427 }
428 if (event->type() == ui::ET_SCROLL_FLING_START)
429 RecordAction(base::UserMetricsAction("TrackpadScrollFling"));
430 }
431
432 event->SetHandled();
433 }
434
435 void RenderWidgetHostViewEventHandler::OnTouchEvent(ui::TouchEvent* event) {
436 TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnTouchEvent");
437
438 bool had_no_pointer = !pointer_state_.GetPointerCount();
439
440 // Update the touch event first.
441 if (!pointer_state_.OnTouch(*event)) {
442 event->StopPropagation();
443 return;
444 }
445
446 blink::WebTouchEvent touch_event;
447 bool handled =
448 delegate_->selection_controller()->WillHandleTouchEvent(pointer_state_);
449 if (handled) {
450 event->SetHandled();
451 } else {
452 touch_event = ui::CreateWebTouchEventFromMotionEvent(
453 pointer_state_, event->may_cause_scrolling());
454 }
455 pointer_state_.CleanupRemovedTouchPoints(*event);
456
457 if (handled)
458 return;
459
460 if (had_no_pointer)
461 delegate_->selection_controller_client()->OnTouchDown();
462 if (!pointer_state_.GetPointerCount())
463 delegate_->selection_controller_client()->OnTouchUp();
464
465 // It is important to always mark events as being handled asynchronously when
466 // they are forwarded. This ensures that the current event does not get
467 // processed by the gesture recognizer before events currently awaiting
468 // dispatch in the touch queue.
469 event->DisableSynchronousHandling();
470
471 // Set unchanged touch point to StateStationary for touchmove and
472 // touchcancel to make sure only send one ack per WebTouchEvent.
473 MarkUnchangedTouchPointsAsStationary(&touch_event, event->touch_id());
474 if (ShouldRouteEvent(event)) {
475 host_->delegate()->GetInputEventRouter()->RouteTouchEvent(
476 host_view_, &touch_event, *event->latency());
477 } else {
478 ProcessTouchEvent(touch_event, *event->latency());
479 }
480 }
481
482 void RenderWidgetHostViewEventHandler::OnGestureEvent(ui::GestureEvent* event) {
483 TRACE_EVENT0("input", "RenderWidgetHostViewBase::OnGestureEvent");
484
485 if ((event->type() == ui::ET_GESTURE_PINCH_BEGIN ||
486 event->type() == ui::ET_GESTURE_PINCH_UPDATE ||
487 event->type() == ui::ET_GESTURE_PINCH_END) &&
488 !pinch_zoom_enabled_) {
489 event->SetHandled();
490 return;
491 }
492
493 HandleGestureForTouchSelection(event);
494 if (event->handled())
495 return;
496
497 // Confirm existing composition text on TAP gesture, to make sure the input
498 // caret won't be moved with an ongoing composition text.
499 if (event->type() == ui::ET_GESTURE_TAP)
500 FinishImeCompositionSession();
501
502 blink::WebGestureEvent gesture =
503 ui::MakeWebGestureEvent(*event, base::Bind(&GetScreenLocationFromEvent));
504 if (event->type() == ui::ET_GESTURE_TAP_DOWN) {
505 // Webkit does not stop a fling-scroll on tap-down. So explicitly send an
506 // event to stop any in-progress flings.
507 blink::WebGestureEvent fling_cancel = gesture;
508 fling_cancel.type = blink::WebInputEvent::GestureFlingCancel;
509 fling_cancel.sourceDevice = blink::WebGestureDeviceTouchscreen;
510 if (ShouldRouteEvent(event)) {
511 host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
512 host_view_, &fling_cancel,
513 ui::LatencyInfo(ui::SourceEventType::TOUCH));
514 } else {
515 host_->ForwardGestureEvent(fling_cancel);
516 }
517 }
518
519 if (gesture.type != blink::WebInputEvent::Undefined) {
520 if (ShouldRouteEvent(event)) {
521 host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
522 host_view_, &gesture, *event->latency());
523 } else {
524 host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency());
525 }
526
527 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN ||
528 event->type() == ui::ET_GESTURE_SCROLL_UPDATE ||
529 event->type() == ui::ET_GESTURE_SCROLL_END) {
530 RecordAction(base::UserMetricsAction("TouchscreenScroll"));
531 } else if (event->type() == ui::ET_SCROLL_FLING_START) {
532 RecordAction(base::UserMetricsAction("TouchscreenScrollFling"));
533 }
534 }
535
536 // If a gesture is not processed by the webpage, then WebKit processes it
537 // (e.g. generates synthetic mouse events).
538 event->SetHandled();
539 }
540
541 bool RenderWidgetHostViewEventHandler::CanRendererHandleEvent(
542 const ui::MouseEvent* event,
543 bool mouse_locked,
544 bool selection_popup) const {
545 if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED)
546 return false;
547
548 if (event->type() == ui::ET_MOUSE_EXITED) {
549 if (mouse_locked || selection_popup)
550 return false;
551 #if defined(OS_WIN)
552 // Don't forward the mouse leave message which is received when the context
553 // menu is displayed by the page. This confuses the page and causes state
554 // changes.
555 if (host_view_->IsShowingContextMenu())
556 return false;
557 #endif
558 return true;
559 }
560
561 #if defined(OS_WIN)
562 // Renderer cannot handle WM_XBUTTON or NC events.
563 switch (event->native_event().message) {
564 case WM_XBUTTONDOWN:
565 case WM_XBUTTONUP:
566 case WM_XBUTTONDBLCLK:
567 case WM_NCMOUSELEAVE:
568 case WM_NCMOUSEMOVE:
569 case WM_NCLBUTTONDOWN:
570 case WM_NCLBUTTONUP:
571 case WM_NCLBUTTONDBLCLK:
572 case WM_NCRBUTTONDOWN:
573 case WM_NCRBUTTONUP:
574 case WM_NCRBUTTONDBLCLK:
575 case WM_NCMBUTTONDOWN:
576 case WM_NCMBUTTONUP:
577 case WM_NCMBUTTONDBLCLK:
578 case WM_NCXBUTTONDOWN:
579 case WM_NCXBUTTONUP:
580 case WM_NCXBUTTONDBLCLK:
581 return false;
582 default:
583 break;
584 }
585 #elif defined(USE_X11)
586 // Renderer only supports standard mouse buttons, so ignore programmable
587 // buttons.
588 switch (event->type()) {
589 case ui::ET_MOUSE_PRESSED:
590 case ui::ET_MOUSE_RELEASED: {
591 const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON |
592 ui::EF_MIDDLE_MOUSE_BUTTON |
593 ui::EF_RIGHT_MOUSE_BUTTON;
594 return (event->flags() & kAllowedButtons) != 0;
595 }
596 default:
597 break;
598 }
599 #endif
600 return true;
601 }
602
603 void RenderWidgetHostViewEventHandler::FinishImeCompositionSession() {
604 if (!host_view_->GetTextInputClient()->HasCompositionText())
605 return;
606
607 TextInputManager* text_input_manager = host_view_->GetTextInputManager();
608 if (!!text_input_manager && !!text_input_manager->GetActiveWidget())
609 text_input_manager->GetActiveWidget()->ImeFinishComposingText(false);
610 host_view_->ImeCancelComposition();
611 }
612
613 void RenderWidgetHostViewEventHandler::ForwardMouseEventToParent(
614 ui::MouseEvent* event) {
615 // Needed to propagate mouse event to |window_->parent()->delegate()|, but
616 // note that it might be something other than a WebContentsViewAura instance.
617 // TODO(pkotwicz): Find a better way of doing this.
618 // In fullscreen mode which is typically used by flash, don't forward
619 // the mouse events to the parent. The renderer and the plugin process
620 // handle these events.
621 if (host_view_->is_fullscreen())
622 return;
623
624 if (event->flags() & ui::EF_FROM_TOUCH)
625 return;
626
627 if (!window_->parent() || !window_->parent()->delegate())
628 return;
629
630 // Take a copy of |event|, to avoid ConvertLocationToTarget mutating the
631 // event.
632 std::unique_ptr<ui::Event> event_copy = ui::Event::Clone(*event);
633 ui::MouseEvent* mouse_event = static_cast<ui::MouseEvent*>(event_copy.get());
634 mouse_event->ConvertLocationToTarget(window_, window_->parent());
635 window_->parent()->delegate()->OnMouseEvent(mouse_event);
636 if (mouse_event->handled())
637 event->SetHandled();
638 }
639
640 void RenderWidgetHostViewEventHandler::HandleGestureForTouchSelection(
641 ui::GestureEvent* event) {
642 switch (event->type()) {
643 case ui::ET_GESTURE_LONG_PRESS:
644 if (delegate_->selection_controller()->WillHandleLongPressEvent(
645 event->time_stamp(), event->location_f())) {
646 event->SetHandled();
647 }
648 break;
649 case ui::ET_GESTURE_TAP:
650 if (delegate_->selection_controller()->WillHandleTapEvent(
651 event->location_f(), event->details().tap_count())) {
652 event->SetHandled();
653 }
654 break;
655 case ui::ET_GESTURE_SCROLL_BEGIN:
656 delegate_->selection_controller_client()->OnScrollStarted();
657 break;
658 case ui::ET_GESTURE_SCROLL_END:
659 delegate_->selection_controller_client()->OnScrollCompleted();
660 break;
661 #if defined(OS_WIN)
662 case ui::ET_GESTURE_LONG_TAP: {
663 if (!last_context_menu_params_)
664 break;
665
666 std::unique_ptr<ContextMenuParams> context_menu_params =
667 std::move(last_context_menu_params_);
668
669 // On Windows we want to display the context menu when the long press
670 // gesture is released. To achieve that, we switch the saved context
671 // menu params source type to MENU_SOURCE_TOUCH. This is to ensure that
672 // the RenderWidgetHostViewBase::OnShowContextMenu function which is
673 // called from the ShowContextMenu call below, does not treat it as
674 // a context menu request coming in from the long press gesture.
675 DCHECK(context_menu_params->source_type == ui::MENU_SOURCE_LONG_PRESS);
676 context_menu_params->source_type = ui::MENU_SOURCE_TOUCH;
677
678 delegate_->ShowContextMenu(*context_menu_params);
679 event->SetHandled();
680 // WARNING: we may have been deleted during the call to ShowContextMenu().
681 break;
682 }
683 #endif
684 default:
685 break;
686 }
687 }
688
689 void RenderWidgetHostViewEventHandler::HandleMouseEventWhileLocked(
690 ui::MouseEvent* event) {
691 aura::client::CursorClient* cursor_client =
692 aura::client::GetCursorClient(window_->GetRootWindow());
693
694 DCHECK(!cursor_client || !cursor_client->IsCursorVisible());
695
696 if (event->type() == ui::ET_MOUSEWHEEL) {
697 blink::WebMouseWheelEvent mouse_wheel_event =
698 ui::MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent&>(*event),
699 base::Bind(&GetScreenLocationFromEvent));
700 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0)
701 host_->ForwardWheelEvent(mouse_wheel_event);
702 return;
703 }
704
705 gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint());
706
707 // If we receive non client mouse messages while we are in the locked state
708 // it probably means that the mouse left the borders of our window and
709 // needs to be moved back to the center.
710 if (event->flags() & ui::EF_IS_NON_CLIENT) {
711 // TODO(jonross): ideally this would not be done for mus (crbug.com/621412)
712 synthetic_move_sent_ = true;
713 window_->MoveCursorTo(center);
714 return;
715 }
716
717 blink::WebMouseEvent mouse_event =
718 ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent));
719
720 bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED ||
721 event->type() == ui::ET_MOUSE_DRAGGED) &&
722 mouse_event.x == center.x() &&
723 mouse_event.y == center.y();
724
725 // For fractional scale factors, the conversion from pixels to dip and
726 // vice versa could result in off by 1 or 2 errors which hurts us because
727 // we want to avoid sending the artificial move to center event to the
728 // renderer. Sending the move to center to the renderer cause the cursor
729 // to bounce around the center of the screen leading to the lock operation
730 // not working correctly.
731 // Workaround is to treat a mouse move or drag event off by at most 2 px
732 // from the center as a move to center event.
733 if (synthetic_move_sent_ &&
734 IsFractionalScaleFactor(host_view_->current_device_scale_factor())) {
735 if (event->type() == ui::ET_MOUSE_MOVED ||
736 event->type() == ui::ET_MOUSE_DRAGGED) {
737 if ((abs(mouse_event.x - center.x()) <= 2) &&
738 (abs(mouse_event.y - center.y()) <= 2)) {
739 is_move_to_center_event = true;
740 }
741 }
742 }
743
744 ModifyEventMovementAndCoords(*event, &mouse_event);
745
746 bool should_not_forward = is_move_to_center_event && synthetic_move_sent_;
747 if (should_not_forward) {
748 synthetic_move_sent_ = false;
749 } else {
750 // Check if the mouse has reached the border and needs to be centered.
751 if (ShouldMoveToCenter()) {
752 synthetic_move_sent_ = true;
753 window_->MoveCursorTo(center);
754 }
755 bool is_selection_popup = NeedsInputGrab(popup_child_host_view_);
756 // Forward event to renderer.
757 if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) &&
758 !(event->flags() & ui::EF_FROM_TOUCH)) {
759 host_->ForwardMouseEvent(mouse_event);
760 // Ensure that we get keyboard focus on mouse down as a plugin window
761 // may have grabbed keyboard focus.
762 if (event->type() == ui::ET_MOUSE_PRESSED)
763 SetKeyboardFocus();
764 }
765 }
766 }
767
768 void RenderWidgetHostViewEventHandler::ModifyEventMovementAndCoords(
769 const ui::MouseEvent& ui_mouse_event,
770 blink::WebMouseEvent* event) {
771 // If the mouse has just entered, we must report zero movementX/Y. Hence we
772 // reset any global_mouse_position set previously.
773 if (ui_mouse_event.type() == ui::ET_MOUSE_ENTERED ||
774 ui_mouse_event.type() == ui::ET_MOUSE_EXITED) {
775 global_mouse_position_.SetPoint(event->globalX, event->globalY);
776 }
777
778 // Movement is computed by taking the difference of the new cursor position
779 // and the previous. Under mouse lock the cursor will be warped back to the
780 // center so that we are not limited by clipping boundaries.
781 // We do not measure movement as the delta from cursor to center because
782 // we may receive more mouse movement events before our warp has taken
783 // effect.
784 event->movementX = event->globalX - global_mouse_position_.x();
785 event->movementY = event->globalY - global_mouse_position_.y();
786
787 global_mouse_position_.SetPoint(event->globalX, event->globalY);
788
789 // Under mouse lock, coordinates of mouse are locked to what they were when
790 // mouse lock was entered.
791 if (mouse_locked_) {
792 event->x = unlocked_mouse_position_.x();
793 event->y = unlocked_mouse_position_.y();
794 event->windowX = unlocked_mouse_position_.x();
795 event->windowY = unlocked_mouse_position_.y();
796 event->globalX = unlocked_global_mouse_position_.x();
797 event->globalY = unlocked_global_mouse_position_.y();
798 } else {
799 unlocked_mouse_position_.SetPoint(event->x, event->y);
800 unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY);
801 }
802 }
803
804 void RenderWidgetHostViewEventHandler::SetKeyboardFocus() {
805 #if defined(OS_WIN)
806 if (window_ && window_->delegate()->CanFocus()) {
807 aura::WindowTreeHost* host = window_->GetHost();
808 if (host) {
809 gfx::AcceleratedWidget hwnd = host->GetAcceleratedWidget();
810 if (!(::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE))
811 ::SetFocus(hwnd);
812 }
813 }
814 #endif
815 // TODO(wjmaclean): can host_ ever be null?
816 if (host_ && set_focus_on_mouse_down_or_key_event_) {
817 set_focus_on_mouse_down_or_key_event_ = false;
818 host_->Focus();
819 }
820 }
821
822 bool RenderWidgetHostViewEventHandler::ShouldMoveToCenter() {
823 gfx::Rect rect = window_->bounds();
824 rect = delegate_->ConvertRectToScreen(rect);
825 int border_x = rect.width() * kMouseLockBorderPercentage / 100;
826 int border_y = rect.height() * kMouseLockBorderPercentage / 100;
827
828 return global_mouse_position_.x() < rect.x() + border_x ||
829 global_mouse_position_.x() > rect.right() - border_x ||
830 global_mouse_position_.y() < rect.y() + border_y ||
831 global_mouse_position_.y() > rect.bottom() - border_y;
832 }
833
834 bool RenderWidgetHostViewEventHandler::ShouldRouteEvent(
835 const ui::Event* event) const {
836 // We should route an event in two cases:
837 // 1) Mouse events are routed only if cross-process frames are possible.
838 // 2) Touch events are always routed. In the absence of a BrowserPlugin
839 // we expect the routing to always send the event to this view. If
840 // one or more BrowserPlugins are present, then the event may be targeted
841 // to one of them, or this view. This allows GuestViews to have access to
842 // them while still forcing pinch-zoom to be handled by the top-level
843 // frame. TODO(wjmaclean): At present, this doesn't work for OOPIF, but
844 // it should be a simple extension to modify RenderWidgetHostViewChildFrame
845 // in a similar manner to RenderWidgetHostViewGuest.
846 bool result = host_->delegate() && host_->delegate()->GetInputEventRouter() &&
847 !disable_input_event_router_for_testing_;
848 // ScrollEvents get transformed into MouseWheel events, and so are treated
849 // the same as mouse events for routing purposes.
850 if (event->IsMouseEvent() || event->type() == ui::ET_SCROLL)
851 result = result && SiteIsolationPolicy::AreCrossProcessFramesPossible();
852 return result;
853 }
854
855 void RenderWidgetHostViewEventHandler::ProcessMouseEvent(
856 const blink::WebMouseEvent& event,
857 const ui::LatencyInfo& latency) {
858 host_->ForwardMouseEventWithLatencyInfo(event, latency);
859 }
860
861 void RenderWidgetHostViewEventHandler::ProcessMouseWheelEvent(
862 const blink::WebMouseWheelEvent& event,
863 const ui::LatencyInfo& latency) {
864 host_->ForwardWheelEventWithLatencyInfo(event, latency);
865 }
866
867 void RenderWidgetHostViewEventHandler::ProcessTouchEvent(
868 const blink::WebTouchEvent& event,
869 const ui::LatencyInfo& latency) {
870 host_->ForwardTouchEventWithLatencyInfo(event, latency);
871 }
872
873 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/render_widget_host_view_event_handler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698