1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_ 6#define CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_ 7 8#include <list> 9#include <map> 10#include <string> 11 12#include "base/compiler_specific.h" 13#include "base/scoped_observer.h" 14#include "content/public/browser/notification_details.h" 15#include "content/public/browser/notification_observer.h" 16#include "content/public/browser/notification_registrar.h" 17#include "content/public/browser/notification_source.h" 18#include "extensions/browser/extension_registry_observer.h" 19 20namespace content { 21class BrowserContext; 22} 23 24namespace ui { 25class Accelerator; 26} 27 28namespace extensions { 29 30class ActiveTabPermissionGranter; 31class Extension; 32class ExtensionRegistry; 33 34// The ExtensionKeybindingRegistry is a class that handles the cross-platform 35// logic for keyboard accelerators. See platform-specific implementations for 36// implementation details for each platform. 37class ExtensionKeybindingRegistry : public content::NotificationObserver, 38 public ExtensionRegistryObserver { 39 public: 40 enum ExtensionFilter { 41 ALL_EXTENSIONS, 42 PLATFORM_APPS_ONLY 43 }; 44 45 class Delegate { 46 public: 47 // Gets the ActiveTabPermissionGranter for the active tab, if any. 48 // If there is no active tab then returns NULL. 49 virtual ActiveTabPermissionGranter* GetActiveTabPermissionGranter() = 0; 50 }; 51 52 // If |extension_filter| is not ALL_EXTENSIONS, only keybindings by 53 // by extensions that match the filter will be registered. 54 ExtensionKeybindingRegistry(content::BrowserContext* context, 55 ExtensionFilter extension_filter, 56 Delegate* delegate); 57 58 virtual ~ExtensionKeybindingRegistry(); 59 60 // Enables/Disables general shortcut handling in Chrome. Implemented in 61 // platform-specific ExtensionKeybindingsRegistry* files. 62 static void SetShortcutHandlingSuspended(bool suspended); 63 64 // Execute the command bound to |accelerator| and provided by the extension 65 // with |extension_id|, if it exists. 66 void ExecuteCommand(const std::string& extension_id, 67 const ui::Accelerator& accelerator); 68 69 // Check whether the specified |accelerator| has been registered. 70 bool IsAcceleratorRegistered(const ui::Accelerator& accelerator) const; 71 72 protected: 73 // Add extension keybinding for the events defined by the |extension|. 74 // |command_name| is optional, but if not blank then only the command 75 // specified will be added. 76 virtual void AddExtensionKeybinding( 77 const Extension* extension, 78 const std::string& command_name) = 0; 79 // Remove extension bindings for |extension|. |command_name| is optional, 80 // but if not blank then only the command specified will be removed. 81 void RemoveExtensionKeybinding( 82 const Extension* extension, 83 const std::string& command_name); 84 // Overridden by platform specific implementations to provide additional 85 // unregistration (which varies between platforms). 86 virtual void RemoveExtensionKeybindingImpl( 87 const ui::Accelerator& accelerator, 88 const std::string& command_name) = 0; 89 90 // Make sure all extensions registered have keybindings added. 91 void Init(); 92 93 // Whether to ignore this command. Only browserAction commands and pageAction 94 // commands are currently ignored, since they are handled elsewhere. 95 bool ShouldIgnoreCommand(const std::string& command) const; 96 97 // Fire event targets which the specified |accelerator| is binding with. 98 // Returns true if we can find the appropriate event targets. 99 bool NotifyEventTargets(const ui::Accelerator& accelerator); 100 101 // Notifies appropriate parties that a command has been executed. 102 void CommandExecuted(const std::string& extension_id, 103 const std::string& command); 104 105 // Add event target (extension_id, command name) to the target list of 106 // |accelerator|. Note that only media keys can have more than one event 107 // target. 108 void AddEventTarget(const ui::Accelerator& accelerator, 109 const std::string& extension_id, 110 const std::string& command_name); 111 112 // Get the first event target by the given |accelerator|. For a valid 113 // accelerator it should have only one event target, except for media keys. 114 // Returns true if we can find it, |extension_id| and |command_name| will be 115 // set to the right target; otherwise, false is returned and |extension_id|, 116 // |command_name| are unchanged. 117 bool GetFirstTarget(const ui::Accelerator& accelerator, 118 std::string* extension_id, 119 std::string* command_name) const; 120 121 // Returns true if the |event_targets_| is empty; otherwise returns false. 122 bool IsEventTargetsEmpty() const; 123 124 // Returns the BrowserContext for this registry. 125 content::BrowserContext* browser_context() const { return browser_context_; } 126 127 private: 128 // Overridden from content::NotificationObserver: 129 virtual void Observe(int type, 130 const content::NotificationSource& source, 131 const content::NotificationDetails& details) OVERRIDE; 132 133 // ExtensionRegistryObserver implementation. 134 virtual void OnExtensionLoaded(content::BrowserContext* browser_context, 135 const Extension* extension) OVERRIDE; 136 virtual void OnExtensionUnloaded( 137 content::BrowserContext* browser_context, 138 const Extension* extension, 139 UnloadedExtensionInfo::Reason reason) OVERRIDE; 140 141 // Returns true if the |extension| matches our extension filter. 142 bool ExtensionMatchesFilter(const extensions::Extension* extension); 143 144 // Execute commands for |accelerator|. If |extension_id| is empty, execute all 145 // commands bound to |accelerator|, otherwise execute only commands bound by 146 // the corresponding extension. Returns true if at least one command was 147 // executed. 148 bool ExecuteCommands(const ui::Accelerator& accelerator, 149 const std::string& extension_id); 150 151 // The content notification registrar for listening to extension events. 152 content::NotificationRegistrar registrar_; 153 154 content::BrowserContext* browser_context_; 155 156 // What extensions to register keybindings for. 157 ExtensionFilter extension_filter_; 158 159 // Weak pointer to our delegate. Not owned by us. Must outlive this class. 160 Delegate* delegate_; 161 162 // Maps an accelerator to a list of string pairs (extension id, command name) 163 // for commands that have been registered. This keeps track of the targets for 164 // the keybinding event (which named command to call in which extension). On 165 // GTK this map contains registration for pageAction and browserAction 166 // commands, whereas on other platforms it does not. Note that normal 167 // accelerator (which isn't media keys) has only one target, while the media 168 // keys can have more than one. 169 typedef std::list<std::pair<std::string, std::string> > TargetList; 170 typedef std::map<ui::Accelerator, TargetList> EventTargets; 171 EventTargets event_targets_; 172 173 // Listen to extension load, unloaded notifications. 174 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 175 extension_registry_observer_; 176 177 DISALLOW_COPY_AND_ASSIGN(ExtensionKeybindingRegistry); 178}; 179 180} // namespace extensions 181 182#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_KEYBINDING_REGISTRY_H_ 183