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 ...
随机推荐
- Ubuntu接显示器问题
1.Could not apply the stored configuration for monitors 解决办法:Ubuntu在开机进入桌面的时候,会调用gnome-setting-deamo ...
- GDB命令
recursiveDescription 打印view层次结构
- VS 多工程代码编写
VS工作目录,输出目录 C++项目,解决方案总文件夹下就只包含解决方案配置文件sln和一个项目总文件夹和一个Debug文件夹以及一个Release文件夹(共四个东东,其中Debug和Release文件 ...
- Linux信号(signal)机制【转】
转自:http://gityuan.com/2015/12/20/signal/ 信号(signal)是一种软中断,信号机制是进程间通信的一种方式,采用异步通信方式 一.信号类型 Linux系统共定义 ...
- Django项目之cookie+session
原文:https://www.cnblogs.com/sss4/p/7071334.html HTTP协议 是短连接.且状态的,所以在客户端向服务端发起请求后,服务端在响应头 加入cokie响应给浏览 ...
- snmp安装
只为成功找方法,不为失败找借口! Snmp学习总结(六)——linux下安装和配置SNMP 一.安装SNMP 1.1.下载Net-SNMP的源代码 选择一个SNMP版本,比如5.7.1,下载地址如下: ...
- java 构造器(constructor)
有一点很重要,即你要时刻询问子句"如果异常发生了,所有东西能被正确清理码?",尽管大多数情况下时非常安全的,但涉及到构造器时,问题出现了,构造器会把对象设置成安全的初始状态,但还会 ...
- Ubuntu18.04安装和配置 Java JDK 和 JRE,并卸载自带OpenJDK
https://blog.csdn.net/freeking101/article/details/80522586
- 如何区分prometheus中Histogram和Summary类型的metrics?
要理解它们的区别,关键还是告业务应用. 但如何在学习时,如何区分呢? 有以下几个维度: histogram有bucket,summary在quatile. summary分位数是客户端计算上报,his ...
- React 中 context 的使用
官方文档说明(英) 看了别人写的中文博客,再看了官方英文文档,发现还是官方文档讲的浅显易懂一些,看了之后,半翻译半理解地写了这篇博客,更易于新手理解. 介绍 context 是在 react @ 0. ...