chrome ui源码剖析-Accelerator(快捷键)
好久没有自己写东西了,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也保证了时效性,所以其还是满足了快捷键使用的需求,非常轻巧
chrome ui源码剖析-Accelerator(快捷键)的更多相关文章
- chrome ui源码剖析-ViewProp
先熟悉set的find原理 http://www.cnblogs.com/Clingingboy/p/3252136.html 这个类改造下,还是非常实用的,可以对于不同的类型做数据存储 一.Vi ...
- Google Chrome源码剖析【序】
[序(本人什么都没做,完全转载)] 开源是口好东西,它让这个充斥着大量工业垃圾代码和教材玩具代码的行业,多了一些艺术气息和美的潜质.它使得每个人,无论你来自米国纽约还是中国铁岭,都有机会站在巨人的肩膀 ...
- Spark源码剖析 - SparkContext的初始化(三)_创建并初始化Spark UI
3. 创建并初始化Spark UI 任何系统都需要提供监控功能,用浏览器能访问具有样式及布局并提供丰富监控数据的页面无疑是一种简单.高效的方式.SparkUI就是这样的服务. 在大型分布式系统中,采用 ...
- Chrome V8 引擎源码剖析
Chrome V8 引擎源码剖析 V8 https://github.com/v8/v8 array & sort https://github.com/v8/v8/search?l=Java ...
- (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)
本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...
- Appuim源码剖析(Bootstrap)
Appuim源码剖析(Bootstrap) SkySeraph Jan. 26th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www. ...
- 老李推荐:第14章1节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-面向控件编程VS面向坐标编程
老李推荐:第14章1节<MonkeyRunner源码剖析> HierarchyViewer实现原理-面向控件编程VS面向坐标编程 poptest是国内唯一一家培养测试开发工程师的培训机 ...
- 老李推荐:第2章2节《MonkeyRunner源码剖析》了解你的测试对象: NotePad窗口Activity之NotesList简介
老李推荐:第2章2节<MonkeyRunner源码剖析>了解你的测试对象: NotePad窗口Activity之NotesList简介 NotePad窗口Activity之NotesL ...
- 老李推荐: 第1章1节《MonkeyRunner源码剖析》概述:前言
老李推荐: 第1章1节<MonkeyRunner源码剖析>概述:前言 前言 相信大家做过安卓移动平台UI自动化开发的必然会用过,至少听过MonkeyRunner这个名字.MonkeyR ...
随机推荐
- eclipse中可以导入其它工具编写的RobotFramework脚本吗?
在Robotframework的官方网站中,提供了非常多的编辑RF的工具.比如Ride,eclipse,sublime,notepad++等. 网上查到的资料,大部分都是Ride这个编辑工具的使用.在 ...
- Linux常见问题总结【转】
作为一名合格的 Linux 运维工程师,一定要有一套清晰.明确的解决故障思路,当问题出现时,才能迅速定位.解决问题,这里给出一个处理问题的一般思路: 重视报错提示信息:每个错误的出现,都是给出错误提示 ...
- .net的锁
一.lock .Monitor 处理并行任务的时候,效率最高的就是多线程.当不同线程需要访问同一资源时候,就需要同步了.就像生活中很多人要一起赶飞机大家都要访问飞机这个资源每个人是一条线程那么就有门 ...
- zabbix3.0.4安装趋势图集中显示插件graphtrees
通过yum方式安装的zabbix 1.将/usr/share/zabbix目录修改权限,因此处我们使用的是apache,所以用户改为apache,如果是nginx需要改为nginx(是否需要修改可以参 ...
- 推荐一些socket工具,TCP、UDP调试、抓包工具 (转载)
还记得我在很久很久以前和大家推荐的Fiddler和Charles debugger么?他们都是HTTP的神器级调试工具,非常非常的好用.好工具能让你事半功倍,基本上,我是属于彻头彻尾的工具控. 假如有 ...
- Java8系列之重新认识HashMap
转自: http://www.importnew.com/20386.html 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是Ha ...
- Android 6.0 API
Android 6.0 (M) 为用户和应用开发者提供了新功能.本文旨在介绍其中最值得关注的 API. 着手开发 要着手开发 Android 6.0 应用,您必须先获得 Android SDK,然后使 ...
- java 持有对象总结
java提供了大量的持有对象的方式: 1)数组将数字和对象联系起来,它保存类型明确的对象,查询对象时,不需要对结果做类型转换,它可以时多维的,可以保存基本数据类型的数据,但是,数组一旦生成,其容量就不 ...
- Git(五)IDEA应用Git
一.IDEA客户端git 1.提交代码到本地仓库 1. 关联Git,创建本地库 关联git 配置git环境变量 设置本地仓库目录,一般是IDEA工作空间,选择VCS->Import into V ...
- docker commit 制作镜像
docker commit -m="commit jdk" --author="gutianlangyu" ae56f6cad215 gutianlangyu/ ...