Commit c1c58a01 authored by finnur@chromium.org's avatar finnur@chromium.org

Make sure manifest specified shortcut for Extension Command can not override the

built-in shortcuts (for Views and GTK).

User is still free to override manually.

TBR=sky (already reviewed, except for the two line change, see below)
BUG=226994
TEST=Automated test included.

NOTE: This is the second attempt at landing, with only the ifdefs in accelerator_utils_views.cc added since last attempt (https://codereview.chromium.org/13044014). Tried building it locally where it failed before (on Win Aura and not) and it passed on both.

Review URL: https://chromiumcodereview.appspot.com/14017017

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194962 0039d316-1c4b-4281-b951-d872f2087c98
parent 1c4782d8
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/accelerator_utils.h"
#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/api/commands/commands_handler.h" #include "chrome/common/extensions/api/commands/commands_handler.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
...@@ -232,37 +233,49 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) { ...@@ -232,37 +233,49 @@ void CommandService::AssignInitialKeybindings(const Extension* extension) {
extensions::CommandMap::const_iterator iter = commands->begin(); extensions::CommandMap::const_iterator iter = commands->begin();
for (; iter != commands->end(); ++iter) { for (; iter != commands->end(); ++iter) {
AddKeybindingPref(iter->second.accelerator(), if (!chrome::IsChromeAccelerator(
extension->id(), iter->second.accelerator(), profile_)) {
iter->second.command_name(), AddKeybindingPref(iter->second.accelerator(),
false); // Overwriting not allowed. extension->id(),
iter->second.command_name(),
false); // Overwriting not allowed.
}
} }
const extensions::Command* browser_action_command = const extensions::Command* browser_action_command =
CommandsInfo::GetBrowserActionCommand(extension); CommandsInfo::GetBrowserActionCommand(extension);
if (browser_action_command) { if (browser_action_command) {
AddKeybindingPref(browser_action_command->accelerator(), if (!chrome::IsChromeAccelerator(
extension->id(), browser_action_command->accelerator(), profile_)) {
browser_action_command->command_name(), AddKeybindingPref(browser_action_command->accelerator(),
false); // Overwriting not allowed. extension->id(),
browser_action_command->command_name(),
false); // Overwriting not allowed.
}
} }
const extensions::Command* page_action_command = const extensions::Command* page_action_command =
CommandsInfo::GetPageActionCommand(extension); CommandsInfo::GetPageActionCommand(extension);
if (page_action_command) { if (page_action_command) {
AddKeybindingPref(page_action_command->accelerator(), if (!chrome::IsChromeAccelerator(
extension->id(), page_action_command->accelerator(), profile_)) {
page_action_command->command_name(), AddKeybindingPref(page_action_command->accelerator(),
false); // Overwriting not allowed. extension->id(),
page_action_command->command_name(),
false); // Overwriting not allowed.
}
} }
const extensions::Command* script_badge_command = const extensions::Command* script_badge_command =
CommandsInfo::GetScriptBadgeCommand(extension); CommandsInfo::GetScriptBadgeCommand(extension);
if (script_badge_command) { if (script_badge_command) {
AddKeybindingPref(script_badge_command->accelerator(), if (!chrome::IsChromeAccelerator(
extension->id(), script_badge_command->accelerator(), profile_)) {
script_badge_command->command_name(), AddKeybindingPref(script_badge_command->accelerator(),
false); // Overwriting not allowed. extension->id(),
script_badge_command->command_name(),
false); // Overwriting not allowed.
}
} }
} }
......
This diff is collapsed.
...@@ -195,4 +195,44 @@ IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) { ...@@ -195,4 +195,44 @@ IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_; ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
} }
// This test validates that an extension cannot request a shortcut that is
// already in use by Chrome.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, DontOverwriteSystemShortcuts) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/dont_overwrite_system")) << message_;
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(tab);
// Activate the shortcut (Alt+Shift+F) to make page blue.
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, false, true, true, false));
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function() {"
" if (document.body.bgColor == 'blue') {"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
// Activate the shortcut (Ctrl+F) to make page red (should not work).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, false, false, false));
// The page should still be blue.
result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function() {"
" if (document.body.bgColor == 'blue') {"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
} // extensions } // extensions
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/active_tab_permission_granter.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
using content::WebContents;
namespace extensions {
class CommandsApiTest : public ExtensionApiTest {
public:
CommandsApiTest() {}
virtual ~CommandsApiTest() {}
protected:
BrowserActionTestUtil GetBrowserActionsBar() {
return BrowserActionTestUtil(browser());
}
};
class ScriptBadgesCommandsApiTest : public ExtensionApiTest {
public:
ScriptBadgesCommandsApiTest() {
// We cannot add this to CommandsApiTest because then PageActions get
// treated like BrowserActions and the PageAction test starts failing.
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kScriptBadges, "1");
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
}
virtual ~ScriptBadgesCommandsApiTest() {}
};
// Test the basic functionality of the Keybinding API:
// - That pressing the shortcut keys should perform actions (activate the
// browser action or send an event).
// - Note: Page action keybindings are tested in PageAction test below.
// - The shortcut keys taken by one extension are not overwritten by the last
// installed extension.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, Basic) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
// Load this extension, which uses the same keybindings but sets the page
// to different colors. This is so we can see that it doesn't interfere. We
// don't test this extension in any other way (it should otherwise be
// immaterial to this test).
ASSERT_TRUE(RunExtensionTest("keybinding/conflicting")) << message_;
// Test that there are two browser actions in the toolbar.
ASSERT_EQ(2, GetBrowserActionsBar().NumberOfBrowserActions());
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
// activeTab shouldn't have been granted yet.
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(tab);
ActiveTabPermissionGranter* granter =
TabHelper::FromWebContents(tab)->active_tab_permission_granter();
EXPECT_FALSE(granter->IsGranted(extension));
// Activate the shortcut (Ctrl+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, true, false, false));
// activeTab should now be granted.
EXPECT_TRUE(granter->IsGranted(extension));
// Verify the command worked.
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'red'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
// Activate the shortcut (Ctrl+Shift+Y).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_Y, true, true, false, false));
result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'blue'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
// Flaky on linux and chromeos, http://crbug.com/165825
#if defined(OS_MACOSX) || defined(OS_WIN)
#define MAYBE_PageAction PageAction
#else
#define MAYBE_PageAction DISABLED_PageAction
#endif
IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_PageAction) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
// Load a page, the extension will detect the navigation and request to show
// the page action icon.
ResultCatcher catcher;
ui_test_utils::NavigateToURL(browser(),
test_server()->GetURL("files/extensions/test_file.txt"));
ASSERT_TRUE(catcher.GetNextResult());
}
// Make sure it appears and is the right one.
ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
int tab_id = SessionTabHelper::FromWebContents(
browser()->tab_strip_model()->GetActiveWebContents())->session_id().id();
ExtensionAction* action =
ExtensionActionManager::Get(browser()->profile())->
GetPageAction(*extension);
ASSERT_TRUE(action);
EXPECT_EQ("Make this page red", action->GetTitle(tab_id));
// Activate the shortcut (Alt+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, false, true, true, false));
// Verify the command worked (the page action turns the page red).
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
bool result = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
tab,
"setInterval(function(){"
" if(document.body.bgColor == 'red'){"
" window.domAutomationController.send(true)}}, 100)",
&result));
ASSERT_TRUE(result);
}
// Checked-in in a disabled state, because the necessary functionality to
// automatically verify that the test works hasn't been implemented for the
// script badges yet (see http://crbug.com/140016). The test results, can be
// verified manually by running the test and verifying that the synthesized
// popup for script badges appear. When bug 140016 has been fixed, the popup
// code can signal to the test that the test passed.
// TODO(finnur): Enable this test once the bug is fixed.
IN_PROC_BROWSER_TEST_F(ScriptBadgesCommandsApiTest, DISABLED_ScriptBadge) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/script_badge")) << message_;
const Extension* extension = GetSingleLoadedExtension();
ASSERT_TRUE(extension) << message_;
{
ResultCatcher catcher;
// Tell the extension to update the script badge state.
ui_test_utils::NavigateToURL(
browser(), GURL(extension->GetResourceURL("show.html")));
ASSERT_TRUE(catcher.GetNextResult());
}
{
ResultCatcher catcher;
// Activate the shortcut (Ctrl+Shift+F).
ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
browser(), ui::VKEY_F, true, true, false, false));
ASSERT_TRUE(catcher.GetNextResult());
}
}
// This test validates that the getAll query API function returns registered
// commands as well as synthesized ones and that inactive commands (like the
// synthesized ones are in nature) have no shortcuts.
IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) {
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_;
}
} // extensions
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_ACCELERATOR_UTILS_H_
#define CHROME_BROWSER_UI_ACCELERATOR_UTILS_H_
class Profile;
namespace ui {
class Accelerator;
}
namespace chrome {
// Returns true if the given |accelerator| is currently registered by
// Chrome.
bool IsChromeAccelerator(const ui::Accelerator& accelerator,
Profile* profile);
} // namespace chrome
#endif // CHROME_BROWSER_UI_ACCELERATOR_UTILS_H_
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/cocoa/accelerators_cocoa.h"
#import "chrome/browser/ui/cocoa/browser_window_utils.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "ui/base/accelerators/accelerator.h"
#import "ui/base/accelerators/platform_accelerator_cocoa.h"
#import "ui/base/keycodes/keyboard_code_conversion_mac.h"
namespace chrome {
bool IsChromeAccelerator(const ui::Accelerator& accelerator, Profile* profile) {
// The |accelerator| passed in contains a Windows key code but no platform
// accelerator info. The Accelerator list is the opposite: It has accelerators
// that have key_code() == VKEY_UNKNOWN but they contain a platform
// accelerator. We find common ground by converting the passed in Windows key
// code to a character and use that when comparing against the Accelerator
// list.
unichar character;
unichar characterIgnoringModifiers;
ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(),
0,
&character,
&characterIgnoringModifiers);
NSString* characters =
[[[NSString alloc] initWithCharacters:&character length:1] autorelease];
NSUInteger modifiers =
(accelerator.IsCtrlDown() ? NSControlKeyMask : 0) |
(accelerator.IsCmdDown() ? NSCommandKeyMask : 0) |
(accelerator.IsAltDown() ? NSAlternateKeyMask : 0) |
(accelerator.IsShiftDown() ? NSShiftKeyMask : 0);
NSEvent* event = [NSEvent keyEventWithType:NSKeyDown
location:NSZeroPoint
modifierFlags:modifiers
timestamp:0
windowNumber:0
context:nil
characters:characters
charactersIgnoringModifiers:characters
isARepeat:NO
keyCode:accelerator.key_code()];
content::NativeWebKeyboardEvent keyboard_event(event);
int id = [BrowserWindowUtils getCommandId:keyboard_event];
return id != -1;
}
} // namespace chrome
...@@ -26,6 +26,10 @@ template <typename T> struct DefaultSingletonTraits; ...@@ -26,6 +26,10 @@ template <typename T> struct DefaultSingletonTraits;
class AcceleratorsCocoa { class AcceleratorsCocoa {
public: public:
typedef std::map<int, ui::Accelerator> AcceleratorMap; typedef std::map<int, ui::Accelerator> AcceleratorMap;
typedef AcceleratorMap::const_iterator const_iterator;
const_iterator const begin() { return accelerators_.begin(); }
const_iterator const end() { return accelerators_.end(); }
// Returns NULL if there is no accelerator for the command. // Returns NULL if there is no accelerator for the command.
const ui::Accelerator* GetAcceleratorForCommand(int command_id); const ui::Accelerator* GetAcceleratorForCommand(int command_id);
......
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
#include "ui/base/accelerators/accelerator.h"
namespace chrome {
bool IsChromeAccelerator(const ui::Accelerator& accelerator, Profile* profile) {
AcceleratorsGtk* accelerators = AcceleratorsGtk::GetInstance();
for (AcceleratorsGtk::const_iterator iter = accelerators->begin();
iter != accelerators->end(); ++iter) {
if (iter->second.key_code() == accelerator.key_code() &&
iter->second.modifiers() == accelerator.modifiers())
return true;
}
return false;
}
} // namespace chrome
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/accelerator_table.h"
#include "ui/base/accelerators/accelerator.h"
#if defined(USE_ASH)
#include "ash/accelerators/accelerator_table.h"
#endif // USE_ASH
namespace chrome {
bool IsChromeAccelerator(const ui::Accelerator& accelerator, Profile* profile) {
#if defined(USE_ASH)
for (size_t i = 0; i < ash::kAcceleratorDataLength; ++i) {
const ash::AcceleratorData& accel_data = ash::kAcceleratorData[i];
if (accel_data.keycode == accelerator.key_code() &&
accel_data.modifiers == accelerator.modifiers()) {
return true;
}
}
#endif
std::vector<chrome::AcceleratorMapping> accelerators =
chrome::GetAcceleratorList();
for (std::vector<chrome::AcceleratorMapping>::const_iterator it =
accelerators.begin(); it != accelerators.end(); ++it) {
if (it->keycode == accelerator.key_code() &&
it->modifiers == accelerator.modifiers())
return true;
}
return false;
}
} // namespace chrome
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/accelerators/accelerator.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
namespace chrome {
#if !defined(USE_AURA)
bool IsChromeAccelerator(const ui::Accelerator& accelerator, Profile* profile) {
Browser* browser = chrome::FindLastActiveWithProfile(
profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
if (!browser)
return false;
BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
browser->window()->GetNativeWindow());
return browser_view->IsAcceleratorRegistered(accelerator);
}
#endif // !USE_AURA
} // namespace chrome
...@@ -638,6 +638,10 @@ bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { ...@@ -638,6 +638,10 @@ bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
cmd_id, browser_->host_desktop_type(), accelerator); cmd_id, browser_->host_desktop_type(), accelerator);
} }
bool BrowserView::IsAcceleratorRegistered(const ui::Accelerator& accelerator) {
return accelerator_table_.find(accelerator) != accelerator_table_.end();
}
WebContents* BrowserView::GetActiveWebContents() const { WebContents* BrowserView::GetActiveWebContents() const {
return browser_->tab_strip_model()->GetActiveWebContents(); return browser_->tab_strip_model()->GetActiveWebContents();
} }
......
...@@ -188,6 +188,9 @@ class BrowserView : public BrowserWindow, ...@@ -188,6 +188,9 @@ class BrowserView : public BrowserWindow,
// otherwise. // otherwise.
bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator); bool GetAccelerator(int cmd_id, ui::Accelerator* accelerator);
// Returns true if the specificed |accelerator| is registered with this view.
bool IsAcceleratorRegistered(const ui::Accelerator& accelerator);
// Returns the active WebContents. Used by our NonClientView's // Returns the active WebContents. Used by our NonClientView's
// TabIconView::TabContentsProvider implementations. // TabIconView::TabContentsProvider implementations.
// TODO(beng): exposing this here is a bit bogus, since it's only used to // TODO(beng): exposing this here is a bit bogus, since it's only used to
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
'sources': [ 'sources': [
# All .cc, .h, .m, and .mm files under browser/ui except for: # All .cc, .h, .m, and .mm files under browser/ui except for:
# * tests and mocks. # * tests and mocks.
'browser/ui/accelerator_utils.h',
'browser/ui/active_tab_tracker.cc', 'browser/ui/active_tab_tracker.cc',
'browser/ui/active_tab_tracker.h', 'browser/ui/active_tab_tracker.h',
'browser/ui/alternate_error_tab_observer.cc', 'browser/ui/alternate_error_tab_observer.cc',
...@@ -329,6 +330,7 @@ ...@@ -329,6 +330,7 @@
'browser/ui/chrome_select_file_policy.h', 'browser/ui/chrome_select_file_policy.h',
'browser/ui/chrome_style.cc', 'browser/ui/chrome_style.cc',
'browser/ui/chrome_style.h', 'browser/ui/chrome_style.h',
'browser/ui/cocoa/accelerator_utils_cocoa.mm',
'browser/ui/cocoa/about_ipc_controller.h', 'browser/ui/cocoa/about_ipc_controller.h',
'browser/ui/cocoa/about_ipc_controller.mm', 'browser/ui/cocoa/about_ipc_controller.mm',
'browser/ui/cocoa/about_ipc_dialog.h', 'browser/ui/cocoa/about_ipc_dialog.h',
...@@ -912,6 +914,7 @@ ...@@ -912,6 +914,7 @@
'browser/ui/global_error/global_error_service.h', 'browser/ui/global_error/global_error_service.h',
'browser/ui/global_error/global_error_service_factory.cc', 'browser/ui/global_error/global_error_service_factory.cc',
'browser/ui/global_error/global_error_service_factory.h', 'browser/ui/global_error/global_error_service_factory.h',
'browser/ui/gtk/accelerator_utils_gtk.cc',
'browser/ui/gtk/accelerators_gtk.cc', 'browser/ui/gtk/accelerators_gtk.cc',
'browser/ui/gtk/accelerators_gtk.h', 'browser/ui/gtk/accelerators_gtk.h',
'browser/ui/gtk/action_box_button_gtk.cc', 'browser/ui/gtk/action_box_button_gtk.cc',
...@@ -1351,8 +1354,8 @@ ...@@ -1351,8 +1354,8 @@
'browser/ui/sync/one_click_signin_infobar_delegate.h', 'browser/ui/sync/one_click_signin_infobar_delegate.h',
'browser/ui/sync/one_click_signin_sync_starter.cc', 'browser/ui/sync/one_click_signin_sync_starter.cc',
'browser/ui/sync/one_click_signin_sync_starter.h', 'browser/ui/sync/one_click_signin_sync_starter.h',
'browser/ui/sync/profile_signin_confirmation_helper.cc', 'browser/ui/sync/profile_signin_confirmation_helper.cc',
'browser/ui/sync/profile_signin_confirmation_helper.h', 'browser/ui/sync/profile_signin_confirmation_helper.h',
'browser/ui/sync/signin_histogram.h', 'browser/ui/sync/signin_histogram.h',
'browser/ui/sync/tab_contents_synced_tab_delegate.cc', 'browser/ui/sync/tab_contents_synced_tab_delegate.cc',
'browser/ui/sync/tab_contents_synced_tab_delegate.h', 'browser/ui/sync/tab_contents_synced_tab_delegate.h',
...@@ -1427,6 +1430,8 @@ ...@@ -1427,6 +1430,8 @@
'browser/ui/unload_controller.h', 'browser/ui/unload_controller.h',
'browser/ui/user_data_dir_dialog.h', 'browser/ui/user_data_dir_dialog.h',
'browser/ui/view_ids.h', 'browser/ui/view_ids.h',
'browser/ui/views/accelerator_utils_aura.cc',
'browser/ui/views/accelerator_utils_views.cc',
'browser/ui/views/about_ipc_dialog.cc', 'browser/ui/views/about_ipc_dialog.cc',
'browser/ui/views/about_ipc_dialog.h', 'browser/ui/views/about_ipc_dialog.h',
'browser/ui/views/accessibility/accessibility_event_router_views.cc', 'browser/ui/views/accessibility/accessibility_event_router_views.cc',
......
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Called when the user activates the command.
chrome.commands.onCommand.addListener(function(command) {
chrome.tabs.executeScript(null, {
code: "document.body.bgColor='" + command + "'" });
});
chrome.test.notifyPass();
{
"name": "An extension that tries to overwrite system keybindings",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions": ["activeTab"],
"commands": {
"red": {
"suggested_key": "Ctrl+F",
"description": "Make the page red"
},
"blue": {
"suggested_key": "Alt+Shift+F",
"description": "Make the page blue"
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment