Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(649)

Side by Side Diff: chrome/common/extensions/extension.cc

Issue 9812008: Polish the keybinding implementation a bit. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/extension.h" 5 #include "chrome/common/extensions/extension.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 237
238 Extension::TtsVoice::TtsVoice() {} 238 Extension::TtsVoice::TtsVoice() {}
239 Extension::TtsVoice::~TtsVoice() {} 239 Extension::TtsVoice::~TtsVoice() {}
240 240
241 Extension::OAuth2Info::OAuth2Info() {} 241 Extension::OAuth2Info::OAuth2Info() {}
242 Extension::OAuth2Info::~OAuth2Info() {} 242 Extension::OAuth2Info::~OAuth2Info() {}
243 243
244 Extension::ExtensionKeybinding::ExtensionKeybinding() {} 244 Extension::ExtensionKeybinding::ExtensionKeybinding() {}
245 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} 245 Extension::ExtensionKeybinding::~ExtensionKeybinding() {}
246 246
247 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, 247 ui::Accelerator Extension::ExtensionKeybinding::ParseImpl(
248 const std::string& command_name, 248 const std::string& shortcut,
249 int index, 249 const std::string& platform_key,
250 string16* error) { 250 int index,
251 DCHECK(!command_name.empty()); 251 string16* error) {
252 std::string key_binding; 252 if (platform_key != values::kKeybindingPlatformWin &&
253 if (!command->GetString(keys::kKey, &key_binding) || 253 platform_key != values::kKeybindingPlatformMac &&
254 key_binding.empty()) { 254 platform_key != values::kKeybindingPlatformChromeOs &&
255 platform_key != values::kKeybindingPlatformLinux &&
256 platform_key != values::kKeybindingPlatformDefault) {
255 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 257 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
256 errors::kInvalidKeyBinding, 258 errors::kInvalidKeyBindingUnknownPlatform,
257 base::IntToString(index), 259 base::IntToString(index),
258 "Missing"); 260 platform_key);
259 return false; 261 return ui::Accelerator();
260 } 262 }
261 263
262 std::string original_keybinding = key_binding;
263 // Normalize '-' to '+'.
264 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+");
265 // Remove all spaces.
266 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", "");
267 // And finally, lower-case it.
268 key_binding = StringToLowerASCII(key_binding);
269
270 std::vector<std::string> tokens; 264 std::vector<std::string> tokens;
271 base::SplitString(key_binding, '+', &tokens); 265 base::SplitString(shortcut, '+', &tokens);
272 if (tokens.size() < 2 || tokens.size() > 3) { 266 if (tokens.size() < 2 || tokens.size() > 3) {
273 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 267 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
274 errors::kInvalidKeyBinding, 268 errors::kInvalidKeyBinding,
275 base::IntToString(index), 269 base::IntToString(index),
276 original_keybinding); 270 platform_key,
277 return false; 271 shortcut);
272 return ui::Accelerator();
278 } 273 }
279 274
280 // Now, parse it into an accelerator. 275 // Now, parse it into an accelerator.
281 bool ctrl = false; 276 bool ctrl = false;
282 bool alt = false; 277 bool alt = false;
283 bool shift = false; 278 bool shift = false;
284 ui::KeyboardCode key = ui::VKEY_UNKNOWN; 279 ui::KeyboardCode key = ui::VKEY_UNKNOWN;
285 for (size_t i = 0; i < tokens.size(); i++) { 280 for (size_t i = 0; i < tokens.size(); i++) {
286 if (tokens[i] == "ctrl") { 281 if (tokens[i] == "Ctrl") {
287 ctrl = true; 282 ctrl = true;
288 } else if (tokens[i] == "alt") { 283 } else if (tokens[i] == "Alt") {
289 alt = true; 284 alt = true;
290 } else if (tokens[i] == "shift") { 285 } else if (tokens[i] == "Shift") {
291 shift = true; 286 shift = true;
287 } else if (tokens[i] == "Command" && platform_key == "mac") {
288 // TODO(finnur): Implement for Mac.
289 } else if (tokens[i] == "Option" && platform_key == "mac") {
290 // TODO(finnur): Implement for Mac.
292 } else if (tokens[i].size() == 1 && 291 } else if (tokens[i].size() == 1 &&
293 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { 292 tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
294 if (key != ui::VKEY_UNKNOWN) { 293 if (key != ui::VKEY_UNKNOWN) {
295 // Multiple key assignments. 294 // Multiple key assignments.
296 key = ui::VKEY_UNKNOWN; 295 key = ui::VKEY_UNKNOWN;
297 break; 296 break;
298 } 297 }
299 298
300 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); 299 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
301 } else { 300 } else {
302 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 301 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
303 errors::kInvalidKeyBinding, 302 errors::kInvalidKeyBinding,
304 base::IntToString(index), 303 base::IntToString(index),
305 original_keybinding); 304 platform_key,
306 return false; 305 shortcut);
306 return ui::Accelerator();
307 } 307 }
308 } 308 }
309 309
310 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 310 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not
311 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: 311 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo:
312 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 312 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx.
313 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { 313 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) {
314 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 314 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
315 errors::kInvalidKeyBinding, 315 errors::kInvalidKeyBinding,
316 base::IntToString(index), 316 base::IntToString(index),
317 original_keybinding); 317 platform_key,
318 return false; 318 shortcut);
319 return ui::Accelerator();
319 } 320 }
320 321
321 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); 322 return ui::Accelerator(key, shift, ctrl, alt);
323 }
322 324
323 if (command_name != 325 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command,
324 extension_manifest_values::kPageActionKeybindingEvent && 326 const std::string& command_name,
325 command_name != 327 int index,
326 extension_manifest_values::kBrowserActionKeybindingEvent) { 328 string16* error) {
327 if (!command->GetString(keys::kDescription, &description_) || 329 DCHECK(!command_name.empty());
328 description_.empty()) { 330
331 // We'll build up a map of platform-to-shortcut suggestions.
332 std::map<const std::string, std::string> suggestions;
333
334 // First try to parse the |suggested_key| as a dictionary.
335 DictionaryValue* suggested_key_dict;
336 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) {
337 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys();
338 for ( ; iter != suggested_key_dict->end_keys(); ++iter) {
339 // For each item in the dictionary, extract the platforms specified.
340 std::string suggested_key_string;
341 if (suggested_key_dict->GetString(*iter, &suggested_key_string) &&
342 !suggested_key_string.empty()) {
343 // Found a platform, add it to the suggestions list.
344 suggestions[*iter] = suggested_key_string;
345 } else {
346 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
347 errors::kInvalidKeyBinding,
348 base::IntToString(index),
349 keys::kSuggestedKey,
350 "Missing");
351 return false;
352 }
353 }
354 } else {
355 // No dictionary was found, fall back to using just a string, so developers
356 // don't have to specify a dictionary if they just want to use one default
357 // for all platforms.
358 std::string suggested_key_string;
359 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) &&
360 !suggested_key_string.empty()) {
361 // If only a signle string is provided, it must be default for all.
362 suggestions["default"] = suggested_key_string;
363 } else {
329 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 364 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
330 errors::kInvalidKeyBindingDescription, 365 errors::kInvalidKeyBinding,
331 base::IntToString(index)); 366 base::IntToString(index),
332 return false; 367 keys::kSuggestedKey,
368 "Missing");
369 return false;
333 } 370 }
334 } 371 }
335 372
336 command_name_ = command_name; 373 std::string platform =
374 #if defined(OS_WIN)
375 values::kKeybindingPlatformWin;
376 #elif defined(OS_MACOSX)
377 values::kKeybindingPlatformMac;
378 #elif defined(OS_CHROMEOS)
379 values::kKeybindingPlatformChromeOs;
380 #elif defined(OS_LINUX)
381 values::kKeybindingPlatformLinux;
382 #else
383 "";
384 #endif
385
386 std::string key = platform;
387 if (suggestions.find(key) == suggestions.end())
388 key = values::kKeybindingPlatformDefault;
389 if (suggestions.find(key) == suggestions.end()) {
390 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
391 errors::kInvalidKeyBindingMissingPlatform,
392 base::IntToString(index),
393 keys::kSuggestedKey,
394 platform);
395 return false; // No platform specified and no fallback. Bail.
396 }
397
398 // For developer convenience, we parse all the suggestions (and complain about
399 // errors for platforms other than the current one) but use only what we need.
400 std::map<const std::string, std::string>::const_iterator iter =
401 suggestions.begin();
402 for ( ; iter != suggestions.end(); ++iter) {
403 // Note that we pass iter->first to pretend we are on a platform we're not
404 // on.
405 ui::Accelerator accelerator =
406 ParseImpl(iter->second, iter->first, index, error);
407 if (accelerator.key_code() == ui::VKEY_UNKNOWN) {
408 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
409 errors::kInvalidKeyBinding,
410 base::IntToString(index),
411 iter->first,
412 iter->second);
413 return false;
414 }
415
416 if (iter->first == key) {
417 // This platform is our platform, so grab this key.
418 accelerator_ = accelerator;
419 command_name_ = command_name;
420
421 if (command_name !=
422 extension_manifest_values::kPageActionKeybindingEvent &&
423 command_name !=
424 extension_manifest_values::kBrowserActionKeybindingEvent) {
425 if (!command->GetString(keys::kDescription, &description_) ||
426 description_.empty()) {
427 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
428 errors::kInvalidKeyBindingDescription,
429 base::IntToString(index));
430 return false;
431 }
432 }
433 }
434 }
337 return true; 435 return true;
338 } 436 }
339 437
340 // 438 //
341 // Extension 439 // Extension
342 // 440 //
343 441
344 // static 442 // static
345 scoped_refptr<Extension> Extension::Create(const FilePath& path, 443 scoped_refptr<Extension> Extension::Create(const FilePath& path,
346 Location location, 444 Location location,
(...skipping 1172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1519 ++command_index; 1617 ++command_index;
1520 1618
1521 DictionaryValue* command = NULL; 1619 DictionaryValue* command = NULL;
1522 if (!commands->GetDictionary(*iter, &command)) { 1620 if (!commands->GetDictionary(*iter, &command)) {
1523 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1621 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1524 errors::kInvalidKeyBindingDictionary, 1622 errors::kInvalidKeyBindingDictionary,
1525 base::IntToString(command_index)); 1623 base::IntToString(command_index));
1526 return false; 1624 return false;
1527 } 1625 }
1528 1626
1529 ExtensionKeybinding binding; 1627 scoped_ptr<Extension::ExtensionKeybinding> binding(
1530 if (!binding.Parse(command, *iter, command_index, error)) 1628 new ExtensionKeybinding());
1629 if (!binding->Parse(command, *iter, command_index, error))
1531 return false; // |error| already set. 1630 return false; // |error| already set.
1532 1631
1533 commands_.push_back(binding); 1632 std::string command_name = binding->command_name();
1633 if (command_name == values::kPageActionKeybindingEvent) {
1634 page_action_command_.reset(binding.release());
1635 } else if (command_name == values::kBrowserActionKeybindingEvent) {
1636 browser_action_command_.reset(binding.release());
1637 } else {
1638 if (command_name[0] != '_') // All commands w/underscore are reserved.
1639 named_commands_[command_name] = *binding.release();
1640 }
1534 } 1641 }
1535 } 1642 }
1536 return true; 1643 return true;
1537 } 1644 }
1538 1645
1539 bool Extension::LoadPlugins(string16* error) { 1646 bool Extension::LoadPlugins(string16* error) {
1540 if (!manifest_->HasKey(keys::kPlugins)) 1647 if (!manifest_->HasKey(keys::kPlugins))
1541 return true; 1648 return true;
1542 ListValue* list_value = NULL; 1649 ListValue* list_value = NULL;
1543 if (!manifest_->GetList(keys::kPlugins, &list_value)) { 1650 if (!manifest_->GetList(keys::kPlugins, &list_value)) {
(...skipping 2018 matching lines...) Expand 10 before | Expand all | Expand 10 after
3562 already_disabled(false), 3669 already_disabled(false),
3563 extension(extension) {} 3670 extension(extension) {}
3564 3671
3565 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3672 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
3566 const Extension* extension, 3673 const Extension* extension,
3567 const ExtensionPermissionSet* permissions, 3674 const ExtensionPermissionSet* permissions,
3568 Reason reason) 3675 Reason reason)
3569 : reason(reason), 3676 : reason(reason),
3570 extension(extension), 3677 extension(extension),
3571 permissions(permissions) {} 3678 permissions(permissions) {}
OLDNEW
« no previous file with comments | « chrome/common/extensions/extension.h ('k') | chrome/common/extensions/extension_manifest_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698