好久没有自己写东西了,chrome有着取之不尽的技术精华供学习,记录一下.
源码目录:
http://src.chromium.org/viewvc/chrome/trunk/src/ui/base/accelerators/
一.Accelerator 类
// This class describe a keyboard accelerator (or keyboard shortcut). // Keyboard accelerators are registered with the FocusManager. // It has a copy constructor and assignment operator so that it can be copied. // It also defines the < operator so that it can be used as a key in a std::map. // #ifndef UI_BASE_ACCELERATORS_ACCELERATOR_H_ #define UI_BASE_ACCELERATORS_ACCELERATOR_H_ namespace ui { class PlatformAccelerator; // This is a cross-platform class for accelerator keys used in menus. // |platform_accelerator| should be used to store platform specific data. class UI_EXPORT Accelerator { public: Accelerator(); Accelerator(ui::KeyboardCode keycode, int modifiers); Accelerator(const Accelerator& accelerator); ~Accelerator(); ui::KeyboardCode key_code() const { return key_code_; } // Sets the event type if the accelerator should be processed on an event // other than ui::ET_KEY_PRESSED. void set_type(ui::EventType type) { type_ = type; } ui::EventType type() const { return type_; } int modifiers() const { return modifiers_; } bool IsShiftDown() const; bool IsCtrlDown() const; bool IsAltDown() const; bool IsCmdDown() const; protected: // The keycode (VK_...). KeyboardCode key_code_; // The event type (usually ui::ET_KEY_PRESSED). EventType type_; // The state of the Shift/Ctrl/Alt keys. int modifiers_; // Stores platform specific data. May be NULL. scoped_ptr<PlatformAccelerator> platform_accelerator_; };
定义了快捷键属性
主要有三个属性
- key_code_:按下的键盘键
- type_:触发的事件,比如keydown,keyup
- modifiers_:特殊组合按钮
二.AcceleratorTarget
// An interface that classes that want to register for keyboard accelerators // should implement. class UI_EXPORT AcceleratorTarget { public: // Should return true if the accelerator was processed. virtual bool AcceleratorPressed(const Accelerator& accelerator) = 0; // Should return true if the target can handle the accelerator events. The // AcceleratorPressed method is invoked only for targets for which // CanHandleAccelerators returns true. virtual bool CanHandleAccelerators() const = 0; protected: virtual ~AcceleratorTarget() {} };
注册快捷键的对象,
- AcceleratorPressed方法为处理快捷键事件,返回true则表明处理完毕
- CanHandleAccelerators方法是处理快捷键之前的状态检查
三.AcceleratorManager
#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_ #define UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_ #include <list> #include <map> #include <utility> namespace ui { // The AcceleratorManger is used to handle keyboard accelerators. class UI_EXPORT AcceleratorManager { public: enum HandlerPriority { kNormalPriority, kHighPriority, }; AcceleratorManager(); ~AcceleratorManager(); // Register a keyboard accelerator for the specified target. If multiple // targets are registered for an accelerator, a target registered later has // higher priority. // |accelerator| is the accelerator to register. // |priority| denotes the priority of the handler. // NOTE: In almost all cases, you should specify kNormalPriority for this // parameter. Setting it to kHighPriority prevents Chrome from sending the // shortcut to the webpage if the renderer has focus, which is not desirable // except for very isolated cases. // |target| is the AcceleratorTarget that handles the event once the // accelerator is pressed. // Note that we are currently limited to accelerators that are either: // - a key combination including Ctrl or Alt // - the escape key // - the enter key // - any F key (F1, F2, F3 ...) // - any browser specific keys (as available on special keyboards) void Register(const Accelerator& accelerator, HandlerPriority priority, AcceleratorTarget* target); // Unregister the specified keyboard accelerator for the specified target. void Unregister(const Accelerator& accelerator, AcceleratorTarget* target); // Unregister all keyboard accelerator for the specified target. void UnregisterAll(AcceleratorTarget* target); // Activate the target associated with the specified accelerator. // First, AcceleratorPressed handler of the most recently registered target // is called, and if that handler processes the event (i.e. returns true), // this method immediately returns. If not, we do the same thing on the next // target, and so on. // Returns true if an accelerator was activated. bool Process(const Accelerator& accelerator); // Returns the AcceleratorTarget that should be activated for the specified // keyboard accelerator, or NULL if no view is registered for that keyboard // accelerator. AcceleratorTarget* GetCurrentTarget(const Accelerator& accelertor) const; // Whether the given |accelerator| has a priority handler associated with it. bool HasPriorityHandler(const Accelerator& accelerator) const; private: // The accelerators and associated targets. typedef std::list<AcceleratorTarget*> AcceleratorTargetList; // This construct pairs together a |bool| (denoting whether the list contains // a priority_handler at the front) with the list of AcceleratorTargets. typedef std::pair<bool, AcceleratorTargetList> AcceleratorTargets; typedef std::map<Accelerator, AcceleratorTargets> AcceleratorMap; AcceleratorMap accelerators_; DISALLOW_COPY_AND_ASSIGN(AcceleratorManager); }; } // namespace ui #endif // UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_
数据结构为一个Accelerator对应一个AcceleratorTargets列表,bool用来表示优先级
Process方法用来处理快捷键流程
bool AcceleratorManager::Process(const Accelerator& accelerator) { bool result = false; AcceleratorMap::iterator map_iter = accelerators_.find(accelerator); if (map_iter != accelerators_.end()) { // 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; } } } return result; }
再来看下Register方法,新注册的快捷键都排到前面来了,这个是比较关键的
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); }
测试代码:
1.注册一个快捷键
TEST_F(AcceleratorManagerTest, Register) { const Accelerator accelerator_a(VKEY_A, EF_NONE); TestTarget target; manager_.Register(accelerator_a, AcceleratorManager::kNormalPriority, &target); // The registered accelerator is processed. EXPECT_TRUE(manager_.Process(accelerator_a)); EXPECT_EQ(1, target.accelerator_pressed_count()); }
2.注册多个快捷键
TEST_F(AcceleratorManagerTest, RegisterMultipleTarget) { const Accelerator accelerator_a(VKEY_A, EF_NONE); TestTarget target1; manager_.Register(accelerator_a, AcceleratorManager::kNormalPriority, &target1); TestTarget target2; manager_.Register(accelerator_a, AcceleratorManager::kNormalPriority, &target2); // If multiple targets are registered with the same accelerator, the target // registered later processes the accelerator. EXPECT_TRUE(manager_.Process(accelerator_a)); EXPECT_EQ(0, target1.accelerator_pressed_count()); EXPECT_EQ(1, target2.accelerator_pressed_count()); }
简单的用以上关系来表达三者之间的关系,其实逻辑还是比较清晰的,使用map查找起来速度也比较快,不会存在什么性能上面的问题,Register方法都是push_front也保证了时效性,所以其还是满足了快捷键使用的需求,非常轻巧