• 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_;
    };

    定义了快捷键属性

    主要有三个属性

    1. key_code_:按下的键盘键
    2. type_:触发的事件,比如keydown,keyup
    3. 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() {}
    };

    注册快捷键的对象,

    1. AcceleratorPressed方法为处理快捷键事件,返回true则表明处理完毕
    2. 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());
    }

    image

     

    简单的用以上关系来表达三者之间的关系,其实逻辑还是比较清晰的,使用map查找起来速度也比较快,不会存在什么性能上面的问题,Register方法都是push_front也保证了时效性,所以其还是满足了快捷键使用的需求,非常轻巧

  • 相关阅读:
    【独立开发人员er Cocos2d-x实战 001】csb文件导出和载入
    Best Time to Buy and Sell Stock I &amp;&amp; II &amp;&amp; III
    cocos2d-x项目101次相遇-安装和环境搭建 -xcode
    使用 C# 开发智能手机软件:推箱子(十二)
    javascript实现掉落弹出层------Day29
    Android中onTouch与onClick事件的关系
    CSDN编程挑战——《交替字符串》
    【NPR】非真实感渲染实验室
    CSS自己主动换行、强制不换行、强制断行、超出显示省略号
    在Ubuntu 14.04安装和使用Docker
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/3239675.html
Copyright © 2020-2023  润新知