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 |