command.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/command.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_manifest_constants.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace errors = extension_manifest_errors; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace keys = extension_manifest_keys; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace values = extension_manifest_values; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::ErrorUtils; 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kMissing[] = "Missing"; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kCommandKeyNotSupported[] = 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Command key is not supported. Note: Ctrl means Command on Mac"; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator ParseImpl(const std::string& accelerator, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform_key, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* error) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform_key != values::kKeybindingPlatformWin && 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformMac && 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformChromeOs && 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformLinux && 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformDefault) { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingUnknownPlatform, 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(accelerator, '+', &tokens); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tokens.size() < 2 || tokens.size() > 3) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, parse it into an accelerator. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int modifiers = ui::EF_NONE; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::KeyboardCode key = ui::VKEY_UNKNOWN; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tokens[i] == "Ctrl") { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_CONTROL_DOWN; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tokens[i] == "Command") { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform_key == "mac") { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either the developer specified Command+foo in the manifest for Mac or 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they specified Ctrl and it got normalized to Command (to get Ctrl on 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac the developer has to specify MacCtrl). Therefore we treat this 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as Command. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (platform_key == "default") { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we see "Command+foo" in the Default section it can mean two 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // things, depending on the platform: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The developer specified "Ctrl+foo" for Default and it got normalized 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on Mac to "Command+foo". This is fine. Treat it as Command. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No other platform supports Command. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tokens[i] == "Alt") { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_ALT_DOWN; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tokens[i] == "Shift") { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_SHIFT_DOWN; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tokens[i].size() == 1) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key != ui::VKEY_UNKNOWN) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple key assignments. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't support Ctrl+Alt+foo see this article: 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On Mac Command can also be used in combination with Shift or on its own, 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a modifier. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (shift && !ctrl && !alt && !command)) { 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(key, modifiers); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// platforms leave the shortcut untouched. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NormalizeShortcutSuggestion(const std::string& suggestion, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool normalize = false; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform == "mac") { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (platform == "default") { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!normalize) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return suggestion; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(suggestion, '+', &tokens); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tokens[i] == "Ctrl") 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tokens[i] = "Command"; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (tokens[i] == "MacCtrl") 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tokens[i] = "Ctrl"; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JoinString(tokens, '+'); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::Command() {} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::Command(const std::string& command_name, 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& description, 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& accelerator) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : command_name_(command_name), 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) description_(description) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 error; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, &error); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::~Command() {} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Command::CommandPlatform() { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformWin; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformMac; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_CHROMEOS) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformChromeOs; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformLinux; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator Command::StringToAccelerator(const std::string& accelerator) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 error; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Command command; 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator parsed = 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseImpl(accelerator, Command::CommandPlatform(), 0, &error); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Command::Parse(const DictionaryValue* command, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name, 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* error) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!command_name.empty()); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 description; 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (command_name != values::kPageActionCommandEvent && 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) command_name != values::kBrowserActionCommandEvent && 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) command_name != values::kScriptBadgeCommandEvent) { 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!command->GetString(keys::kDescription, &description) || 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description.empty()) { 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kInvalidKeyBindingDescription, 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::IntToString(index)); 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We'll build up a map of platform-to-shortcut suggestions. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<const std::string, std::string> SuggestionMap; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SuggestionMap suggestions; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First try to parse the |suggested_key| as a dictionary. 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const DictionaryValue* suggested_key_dict; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (DictionaryValue::Iterator iter(*suggested_key_dict); !iter.IsAtEnd(); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iter.Advance()) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For each item in the dictionary, extract the platforms specified. 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iter.value().GetAsString(&suggested_key_string) && 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found a platform, add it to the suggestions list. 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) suggestions[iter.key()] = suggested_key_string; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMissing); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No dictionary was found, fall back to using just a string, so developers 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't have to specify a dictionary if they just want to use one default 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for all platforms. 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If only a single string is provided, it must be default for all. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions["default"] = suggested_key_string; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) suggestions["default"] = ""; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normalize the suggestions. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SuggestionMap::iterator iter = suggestions.begin(); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != suggestions.end(); ++iter) { 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we normalize Ctrl to Command we must detect when the developer 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specified Command in the Default section, which will work on Mac after 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // normalization but only fail on other platforms when they try it out on 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other platforms, which is not what we want. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter->first == "default" && 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->second.find("Command+") != std::string::npos) { 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCommandKeyNotSupported); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->first); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string platform = CommandPlatform(); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = platform; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = values::kKeybindingPlatformDefault; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) { 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingMissingPlatform, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // No platform specified and no fallback. Bail. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For developer convenience, we parse all the suggestions (and complain about 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors for platforms other than the current one) but use only what we need. 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<const std::string, std::string>::const_iterator iter = 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions.begin(); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; iter != suggestions.end(); ++iter) { 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::Accelerator accelerator; 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!iter->second.empty()) { 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note that we pass iter->first to pretend we are on a platform we're not 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on. 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) accelerator = ParseImpl(iter->second, iter->first, index, error); 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (accelerator.key_code() == ui::VKEY_UNKNOWN) { 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kInvalidKeyBinding, 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::IntToString(index), 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter->first, 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) iter->second); 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter->first == key) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This platform is our platform, so grab this key. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator_ = accelerator; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name_ = command_name; 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description_ = description; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DictionaryValue* Command::ToValue(const Extension* extension, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool active) const { 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DictionaryValue* extension_data = new DictionaryValue(); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 command_description; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_name() == values::kBrowserActionCommandEvent || 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name() == values::kPageActionCommandEvent || 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name() == values::kScriptBadgeCommandEvent) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = description(); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("description", command_description); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetBoolean("active", active); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("keybinding", accelerator().GetShortcutText()); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("command_name", command_name()); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("extension_id", extension->id()); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extension_data; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 349