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 ...
随机推荐
- Vue 使用 prerender-spa-plugin 添加loading
主要配置代码: new PrerenderSPAPlugin({ staticDir: path.join(__dirname, 'dist'), routes: ['/', '/introducti ...
- if 语句 写了return 报错
- 【Python】【持续项目】Python-安全项目搜集
1.前言 Python发展以来,除了web安全方向,二进制方向也早已经积累有很多用Python写的项目.作为搜集者当然不能错过! 2.项目分类 安全编程 多功能Python键盘记录工具:Radium ...
- 解决方案:centos运行shell脚本时报“$'\r': 未找到命令”
=============================================== 2018/9/12_第1次修改 ccb_warlock == ...
- Ext.util.Format.date 时间格式的设置与转换
Ext.util.Format.date 如下这段简单的代码: var d = new Date(value.time); var s = Ext.util.Format.date(d, 'Y-m- ...
- JavaScript中的普通函数与构造函数
问题 什么是构造函数? 构造函数与普通函数区别是什么? 用new关键字的时候到底做了什么? 构造函数有返回值怎么办? 构造函数能当普通函数调用吗? 以下是我的一些理解,理解错误的地方恳请大家帮忙指正, ...
- [转] Web移动端Fixed布局的解决方案
移动端业务开发,iOS 下经常会有 fixed 元素和输入框(input 元素)同时存在的情况. 但是 fixed 元素在有软键盘唤起的情况下,会出现许多莫名其妙的问题. 这篇文章里就提供一个简单的有 ...
- JQuery表格插件
http://www.datatables.club/example/#styling Datatables快速入门开发--一款好用的JQuery表格插件 博主是一个java后端程序员,前端技术会 ...
- Docker化高可用redis集群
最近遇到部分系统因为redis服务挂掉,导致部分服务不可用.所以希望搭建一个redis集群镜像,把原先散落各处的redis服务器统一管理起来,并且保障高可用和故障自动迁移. 一:redis集群分类 大 ...
- JAVAEE——宜立方商城14:项目部署规划、Tomcat热部署、反向代理的配置
1. 学习计划 1.系统部署 2. 项目部署 2.1. 项目架构讲解 2.2. 网络拓扑图 2.3. 系统部署 2.3.1. 部署分析 e3-manager e3-manager-web e3-por ...