command.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h" 14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace extensions { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace errors = manifest_errors; 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace keys = manifest_keys; 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace values = manifest_values; 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) 3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool IsNamedCommand(const std::string& command_name) { 3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return command_name != values::kPageActionCommandEvent && 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) command_name != values::kBrowserActionCommandEvent && 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) command_name != values::kScriptBadgeCommandEvent; 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DoesRequireModifier(const std::string& accelerator) { 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return accelerator != values::kKeyMediaNextTrack && 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPlayPause && 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPrevTrack && 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaStop; 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator ParseImpl(const std::string& accelerator, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform_key, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool should_parse_media_keys, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* error) { 4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) error->clear(); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform_key != values::kKeybindingPlatformWin && 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformMac && 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformChromeOs && 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformLinux && 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformDefault) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingUnknownPlatform, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(accelerator, '+', &tokens); 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (tokens.size() == 0 || 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (tokens.size() == 1 && DoesRequireModifier(accelerator)) || 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens.size() > 3) { 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, parse it into an accelerator. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int modifiers = ui::EF_NONE; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::KeyboardCode key = ui::VKEY_UNKNOWN; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_CONTROL_DOWN; 81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyCommand) { 82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform_key == values::kKeybindingPlatformMac) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either the developer specified Command+foo in the manifest for Mac or 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they specified Ctrl and it got normalized to Command (to get Ctrl on 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac the developer has to specify MacCtrl). Therefore we treat this 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as Command. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform_key == values::kKeybindingPlatformDefault) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we see "Command+foo" in the Default section it can mean two 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // things, depending on the platform: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The developer specified "Ctrl+foo" for Default and it got normalized 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on Mac to "Command+foo". This is fine. Treat it as Command. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No other platform supports Command. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyAlt) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_ALT_DOWN; 103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyShift) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_SHIFT_DOWN; 105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 || // A-Z, 0-9. 106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyComma || 107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPeriod || 108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyUp || 109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDown || 110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyLeft || 111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyRight || 112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyIns || 113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDel || 114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyHome || 115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyEnd || 116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgUp || 117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgDwn || 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyTab || 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaNextTrack || 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPlayPause || 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPrevTrack || 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaStop) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key != ui::VKEY_UNKNOWN) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple key assignments. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyComma) { 130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_COMMA; 131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPeriod) { 132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_PERIOD; 133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyUp) { 134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_UP; 135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDown) { 136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DOWN; 137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyLeft) { 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_LEFT; 139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyRight) { 140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_RIGHT; 141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyIns) { 142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_INSERT; 143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDel) { 144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DELETE; 145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyHome) { 146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_HOME; 147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyEnd) { 148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_END; 149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgUp) { 150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_PRIOR; 151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgDwn) { 152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_NEXT; 153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyTab) { 154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_TAB; 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaNextTrack && 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_NEXT_TRACK; 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPlayPause && 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PLAY_PAUSE; 16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPrevTrack && 16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PREV_TRACK; 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaStop && 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_STOP; 167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); 170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= '0' && tokens[i][0] <= '9') { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't support Ctrl+Alt+foo see this article: 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On Mac Command can also be used in combination with Shift or on its own, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a modifier. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (shift && !ctrl && !alt && !command)) { 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if ((key == ui::VKEY_MEDIA_NEXT_TRACK || 20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PREV_TRACK || 21058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PLAY_PAUSE || 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_STOP) && 21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (shift || ctrl || alt || command)) { 21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBindingMediaKeyWithModifier, 21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) platform_key, 21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator); 21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return ui::Accelerator(); 21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(key, modifiers); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// platforms leave the shortcut untouched. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NormalizeShortcutSuggestion(const std::string& suggestion, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool normalize = false; 229a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform == values::kKeybindingPlatformMac) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform == values::kKeybindingPlatformDefault) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!normalize) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return suggestion; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(suggestion, '+', &tokens); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) 244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCommand; 245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (tokens[i] == values::kKeyMacCtrl) 246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCtrl; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JoinString(tokens, '+'); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Command::Command() : global_(false) {} 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::Command(const std::string& command_name, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& description, 2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& accelerator, 2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : command_name_(command_name), 2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) description_(description), 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_(global) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 error; 26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, 26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::~Command() {} 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Command::CommandPlatform() { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformWin; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformMac; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_CHROMEOS) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformChromeOs; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformLinux; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)ui::Accelerator Command::StringToAccelerator(const std::string& accelerator, 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& command_name) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 error; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator parsed = 28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ParseImpl(accelerator, Command::CommandPlatform(), 0, 29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 294a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static 295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) { 296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::string shortcut; 297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 298a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Ctrl and Alt are mutually exclusive. 299a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCtrlDown()) 300a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCtrl; 301a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (accelerator.IsAltDown()) 302a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyAlt; 303a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!shortcut.empty()) 304a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCmdDown()) { 307a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCommand; 308a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 310a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsShiftDown()) { 312a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyShift; 313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 314a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 315a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 316a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.key_code() >= ui::VKEY_0 && 317a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_9) { 318a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += '0' + (accelerator.key_code() - ui::VKEY_0); 319a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (accelerator.key_code() >= ui::VKEY_A && 320a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_Z) { 321a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += 'A' + (accelerator.key_code() - ui::VKEY_A); 322a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 323a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) switch (accelerator.key_code()) { 324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_COMMA: 325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyComma; 326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_PERIOD: 328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPeriod; 329a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 330a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_UP: 331a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyUp; 332a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 333a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DOWN: 334a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDown; 335a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 336a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_LEFT: 337a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyLeft; 338a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 339a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_RIGHT: 340a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyRight; 341a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 342a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_INSERT: 343a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyIns; 344a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 345a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DELETE: 346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDel; 347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 348a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_HOME: 349a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyHome; 350a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 351a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_END: 352a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyEnd; 353a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 354a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_PRIOR: 355a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgUp; 356a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 357a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_NEXT: 358a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgDwn; 359a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 360a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_TAB: 361a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyTab; 362a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 36358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_NEXT_TRACK: 36458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaNextTrack; 36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PLAY_PAUSE: 36758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPlayPause; 36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 36958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PREV_TRACK: 37058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPrevTrack; 37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_STOP: 37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaStop; 37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 375a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) default: 376a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return ""; 377a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 378a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 379a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return shortcut; 380a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 381a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Command::Parse(const base::DictionaryValue* command, 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name, 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16* error) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!command_name.empty()); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 description; 38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (IsNamedCommand(command_name)) { 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!command->GetString(keys::kDescription, &description) || 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description.empty()) { 392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kInvalidKeyBindingDescription, 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::IntToString(index)); 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We'll build up a map of platform-to-shortcut suggestions. 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<const std::string, std::string> SuggestionMap; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SuggestionMap suggestions; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First try to parse the |suggested_key| as a dictionary. 4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::DictionaryValue* suggested_key_dict; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { 4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for (base::DictionaryValue::Iterator iter(*suggested_key_dict); 4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) !iter.IsAtEnd(); iter.Advance()) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For each item in the dictionary, extract the platforms specified. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iter.value().GetAsString(&suggested_key_string) && 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found a platform, add it to the suggestions list. 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) suggestions[iter.key()] = suggested_key_string; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMissing); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No dictionary was found, fall back to using just a string, so developers 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't have to specify a dictionary if they just want to use one default 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for all platforms. 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If only a single string is provided, it must be default for all. 431a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = suggested_key_string; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 433a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = ""; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Check if this is a global or a regular shortcut. 4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global = false; 4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) command->GetBoolean(keys::kGlobal, &global); 4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normalize the suggestions. 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SuggestionMap::iterator iter = suggestions.begin(); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != suggestions.end(); ++iter) { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we normalize Ctrl to Command we must detect when the developer 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specified Command in the Default section, which will work on Mac after 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // normalization but only fail on other platforms when they try it out on 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other platforms, which is not what we want. 448a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (iter->first == values::kKeybindingPlatformDefault && 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->second.find("Command+") != std::string::npos) { 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCommandKeyNotSupported); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->first); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string platform = CommandPlatform(); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = platform; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = values::kKeybindingPlatformDefault; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) { 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingMissingPlatform, 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // No platform specified and no fallback. Bail. 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For developer convenience, we parse all the suggestions (and complain about 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors for platforms other than the current one) but use only what we need. 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<const std::string, std::string>::const_iterator iter = 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions.begin(); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; iter != suggestions.end(); ++iter) { 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::Accelerator accelerator; 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!iter->second.empty()) { 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note that we pass iter->first to pretend we are on a platform we're not 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on. 48458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator = ParseImpl(iter->second, iter->first, index, 48558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), error); 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (accelerator.key_code() == ui::VKEY_UNKNOWN) { 48758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error->empty()) { 48858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 48958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBinding, 49058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 49158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->first, 49258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->second); 49358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter->first == key) { 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This platform is our platform, so grab this key. 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator_ = accelerator; 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name_ = command_name; 502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description_ = description; 5034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_ = global; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::DictionaryValue* Command::ToValue(const Extension* extension, 5107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool active) const { 5117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* extension_data = new base::DictionaryValue(); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 command_description; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_name() == values::kBrowserActionCommandEvent || 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name() == values::kPageActionCommandEvent || 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name() == values::kScriptBadgeCommandEvent) { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = description(); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("description", command_description); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetBoolean("active", active); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("keybinding", accelerator().GetShortcutText()); 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("command_name", command_name()); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("extension_id", extension->id()); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extension_data; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 532