// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "athena/input/accelerator_manager_impl.h" #include "athena/input/public/input_manager.h" #include "athena/util/switches.h" #include "base/logging.h" #include "ui/aura/window.h" #include "ui/base/accelerators/accelerator_manager.h" #include "ui/events/event.h" #include "ui/events/event_target.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_manager_delegate.h" #include "ui/views/focus/focus_manager_factory.h" #include "ui/wm/core/accelerator_delegate.h" #include "ui/wm/core/accelerator_filter.h" #include "ui/wm/core/nested_accelerator_controller.h" #include "ui/wm/core/nested_accelerator_delegate.h" #include "ui/wm/public/dispatcher_client.h" namespace athena { // This wrapper interface provides a common interface that handles global // accelerators as well as local accelerators. class AcceleratorManagerImpl::AcceleratorWrapper { public: virtual ~AcceleratorWrapper() {} virtual void Register(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) = 0; virtual void Unregister(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) = 0; virtual bool Process(const ui::Accelerator& accelerator) = 0; virtual ui::AcceleratorTarget* GetCurrentTarget( const ui::Accelerator& accelerator) const = 0; }; namespace { // Accelerators inside nested message loop are handled by // wm::NestedAcceleratorController while accelerators in normal case are // handled by wm::AcceleratorFilter. These delegates act bridges in these // two different environment so that AcceleratorManagerImpl can handle // accelerators in an uniform way. class NestedAcceleratorDelegate : public wm::NestedAcceleratorDelegate { public: explicit NestedAcceleratorDelegate( AcceleratorManagerImpl* accelerator_manager) : accelerator_manager_(accelerator_manager) {} ~NestedAcceleratorDelegate() override {} private: // wm::NestedAcceleratorDelegate: Result ProcessAccelerator(const ui::Accelerator& accelerator) override { return accelerator_manager_->Process(accelerator) ? RESULT_PROCESSED : RESULT_NOT_PROCESSED; } AcceleratorManagerImpl* accelerator_manager_; DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDelegate); }; class AcceleratorDelegate : public wm::AcceleratorDelegate { public: explicit AcceleratorDelegate(AcceleratorManagerImpl* accelerator_manager) : accelerator_manager_(accelerator_manager) {} ~AcceleratorDelegate() override {} private: // wm::AcceleratorDelegate: bool ProcessAccelerator(const ui::KeyEvent& event, const ui::Accelerator& accelerator, KeyType key_type) override { aura::Window* target = static_cast(event.target()); if (!target->IsRootWindow() && !accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) { // TODO(oshima): do the same when the active window is in fullscreen. return false; } return accelerator_manager_->Process(accelerator); } AcceleratorManagerImpl* accelerator_manager_; DISALLOW_COPY_AND_ASSIGN(AcceleratorDelegate); }; class FocusManagerDelegate : public views::FocusManagerDelegate { public: explicit FocusManagerDelegate(AcceleratorManagerImpl* accelerator_manager) : accelerator_manager_(accelerator_manager) {} ~FocusManagerDelegate() override {} bool ProcessAccelerator(const ui::Accelerator& accelerator) override { return accelerator_manager_->Process(accelerator); } ui::AcceleratorTarget* GetCurrentTargetForAccelerator( const ui::Accelerator& accelerator) const override { return accelerator_manager_->IsRegistered(accelerator, AF_NONE) ? accelerator_manager_ : nullptr; } private: AcceleratorManagerImpl* accelerator_manager_; DISALLOW_COPY_AND_ASSIGN(FocusManagerDelegate); }; // Key strokes must be sent to web contents to give them a chance to // consume them unless they are reserved, and unhandled key events are // sent back to focus manager asynchronously. This installs the athena's // focus manager that handles athena shell's accelerators. class FocusManagerFactory : public views::FocusManagerFactory { public: explicit FocusManagerFactory(AcceleratorManagerImpl* accelerator_manager) : accelerator_manager_(accelerator_manager) {} ~FocusManagerFactory() override {} views::FocusManager* CreateFocusManager(views::Widget* widget, bool desktop_widget) override { return new views::FocusManager( widget, desktop_widget ? nullptr : new FocusManagerDelegate(accelerator_manager_)); } private: AcceleratorManagerImpl* accelerator_manager_; DISALLOW_COPY_AND_ASSIGN(FocusManagerFactory); }; class UIAcceleratorManagerWrapper : public AcceleratorManagerImpl::AcceleratorWrapper { public: UIAcceleratorManagerWrapper() : ui_accelerator_manager_(new ui::AcceleratorManager) {} ~UIAcceleratorManagerWrapper() override {} virtual void Register(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) override { ui_accelerator_manager_->Register( accelerator, ui::AcceleratorManager::kNormalPriority, target); } virtual void Unregister(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) override { ui_accelerator_manager_->Unregister(accelerator, target); } virtual bool Process(const ui::Accelerator& accelerator) override { return ui_accelerator_manager_->Process(accelerator); } virtual ui::AcceleratorTarget* GetCurrentTarget( const ui::Accelerator& accelerator) const override { return ui_accelerator_manager_->GetCurrentTarget(accelerator); } private: scoped_ptr ui_accelerator_manager_; DISALLOW_COPY_AND_ASSIGN(UIAcceleratorManagerWrapper); }; class FocusManagerWrapper : public AcceleratorManagerImpl::AcceleratorWrapper { public: explicit FocusManagerWrapper(views::FocusManager* focus_manager) : focus_manager_(focus_manager) {} ~FocusManagerWrapper() override {} virtual void Register(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) override { return focus_manager_->RegisterAccelerator( accelerator, ui::AcceleratorManager::kNormalPriority, target); } virtual void Unregister(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) override { focus_manager_->UnregisterAccelerator(accelerator, target); } virtual bool Process(const ui::Accelerator& accelerator) override { NOTREACHED(); return true; } virtual ui::AcceleratorTarget* GetCurrentTarget( const ui::Accelerator& accelerator) const override { return focus_manager_->GetCurrentTargetForAccelerator(accelerator); } private: views::FocusManager* focus_manager_; DISALLOW_COPY_AND_ASSIGN(FocusManagerWrapper); }; } // namespace class AcceleratorManagerImpl::InternalData { public: InternalData(int command_id, AcceleratorHandler* handler, int flags) : command_id_(command_id), handler_(handler), flags_(flags) {} bool IsNonAutoRepeatable() const { return flags_ & AF_NON_AUTO_REPEATABLE; } bool IsDebug() const { return flags_ & AF_DEBUG; } int flags() const { return flags_; } bool IsCommandEnabled() const { return handler_->IsCommandEnabled(command_id_); } bool OnAcceleratorFired(const ui::Accelerator& accelerator) { return handler_->OnAcceleratorFired(command_id_, accelerator); } private: int command_id_; AcceleratorHandler* handler_; int flags_; // This class is copyable by design. }; // static AcceleratorManagerImpl* AcceleratorManagerImpl::CreateGlobalAcceleratorManager() { return new AcceleratorManagerImpl(new UIAcceleratorManagerWrapper(), true); } scoped_ptr AcceleratorManagerImpl::CreateForFocusManager( views::FocusManager* focus_manager) { return scoped_ptr( new AcceleratorManagerImpl(new FocusManagerWrapper(focus_manager), false)).Pass(); } AcceleratorManagerImpl::~AcceleratorManagerImpl() { nested_accelerator_controller_.reset(); accelerator_filter_.reset(); // Reset to use the default focus manager because the athena's // FocusManager has the reference to this object. if (global_) views::FocusManagerFactory::Install(nullptr); } void AcceleratorManagerImpl::Init() { if (global_) views::FocusManagerFactory::Install(new FocusManagerFactory(this)); ui::EventTarget* toplevel = InputManager::Get()->GetTopmostEventTarget(); nested_accelerator_controller_.reset( new wm::NestedAcceleratorController(new NestedAcceleratorDelegate(this))); scoped_ptr accelerator_delegate( new AcceleratorDelegate(this)); accelerator_filter_.reset( new wm::AcceleratorFilter(accelerator_delegate.Pass())); toplevel->AddPreTargetHandler(accelerator_filter_.get()); } void AcceleratorManagerImpl::OnRootWindowCreated(aura::Window* root_window) { aura::client::SetDispatcherClient(root_window, nested_accelerator_controller_.get()); } bool AcceleratorManagerImpl::Process(const ui::Accelerator& accelerator) { return accelerator_wrapper_->Process(accelerator); } bool AcceleratorManagerImpl::IsRegistered(const ui::Accelerator& accelerator, int flags) const { std::map::const_iterator iter = accelerators_.find(accelerator); if (iter == accelerators_.end()) return false; DCHECK(accelerator_wrapper_->GetCurrentTarget(accelerator)); return flags == AF_NONE || iter->second.flags() & flags; } AcceleratorManagerImpl::AcceleratorManagerImpl( AcceleratorWrapper* accelerator_wrapper, bool global) : accelerator_wrapper_(accelerator_wrapper), debug_accelerators_enabled_(switches::IsDebugAcceleratorsEnabled()), global_(global) { } void AcceleratorManagerImpl::RegisterAccelerators( const AcceleratorData accelerators[], size_t num_accelerators, AcceleratorHandler* handler) { for (size_t i = 0; i < num_accelerators; ++i) RegisterAccelerator(accelerators[i], handler); } void AcceleratorManagerImpl::SetDebugAcceleratorsEnabled(bool enabled) { debug_accelerators_enabled_ = enabled; } bool AcceleratorManagerImpl::AcceleratorPressed( const ui::Accelerator& accelerator) { std::map::iterator iter = accelerators_.find(accelerator); DCHECK(iter != accelerators_.end()); if (iter == accelerators_.end()) return false; InternalData& data = iter->second; if (data.IsDebug() && !debug_accelerators_enabled_) return false; if (accelerator.IsRepeat() && data.IsNonAutoRepeatable()) return false; return data.IsCommandEnabled() ? data.OnAcceleratorFired(accelerator) : false; } bool AcceleratorManagerImpl::CanHandleAccelerators() const { return true; } void AcceleratorManagerImpl::RegisterAccelerator( const AcceleratorData& accelerator_data, AcceleratorHandler* handler) { ui::Accelerator accelerator(accelerator_data.keycode, accelerator_data.keyevent_flags); accelerator.set_type(accelerator_data.trigger_event == TRIGGER_ON_PRESS ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED); accelerator_wrapper_->Register(accelerator, this); accelerators_.insert( std::make_pair(accelerator, InternalData(accelerator_data.command_id, handler, accelerator_data.accelerator_flags))); } void AcceleratorManagerImpl::UnregisterAccelerator( const AcceleratorData& accelerator_data, AcceleratorHandler* handler) { ui::Accelerator accelerator(accelerator_data.keycode, accelerator_data.keyevent_flags); accelerator.set_type(accelerator_data.trigger_event == TRIGGER_ON_PRESS ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED); accelerator_wrapper_->Unregister(accelerator, this); accelerators_.erase(accelerator); } // static AcceleratorManager* AcceleratorManager::Get() { return InputManager::Get()->GetAcceleratorManager(); } // static scoped_ptr AcceleratorManager::CreateForFocusManager( views::FocusManager* focus_manager) { return AcceleratorManagerImpl::CreateForFocusManager(focus_manager).Pass(); } } // namespace athena