1 // Copyright (c) 2012 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 "ui/wm/core/compound_event_filter.h"
7 #include "base/containers/hash_tables.h"
8 #include "base/logging.h"
9 #include "ui/aura/client/cursor_client.h"
10 #include "ui/aura/env.h"
11 #include "ui/aura/window.h"
12 #include "ui/aura/window_delegate.h"
13 #include "ui/aura/window_event_dispatcher.h"
14 #include "ui/aura/window_tracker.h"
15 #include "ui/base/hit_test.h"
16 #include "ui/events/event.h"
17 #include "ui/wm/public/activation_client.h"
18 #include "ui/wm/public/drag_drop_client.h"
20 #if defined(OS_CHROMEOS) && defined(USE_X11)
21 #include "ui/events/x/touch_factory_x11.h"
28 bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) {
29 #if defined(OS_CHROMEOS)
30 // All alt and control key commands are ignored.
31 if (event.IsAltDown() || event.IsControlDown())
34 static bool inited = false;
35 static base::hash_set<int32> ignored_keys;
38 ignored_keys.insert(ui::VKEY_SHIFT);
39 ignored_keys.insert(ui::VKEY_CONTROL);
40 ignored_keys.insert(ui::VKEY_MENU);
42 // Search key == VKEY_LWIN.
43 ignored_keys.insert(ui::VKEY_LWIN);
46 for (int key = ui::VKEY_F1; key <= ui::VKEY_F24; ++key)
47 ignored_keys.insert(key);
50 for (int key = ui::VKEY_BROWSER_BACK; key <= ui::VKEY_MEDIA_LAUNCH_APP2;
52 ignored_keys.insert(key);
56 ignored_keys.insert(ui::VKEY_WLAN);
57 ignored_keys.insert(ui::VKEY_POWER);
58 ignored_keys.insert(ui::VKEY_BRIGHTNESS_DOWN);
59 ignored_keys.insert(ui::VKEY_BRIGHTNESS_UP);
60 ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_DOWN);
61 ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_UP);
67 if (ignored_keys.count(event.key_code()) > 0)
71 #else // !defined(OS_CHROMEOS)
73 #endif // defined(OS_CHROMEOS)
76 // Returns true if the cursor should be hidden on touch events.
77 bool ShouldHideCursorOnTouch(const ui::TouchEvent& event) {
78 #if defined(OS_CHROMEOS)
80 int device_id = event.source_device_id();
82 !ui::TouchFactory::GetInstance()->IsMultiTouchDevice(device_id)) {
83 // If the touch event is coming from a mouse-device (i.e. not a real
84 // touch-device), then do not hide the cursor.
87 #endif // defined(USE_X11)
90 // Windows hides the cursor on touch, but we cannot track the cursor
91 // visibility or enabledness state reliably until we are able to
92 // properly flag all incoming mouse messages in HWNDMessageHandler.
93 // TODO(ananta|tdanderson): crbug.com/332430
100 ////////////////////////////////////////////////////////////////////////////////
101 // CompoundEventFilter, public:
103 CompoundEventFilter::CompoundEventFilter() {
106 CompoundEventFilter::~CompoundEventFilter() {
107 // Additional filters are not owned by CompoundEventFilter and they
108 // should all be removed when running here. |handlers_| has
109 // check_empty == true and will DCHECK failure if it is not empty.
113 gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
114 int window_component) {
115 switch (window_component) {
117 return ui::kCursorSouthResize;
119 return ui::kCursorSouthWestResize;
121 return ui::kCursorSouthEastResize;
123 return ui::kCursorWestResize;
125 return ui::kCursorEastResize;
127 return ui::kCursorNorthResize;
129 return ui::kCursorNorthWestResize;
131 return ui::kCursorNorthEastResize;
133 return ui::kCursorNull;
137 void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
138 handlers_.AddObserver(handler);
141 void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
142 handlers_.RemoveObserver(handler);
145 ////////////////////////////////////////////////////////////////////////////////
146 // CompoundEventFilter, private:
148 void CompoundEventFilter::UpdateCursor(aura::Window* target,
149 ui::MouseEvent* event) {
150 // If drag and drop is in progress, let the drag drop client set the cursor
151 // instead of setting the cursor here.
152 aura::Window* root_window = target->GetRootWindow();
153 aura::client::DragDropClient* drag_drop_client =
154 aura::client::GetDragDropClient(root_window);
155 if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
158 aura::client::CursorClient* cursor_client =
159 aura::client::GetCursorClient(root_window);
161 gfx::NativeCursor cursor = target->GetCursor(event->location());
162 if ((event->flags() & ui::EF_IS_NON_CLIENT)) {
163 if (target->delegate()) {
164 int window_component =
165 target->delegate()->GetNonClientComponent(event->location());
166 cursor = CursorForWindowComponent(window_component);
168 // Allow the OS to handle non client cursors if we don't have a
169 // a delegate to handle the non client hittest.
173 cursor_client->SetCursor(cursor);
177 void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
178 if (handlers_.might_have_observers()) {
179 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
180 ui::EventHandler* handler;
181 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
182 handler->OnKeyEvent(event);
186 void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
187 if (handlers_.might_have_observers()) {
188 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
189 ui::EventHandler* handler;
190 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
191 handler->OnMouseEvent(event);
195 void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
196 if (handlers_.might_have_observers()) {
197 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
198 ui::EventHandler* handler;
199 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
200 handler->OnTouchEvent(event);
204 void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
207 if (event->flags() & ui::EF_IS_SYNTHESIZED)
210 aura::client::CursorClient* client =
211 aura::client::GetCursorClient(target->GetRootWindow());
216 client->ShowCursor();
218 client->HideCursor();
221 void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
224 if (event->flags() & ui::EF_IS_SYNTHESIZED)
226 aura::client::CursorClient* client =
227 aura::client::GetCursorClient(target->GetRootWindow());
232 client->EnableMouseEvents();
234 client->DisableMouseEvents();
237 ////////////////////////////////////////////////////////////////////////////////
238 // CompoundEventFilter, ui::EventHandler implementation:
240 void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
241 if (ShouldHideCursorOnKeyEvent(*event)) {
242 SetCursorVisibilityOnEvent(
243 static_cast<aura::Window*>(event->target()), event, false);
246 FilterKeyEvent(event);
249 void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
250 aura::Window* window = static_cast<aura::Window*>(event->target());
251 aura::WindowTracker window_tracker;
252 window_tracker.Add(window);
254 // We must always update the cursor, otherwise the cursor can get stuck if an
255 // event filter registered with us consumes the event.
256 // It should also update the cursor for clicking and wheels for ChromeOS boot.
257 // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
258 // operation will show the cursor.
259 // We also update the cursor for mouse enter in case a mouse cursor is sent to
260 // outside of the root window and moved back for some reasons (e.g. running on
261 // on Desktop for testing, or a bug in pointer barrier).
262 if (event->type() == ui::ET_MOUSE_ENTERED ||
263 event->type() == ui::ET_MOUSE_MOVED ||
264 event->type() == ui::ET_MOUSE_PRESSED ||
265 event->type() == ui::ET_MOUSEWHEEL) {
266 SetMouseEventsEnableStateOnEvent(window, event, true);
267 SetCursorVisibilityOnEvent(window, event, true);
268 UpdateCursor(window, event);
271 FilterMouseEvent(event);
274 void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
277 void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
278 FilterTouchEvent(event);
279 if (!event->handled() && event->type() == ui::ET_TOUCH_PRESSED &&
280 ShouldHideCursorOnTouch(*event) &&
281 !aura::Env::GetInstance()->IsMouseButtonDown()) {
282 SetMouseEventsEnableStateOnEvent(
283 static_cast<aura::Window*>(event->target()), event, false);
287 void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
288 if (handlers_.might_have_observers()) {
289 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
290 ui::EventHandler* handler;
291 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
292 handler->OnGestureEvent(event);