| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/extensions/command.h" | 5 #include "chrome/common/extensions/command.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
| 9 #include "base/string_split.h" | 9 #include "base/string_split.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "chrome/common/extensions/extension.h" | 12 #include "chrome/common/extensions/extension.h" |
| 13 #include "chrome/common/extensions/extension_error_utils.h" | |
| 14 #include "chrome/common/extensions/extension_manifest_constants.h" | 13 #include "chrome/common/extensions/extension_manifest_constants.h" |
| 14 #include "extensions/common/error_utils.h" |
| 15 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
| 16 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
| 17 | 17 |
| 18 namespace errors = extension_manifest_errors; | 18 namespace errors = extension_manifest_errors; |
| 19 namespace keys = extension_manifest_keys; | 19 namespace keys = extension_manifest_keys; |
| 20 namespace values = extension_manifest_values; | 20 namespace values = extension_manifest_values; |
| 21 | 21 |
| 22 using extensions::ErrorUtils; |
| 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 static const char kMissing[] = "Missing"; | 26 static const char kMissing[] = "Missing"; |
| 25 | 27 |
| 26 static const char kCommandKeyNotSupported[] = | 28 static const char kCommandKeyNotSupported[] = |
| 27 "Command key is not supported. Note: Ctrl means Command on Mac"; | 29 "Command key is not supported. Note: Ctrl means Command on Mac"; |
| 28 | 30 |
| 29 | 31 |
| 30 ui::Accelerator ParseImpl(const std::string& accelerator, | 32 ui::Accelerator ParseImpl(const std::string& accelerator, |
| 31 const std::string& platform_key, | 33 const std::string& platform_key, |
| 32 int index, | 34 int index, |
| 33 string16* error) { | 35 string16* error) { |
| 34 if (platform_key != values::kKeybindingPlatformWin && | 36 if (platform_key != values::kKeybindingPlatformWin && |
| 35 platform_key != values::kKeybindingPlatformMac && | 37 platform_key != values::kKeybindingPlatformMac && |
| 36 platform_key != values::kKeybindingPlatformChromeOs && | 38 platform_key != values::kKeybindingPlatformChromeOs && |
| 37 platform_key != values::kKeybindingPlatformLinux && | 39 platform_key != values::kKeybindingPlatformLinux && |
| 38 platform_key != values::kKeybindingPlatformDefault) { | 40 platform_key != values::kKeybindingPlatformDefault) { |
| 39 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 41 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 40 errors::kInvalidKeyBindingUnknownPlatform, | 42 errors::kInvalidKeyBindingUnknownPlatform, |
| 41 base::IntToString(index), | 43 base::IntToString(index), |
| 42 platform_key); | 44 platform_key); |
| 43 return ui::Accelerator(); | 45 return ui::Accelerator(); |
| 44 } | 46 } |
| 45 | 47 |
| 46 std::vector<std::string> tokens; | 48 std::vector<std::string> tokens; |
| 47 base::SplitString(accelerator, '+', &tokens); | 49 base::SplitString(accelerator, '+', &tokens); |
| 48 if (tokens.size() < 2 || tokens.size() > 3) { | 50 if (tokens.size() < 2 || tokens.size() > 3) { |
| 49 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 51 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 50 errors::kInvalidKeyBinding, | 52 errors::kInvalidKeyBinding, |
| 51 base::IntToString(index), | 53 base::IntToString(index), |
| 52 platform_key, | 54 platform_key, |
| 53 accelerator); | 55 accelerator); |
| 54 return ui::Accelerator(); | 56 return ui::Accelerator(); |
| 55 } | 57 } |
| 56 | 58 |
| 57 // Now, parse it into an accelerator. | 59 // Now, parse it into an accelerator. |
| 58 int modifiers = ui::EF_NONE; | 60 int modifiers = ui::EF_NONE; |
| 59 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | 61 ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 } | 94 } |
| 93 if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { | 95 if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { |
| 94 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); | 96 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); |
| 95 } else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') { | 97 } else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') { |
| 96 key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); | 98 key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); |
| 97 } else { | 99 } else { |
| 98 key = ui::VKEY_UNKNOWN; | 100 key = ui::VKEY_UNKNOWN; |
| 99 break; | 101 break; |
| 100 } | 102 } |
| 101 } else { | 103 } else { |
| 102 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 104 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 103 errors::kInvalidKeyBinding, | 105 errors::kInvalidKeyBinding, |
| 104 base::IntToString(index), | 106 base::IntToString(index), |
| 105 platform_key, | 107 platform_key, |
| 106 accelerator); | 108 accelerator); |
| 107 return ui::Accelerator(); | 109 return ui::Accelerator(); |
| 108 } | 110 } |
| 109 } | 111 } |
| 110 bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; | 112 bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; |
| 111 bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; | 113 bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; |
| 112 bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; | 114 bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; |
| 113 bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; | 115 bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; |
| 114 | 116 |
| 115 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | 117 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not |
| 116 // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we | 118 // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we |
| 117 // don't support Ctrl+Alt+foo see this article: | 119 // don't support Ctrl+Alt+foo see this article: |
| 118 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | 120 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
| 119 // On Mac Command can also be used in combination with Shift or on its own, | 121 // On Mac Command can also be used in combination with Shift or on its own, |
| 120 // as a modifier. | 122 // as a modifier. |
| 121 if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || | 123 if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || |
| 122 (shift && !ctrl && !alt && !command)) { | 124 (shift && !ctrl && !alt && !command)) { |
| 123 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 125 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 124 errors::kInvalidKeyBinding, | 126 errors::kInvalidKeyBinding, |
| 125 base::IntToString(index), | 127 base::IntToString(index), |
| 126 platform_key, | 128 platform_key, |
| 127 accelerator); | 129 accelerator); |
| 128 return ui::Accelerator(); | 130 return ui::Accelerator(); |
| 129 } | 131 } |
| 130 | 132 |
| 131 return ui::Accelerator(key, modifiers); | 133 return ui::Accelerator(key, modifiers); |
| 132 } | 134 } |
| 133 | 135 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { | 217 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { |
| 216 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys(); | 218 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys(); |
| 217 for ( ; iter != suggested_key_dict->end_keys(); ++iter) { | 219 for ( ; iter != suggested_key_dict->end_keys(); ++iter) { |
| 218 // For each item in the dictionary, extract the platforms specified. | 220 // For each item in the dictionary, extract the platforms specified. |
| 219 std::string suggested_key_string; | 221 std::string suggested_key_string; |
| 220 if (suggested_key_dict->GetString(*iter, &suggested_key_string) && | 222 if (suggested_key_dict->GetString(*iter, &suggested_key_string) && |
| 221 !suggested_key_string.empty()) { | 223 !suggested_key_string.empty()) { |
| 222 // Found a platform, add it to the suggestions list. | 224 // Found a platform, add it to the suggestions list. |
| 223 suggestions[*iter] = suggested_key_string; | 225 suggestions[*iter] = suggested_key_string; |
| 224 } else { | 226 } else { |
| 225 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 227 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 226 errors::kInvalidKeyBinding, | 228 errors::kInvalidKeyBinding, |
| 227 base::IntToString(index), | 229 base::IntToString(index), |
| 228 keys::kSuggestedKey, | 230 keys::kSuggestedKey, |
| 229 kMissing); | 231 kMissing); |
| 230 return false; | 232 return false; |
| 231 } | 233 } |
| 232 } | 234 } |
| 233 } else { | 235 } else { |
| 234 // No dictionary was found, fall back to using just a string, so developers | 236 // No dictionary was found, fall back to using just a string, so developers |
| 235 // don't have to specify a dictionary if they just want to use one default | 237 // don't have to specify a dictionary if they just want to use one default |
| 236 // for all platforms. | 238 // for all platforms. |
| 237 std::string suggested_key_string; | 239 std::string suggested_key_string; |
| 238 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && | 240 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && |
| 239 !suggested_key_string.empty()) { | 241 !suggested_key_string.empty()) { |
| 240 // If only a single string is provided, it must be default for all. | 242 // If only a single string is provided, it must be default for all. |
| 241 suggestions["default"] = suggested_key_string; | 243 suggestions["default"] = suggested_key_string; |
| 242 } else { | 244 } else { |
| 243 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 245 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 244 errors::kInvalidKeyBinding, | 246 errors::kInvalidKeyBinding, |
| 245 base::IntToString(index), | 247 base::IntToString(index), |
| 246 keys::kSuggestedKey, | 248 keys::kSuggestedKey, |
| 247 kMissing); | 249 kMissing); |
| 248 return false; | 250 return false; |
| 249 } | 251 } |
| 250 } | 252 } |
| 251 | 253 |
| 252 // Normalize the suggestions. | 254 // Normalize the suggestions. |
| 253 for (SuggestionMap::iterator iter = suggestions.begin(); | 255 for (SuggestionMap::iterator iter = suggestions.begin(); |
| 254 iter != suggestions.end(); ++iter) { | 256 iter != suggestions.end(); ++iter) { |
| 255 // Before we normalize Ctrl to Command we must detect when the developer | 257 // Before we normalize Ctrl to Command we must detect when the developer |
| 256 // specified Command in the Default section, which will work on Mac after | 258 // specified Command in the Default section, which will work on Mac after |
| 257 // normalization but only fail on other platforms when they try it out on | 259 // normalization but only fail on other platforms when they try it out on |
| 258 // other platforms, which is not what we want. | 260 // other platforms, which is not what we want. |
| 259 if (iter->first == "default" && | 261 if (iter->first == "default" && |
| 260 iter->second.find("Command+") != std::string::npos) { | 262 iter->second.find("Command+") != std::string::npos) { |
| 261 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 263 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 262 errors::kInvalidKeyBinding, | 264 errors::kInvalidKeyBinding, |
| 263 base::IntToString(index), | 265 base::IntToString(index), |
| 264 keys::kSuggestedKey, | 266 keys::kSuggestedKey, |
| 265 kCommandKeyNotSupported); | 267 kCommandKeyNotSupported); |
| 266 return false; | 268 return false; |
| 267 } | 269 } |
| 268 | 270 |
| 269 suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, | 271 suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, |
| 270 iter->first); | 272 iter->first); |
| 271 } | 273 } |
| 272 | 274 |
| 273 std::string platform = CommandPlatform(); | 275 std::string platform = CommandPlatform(); |
| 274 std::string key = platform; | 276 std::string key = platform; |
| 275 if (suggestions.find(key) == suggestions.end()) | 277 if (suggestions.find(key) == suggestions.end()) |
| 276 key = values::kKeybindingPlatformDefault; | 278 key = values::kKeybindingPlatformDefault; |
| 277 if (suggestions.find(key) == suggestions.end()) { | 279 if (suggestions.find(key) == suggestions.end()) { |
| 278 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 280 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 279 errors::kInvalidKeyBindingMissingPlatform, | 281 errors::kInvalidKeyBindingMissingPlatform, |
| 280 base::IntToString(index), | 282 base::IntToString(index), |
| 281 keys::kSuggestedKey, | 283 keys::kSuggestedKey, |
| 282 platform); | 284 platform); |
| 283 return false; // No platform specified and no fallback. Bail. | 285 return false; // No platform specified and no fallback. Bail. |
| 284 } | 286 } |
| 285 | 287 |
| 286 // For developer convenience, we parse all the suggestions (and complain about | 288 // For developer convenience, we parse all the suggestions (and complain about |
| 287 // errors for platforms other than the current one) but use only what we need. | 289 // errors for platforms other than the current one) but use only what we need. |
| 288 std::map<const std::string, std::string>::const_iterator iter = | 290 std::map<const std::string, std::string>::const_iterator iter = |
| 289 suggestions.begin(); | 291 suggestions.begin(); |
| 290 for ( ; iter != suggestions.end(); ++iter) { | 292 for ( ; iter != suggestions.end(); ++iter) { |
| 291 // Note that we pass iter->first to pretend we are on a platform we're not | 293 // Note that we pass iter->first to pretend we are on a platform we're not |
| 292 // on. | 294 // on. |
| 293 ui::Accelerator accelerator = | 295 ui::Accelerator accelerator = |
| 294 ParseImpl(iter->second, iter->first, index, error); | 296 ParseImpl(iter->second, iter->first, index, error); |
| 295 if (accelerator.key_code() == ui::VKEY_UNKNOWN) { | 297 if (accelerator.key_code() == ui::VKEY_UNKNOWN) { |
| 296 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 298 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 297 errors::kInvalidKeyBinding, | 299 errors::kInvalidKeyBinding, |
| 298 base::IntToString(index), | 300 base::IntToString(index), |
| 299 iter->first, | 301 iter->first, |
| 300 iter->second); | 302 iter->second); |
| 301 return false; | 303 return false; |
| 302 } | 304 } |
| 303 | 305 |
| 304 if (iter->first == key) { | 306 if (iter->first == key) { |
| 305 // This platform is our platform, so grab this key. | 307 // This platform is our platform, so grab this key. |
| 306 accelerator_ = accelerator; | 308 accelerator_ = accelerator; |
| 307 command_name_ = command_name; | 309 command_name_ = command_name; |
| 308 | 310 |
| 309 if (command_name != | 311 if (command_name != |
| 310 extension_manifest_values::kPageActionCommandEvent && | 312 extension_manifest_values::kPageActionCommandEvent && |
| 311 command_name != | 313 command_name != |
| 312 extension_manifest_values::kBrowserActionCommandEvent && | 314 extension_manifest_values::kBrowserActionCommandEvent && |
| 313 command_name != | 315 command_name != |
| 314 extension_manifest_values::kScriptBadgeCommandEvent) { | 316 extension_manifest_values::kScriptBadgeCommandEvent) { |
| 315 if (!command->GetString(keys::kDescription, &description_) || | 317 if (!command->GetString(keys::kDescription, &description_) || |
| 316 description_.empty()) { | 318 description_.empty()) { |
| 317 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 319 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 318 errors::kInvalidKeyBindingDescription, | 320 errors::kInvalidKeyBindingDescription, |
| 319 base::IntToString(index)); | 321 base::IntToString(index)); |
| 320 return false; | 322 return false; |
| 321 } | 323 } |
| 322 } | 324 } |
| 323 } | 325 } |
| 324 } | 326 } |
| 325 return true; | 327 return true; |
| 326 } | 328 } |
| 327 | 329 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 341 extension_data->SetString("description", command_description); | 343 extension_data->SetString("description", command_description); |
| 342 extension_data->SetBoolean("active", active); | 344 extension_data->SetBoolean("active", active); |
| 343 extension_data->SetString("keybinding", accelerator().GetShortcutText()); | 345 extension_data->SetString("keybinding", accelerator().GetShortcutText()); |
| 344 extension_data->SetString("command_name", command_name()); | 346 extension_data->SetString("command_name", command_name()); |
| 345 extension_data->SetString("extension_id", extension->id()); | 347 extension_data->SetString("extension_id", extension->id()); |
| 346 | 348 |
| 347 return extension_data; | 349 return extension_data; |
| 348 } | 350 } |
| 349 | 351 |
| 350 } // namespace extensions | 352 } // namespace extensions |
| OLD | NEW |