15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/sticky_keys/sticky_keys_controller.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/sticky_keys/sticky_keys_overlay.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/stack_trace.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_tracker.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_tree_host.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/events/event.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/events/event_processor.h" 151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/events/keycodes/keyboard_code_conversion.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns true if the type of mouse event should be modified by sticky keys. 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ShouldModifyMouseEvent(const ui::MouseEvent& event) { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::EventType type = event.type(); 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED || 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) type == ui::ET_MOUSEWHEEL; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handle the common tail of event rewriting. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::EventRewriteStatus RewriteUpdate(bool consumed, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool released, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mod_down_flags, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* flags) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int changed_down_flags = mod_down_flags & ~*flags; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *flags |= mod_down_flags; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (consumed) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::EVENT_REWRITE_DISCARD; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (released) 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return ui::EVENT_REWRITE_DISPATCH_ANOTHER; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (changed_down_flags) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::EVENT_REWRITE_REWRITTEN; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::EVENT_REWRITE_CONTINUE; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StickyKeys 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StickyKeysController::StickyKeysController() 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : enabled_(false), 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod3_enabled_(false), 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) altgr_enabled_(false) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StickyKeysController::~StickyKeysController() { 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StickyKeysController::Enable(bool enabled) { 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (enabled_ != enabled) { 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enabled_ = enabled; 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Reset key handlers when activating sticky keys to ensure all 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the handlers' states are reset. 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (enabled_) { 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shift_sticky_key_.reset(new StickyKeysHandler(ui::EF_SHIFT_DOWN)); 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) alt_sticky_key_.reset(new StickyKeysHandler(ui::EF_ALT_DOWN)); 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) altgr_sticky_key_.reset(new StickyKeysHandler(ui::EF_ALTGR_DOWN)); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ctrl_sticky_key_.reset(new StickyKeysHandler(ui::EF_CONTROL_DOWN)); 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod3_sticky_key_.reset(new StickyKeysHandler(ui::EF_MOD3_DOWN)); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch overlay_.reset(new StickyKeysOverlay()); 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch overlay_->SetModifierVisible(ui::EF_ALTGR_DOWN, altgr_enabled_); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) overlay_->SetModifierVisible(ui::EF_MOD3_DOWN, mod3_enabled_); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (overlay_) { 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) overlay_->Show(false); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StickyKeysController::SetModifiersEnabled(bool mod3_enabled, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool altgr_enabled) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mod3_enabled_ = mod3_enabled; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) altgr_enabled_ = altgr_enabled; 831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (overlay_) { 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) overlay_->SetModifierVisible(ui::EF_ALTGR_DOWN, altgr_enabled_); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overlay_->SetModifierVisible(ui::EF_MOD3_DOWN, mod3_enabled_); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StickyKeysController::HandleKeyEvent(const ui::KeyEvent& event, 90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ui::KeyboardCode key_code, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* mod_down_flags, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* released) { 93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return shift_sticky_key_->HandleKeyEvent( 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, key_code, mod_down_flags, released) || 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_sticky_key_->HandleKeyEvent( 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, key_code, mod_down_flags, released) || 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) altgr_sticky_key_->HandleKeyEvent( 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, key_code, mod_down_flags, released) || 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_sticky_key_->HandleKeyEvent( 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, key_code, mod_down_flags, released) || 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mod3_sticky_key_->HandleKeyEvent( 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, key_code, mod_down_flags, released); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StickyKeysController::HandleMouseEvent(const ui::MouseEvent& event, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* mod_down_flags, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* released) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return shift_sticky_key_->HandleMouseEvent( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_sticky_key_->HandleMouseEvent( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) altgr_sticky_key_->HandleMouseEvent( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_sticky_key_->HandleMouseEvent( 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mod3_sticky_key_->HandleMouseEvent( 117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event, mod_down_flags, released); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StickyKeysController::HandleScrollEvent(const ui::ScrollEvent& event, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* mod_down_flags, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* released) { 123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return shift_sticky_key_->HandleScrollEvent( 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) alt_sticky_key_->HandleScrollEvent( 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event, mod_down_flags, released) || 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) altgr_sticky_key_->HandleScrollEvent( 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ctrl_sticky_key_->HandleScrollEvent( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released) || 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod3_sticky_key_->HandleScrollEvent( 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event, mod_down_flags, released); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::EventRewriteStatus StickyKeysController::RewriteKeyEvent( 136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const ui::KeyEvent& event, 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::KeyboardCode key_code, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* flags) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ui::EVENT_REWRITE_CONTINUE; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mod_down_flags = 0; 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool released = false; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool consumed = HandleKeyEvent(event, key_code, &mod_down_flags, &released); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateOverlay(); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RewriteUpdate(consumed, released, mod_down_flags, flags); 146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)ui::EventRewriteStatus StickyKeysController::RewriteMouseEvent( 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::MouseEvent& event, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* flags) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ui::EVENT_REWRITE_CONTINUE; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mod_down_flags = 0; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool released = false; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool consumed = HandleMouseEvent(event, &mod_down_flags, &released); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateOverlay(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RewriteUpdate(consumed, released, mod_down_flags, flags); 158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)ui::EventRewriteStatus StickyKeysController::RewriteScrollEvent( 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::ScrollEvent& event, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* flags) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!enabled_) 164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ui::EVENT_REWRITE_CONTINUE; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int mod_down_flags = 0; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool released = false; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool consumed = HandleScrollEvent(event, &mod_down_flags, &released); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateOverlay(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RewriteUpdate(consumed, released, mod_down_flags, flags); 170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)ui::EventRewriteStatus StickyKeysController::NextDispatchEvent( 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<ui::Event>* new_event) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(new_event); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_event->reset(); 176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) int remaining = shift_sticky_key_->GetModifierUpEvent(new_event) + 177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) alt_sticky_key_->GetModifierUpEvent(new_event) + 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) altgr_sticky_key_->GetModifierUpEvent(new_event) + 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ctrl_sticky_key_->GetModifierUpEvent(new_event) + 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mod3_sticky_key_->GetModifierUpEvent(new_event); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!new_event) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::EVENT_REWRITE_CONTINUE; 183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (remaining) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::EVENT_REWRITE_DISPATCH_ANOTHER; 185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ui::EVENT_REWRITE_REWRITTEN; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StickyKeysController::UpdateOverlay() { 189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) overlay_->SetModifierKeyState( 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::EF_SHIFT_DOWN, shift_sticky_key_->current_state()); 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) overlay_->SetModifierKeyState( 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::EF_CONTROL_DOWN, ctrl_sticky_key_->current_state()); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overlay_->SetModifierKeyState( 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::EF_ALT_DOWN, alt_sticky_key_->current_state()); 195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) overlay_->SetModifierKeyState( 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::EF_ALTGR_DOWN, altgr_sticky_key_->current_state()); 197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) overlay_->SetModifierKeyState( 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::EF_MOD3_DOWN, mod3_sticky_key_->current_state()); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool key_in_use = 201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) shift_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED || 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED || 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) altgr_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED || 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ctrl_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED || 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mod3_sticky_key_->current_state() != STICKY_KEY_STATE_DISABLED; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) overlay_->Show(enabled_ && key_in_use); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StickyKeysOverlay* StickyKeysController::GetOverlayForTest() { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return overlay_.get(); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// StickyKeysHandler 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : modifier_flag_(modifier_flag), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_state_(STICKY_KEY_STATE_DISABLED), 219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) preparing_to_enable_(false), 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scroll_delta_(0) { 221a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StickyKeysHandler::~StickyKeysHandler() { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool StickyKeysHandler::HandleKeyEvent(const ui::KeyEvent& event, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::KeyboardCode key_code, 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int* mod_down_flags, 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* released) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (current_state_) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STICKY_KEY_STATE_DISABLED: 232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return HandleDisabledState(event, key_code); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case STICKY_KEY_STATE_ENABLED: 234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return HandleEnabledState(event, key_code, mod_down_flags, released); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case STICKY_KEY_STATE_LOCKED: 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HandleLockedState(event, key_code, mod_down_flags, released); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) NOTREACHED(); 239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool StickyKeysHandler::HandleMouseEvent( 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::MouseEvent& event, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int* mod_down_flags, 245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool* released) { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShouldModifyMouseEvent(event)) 247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) preparing_to_enable_ = false; 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_state_ == STICKY_KEY_STATE_DISABLED || 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !ShouldModifyMouseEvent(event)) { 251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED || 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_state_ == STICKY_KEY_STATE_LOCKED); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *mod_down_flags |= modifier_flag_; 257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Only disable on the mouse released event in normal, non-locked mode. 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_state_ == STICKY_KEY_STATE_ENABLED && 259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event.type() != ui::ET_MOUSE_PRESSED) { 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) current_state_ = STICKY_KEY_STATE_DISABLED; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *released = true; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)bool StickyKeysHandler::HandleScrollEvent( 2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const ui::ScrollEvent& event, 2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int* mod_down_flags, 2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) bool* released) { 2726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) preparing_to_enable_ = false; 2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (current_state_ == STICKY_KEY_STATE_DISABLED) 2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return false; 2756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED || 276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) current_state_ == STICKY_KEY_STATE_LOCKED); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We detect a direction change if the current |scroll_delta_| is assigned 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and the offset of the current scroll event has the opposing sign. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool direction_changed = false; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_state_ == STICKY_KEY_STATE_ENABLED && 282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) event.type() == ui::ET_SCROLL) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset = event.y_offset(); 284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (scroll_delta_) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) direction_changed = offset * scroll_delta_ <= 0; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scroll_delta_ = offset; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 289 if (!direction_changed) 290 *mod_down_flags |= modifier_flag_; 291 292 // We want to modify all the scroll events in the scroll sequence, which ends 293 // with a fling start event. We also stop when the scroll sequence changes 294 // direction. 295 if (current_state_ == STICKY_KEY_STATE_ENABLED && 296 (event.type() == ui::ET_SCROLL_FLING_START || direction_changed)) { 297 current_state_ = STICKY_KEY_STATE_DISABLED; 298 scroll_delta_ = 0; 299 *released = true; 300 return false; 301 } 302 303 return false; 304} 305 306int StickyKeysHandler::GetModifierUpEvent(scoped_ptr<ui::Event>* new_event) { 307 if (current_state_ != STICKY_KEY_STATE_DISABLED || !modifier_up_event_) 308 return 0; 309 DCHECK(new_event); 310 if (*new_event) 311 return 1; 312 new_event->reset(modifier_up_event_.release()); 313 return 0; 314} 315 316StickyKeysHandler::KeyEventType StickyKeysHandler::TranslateKeyEvent( 317 ui::EventType type, 318 ui::KeyboardCode key_code) { 319 bool is_target_key = false; 320 if (key_code == ui::VKEY_SHIFT || 321 key_code == ui::VKEY_LSHIFT || 322 key_code == ui::VKEY_RSHIFT) { 323 is_target_key = (modifier_flag_ == ui::EF_SHIFT_DOWN); 324 } else if (key_code == ui::VKEY_CONTROL || 325 key_code == ui::VKEY_LCONTROL || 326 key_code == ui::VKEY_RCONTROL) { 327 is_target_key = (modifier_flag_ == ui::EF_CONTROL_DOWN); 328 } else if (key_code == ui::VKEY_MENU || 329 key_code == ui::VKEY_LMENU || 330 key_code == ui::VKEY_RMENU) { 331 is_target_key = (modifier_flag_ == ui::EF_ALT_DOWN); 332 } else if (key_code == ui::VKEY_ALTGR) { 333 is_target_key = (modifier_flag_ == ui::EF_ALTGR_DOWN); 334 } else if (key_code == ui::VKEY_OEM_8) { 335 is_target_key = (modifier_flag_ == ui::EF_MOD3_DOWN); 336 } else { 337 return type == ui::ET_KEY_PRESSED ? 338 NORMAL_KEY_DOWN : NORMAL_KEY_UP; 339 } 340 341 if (is_target_key) { 342 return type == ui::ET_KEY_PRESSED ? 343 TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP; 344 } 345 return type == ui::ET_KEY_PRESSED ? 346 OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP; 347} 348 349bool StickyKeysHandler::HandleDisabledState(const ui::KeyEvent& event, 350 ui::KeyboardCode key_code) { 351 switch (TranslateKeyEvent(event.type(), key_code)) { 352 case TARGET_MODIFIER_UP: 353 if (preparing_to_enable_) { 354 preparing_to_enable_ = false; 355 scroll_delta_ = 0; 356 current_state_ = STICKY_KEY_STATE_ENABLED; 357 modifier_up_event_.reset(new ui::KeyEvent(event)); 358 return true; 359 } 360 return false; 361 case TARGET_MODIFIER_DOWN: 362 preparing_to_enable_ = true; 363 return false; 364 case NORMAL_KEY_DOWN: 365 preparing_to_enable_ = false; 366 return false; 367 case NORMAL_KEY_UP: 368 case OTHER_MODIFIER_DOWN: 369 case OTHER_MODIFIER_UP: 370 return false; 371 } 372 NOTREACHED(); 373 return false; 374} 375 376bool StickyKeysHandler::HandleEnabledState(const ui::KeyEvent& event, 377 ui::KeyboardCode key_code, 378 int* mod_down_flags, 379 bool* released) { 380 switch (TranslateKeyEvent(event.type(), key_code)) { 381 case NORMAL_KEY_UP: 382 case TARGET_MODIFIER_DOWN: 383 return false; 384 case TARGET_MODIFIER_UP: 385 current_state_ = STICKY_KEY_STATE_LOCKED; 386 modifier_up_event_.reset(); 387 return true; 388 case NORMAL_KEY_DOWN: { 389 current_state_ = STICKY_KEY_STATE_DISABLED; 390 *mod_down_flags |= modifier_flag_; 391 *released = true; 392 return false; 393 } 394 case OTHER_MODIFIER_DOWN: 395 case OTHER_MODIFIER_UP: 396 return false; 397 } 398 NOTREACHED(); 399 return false; 400} 401 402bool StickyKeysHandler::HandleLockedState(const ui::KeyEvent& event, 403 ui::KeyboardCode key_code, 404 int* mod_down_flags, 405 bool* released) { 406 switch (TranslateKeyEvent(event.type(), key_code)) { 407 case TARGET_MODIFIER_DOWN: 408 return true; 409 case TARGET_MODIFIER_UP: 410 current_state_ = STICKY_KEY_STATE_DISABLED; 411 return false; 412 case NORMAL_KEY_DOWN: 413 case NORMAL_KEY_UP: 414 *mod_down_flags |= modifier_flag_; 415 return false; 416 case OTHER_MODIFIER_DOWN: 417 case OTHER_MODIFIER_UP: 418 return false; 419 } 420 NOTREACHED(); 421 return false; 422} 423 424} // namespace ash 425