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/views/corewm/compound_event_filter.h"
7 #include "base/containers/hash_tables.h"
8 #include "base/logging.h"
9 #include "ui/aura/client/activation_client.h"
10 #include "ui/aura/client/cursor_client.h"
11 #include "ui/aura/client/drag_drop_client.h"
12 #include "ui/aura/env.h"
13 #include "ui/aura/root_window.h"
14 #include "ui/aura/window_delegate.h"
15 #include "ui/aura/window_tracker.h"
16 #include "ui/base/hit_test.h"
17 #include "ui/events/event.h"
24 bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) {
25 #if defined(OS_CHROMEOS)
26 // All alt and control key commands are ignored.
27 if (event.IsAltDown() || event.IsControlDown())
30 static bool inited = false;
31 static base::hash_set<int32> ignored_keys;
34 ignored_keys.insert(ui::VKEY_SHIFT);
35 ignored_keys.insert(ui::VKEY_CONTROL);
36 ignored_keys.insert(ui::VKEY_MENU);
38 // Search key == VKEY_LWIN.
39 ignored_keys.insert(ui::VKEY_LWIN);
42 for (int key = ui::VKEY_F1; key <= ui::VKEY_F24; ++key)
43 ignored_keys.insert(key);
46 for (int key = ui::VKEY_BROWSER_BACK; key <= ui::VKEY_MEDIA_LAUNCH_APP2;
48 ignored_keys.insert(key);
52 ignored_keys.insert(ui::VKEY_WLAN);
53 ignored_keys.insert(ui::VKEY_POWER);
54 ignored_keys.insert(ui::VKEY_BRIGHTNESS_DOWN);
55 ignored_keys.insert(ui::VKEY_BRIGHTNESS_UP);
56 ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_DOWN);
57 ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_UP);
63 if (ignored_keys.count(event.key_code()) > 0)
67 #else // !defined(OS_CHROMEOS)
69 #endif // defined(OS_CHROMEOS)
72 // Returns true if the cursor should be hidden on touch events.
73 bool ShouldHideCursorOnTouch() {
74 #if defined(OS_CHROMEOS)
77 // Not necessary on windows as windows does it for us. If we do need this
78 // funcionality on linux (non-chromeos) we need to make sure
79 // CompoundEventFilter shows on the right root (it currently doesn't always).
86 ////////////////////////////////////////////////////////////////////////////////
87 // CompoundEventFilter, public:
89 CompoundEventFilter::CompoundEventFilter() : cursor_hidden_by_filter_(false) {
92 CompoundEventFilter::~CompoundEventFilter() {
93 // Additional filters are not owned by CompoundEventFilter and they
94 // should all be removed when running here. |handlers_| has
95 // check_empty == true and will DCHECK failure if it is not empty.
99 gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
100 int window_component) {
101 switch (window_component) {
103 return ui::kCursorSouthResize;
105 return ui::kCursorSouthWestResize;
107 return ui::kCursorSouthEastResize;
109 return ui::kCursorWestResize;
111 return ui::kCursorEastResize;
113 return ui::kCursorNorthResize;
115 return ui::kCursorNorthWestResize;
117 return ui::kCursorNorthEastResize;
119 return ui::kCursorNull;
123 void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
124 handlers_.AddObserver(handler);
127 void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
128 handlers_.RemoveObserver(handler);
131 ////////////////////////////////////////////////////////////////////////////////
132 // CompoundEventFilter, private:
134 void CompoundEventFilter::UpdateCursor(aura::Window* target,
135 ui::MouseEvent* event) {
136 // If drag and drop is in progress, let the drag drop client set the cursor
137 // instead of setting the cursor here.
138 aura::Window* root_window = target->GetRootWindow();
139 aura::client::DragDropClient* drag_drop_client =
140 aura::client::GetDragDropClient(root_window);
141 if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
144 aura::client::CursorClient* cursor_client =
145 aura::client::GetCursorClient(root_window);
147 gfx::NativeCursor cursor = target->GetCursor(event->location());
148 if (event->flags() & ui::EF_IS_NON_CLIENT) {
149 int window_component =
150 target->delegate()->GetNonClientComponent(event->location());
151 cursor = CursorForWindowComponent(window_component);
154 cursor_client->SetCursor(cursor);
158 void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
159 if (handlers_.might_have_observers()) {
160 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
161 ui::EventHandler* handler;
162 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
163 handler->OnKeyEvent(event);
167 void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
168 if (handlers_.might_have_observers()) {
169 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
170 ui::EventHandler* handler;
171 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
172 handler->OnMouseEvent(event);
176 void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
177 if (handlers_.might_have_observers()) {
178 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
179 ui::EventHandler* handler;
180 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
181 handler->OnTouchEvent(event);
185 void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
188 DCHECK(ShouldHideCursorOnTouch());
189 if (event->flags() & ui::EF_IS_SYNTHESIZED)
192 aura::client::CursorClient* client =
193 aura::client::GetCursorClient(target->GetRootWindow());
197 if (show && cursor_hidden_by_filter_) {
198 cursor_hidden_by_filter_ = false;
199 client->ShowCursor();
200 } else if (!show && !cursor_hidden_by_filter_) {
201 cursor_hidden_by_filter_ = true;
202 client->HideCursor();
203 } else if (show && !client->IsCursorVisible() && !client->IsCursorLocked()) {
204 // TODO(tdanderson): Remove this temporary logging once the issues related
205 // to a disappearing mouse cursor on the Pixel login screen / Pixel
206 // wakeup have been resolved. See crbug.com/275826.
207 LOG(ERROR) << "Event of type " << event->type() << " did not show cursor."
208 << " Mouse enabled state is " << client->IsMouseEventsEnabled();
212 void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
215 if (event->flags() & ui::EF_IS_SYNTHESIZED)
217 aura::client::CursorClient* client =
218 aura::client::GetCursorClient(target->GetRootWindow());
223 client->EnableMouseEvents();
225 client->DisableMouseEvents();
228 ////////////////////////////////////////////////////////////////////////////////
229 // CompoundEventFilter, ui::EventHandler implementation:
231 void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
232 if (ShouldHideCursorOnKeyEvent(*event)) {
233 SetCursorVisibilityOnEvent(
234 static_cast<aura::Window*>(event->target()), event, false);
237 FilterKeyEvent(event);
240 void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
241 aura::Window* window = static_cast<aura::Window*>(event->target());
242 aura::WindowTracker window_tracker;
243 window_tracker.Add(window);
245 // We must always update the cursor, otherwise the cursor can get stuck if an
246 // event filter registered with us consumes the event.
247 // It should also update the cursor for clicking and wheels for ChromeOS boot.
248 // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
249 // operation will show the cursor.
250 // We also update the cursor for mouse enter in case a mouse cursor is sent to
251 // outside of the root window and moved back for some reasons (e.g. running on
252 // on Desktop for testing, or a bug in pointer barrier).
253 if (event->type() == ui::ET_MOUSE_ENTERED ||
254 event->type() == ui::ET_MOUSE_MOVED ||
255 event->type() == ui::ET_MOUSE_PRESSED ||
256 event->type() == ui::ET_MOUSEWHEEL) {
257 if (ShouldHideCursorOnTouch()) {
258 SetMouseEventsEnableStateOnEvent(window, event, true);
259 SetCursorVisibilityOnEvent(window, event, true);
261 UpdateCursor(window, event);
264 FilterMouseEvent(event);
267 void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
270 void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
271 FilterTouchEvent(event);
272 if (ShouldHideCursorOnTouch() && !event->handled() &&
273 event->type() == ui::ET_TOUCH_PRESSED &&
274 !aura::Env::GetInstance()->IsMouseButtonDown()) {
275 SetMouseEventsEnableStateOnEvent(
276 static_cast<aura::Window*>(event->target()), event, false);
280 void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
281 if (handlers_.might_have_observers()) {
282 ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
283 ui::EventHandler* handler;
284 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
285 handler->OnGestureEvent(event);
289 } // namespace corewm