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

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, 9 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 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 } 234 }
235 235
236 Extension::InputComponentInfo::~InputComponentInfo() {} 236 Extension::InputComponentInfo::~InputComponentInfo() {}
237 237
238 Extension::TtsVoice::TtsVoice() {} 238 Extension::TtsVoice::TtsVoice() {}
239 Extension::TtsVoice::~TtsVoice() {} 239 Extension::TtsVoice::~TtsVoice() {}
240 240
241 Extension::ExtensionKeybinding::ExtensionKeybinding() {} 241 Extension::ExtensionKeybinding::ExtensionKeybinding() {}
242 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} 242 Extension::ExtensionKeybinding::~ExtensionKeybinding() {}
243 243
244 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, 244 ui::Accelerator Extension::ExtensionKeybinding::ParseImpl(
245 const std::string& command_name, 245 const std::string& shortcut,
246 int index, 246 const std::string& platform_key,
247 string16* error) { 247 int index,
248 DCHECK(!command_name.empty()); 248 string16* error) {
249 std::string key_binding; 249 std::string shortcut_normalized = StringToLowerASCII(shortcut);
250 if (!command->GetString(keys::kKey, &key_binding) ||
251 key_binding.empty()) {
252 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
253 errors::kInvalidKeyBinding,
254 base::IntToString(index),
255 "Missing");
256 return false;
257 }
258
259 std::string original_keybinding = key_binding;
260 // Normalize '-' to '+'.
261 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+");
262 // Remove all spaces.
263 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", "");
264 // And finally, lower-case it.
265 key_binding = StringToLowerASCII(key_binding);
266 250
267 std::vector<std::string> tokens; 251 std::vector<std::string> tokens;
268 base::SplitString(key_binding, '+', &tokens); 252 base::SplitString(shortcut_normalized, '+', &tokens);
269 if (tokens.size() < 2 || tokens.size() > 3) { 253 if (tokens.size() < 2 || tokens.size() > 3) {
270 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 254 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
271 errors::kInvalidKeyBinding, 255 errors::kInvalidKeyBinding,
272 base::IntToString(index), 256 base::IntToString(index),
273 original_keybinding); 257 platform_key,
274 return false; 258 shortcut);
259 return ui::Accelerator();
275 } 260 }
276 261
277 // Now, parse it into an accelerator. 262 // Now, parse it into an accelerator.
278 bool ctrl = false; 263 bool ctrl = false;
279 bool alt = false; 264 bool alt = false;
280 bool shift = false; 265 bool shift = false;
266 bool command = false;
267 bool option = false;
281 ui::KeyboardCode key = ui::VKEY_UNKNOWN; 268 ui::KeyboardCode key = ui::VKEY_UNKNOWN;
282 for (size_t i = 0; i < tokens.size(); i++) { 269 for (size_t i = 0; i < tokens.size(); i++) {
283 if (tokens[i] == "ctrl") { 270 if (tokens[i] == "ctrl") {
284 ctrl = true; 271 ctrl = true;
285 } else if (tokens[i] == "alt") { 272 } else if (tokens[i] == "alt") {
286 alt = true; 273 alt = true;
287 } else if (tokens[i] == "shift") { 274 } else if (tokens[i] == "shift") {
288 shift = true; 275 shift = true;
276 } else if (tokens[i] == "command" && platform_key == "mac") {
277 command = true;
278 } else if (tokens[i] == "option" && platform_key == "mac") {
279 option = true;
289 } else if (tokens[i].size() == 1 && 280 } else if (tokens[i].size() == 1 &&
290 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { 281 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') {
291 if (key != ui::VKEY_UNKNOWN) { 282 if (key != ui::VKEY_UNKNOWN) {
292 // Multiple key assignments. 283 // Multiple key assignments.
293 key = ui::VKEY_UNKNOWN; 284 key = ui::VKEY_UNKNOWN;
294 break; 285 break;
295 } 286 }
296 287
297 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); 288 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a'));
298 } else { 289 } else {
299 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 290 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
300 errors::kInvalidKeyBinding, 291 errors::kInvalidKeyBinding,
301 base::IntToString(index), 292 base::IntToString(index),
302 original_keybinding); 293 platform_key,
303 return false; 294 shortcut);
295 return ui::Accelerator();
304 } 296 }
305 } 297 }
306 298
307 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 299 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not
308 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: 300 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo:
309 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 301 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx.
310 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { 302 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) {
311 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 303 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
312 errors::kInvalidKeyBinding, 304 errors::kInvalidKeyBinding,
313 base::IntToString(index), 305 base::IntToString(index),
314 original_keybinding); 306 platform_key,
315 return false; 307 shortcut);
308 return ui::Accelerator();
316 } 309 }
317 310
318 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); 311 return ui::Accelerator(key, shift, ctrl, alt);
312 }
319 313
320 if (command_name != 314 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command,
321 extension_manifest_values::kPageActionKeybindingEvent && 315 const std::string& command_name,
322 command_name != 316 int index,
323 extension_manifest_values::kBrowserActionKeybindingEvent) { 317 string16* error) {
324 if (!command->GetString(keys::kDescription, &description_) || 318 DCHECK(!command_name.empty());
325 description_.empty()) { 319
320 // We'll build up a map of platform-to-shortcut suggestions.
321 std::map<const std::string, std::string> suggestions;
322
323 // First try to parse the |commands| section as a dictionary.
324 DictionaryValue* suggested_key_dict;
325 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) {
326 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys();
327 for ( ; iter != suggested_key_dict->end_keys(); ++iter) {
328 // For each item in the dictionary, extract the platforms specified.
329 std::string suggested_key_string;
330 if (suggested_key_dict->GetString(*iter, &suggested_key_string) &&
331 !suggested_key_string.empty()) {
332 // Found a platform, add it to the suggestions list.
333 suggestions[StringToLowerASCII(*iter)] = suggested_key_string;
334 } else {
335 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
336 errors::kInvalidKeyBinding,
337 base::IntToString(index),
338 keys::kSuggestedKey,
339 "Missing");
340 return false;
341 }
342 }
343 } else {
344 // No dictionary was found, fall back to using just a string, so developers
345 // don't have to specify a dictionary if they just want to use one default
346 // for all platforms.
347 std::string suggested_key_string;
348 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) &&
349 !suggested_key_string.empty()) {
350 // If only a signle string is provided, it must be default for all.
351 suggestions["default"] = suggested_key_string;
352 } else {
326 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 353 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
327 errors::kInvalidKeyBindingDescription, 354 errors::kInvalidKeyBinding,
328 base::IntToString(index)); 355 base::IntToString(index),
329 return false; 356 keys::kSuggestedKey,
357 "Missing");
358 return false;
330 } 359 }
331 } 360 }
332 361
333 command_name_ = command_name; 362 std::string platform =
363 #if defined(OS_WIN)
364 values::kKeybindingPlatformWin;
365 #elif defined(OS_MACOSX)
366 values::kKeybindingPlatformMac;
367 #elif defined(OS_CHROMEOS)
368 values::kKeybindingPlatformChromeOs;
369 #elif defined(OS_LINUX)
370 values::kKeybindingPlatformLinux;
371 #else
372 "";
373 #endif
374
375 std::string key = platform;
376 if (suggestions.find(key) == suggestions.end())
377 key = "default";
378 if (suggestions.find(key) == suggestions.end()) {
379 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
380 errors::kInvalidKeyBindingMissingPlatform,
381 base::IntToString(index),
382 keys::kSuggestedKey,
383 platform);
384 return false; // No platform specified and no fallback. Bail.
385 }
386
387 // For developer convenience, we parse all the suggestions (and complain about
388 // errors for platforms other than the current one) but use only what we need.
389 std::map<const std::string, std::string>::const_iterator iter =
390 suggestions.begin();
391 for ( ; iter != suggestions.end(); ++iter) {
392 // Note that we pass iter->first to pretend we are on a platform we're not
393 // on.
394 ui::Accelerator accelerator =
395 ParseImpl(iter->second, iter->first, index, error);
396 if (accelerator.key_code() == ui::VKEY_UNKNOWN) {
397 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
398 errors::kInvalidKeyBinding,
399 base::IntToString(index),
400 iter->first,
401 iter->second);
402 return false;
403 }
404
405 if (iter->first == key) {
406 // This platform is our platform, so grab this key.
407 accelerator_ = accelerator;
408 command_name_ = command_name;
409
410 if (command_name !=
411 extension_manifest_values::kPageActionKeybindingEvent &&
412 command_name !=
413 extension_manifest_values::kBrowserActionKeybindingEvent) {
414 if (!command->GetString(keys::kDescription, &description_) ||
415 description_.empty()) {
416 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
417 errors::kInvalidKeyBindingDescription,
418 base::IntToString(index));
419 return false;
420 }
421 }
422 }
423 }
334 return true; 424 return true;
335 } 425 }
336 426
337 // 427 //
338 // Extension 428 // Extension
339 // 429 //
340 430
341 // static 431 // static
342 scoped_refptr<Extension> Extension::Create(const FilePath& path, 432 scoped_refptr<Extension> Extension::Create(const FilePath& path,
343 Location location, 433 Location location,
(...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after
1481 ++command_index; 1571 ++command_index;
1482 1572
1483 DictionaryValue* command = NULL; 1573 DictionaryValue* command = NULL;
1484 if (!commands->GetDictionary(*iter, &command)) { 1574 if (!commands->GetDictionary(*iter, &command)) {
1485 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1575 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1486 errors::kInvalidKeyBindingDictionary, 1576 errors::kInvalidKeyBindingDictionary,
1487 base::IntToString(command_index)); 1577 base::IntToString(command_index));
1488 return false; 1578 return false;
1489 } 1579 }
1490 1580
1491 ExtensionKeybinding binding; 1581 scoped_ptr<Extension::ExtensionKeybinding> binding(
1492 if (!binding.Parse(command, *iter, command_index, error)) 1582 new ExtensionKeybinding());
1583 if (!binding->Parse(command, *iter, command_index, error))
1493 return false; // |error| already set. 1584 return false; // |error| already set.
1494 1585
1495 commands_.push_back(binding); 1586 std::string command_name = binding->command_name();
1587 if (command_name == values::kPageActionKeybindingEvent)
1588 page_action_command_.reset(binding.release());
1589 else if (command_name == values::kBrowserActionKeybindingEvent)
1590 browser_action_command_.reset(binding.release());
1591 else
1592 named_commands_[command_name] = *binding.release();
1496 } 1593 }
1497 } 1594 }
1498 return true; 1595 return true;
1499 } 1596 }
1500 1597
1501 bool Extension::LoadPlugins(string16* error) { 1598 bool Extension::LoadPlugins(string16* error) {
1502 if (!manifest_->HasKey(keys::kPlugins)) 1599 if (!manifest_->HasKey(keys::kPlugins))
1503 return true; 1600 return true;
1504 ListValue* list_value = NULL; 1601 ListValue* list_value = NULL;
1505 if (!manifest_->GetList(keys::kPlugins, &list_value)) { 1602 if (!manifest_->GetList(keys::kPlugins, &list_value)) {
(...skipping 1992 matching lines...) Expand 10 before | Expand all | Expand 10 after
3498 already_disabled(false), 3595 already_disabled(false),
3499 extension(extension) {} 3596 extension(extension) {}
3500 3597
3501 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3598 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
3502 const Extension* extension, 3599 const Extension* extension,
3503 const ExtensionPermissionSet* permissions, 3600 const ExtensionPermissionSet* permissions,
3504 Reason reason) 3601 Reason reason)
3505 : reason(reason), 3602 : reason(reason),
3506 extension(extension), 3603 extension(extension),
3507 permissions(permissions) {} 3604 permissions(permissions) {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698