compound_event_filter.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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. 4 5#include "ui/views/corewm/compound_event_filter.h" 6 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" 18 19namespace views { 20namespace corewm { 21 22namespace { 23 24bool 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()) 28 return false; 29 30 static bool inited = false; 31 static base::hash_set<int32> ignored_keys; 32 if (!inited) { 33 // Modifiers. 34 ignored_keys.insert(ui::VKEY_SHIFT); 35 ignored_keys.insert(ui::VKEY_CONTROL); 36 ignored_keys.insert(ui::VKEY_MENU); 37 38 // Search key == VKEY_LWIN. 39 ignored_keys.insert(ui::VKEY_LWIN); 40 41 // Function keys. 42 for (int key = ui::VKEY_F1; key <= ui::VKEY_F24; ++key) 43 ignored_keys.insert(key); 44 45 // Media keys. 46 for (int key = ui::VKEY_BROWSER_BACK; key <= ui::VKEY_MEDIA_LAUNCH_APP2; 47 ++key) { 48 ignored_keys.insert(key); 49 } 50 51#if defined(OS_POSIX) 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); 58#endif 59 60 inited = true; 61 } 62 63 if (ignored_keys.count(event.key_code()) > 0) 64 return false; 65 66 return true; 67#else // !defined(OS_CHROMEOS) 68 return false; 69#endif // defined(OS_CHROMEOS) 70} 71 72} // namespace 73 74//////////////////////////////////////////////////////////////////////////////// 75// CompoundEventFilter, public: 76 77CompoundEventFilter::CompoundEventFilter() : cursor_hidden_by_filter_(false) { 78} 79 80CompoundEventFilter::~CompoundEventFilter() { 81 // Additional filters are not owned by CompoundEventFilter and they 82 // should all be removed when running here. |handlers_| has 83 // check_empty == true and will DCHECK failure if it is not empty. 84} 85 86// static 87gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent( 88 int window_component) { 89 switch (window_component) { 90 case HTBOTTOM: 91 return ui::kCursorSouthResize; 92 case HTBOTTOMLEFT: 93 return ui::kCursorSouthWestResize; 94 case HTBOTTOMRIGHT: 95 return ui::kCursorSouthEastResize; 96 case HTLEFT: 97 return ui::kCursorWestResize; 98 case HTRIGHT: 99 return ui::kCursorEastResize; 100 case HTTOP: 101 return ui::kCursorNorthResize; 102 case HTTOPLEFT: 103 return ui::kCursorNorthWestResize; 104 case HTTOPRIGHT: 105 return ui::kCursorNorthEastResize; 106 default: 107 return ui::kCursorNull; 108 } 109} 110 111void CompoundEventFilter::AddHandler(ui::EventHandler* handler) { 112 handlers_.AddObserver(handler); 113} 114 115void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) { 116 handlers_.RemoveObserver(handler); 117} 118 119//////////////////////////////////////////////////////////////////////////////// 120// CompoundEventFilter, private: 121 122void CompoundEventFilter::UpdateCursor(aura::Window* target, 123 ui::MouseEvent* event) { 124 // If drag and drop is in progress, let the drag drop client set the cursor 125 // instead of setting the cursor here. 126 aura::RootWindow* root_window = target->GetRootWindow(); 127 aura::client::DragDropClient* drag_drop_client = 128 aura::client::GetDragDropClient(root_window); 129 if (drag_drop_client && drag_drop_client->IsDragDropInProgress()) 130 return; 131 132 aura::client::CursorClient* cursor_client = 133 aura::client::GetCursorClient(root_window); 134 if (cursor_client) { 135 gfx::NativeCursor cursor = target->GetCursor(event->location()); 136 if (event->flags() & ui::EF_IS_NON_CLIENT) { 137 int window_component = 138 target->delegate()->GetNonClientComponent(event->location()); 139 cursor = CursorForWindowComponent(window_component); 140 } 141 142 cursor_client->SetCursor(cursor); 143 } 144} 145 146void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) { 147 if (handlers_.might_have_observers()) { 148 ObserverListBase<ui::EventHandler>::Iterator it(handlers_); 149 ui::EventHandler* handler; 150 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL) 151 handler->OnKeyEvent(event); 152 } 153} 154 155void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) { 156 if (handlers_.might_have_observers()) { 157 ObserverListBase<ui::EventHandler>::Iterator it(handlers_); 158 ui::EventHandler* handler; 159 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL) 160 handler->OnMouseEvent(event); 161 } 162} 163 164void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) { 165 if (handlers_.might_have_observers()) { 166 ObserverListBase<ui::EventHandler>::Iterator it(handlers_); 167 ui::EventHandler* handler; 168 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL) 169 handler->OnTouchEvent(event); 170 } 171} 172 173void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target, 174 ui::Event* event, 175 bool show) { 176 if (event->flags() & ui::EF_IS_SYNTHESIZED) 177 return; 178 179 aura::client::CursorClient* client = 180 aura::client::GetCursorClient(target->GetRootWindow()); 181 if (!client) 182 return; 183 184 if (show && cursor_hidden_by_filter_) { 185 cursor_hidden_by_filter_ = false; 186 client->ShowCursor(); 187 } else if (!show && !cursor_hidden_by_filter_) { 188 cursor_hidden_by_filter_ = true; 189 client->HideCursor(); 190 } else if (show && !client->IsCursorVisible() && !client->IsCursorLocked()) { 191 // TODO(tdanderson): Remove this temporary logging once the issues related 192 // to a disappearing mouse cursor on the Pixel login screen / Pixel 193 // wakeup have been resolved. See crbug.com/275826. 194 LOG(ERROR) << "Event of type " << event->type() << " did not show cursor." 195 << " Mouse enabled state is " << client->IsMouseEventsEnabled(); 196 } 197} 198 199void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target, 200 ui::Event* event, 201 bool enable) { 202 if (event->flags() & ui::EF_IS_SYNTHESIZED) 203 return; 204 aura::client::CursorClient* client = 205 aura::client::GetCursorClient(target->GetRootWindow()); 206 if (!client) 207 return; 208 209 if (enable) 210 client->EnableMouseEvents(); 211 else 212 client->DisableMouseEvents(); 213} 214 215//////////////////////////////////////////////////////////////////////////////// 216// CompoundEventFilter, ui::EventHandler implementation: 217 218void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) { 219 if (ShouldHideCursorOnKeyEvent(*event)) { 220 SetCursorVisibilityOnEvent( 221 static_cast<aura::Window*>(event->target()), event, false); 222 } 223 224 FilterKeyEvent(event); 225} 226 227void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) { 228 aura::Window* window = static_cast<aura::Window*>(event->target()); 229 aura::WindowTracker window_tracker; 230 window_tracker.Add(window); 231 232 // We must always update the cursor, otherwise the cursor can get stuck if an 233 // event filter registered with us consumes the event. 234 // It should also update the cursor for clicking and wheels for ChromeOS boot. 235 // When ChromeOS is booted, it hides the mouse cursor but immediate mouse 236 // operation will show the cursor. 237 // We also update the cursor for mouse enter in case a mouse cursor is sent to 238 // outside of the root window and moved back for some reasons (e.g. running on 239 // on Desktop for testing, or a bug in pointer barrier). 240 if (event->type() == ui::ET_MOUSE_ENTERED || 241 event->type() == ui::ET_MOUSE_MOVED || 242 event->type() == ui::ET_MOUSE_PRESSED || 243 event->type() == ui::ET_MOUSEWHEEL) { 244 SetMouseEventsEnableStateOnEvent(window, event, true); 245 SetCursorVisibilityOnEvent(window, event, true); 246 UpdateCursor(window, event); 247 } 248 249 FilterMouseEvent(event); 250} 251 252void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) { 253} 254 255void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) { 256 FilterTouchEvent(event); 257 if (!event->handled() && event->type() == ui::ET_TOUCH_PRESSED && 258 !aura::Env::GetInstance()->IsMouseButtonDown()) { 259 SetMouseEventsEnableStateOnEvent( 260 static_cast<aura::Window*>(event->target()), event, false); 261 } 262} 263 264void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) { 265 if (handlers_.might_have_observers()) { 266 ObserverListBase<ui::EventHandler>::Iterator it(handlers_); 267 ui::EventHandler* handler; 268 while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL) 269 handler->OnGestureEvent(event); 270 } 271} 272 273} // namespace corewm 274} // namespace views 275