Move render_view_context_menu.* and related files out of tab_contents.
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_controller.cc
blobca7f6ee6c1a5450a70e351fc215ce03b1dd70928
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 "ash/sticky_keys/sticky_keys_controller.h"
7 #if defined(USE_X11)
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10 #undef RootWindow
11 #endif
13 #include "ash/sticky_keys/sticky_keys_overlay.h"
14 #include "base/basictypes.h"
15 #include "base/debug/stack_trace.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_event_dispatcher.h"
18 #include "ui/aura/window_tracker.h"
19 #include "ui/events/event.h"
20 #include "ui/events/keycodes/keyboard_code_conversion.h"
22 namespace ash {
24 namespace {
26 // Returns true if the type of mouse event should be modified by sticky keys.
27 bool ShouldModifyMouseEvent(ui::MouseEvent* event) {
28 ui::EventType type = event->type();
29 return type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED ||
30 type == ui::ET_MOUSEWHEEL;
33 // An implementation of StickyKeysHandler::StickyKeysHandlerDelegate.
34 class StickyKeysHandlerDelegateImpl :
35 public StickyKeysHandler::StickyKeysHandlerDelegate {
36 public:
37 StickyKeysHandlerDelegateImpl();
38 virtual ~StickyKeysHandlerDelegateImpl();
40 // StickyKeysHandlerDelegate overrides.
41 virtual void DispatchKeyEvent(ui::KeyEvent* event,
42 aura::Window* target) OVERRIDE;
44 virtual void DispatchMouseEvent(ui::MouseEvent* event,
45 aura::Window* target) OVERRIDE;
47 virtual void DispatchScrollEvent(ui::ScrollEvent* event,
48 aura::Window* target) OVERRIDE;
49 private:
50 void DispatchEvent(ui::Event* event, aura::Window* target);
52 DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl);
55 StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() {
58 StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() {
61 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event,
62 aura::Window* target) {
63 DispatchEvent(event, target);
66 void StickyKeysHandlerDelegateImpl::DispatchMouseEvent(ui::MouseEvent* event,
67 aura::Window* target) {
68 DCHECK(target);
69 // We need to send a new, untransformed mouse event to the host.
70 if (event->IsMouseWheelEvent()) {
71 ui::MouseWheelEvent new_event(*static_cast<ui::MouseWheelEvent*>(event));
72 DispatchEvent(&new_event, target);
73 } else {
74 ui::MouseEvent new_event(*event, target, target->GetRootWindow());
75 DispatchEvent(&new_event, target);
79 void StickyKeysHandlerDelegateImpl::DispatchScrollEvent(
80 ui::ScrollEvent* event,
81 aura::Window* target) {
82 DispatchEvent(event, target);
85 void StickyKeysHandlerDelegateImpl::DispatchEvent(ui::Event* event,
86 aura::Window* target) {
87 DCHECK(target);
88 ui::EventDispatchDetails details =
89 target->GetDispatcher()->OnEventFromSource(event);
90 if (details.dispatcher_destroyed)
91 return;
94 } // namespace
96 ///////////////////////////////////////////////////////////////////////////////
97 // StickyKeys
98 StickyKeysController::StickyKeysController()
99 : enabled_(false) {
102 StickyKeysController::~StickyKeysController() {
105 void StickyKeysController::Enable(bool enabled) {
106 if (enabled_ != enabled) {
107 enabled_ = enabled;
109 // Reset key handlers when activating sticky keys to ensure all
110 // the handlers' states are reset.
111 if (enabled_) {
112 shift_sticky_key_.reset(
113 new StickyKeysHandler(ui::EF_SHIFT_DOWN,
114 new StickyKeysHandlerDelegateImpl()));
115 alt_sticky_key_.reset(
116 new StickyKeysHandler(ui::EF_ALT_DOWN,
117 new StickyKeysHandlerDelegateImpl()));
118 ctrl_sticky_key_.reset(
119 new StickyKeysHandler(ui::EF_CONTROL_DOWN,
120 new StickyKeysHandlerDelegateImpl()));
122 overlay_.reset(new StickyKeysOverlay());
123 } else if (overlay_.get()) {
124 overlay_->Show(false);
129 bool StickyKeysController::HandleKeyEvent(ui::KeyEvent* event) {
130 return shift_sticky_key_->HandleKeyEvent(event) ||
131 alt_sticky_key_->HandleKeyEvent(event) ||
132 ctrl_sticky_key_->HandleKeyEvent(event);
135 bool StickyKeysController::HandleMouseEvent(ui::MouseEvent* event) {
136 return shift_sticky_key_->HandleMouseEvent(event) ||
137 alt_sticky_key_->HandleMouseEvent(event) ||
138 ctrl_sticky_key_->HandleMouseEvent(event);
141 bool StickyKeysController::HandleScrollEvent(ui::ScrollEvent* event) {
142 return shift_sticky_key_->HandleScrollEvent(event) ||
143 alt_sticky_key_->HandleScrollEvent(event) ||
144 ctrl_sticky_key_->HandleScrollEvent(event);
147 void StickyKeysController::OnKeyEvent(ui::KeyEvent* event) {
148 // Do not consume a translated key event which is generated by an IME.
149 if (event->type() == ui::ET_TRANSLATED_KEY_PRESS ||
150 event->type() == ui::ET_TRANSLATED_KEY_RELEASE) {
151 return;
154 if (enabled_) {
155 if (HandleKeyEvent(event))
156 event->StopPropagation();
157 UpdateOverlay();
161 void StickyKeysController::OnMouseEvent(ui::MouseEvent* event) {
162 if (enabled_) {
163 if (HandleMouseEvent(event))
164 event->StopPropagation();
165 UpdateOverlay();
169 void StickyKeysController::OnScrollEvent(ui::ScrollEvent* event) {
170 if (enabled_) {
171 if (HandleScrollEvent(event))
172 event->StopPropagation();
173 UpdateOverlay();
177 void StickyKeysController::UpdateOverlay() {
178 overlay_->SetModifierKeyState(
179 ui::EF_SHIFT_DOWN, shift_sticky_key_->current_state());
180 overlay_->SetModifierKeyState(
181 ui::EF_CONTROL_DOWN, ctrl_sticky_key_->current_state());
182 overlay_->SetModifierKeyState(
183 ui::EF_ALT_DOWN, alt_sticky_key_->current_state());
185 bool key_in_use =
186 shift_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED ||
187 alt_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED ||
188 ctrl_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED;
190 overlay_->Show(enabled_ && key_in_use);
193 StickyKeysOverlay* StickyKeysController::GetOverlayForTest() {
194 return overlay_.get();
197 ///////////////////////////////////////////////////////////////////////////////
198 // StickyKeysHandler
199 StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag,
200 StickyKeysHandlerDelegate* delegate)
201 : modifier_flag_(modifier_flag),
202 current_state_(STICKY_KEY_STATE_DISABLED),
203 event_from_myself_(false),
204 preparing_to_enable_(false),
205 scroll_delta_(0),
206 delegate_(delegate) {
209 StickyKeysHandler::~StickyKeysHandler() {
212 StickyKeysHandler::StickyKeysHandlerDelegate::StickyKeysHandlerDelegate() {
215 StickyKeysHandler::StickyKeysHandlerDelegate::~StickyKeysHandlerDelegate() {
218 bool StickyKeysHandler::HandleKeyEvent(ui::KeyEvent* event) {
219 if (event_from_myself_)
220 return false; // Do not handle self-generated key event.
221 switch (current_state_) {
222 case STICKY_KEY_STATE_DISABLED:
223 return HandleDisabledState(event);
224 case STICKY_KEY_STATE_ENABLED:
225 return HandleEnabledState(event);
226 case STICKY_KEY_STATE_LOCKED:
227 return HandleLockedState(event);
229 NOTREACHED();
230 return false;
233 bool StickyKeysHandler::HandleMouseEvent(ui::MouseEvent* event) {
234 if (ShouldModifyMouseEvent(event))
235 preparing_to_enable_ = false;
237 if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED
238 || !ShouldModifyMouseEvent(event)) {
239 return false;
241 DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
242 current_state_ == STICKY_KEY_STATE_LOCKED);
244 AppendModifier(event);
245 // Only disable on the mouse released event in normal, non-locked mode.
246 if (current_state_ == STICKY_KEY_STATE_ENABLED &&
247 event->type() != ui::ET_MOUSE_PRESSED) {
248 current_state_ = STICKY_KEY_STATE_DISABLED;
249 DispatchEventAndReleaseModifier(event);
250 return true;
253 return false;
256 bool StickyKeysHandler::HandleScrollEvent(ui::ScrollEvent* event) {
257 preparing_to_enable_ = false;
258 if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED)
259 return false;
260 DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
261 current_state_ == STICKY_KEY_STATE_LOCKED);
263 // We detect a direction change if the current |scroll_delta_| is assigned
264 // and the offset of the current scroll event has the opposing sign.
265 bool direction_changed = false;
266 if (current_state_ == STICKY_KEY_STATE_ENABLED &&
267 event->type() == ui::ET_SCROLL) {
268 int offset = event->y_offset();
269 if (scroll_delta_)
270 direction_changed = offset * scroll_delta_ <= 0;
271 scroll_delta_ = offset;
274 if (!direction_changed)
275 AppendModifier(event);
277 // We want to modify all the scroll events in the scroll sequence, which ends
278 // with a fling start event. We also stop when the scroll sequence changes
279 // direction.
280 if (current_state_ == STICKY_KEY_STATE_ENABLED &&
281 (event->type() == ui::ET_SCROLL_FLING_START || direction_changed)) {
282 current_state_ = STICKY_KEY_STATE_DISABLED;
283 scroll_delta_ = 0;
284 DispatchEventAndReleaseModifier(event);
285 return true;
288 return false;
291 StickyKeysHandler::KeyEventType
292 StickyKeysHandler::TranslateKeyEvent(ui::KeyEvent* event) {
293 bool is_target_key = false;
294 if (event->key_code() == ui::VKEY_SHIFT ||
295 event->key_code() == ui::VKEY_LSHIFT ||
296 event->key_code() == ui::VKEY_RSHIFT) {
297 is_target_key = (modifier_flag_ == ui::EF_SHIFT_DOWN);
298 } else if (event->key_code() == ui::VKEY_CONTROL ||
299 event->key_code() == ui::VKEY_LCONTROL ||
300 event->key_code() == ui::VKEY_RCONTROL) {
301 is_target_key = (modifier_flag_ == ui::EF_CONTROL_DOWN);
302 } else if (event->key_code() == ui::VKEY_MENU ||
303 event->key_code() == ui::VKEY_LMENU ||
304 event->key_code() == ui::VKEY_RMENU) {
305 is_target_key = (modifier_flag_ == ui::EF_ALT_DOWN);
306 } else {
307 return event->type() == ui::ET_KEY_PRESSED ?
308 NORMAL_KEY_DOWN : NORMAL_KEY_UP;
311 if (is_target_key) {
312 return event->type() == ui::ET_KEY_PRESSED ?
313 TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP;
315 return event->type() == ui::ET_KEY_PRESSED ?
316 OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP;
319 bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
320 switch (TranslateKeyEvent(event)) {
321 case TARGET_MODIFIER_UP:
322 if (preparing_to_enable_) {
323 preparing_to_enable_ = false;
324 scroll_delta_ = 0;
325 current_state_ = STICKY_KEY_STATE_ENABLED;
326 modifier_up_event_.reset(new ui::KeyEvent(*event));
327 return true;
329 return false;
330 case TARGET_MODIFIER_DOWN:
331 preparing_to_enable_ = true;
332 return false;
333 case NORMAL_KEY_DOWN:
334 preparing_to_enable_ = false;
335 return false;
336 case NORMAL_KEY_UP:
337 case OTHER_MODIFIER_DOWN:
338 case OTHER_MODIFIER_UP:
339 return false;
341 NOTREACHED();
342 return false;
345 bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
346 switch (TranslateKeyEvent(event)) {
347 case NORMAL_KEY_UP:
348 case TARGET_MODIFIER_DOWN:
349 return true;
350 case TARGET_MODIFIER_UP:
351 current_state_ = STICKY_KEY_STATE_LOCKED;
352 modifier_up_event_.reset();
353 return true;
354 case NORMAL_KEY_DOWN: {
355 current_state_ = STICKY_KEY_STATE_DISABLED;
356 AppendModifier(event);
357 DispatchEventAndReleaseModifier(event);
358 return true;
360 case OTHER_MODIFIER_DOWN:
361 case OTHER_MODIFIER_UP:
362 return false;
364 NOTREACHED();
365 return false;
368 bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
369 switch (TranslateKeyEvent(event)) {
370 case TARGET_MODIFIER_DOWN:
371 return true;
372 case TARGET_MODIFIER_UP:
373 current_state_ = STICKY_KEY_STATE_DISABLED;
374 return false;
375 case NORMAL_KEY_DOWN:
376 case NORMAL_KEY_UP:
377 AppendModifier(event);
378 return false;
379 case OTHER_MODIFIER_DOWN:
380 case OTHER_MODIFIER_UP:
381 return false;
383 NOTREACHED();
384 return false;
387 void StickyKeysHandler::DispatchEventAndReleaseModifier(ui::Event* event) {
388 DCHECK(event->IsKeyEvent() ||
389 event->IsMouseEvent() ||
390 event->IsScrollEvent());
391 DCHECK(modifier_up_event_.get());
392 aura::Window* target = static_cast<aura::Window*>(event->target());
393 DCHECK(target);
394 aura::Window* root_window = target->GetRootWindow();
395 DCHECK(root_window);
397 aura::WindowTracker window_tracker;
398 window_tracker.Add(target);
400 event_from_myself_ = true;
401 if (event->IsKeyEvent()) {
402 delegate_->DispatchKeyEvent(static_cast<ui::KeyEvent*>(event), target);
403 } else if (event->IsMouseEvent()) {
404 delegate_->DispatchMouseEvent(static_cast<ui::MouseEvent*>(event), target);
405 } else {
406 delegate_->DispatchScrollEvent(
407 static_cast<ui::ScrollEvent*>(event), target);
410 // The action triggered above may have destroyed the event target, in which
411 // case we will dispatch the modifier up event to the root window instead.
412 aura::Window* modifier_up_target =
413 window_tracker.Contains(target) ? target : root_window;
414 delegate_->DispatchKeyEvent(modifier_up_event_.get(), modifier_up_target);
415 event_from_myself_ = false;
418 void StickyKeysHandler::AppendNativeEventMask(unsigned int* state) {
419 #if defined(USE_X11)
420 unsigned int& state_ref = *state;
421 switch (modifier_flag_) {
422 case ui::EF_CONTROL_DOWN:
423 state_ref |= ControlMask;
424 break;
425 case ui::EF_ALT_DOWN:
426 state_ref |= Mod1Mask;
427 break;
428 case ui::EF_SHIFT_DOWN:
429 state_ref |= ShiftMask;
430 break;
431 default:
432 NOTREACHED();
434 #endif
437 void StickyKeysHandler::AppendModifier(ui::KeyEvent* event) {
438 #if defined(USE_X11)
439 XEvent* xev = event->native_event();
440 if (xev) {
441 XKeyEvent* xkey = &(xev->xkey);
442 AppendNativeEventMask(&xkey->state);
444 #elif defined(USE_OZONE)
445 NOTIMPLEMENTED() << "Modifier key is not handled";
446 #endif
447 event->set_flags(event->flags() | modifier_flag_);
448 event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
449 event->flags()));
450 event->NormalizeFlags();
453 void StickyKeysHandler::AppendModifier(ui::MouseEvent* event) {
454 #if defined(USE_X11)
455 XEvent* xev = event->native_event();
456 if (xev) {
457 XButtonEvent* xkey = &(xev->xbutton);
458 AppendNativeEventMask(&xkey->state);
460 #elif defined(USE_OZONE)
461 NOTIMPLEMENTED() << "Modifier key is not handled";
462 #endif
463 event->set_flags(event->flags() | modifier_flag_);
466 void StickyKeysHandler::AppendModifier(ui::ScrollEvent* event) {
467 #if defined(USE_X11)
468 XEvent* xev = event->native_event();
469 if (xev) {
470 XIDeviceEvent* xievent =
471 static_cast<XIDeviceEvent*>(xev->xcookie.data);
472 if (xievent) {
473 AppendNativeEventMask(reinterpret_cast<unsigned int*>(
474 &xievent->mods.effective));
477 #elif defined(USE_OZONE)
478 NOTIMPLEMENTED() << "Modifier key is not handled";
479 #endif
480 event->set_flags(event->flags() | modifier_flag_);
483 } // namespace ash