summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorzhchbin@gmail.com <zhchbin@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-04 04:07:59 +0000
committerzhchbin@gmail.com <zhchbin@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-04 04:07:59 +0000
commit5eb4043e4f5c9db268145817598197beb20e2f08 (patch)
treedfe83c5eca61e23167adb47b207383a49a1921f8 /chrome
parentdc5f8fd28b7c71926ba26b7bb8deedd5bbd32c62 (diff)
downloadchromium_src-5eb4043e4f5c9db268145817598197beb20e2f08.zip
chromium_src-5eb4043e4f5c9db268145817598197beb20e2f08.tar.gz
chromium_src-5eb4043e4f5c9db268145817598197beb20e2f08.tar.bz2
Parse media keys for named command in the manifest.
BUG=131612 Review URL: https://chromiumcodereview.appspot.com/23445013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221143 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/api/commands/command_service.cc5
-rw-r--r--chrome/browser/extensions/api/commands/command_service_new.cc363
-rw-r--r--chrome/common/extensions/command.cc92
-rw-r--r--chrome/common/extensions/command.h3
-rw-r--r--chrome/common/extensions/command_unittest.cc16
-rw-r--r--chrome/common/extensions/docs/templates/intros/commands.html6
-rw-r--r--chrome/common/extensions/extension_manifest_constants.cc6
-rw-r--r--chrome/common/extensions/extension_manifest_constants.h5
8 files changed, 113 insertions, 383 deletions
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 2978a1f..5d38936 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -216,7 +216,8 @@ void CommandService::UpdateKeybindingPrefs(const std::string& extension_id,
// shortcut before proceeding.
RemoveKeybindingPrefs(extension_id, command_name);
- ui::Accelerator accelerator = Command::StringToAccelerator(keystroke);
+ ui::Accelerator accelerator =
+ Command::StringToAccelerator(keystroke, command_name);
AddKeybindingPref(accelerator, extension_id, command_name, true);
}
@@ -242,7 +243,7 @@ ui::Accelerator CommandService::FindShortcutForCommand(
if (StartsWithASCII(shortcut, Command::CommandPlatform() + ":", true))
shortcut = shortcut.substr(Command::CommandPlatform().length() + 1);
- return Command::StringToAccelerator(shortcut);
+ return Command::StringToAccelerator(shortcut, command_name);
}
return ui::Accelerator();
diff --git a/chrome/browser/extensions/api/commands/command_service_new.cc b/chrome/browser/extensions/api/commands/command_service_new.cc
deleted file mode 100644
index 296180f..0000000
--- a/chrome/browser/extensions/api/commands/command_service_new.cc
+++ /dev/null
@@ -1,363 +0,0 @@
-// 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/api/commands/command_service.h"
-
-#include "base/lazy_instance.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/api/commands/commands.h"
-#include "chrome/browser/extensions/extension_function_registry.h"
-#include "chrome/browser/extensions/extension_keybinding_registry.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/prefs/scoped_user_pref_update.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/pref_names.h"
-#include "components/user_prefs/pref_registry_syncable.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-
-using extensions::Extension;
-
-namespace {
-
-const char kExtension[] = "extension";
-const char kCommandName[] = "command_name";
-
-std::string GetPlatformKeybindingKeyForAccelerator(
- const ui::Accelerator& accelerator) {
- return extensions::Command::CommandPlatform() + ":" +
- UTF16ToUTF8(accelerator.GetShortcutText());
-}
-
-} // namespace
-
-namespace extensions {
-
-// static
-void CommandService::RegisterProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterDictionaryPref(
- prefs::kExtensionCommands,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-}
-
-CommandService::CommandService(Profile* profile)
- : profile_(profile) {
- ExtensionFunctionRegistry::GetInstance()->
- RegisterFunction<GetAllCommandsFunction>();
-
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
- content::Source<Profile>(profile));
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
- content::Source<Profile>(profile));
-}
-
-CommandService::~CommandService() {
-}
-
-static base::LazyInstance<ProfileKeyedAPIFactory<CommandService> >
-g_factory = LAZY_INSTANCE_INITIALIZER;
-
-// static
-ProfileKeyedAPIFactory<CommandService>* CommandService::GetFactoryInstance() {
- return &g_factory.Get();
-}
-
-// static
-CommandService* CommandService::Get(Profile* profile) {
- return ProfileKeyedAPIFactory<CommandService>::GetForProfile(profile);
-}
-
-bool CommandService::GetBrowserActionCommand(
- const std::string& extension_id,
- QueryType type,
- extensions::Command* command,
- bool* active) {
- return GetExtensionActionCommand(
- extension_id, type, command, active, BROWSER_ACTION);
-}
-
-bool CommandService::GetPageActionCommand(
- const std::string& extension_id,
- QueryType type,
- extensions::Command* command,
- bool* active) {
- return GetExtensionActionCommand(
- extension_id, type, command, active, PAGE_ACTION);
-}
-
-bool CommandService::GetScriptBadgeCommand(
- const std::string& extension_id,
- QueryType type,
- extensions::Command* command,
- bool* active) {
- return GetExtensionActionCommand(
- extension_id, type, command, active, SCRIPT_BADGE);
-}
-
-bool CommandService::GetNamedCommands(const std::string& extension_id,
- QueryType type,
- extensions::CommandMap* command_map) {
- const ExtensionSet* extensions =
- ExtensionSystem::Get(profile_)->extension_service()->extensions();
- const Extension* extension = extensions->GetByID(extension_id);
- CHECK(extension);
-
- command_map->clear();
- const extensions::CommandMap* commands =
- CommandsInfo::GetNamedCommands(extension);
- if (!commands)
- return false;
-
- extensions::CommandMap::const_iterator iter = commands->begin();
- for (; iter != commands->end(); ++iter) {
- ui::Accelerator shortcut_assigned =
- FindShortcutForCommand(extension_id, iter->second.command_name());
-
- if (type == ACTIVE_ONLY && shortcut_assigned.key_code() == ui::VKEY_UNKNOWN)
- continue;
-
- extensions::Command command = iter->second;
- if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN)
- command.set_accelerator(shortcut_assigned);
-
- (*command_map)[iter->second.command_name()] = command;
- }
-
- return true;
-}
-
-bool CommandService::AddKeybindingPref(
- const ui::Accelerator& accelerator,
- std::string extension_id,
- std::string command_name,
- bool allow_overrides) {
- if (accelerator.key_code() == ui::VKEY_UNKNOWN)
- return false;
-
- DictionaryPrefUpdate updater(profile_->GetPrefs(),
- prefs::kExtensionCommands);
- base::DictionaryValue* bindings = updater.Get();
-
- std::string key = GetPlatformKeybindingKeyForAccelerator(accelerator);
-
- if (!allow_overrides && bindings->HasKey(key))
- return false; // Already taken.
-
- base::DictionaryValue* keybinding = new base::DictionaryValue();
- keybinding->SetString(kExtension, extension_id);
- keybinding->SetString(kCommandName, command_name);
-
- bindings->Set(key, keybinding);
-
- std::pair<const std::string, const std::string> details =
- std::make_pair(extension_id, command_name);
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_EXTENSION_COMMAND_ADDED,
- content::Source<Profile>(profile_),
- content::Details<
- std::pair<const std::string, const std::string> >(&details));
-
- return true;
-}
-
-void CommandService::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- switch (type) {
- case chrome::NOTIFICATION_EXTENSION_INSTALLED:
- AssignInitialKeybindings(
- content::Details<const InstalledExtensionInfo>(details)->extension);
- break;
- case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
- RemoveKeybindingPrefs(
- content::Details<const Extension>(details)->id(),
- std::string());
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-void CommandService::UpdateKeybindingPrefs(const std::string& extension_id,
- const std::string& command_name,
- const std::string& keystroke) {
- // The extension command might be assigned another shortcut. Remove that
- // shortcut before proceeding.
- RemoveKeybindingPrefs(extension_id, command_name);
-
- ui::Accelerator accelerator = Command::StringToAccelerator(keystroke);
- AddKeybindingPref(accelerator, extension_id, command_name, true);
-}
-
-ui::Accelerator CommandService::FindShortcutForCommand(
- const std::string& extension_id, const std::string& command) {
- const base::DictionaryValue* bindings =
- profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
- for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
- it.Advance()) {
- const base::DictionaryValue* item = NULL;
- it.value().GetAsDictionary(&item);
-
- std::string extension;
- item->GetString(kExtension, &extension);
- if (extension != extension_id)
- continue;
- std::string command_name;
- item->GetString(kCommandName, &command_name);
- if (command != command_name)
- continue;
-
- std::string shortcut = it.key();
- if (StartsWithASCII(shortcut, Command::CommandPlatform() + ":", true))
- shortcut = shortcut.substr(Command::CommandPlatform().length() + 1);
-
- return Command::StringToAccelerator(shortcut);
- }
-
- return ui::Accelerator();
-}
-
-void CommandService::AssignInitialKeybindings(const Extension* extension) {
- const extensions::CommandMap* commands =
- CommandsInfo::GetNamedCommands(extension);
- if (!commands)
- return;
-
- extensions::CommandMap::const_iterator iter = commands->begin();
- for (; iter != commands->end(); ++iter) {
- AddKeybindingPref(iter->second.accelerator(),
- extension->id(),
- iter->second.command_name(),
- false); // Overwriting not allowed.
- }
-
- const extensions::Command* browser_action_command =
- CommandsInfo::GetBrowserActionCommand(extension);
- if (browser_action_command) {
- AddKeybindingPref(browser_action_command->accelerator(),
- extension->id(),
- browser_action_command->command_name(),
- false); // Overwriting not allowed.
- }
-
- const extensions::Command* page_action_command =
- CommandsInfo::GetPageActionCommand(extension);
- if (page_action_command) {
- AddKeybindingPref(page_action_command->accelerator(),
- extension->id(),
- page_action_command->command_name(),
- false); // Overwriting not allowed.
- }
-
- const extensions::Command* script_badge_command =
- CommandsInfo::GetScriptBadgeCommand(extension);
- if (script_badge_command) {
- AddKeybindingPref(script_badge_command->accelerator(),
- extension->id(),
- script_badge_command->command_name(),
- false); // Overwriting not allowed.
- }
-}
-
-void CommandService::RemoveKeybindingPrefs(const std::string& extension_id,
- const std::string& command_name) {
- DictionaryPrefUpdate updater(profile_->GetPrefs(),
- prefs::kExtensionCommands);
- base::DictionaryValue* bindings = updater.Get();
-
- typedef std::vector<std::string> KeysToRemove;
- KeysToRemove keys_to_remove;
- for (base::DictionaryValue::Iterator it(*bindings); !it.IsAtEnd();
- it.Advance()) {
- const base::DictionaryValue* item = NULL;
- it.value().GetAsDictionary(&item);
-
- std::string extension;
- item->GetString(kExtension, &extension);
-
- if (extension == extension_id) {
- // If |command_name| is specified, delete only that command. Otherwise,
- // delete all commands.
- if (!command_name.empty()) {
- std::string command;
- item->GetString(kCommandName, &command);
- if (command_name != command)
- continue;
- }
-
- keys_to_remove.push_back(it.key());
- }
- }
-
- for (KeysToRemove::const_iterator it = keys_to_remove.begin();
- it != keys_to_remove.end(); ++it) {
- std::string key = *it;
- bindings->Remove(key, NULL);
-
- std::pair<const std::string, const std::string> details =
- std::make_pair(extension_id, command_name);
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_EXTENSION_COMMAND_REMOVED,
- content::Source<Profile>(profile_),
- content::Details<
- std::pair<const std::string, const std::string> >(&details));
- }
-}
-
-bool CommandService::GetExtensionActionCommand(
- const std::string& extension_id,
- QueryType query_type,
- extensions::Command* command,
- bool* active,
- ExtensionActionType action_type) {
- ExtensionService* service =
- ExtensionSystem::Get(profile_)->extension_service();
- if (!service)
- return false; // Can happen in tests.
- const ExtensionSet* extensions = service->extensions();
- const Extension* extension = extensions->GetByID(extension_id);
- CHECK(extension);
-
- if (active)
- *active = false;
-
- const extensions::Command* requested_command = NULL;
- switch (action_type) {
- case BROWSER_ACTION:
- requested_command = CommandsInfo::GetBrowserActionCommand(extension);
- break;
- case PAGE_ACTION:
- requested_command = CommandsInfo::GetPageActionCommand(extension);
- break;
- case SCRIPT_BADGE:
- requested_command = CommandsInfo::GetScriptBadgeCommand(extension);
- break;
- }
- if (!requested_command)
- return false;
-
- ui::Accelerator shortcut_assigned =
- FindShortcutForCommand(extension_id, requested_command->command_name());
-
- if (active)
- *active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN);
-
- if (query_type == ACTIVE_ONLY &&
- shortcut_assigned.key_code() == ui::VKEY_UNKNOWN)
- return false;
-
- *command = *requested_command;
- if (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN)
- command->set_accelerator(shortcut_assigned);
-
- return true;
-}
-
-} // namespace extensions
diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc
index fffc55e..be46c20 100644
--- a/chrome/common/extensions/command.cc
+++ b/chrome/common/extensions/command.cc
@@ -29,10 +29,25 @@ static const char kMissing[] = "Missing";
static const char kCommandKeyNotSupported[] =
"Command key is not supported. Note: Ctrl means Command on Mac";
+bool IsNamedCommand(const std::string& command_name) {
+ return command_name != values::kPageActionCommandEvent &&
+ command_name != values::kBrowserActionCommandEvent &&
+ command_name != values::kScriptBadgeCommandEvent;
+}
+
+bool DoesRequireModifier(const std::string& accelerator) {
+ return accelerator != values::kKeyMediaNextTrack &&
+ accelerator != values::kKeyMediaPlayPause &&
+ accelerator != values::kKeyMediaPrevTrack &&
+ accelerator != values::kKeyMediaStop;
+}
+
ui::Accelerator ParseImpl(const std::string& accelerator,
const std::string& platform_key,
int index,
+ bool should_parse_media_keys,
string16* error) {
+ error->clear();
if (platform_key != values::kKeybindingPlatformWin &&
platform_key != values::kKeybindingPlatformMac &&
platform_key != values::kKeybindingPlatformChromeOs &&
@@ -47,7 +62,9 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
std::vector<std::string> tokens;
base::SplitString(accelerator, '+', &tokens);
- if (tokens.size() < 2 || tokens.size() > 3) {
+ if (tokens.size() == 0 ||
+ (tokens.size() == 1 && DoesRequireModifier(accelerator)) ||
+ tokens.size() > 3) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidKeyBinding,
base::IntToString(index),
@@ -99,7 +116,11 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
tokens[i] == values::kKeyEnd ||
tokens[i] == values::kKeyPgUp ||
tokens[i] == values::kKeyPgDwn ||
- tokens[i] == values::kKeyTab) {
+ tokens[i] == values::kKeyTab ||
+ tokens[i] == values::kKeyMediaNextTrack ||
+ tokens[i] == values::kKeyMediaPlayPause ||
+ tokens[i] == values::kKeyMediaPrevTrack ||
+ tokens[i] == values::kKeyMediaStop) {
if (key != ui::VKEY_UNKNOWN) {
// Multiple key assignments.
key = ui::VKEY_UNKNOWN;
@@ -132,6 +153,18 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
key = ui::VKEY_NEXT;
} else if (tokens[i] == values::kKeyTab) {
key = ui::VKEY_TAB;
+ } else if (tokens[i] == values::kKeyMediaNextTrack &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_NEXT_TRACK;
+ } else if (tokens[i] == values::kKeyMediaPlayPause &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_PLAY_PAUSE;
+ } else if (tokens[i] == values::kKeyMediaPrevTrack &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_PREV_TRACK;
+ } else if (tokens[i] == values::kKeyMediaStop &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_STOP;
} else if (tokens[i].size() == 1 &&
tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
@@ -151,6 +184,7 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
return ui::Accelerator();
}
}
+
bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0;
bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0;
bool alt = (modifiers & ui::EF_ALT_DOWN) != 0;
@@ -172,6 +206,19 @@ ui::Accelerator ParseImpl(const std::string& accelerator,
return ui::Accelerator();
}
+ if ((key == ui::VKEY_MEDIA_NEXT_TRACK ||
+ key == ui::VKEY_MEDIA_PREV_TRACK ||
+ key == ui::VKEY_MEDIA_PLAY_PAUSE ||
+ key == ui::VKEY_MEDIA_STOP) &&
+ (shift || ctrl || alt || command)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingMediaKeyWithModifier,
+ base::IntToString(index),
+ platform_key,
+ accelerator);
+ return ui::Accelerator();
+ }
+
return ui::Accelerator(key, modifiers);
}
@@ -214,7 +261,8 @@ Command::Command(const std::string& command_name,
: command_name_(command_name),
description_(description) {
string16 error;
- accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, &error);
+ accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0,
+ IsNamedCommand(command_name), &error);
}
Command::~Command() {}
@@ -235,11 +283,12 @@ std::string Command::CommandPlatform() {
}
// static
-ui::Accelerator Command::StringToAccelerator(const std::string& accelerator) {
+ui::Accelerator Command::StringToAccelerator(const std::string& accelerator,
+ const std::string& command_name) {
string16 error;
- Command command;
ui::Accelerator parsed =
- ParseImpl(accelerator, Command::CommandPlatform(), 0, &error);
+ ParseImpl(accelerator, Command::CommandPlatform(), 0,
+ IsNamedCommand(command_name), &error);
return parsed;
}
@@ -312,6 +361,18 @@ std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) {
case ui::VKEY_TAB:
shortcut += values::kKeyTab;
break;
+ case ui::VKEY_MEDIA_NEXT_TRACK:
+ shortcut += values::kKeyMediaNextTrack;
+ break;
+ case ui::VKEY_MEDIA_PLAY_PAUSE:
+ shortcut += values::kKeyMediaPlayPause;
+ break;
+ case ui::VKEY_MEDIA_PREV_TRACK:
+ shortcut += values::kKeyMediaPrevTrack;
+ break;
+ case ui::VKEY_MEDIA_STOP:
+ shortcut += values::kKeyMediaStop;
+ break;
default:
return "";
}
@@ -326,9 +387,7 @@ bool Command::Parse(const base::DictionaryValue* command,
DCHECK(!command_name.empty());
string16 description;
- if (command_name != values::kPageActionCommandEvent &&
- command_name != values::kBrowserActionCommandEvent &&
- command_name != values::kScriptBadgeCommandEvent) {
+ if (IsNamedCommand(command_name)) {
if (!command->GetString(keys::kDescription, &description) ||
description.empty()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
@@ -419,13 +478,16 @@ bool Command::Parse(const base::DictionaryValue* command,
if (!iter->second.empty()) {
// Note that we pass iter->first to pretend we are on a platform we're not
// on.
- accelerator = ParseImpl(iter->second, iter->first, index, error);
+ accelerator = ParseImpl(iter->second, iter->first, index,
+ IsNamedCommand(command_name), error);
if (accelerator.key_code() == ui::VKEY_UNKNOWN) {
- *error = ErrorUtils::FormatErrorMessageUTF16(
- errors::kInvalidKeyBinding,
- base::IntToString(index),
- iter->first,
- iter->second);
+ if (error->empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBinding,
+ base::IntToString(index),
+ iter->first,
+ iter->second);
+ }
return false;
}
}
diff --git a/chrome/common/extensions/command.h b/chrome/common/extensions/command.h
index 77ff28a..963d26b 100644
--- a/chrome/common/extensions/command.h
+++ b/chrome/common/extensions/command.h
@@ -34,7 +34,8 @@ class Command {
// Parse a string as an accelerator. If the accelerator is unparsable then
// a generic ui::Accelerator object will be returns (with key_code Unknown).
- static ui::Accelerator StringToAccelerator(const std::string& accelerator);
+ static ui::Accelerator StringToAccelerator(const std::string& accelerator,
+ const std::string& command_name);
// Returns the string representation of an accelerator without localizing the
// shortcut text (like accelerator::GetShortcutText() does).
diff --git a/chrome/common/extensions/command_unittest.cc b/chrome/common/extensions/command_unittest.cc
index 56b9686..cd985e6 100644
--- a/chrome/common/extensions/command_unittest.cc
+++ b/chrome/common/extensions/command_unittest.cc
@@ -43,6 +43,14 @@ TEST(CommandTest, ExtensionCommandParsing) {
const ui::Accelerator ctrl_end = ui::Accelerator(ui::VKEY_END, ctrl);
const ui::Accelerator ctrl_pgup = ui::Accelerator(ui::VKEY_PRIOR, ctrl);
const ui::Accelerator ctrl_pgdwn = ui::Accelerator(ui::VKEY_NEXT, ctrl);
+ const ui::Accelerator next_track =
+ ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE);
+ const ui::Accelerator prev_track =
+ ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE);
+ const ui::Accelerator play_pause =
+ ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE);
+ const ui::Accelerator stop =
+ ui::Accelerator(ui::VKEY_MEDIA_STOP, ui::EF_NONE);
const struct {
bool expected_result;
@@ -100,6 +108,14 @@ TEST(CommandTest, ExtensionCommandParsing) {
{ true, ctrl_end, "_execute_browser_action", "Ctrl+End", "" },
{ true, ctrl_pgup, "_execute_browser_action", "Ctrl+PageUp", "" },
{ true, ctrl_pgdwn, "_execute_browser_action", "Ctrl+PageDown", "" },
+ // Media keys.
+ { true, next_track, "command", "MediaNextTrack", "description" },
+ { true, play_pause, "command", "MediaPlayPause", "description" },
+ { true, prev_track, "command", "MediaPrevTrack", "description" },
+ { true, stop, "command", "MediaStop", "description" },
+ { false, none, "_execute_browser_action", "MediaNextTrack", "" },
+ { false, none, "_execute_page_action", "MediaPrevTrack", "" },
+ { false, none, "command", "Ctrl+Shift+MediaPrevTrack", "description" },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
diff --git a/chrome/common/extensions/docs/templates/intros/commands.html b/chrome/common/extensions/docs/templates/intros/commands.html
index 8720da7..94db67d 100644
--- a/chrome/common/extensions/docs/templates/intros/commands.html
+++ b/chrome/common/extensions/docs/templates/intros/commands.html
@@ -11,11 +11,13 @@ have many commands but only 4 suggested keys can be specified. The user can
manually add more shortcuts from the chrome://extensions page.</p>
<p>Supported keys: A-Z, 0-9, Comma, Period, Home, End, PageUp, PageDown, Insert,
-Delete, Tab and the arrow keys (Up, Down, Left, Right).</p>
+Delete, Tab, Arrow keys (Up, Down, Left, Right) and the Media Keys
+(MediaNextTrack, MediaPlayPause, MediaPrevTrack, MediaStop).</p>
<p>Note: All key combinations must include either Ctrl* or Alt. Combinations
that involve Ctrl+Alt are not permitted in order to avoid conflicts with the
-AltGr key. Shift can be used in addition to Alt or Ctrl, but is not required.<p>
+AltGr key. Shift can be used in addition to Alt or Ctrl, but is not required.
+Modifiers (such as Ctrl) can not be used in combination with the Media Keys.<p>
<p>* Also note that on Mac 'Ctrl' is automatically converted to 'Command'. If
you want 'Ctrl' instead, please specify 'MacCtrl'.</p>
diff --git a/chrome/common/extensions/extension_manifest_constants.cc b/chrome/common/extensions/extension_manifest_constants.cc
index 0967243..92c82c4 100644
--- a/chrome/common/extensions/extension_manifest_constants.cc
+++ b/chrome/common/extensions/extension_manifest_constants.cc
@@ -27,6 +27,10 @@ const char kKeyHome[] = "Home";
const char kKeyIns[] = "Insert";
const char kKeyLeft[] = "Left";
const char kKeyMacCtrl[] = "MacCtrl";
+const char kKeyMediaNextTrack[] = "MediaNextTrack";
+const char kKeyMediaPlayPause[] = "MediaPlayPause";
+const char kKeyMediaPrevTrack[] = "MediaPrevTrack";
+const char kKeyMediaStop[] = "MediaStop";
const char kKeyPgDwn[] = "PageDown";
const char kKeyPgUp[] = "PageUp";
const char kKeyPeriod[] = "Period";
@@ -251,6 +255,8 @@ const char kInvalidKeyBindingDescription[] =
"Invalid value for 'commands[*].description'.";
const char kInvalidKeyBindingDictionary[] =
"Contents of 'commands[*]' invalid.";
+const char kInvalidKeyBindingMediaKeyWithModifier[] =
+ "Media key cannot have any modifier for 'commands[*].*': *.";
const char kInvalidKeyBindingMissingPlatform[] =
"Could not find key specification for 'command[*].*': Either specify a key "
"for '*', or specify a default key.";
diff --git a/chrome/common/extensions/extension_manifest_constants.h b/chrome/common/extensions/extension_manifest_constants.h
index 411c52d..37500da 100644
--- a/chrome/common/extensions/extension_manifest_constants.h
+++ b/chrome/common/extensions/extension_manifest_constants.h
@@ -37,6 +37,10 @@ namespace extension_manifest_values {
extern const char kKeyIns[];
extern const char kKeyLeft[];
extern const char kKeyMacCtrl[];
+ extern const char kKeyMediaNextTrack[];
+ extern const char kKeyMediaPlayPause[];
+ extern const char kKeyMediaPrevTrack[];
+ extern const char kKeyMediaStop[];
extern const char kKeyPgDwn[];
extern const char kKeyPgUp[];
extern const char kKeyPeriod[];
@@ -158,6 +162,7 @@ namespace extension_manifest_errors {
extern const char kInvalidKeyBinding[];
extern const char kInvalidKeyBindingDescription[];
extern const char kInvalidKeyBindingDictionary[];
+ extern const char kInvalidKeyBindingMediaKeyWithModifier[];
extern const char kInvalidKeyBindingMissingPlatform[];
extern const char kInvalidKeyBindingTooMany[];
extern const char kInvalidKeyBindingUnknownPlatform[];