// Copyright (c) 2012 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 "ui/base/accelerators/accelerator_manager.h" #include #include "base/logging.h" namespace ui { AcceleratorManager::AcceleratorManager() : last_event_type_(ET_KEY_PRESSED) { } AcceleratorManager::~AcceleratorManager() { } void AcceleratorManager::Register(const Accelerator& accelerator, HandlerPriority priority, AcceleratorTarget* target) { AcceleratorTargetList& targets = accelerators_[accelerator].second; DCHECK(std::find(targets.begin(), targets.end(), target) == targets.end()) << "Registering the same target multiple times"; // All priority accelerators go to the front of the line. if (priority) { DCHECK(!accelerators_[accelerator].first) << "Only one _priority_ handler can be registered"; targets.push_front(target); // Mark that we have a priority accelerator at the front. accelerators_[accelerator].first = true; return; } // We are registering a normal priority handler. If no priority accelerator // handler has been registered before us, just add the new handler to the // front. Otherwise, register it after the first (only) priority handler. if (!accelerators_[accelerator].first) targets.push_front(target); else targets.insert(++targets.begin(), target); } void AcceleratorManager::Unregister(const Accelerator& accelerator, AcceleratorTarget* target) { AcceleratorMap::iterator map_iter = accelerators_.find(accelerator); if (map_iter == accelerators_.end()) { NOTREACHED() << "Unregistering non-existing accelerator"; return; } AcceleratorTargetList* targets = &map_iter->second.second; AcceleratorTargetList::iterator target_iter = std::find(targets->begin(), targets->end(), target); if (target_iter == targets->end()) { NOTREACHED() << "Unregistering accelerator for wrong target"; return; } // Check to see if we have a priority handler and whether we are removing it. if (accelerators_[accelerator].first && target_iter == targets->begin()) { // We've are taking the priority accelerator away, flip the priority flag. accelerators_[accelerator].first = false; } targets->erase(target_iter); } void AcceleratorManager::UnregisterAll(AcceleratorTarget* target) { for (AcceleratorMap::iterator map_iter = accelerators_.begin(); map_iter != accelerators_.end(); ++map_iter) { AcceleratorTargetList* targets = &map_iter->second.second; targets->remove(target); } } bool AcceleratorManager::Process(const Accelerator& accelerator) { bool result = false; AcceleratorMap::iterator map_iter = accelerators_.find(accelerator); if (map_iter != accelerators_.end() && ShouldHandle(accelerator)) { // We have to copy the target list here, because an AcceleratorPressed // event handler may modify the list. AcceleratorTargetList targets(map_iter->second.second); for (AcceleratorTargetList::iterator iter = targets.begin(); iter != targets.end(); ++iter) { if ((*iter)->CanHandleAccelerators() && (*iter)->AcceleratorPressed(accelerator)) { result = true; break; } } } last_event_type_ = accelerator.type(); return result; } AcceleratorTarget* AcceleratorManager::GetCurrentTarget( const Accelerator& accelerator) const { AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator); if (map_iter == accelerators_.end() || map_iter->second.second.empty()) return NULL; return map_iter->second.second.front(); } bool AcceleratorManager::HasPriorityHandler( const Accelerator& accelerator) const { AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator); if (map_iter == accelerators_.end() || map_iter->second.second.empty()) return false; // Check if we have a priority handler. If not, there's no more work needed. if (!map_iter->second.first) return false; // If the priority handler says it cannot handle the accelerator, we must not // count it as one. return map_iter->second.second.front()->CanHandleAccelerators(); } bool AcceleratorManager::ShouldHandle(const Accelerator& accelerator) const { if (accelerator.type() != ET_KEY_RELEASED) return true; // This check is necessary e.g. not to process the Shift+Alt+ET_KEY_RELEASED // Accelerator for Chrome OS (see ash/accelerators/accelerator_controller.cc) // when Shift+Alt+Tab is pressed and then Tab is released. return last_event_type_ == ET_KEY_PRESSED; } } // namespace ui