Chromium Code Reviews| Index: chrome/common/extensions/extension.cc |
| =================================================================== |
| --- chrome/common/extensions/extension.cc (revision 122745) |
| +++ chrome/common/extensions/extension.cc (working copy) |
| @@ -18,6 +18,7 @@ |
| #include "base/string16.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_piece.h" |
| +#include "base/string_split.h" |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/values.h" |
| @@ -42,6 +43,7 @@ |
| #include "grit/theme_resources.h" |
| #include "net/base/registry_controlled_domain.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| +#include "ui/base/keycodes/keyboard_codes.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "webkit/glue/image_decoder.h" |
| @@ -219,6 +221,104 @@ |
| Extension::TtsVoice::TtsVoice() {} |
| Extension::TtsVoice::~TtsVoice() {} |
| +Extension::ExtensionKeybinding::ExtensionKeybinding() {} |
| +Extension::ExtensionKeybinding::~ExtensionKeybinding() {} |
| + |
| +bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, |
| + const std::string& command_name, |
| + int index, |
| + string16* error) { |
| + DCHECK(!command_name.empty()); |
| + std::string key_binding; |
| + if (!command->GetString(keys::kKey, &key_binding) || |
| + key_binding.empty()) { |
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBinding, |
| + base::IntToString(index), |
| + "Missing"); |
| + return false; |
| + } |
| + |
| + std::string original_keybinding = key_binding; |
| + // Normalize '-' to '+'. |
| + ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+"); |
| + // Remove all spaces. |
| + ReplaceSubstringsAfterOffset(&key_binding, 0, " ", ""); |
| + // And finally, lower-case it. |
| + key_binding = StringToLowerASCII(key_binding); |
| + |
| + std::vector<std::string> tokens; |
| + base::SplitString(key_binding, '+', &tokens); |
| + if (tokens.size() < 2 || tokens.size() > 3) { |
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBinding, |
| + base::IntToString(index), |
| + original_keybinding); |
| + return false; |
| + } |
| + |
| + // Now, parse it into an accelerator. |
| + bool ctrl = false; |
| + bool alt = false; |
| + bool shift = false; |
| + ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
| + for (size_t i = 0; i < tokens.size(); i++) { |
| + if (tokens[i] == "ctrl") { |
| + ctrl = true; |
| + } else if (tokens[i] == "alt") { |
| + alt = true; |
| + } else if (tokens[i] == "shift") { |
| + shift = true; |
| + } else if (tokens[i].size() == 1 && |
| + base::ToUpperASCII(tokens[i][0]) >= ui::VKEY_A && |
|
Matt Perry
2012/02/22 23:59:42
Just use 'a' so you don't have to uppercase it. Al
|
| + base::ToUpperASCII(tokens[i][0]) <= ui::VKEY_Z) { |
| + if (key != ui::VKEY_UNKNOWN) { |
| + // Multiple key assignments. |
| + key = ui::VKEY_UNKNOWN; |
| + break; |
| + } |
| + |
| + key = static_cast<ui::KeyboardCode>( |
| + ui::VKEY_A + (base::ToUpperASCII(tokens[i][0]) - ui::VKEY_A)); |
|
Matt Perry
2012/02/22 23:59:42
see above, second VKEY_A => 'a'
|
| + } else { |
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBinding, |
| + base::IntToString(index), |
| + original_keybinding); |
| + return false; |
| + } |
| + } |
| + |
| + // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not |
| + // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: |
| + // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
| + if (key == ui::VKEY_UNKNOWN || ctrl == true && alt == true) { |
|
Matt Perry
2012/02/22 23:59:42
Please add parens around (ctrl == true && alt == t
|
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBinding, |
| + base::IntToString(index), |
| + original_keybinding); |
| + return false; |
| + } |
| + |
| + accelerator_ = ui::Accelerator(key, shift, ctrl, alt); |
| + |
| + if (command_name != |
| + extension_manifest_values::kPageActionKeybindingEvent && |
| + command_name != |
| + extension_manifest_values::kBrowserActionKeybindingEvent) { |
| + if (!command->GetString(keys::kDescription, &description_) || |
| + description_.empty()) { |
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBindingDescription, |
| + base::IntToString(index)); |
| + return false; |
| + } |
| + } |
| + |
| + command_name_ = command_name; |
| + return true; |
| +} |
| + |
| // |
| // Extension |
| // |
| @@ -858,7 +958,7 @@ |
| // Read the file browser action |default_icon| (optional). |
| if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { |
| if (!file_browser_handler->GetString( |
| - keys::kPageActionDefaultIcon,&default_icon) || |
| + keys::kPageActionDefaultIcon, &default_icon) || |
| default_icon.empty()) { |
| *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); |
| return NULL; |
| @@ -1162,7 +1262,7 @@ |
| !one_service->GetList(keys::kIntentType, &mime_types) || |
| mime_types->GetSize() == 0) { |
| *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| - errors::kInvalidIntentType,*iter); |
| + errors::kInvalidIntentType, *iter); |
| return false; |
| } |
| @@ -1177,7 +1277,7 @@ |
| if (!service_url.is_valid() || |
| !(web_extent().MatchesURL(service_url))) { |
| *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| - errors::kInvalidIntentPageInHostedApp,*iter); |
| + errors::kInvalidIntentPageInHostedApp, *iter); |
| return false; |
| } |
| service.service_url = service_url; |
| @@ -1185,7 +1285,7 @@ |
| // We do not allow absolute intent URLs in non-hosted apps. |
| if (GURL(value).is_valid()) { |
| *error =ExtensionErrorUtils::FormatErrorMessageUTF16( |
| - errors::kCannotAccessPage,value.c_str()); |
| + errors::kCannotAccessPage, value.c_str()); |
| return false; |
| } |
| service.service_url = GetResourceURL(value); |
| @@ -1719,6 +1819,35 @@ |
| manifest->GetBoolean(keys::kConvertedFromUserScript, |
| &converted_from_user_script_); |
| + // Initialize commands (if present). |
| + if (manifest->HasKey(keys::kCommands)) { |
| + DictionaryValue* commands = NULL; |
| + if (!manifest->GetDictionary(keys::kCommands, &commands)) { |
| + *error = ASCIIToUTF16(errors::kInvalidCommandsKey); |
| + return false; |
| + } |
| + |
| + int command_index = 0; |
| + for (DictionaryValue::key_iterator iter = commands->begin_keys(); |
| + iter != commands->end_keys(); ++iter) { |
| + ++command_index; |
| + |
| + DictionaryValue* command = NULL; |
| + if (!commands->GetDictionary(*iter, &command)) { |
| + *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| + errors::kInvalidKeyBindingDictionary, |
| + base::IntToString(command_index)); |
| + return false; |
| + } |
| + |
| + ExtensionKeybinding binding; |
| + if (!binding.Parse(command, *iter, command_index, error)) |
| + return false; // |error| already set. |
| + |
| + commands_.push_back(binding); |
| + } |
| + } |
| + |
| // Initialize icons (if present). |
| if (manifest->HasKey(keys::kIcons)) { |
| DictionaryValue* icons_value = NULL; |
| @@ -2882,7 +3011,7 @@ |
| bool supports_type = false; |
| switch (GetType()) { |
| - case TYPE_USER_SCRIPT: // Pass through. |
| + case TYPE_USER_SCRIPT: // Pass through. |
| case TYPE_EXTENSION: |
| supports_type = permission->supports_extensions(); |
| break; |
| @@ -3038,7 +3167,6 @@ |
| // their positions should sync. |
| return location_ == Extension::INTERNAL || |
| ShouldDisplayInLauncher(); |
| - |
| } |
| bool Extension::ShouldDisplayInLauncher() const { |