command.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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" 128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "chrome/common/chrome_version_info.h" // TODO(finnur): Remove. 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/feature_switch.h" 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace extensions { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace errors = manifest_errors; 23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace keys = manifest_keys; 24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace values = manifest_values; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kMissing[] = "Missing"; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kCommandKeyNotSupported[] = 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Command key is not supported. Note: Ctrl means Command on Mac"; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool IsNamedCommand(const std::string& command_name) { 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return command_name != values::kPageActionCommandEvent && 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_name != values::kBrowserActionCommandEvent; 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DoesRequireModifier(const std::string& accelerator) { 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return accelerator != values::kKeyMediaNextTrack && 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPlayPause && 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPrevTrack && 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaStop; 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator ParseImpl(const std::string& accelerator, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform_key, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool should_parse_media_keys, 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* error) { 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) error->clear(); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform_key != values::kKeybindingPlatformWin && 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformMac && 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformChromeOs && 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformLinux && 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformDefault) { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingUnknownPlatform, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(accelerator, '+', &tokens); 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (tokens.size() == 0 || 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (tokens.size() == 1 && DoesRequireModifier(accelerator)) || 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens.size() > 3) { 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, parse it into an accelerator. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int modifiers = ui::EF_NONE; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::KeyboardCode key = ui::VKEY_UNKNOWN; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_CONTROL_DOWN; 82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyCommand) { 83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform_key == values::kKeybindingPlatformMac) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either the developer specified Command+foo in the manifest for Mac or 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they specified Ctrl and it got normalized to Command (to get Ctrl on 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac the developer has to specify MacCtrl). Therefore we treat this 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as Command. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform_key == values::kKeybindingPlatformDefault) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we see "Command+foo" in the Default section it can mean two 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // things, depending on the platform: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The developer specified "Ctrl+foo" for Default and it got normalized 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on Mac to "Command+foo". This is fine. Treat it as Command. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No other platform supports Command. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyAlt) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_ALT_DOWN; 104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyShift) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_SHIFT_DOWN; 106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 || // A-Z, 0-9. 107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyComma || 108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPeriod || 109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyUp || 110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDown || 111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyLeft || 112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyRight || 113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyIns || 114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDel || 115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyHome || 116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyEnd || 117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgUp || 118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgDwn || 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyTab || 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaNextTrack || 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPlayPause || 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPrevTrack || 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaStop) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key != ui::VKEY_UNKNOWN) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple key assignments. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyComma) { 131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_COMMA; 132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPeriod) { 133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_PERIOD; 134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyUp) { 135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_UP; 136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDown) { 137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DOWN; 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyLeft) { 139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_LEFT; 140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyRight) { 141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_RIGHT; 142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyIns) { 143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_INSERT; 144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDel) { 145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DELETE; 146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyHome) { 147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_HOME; 148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyEnd) { 149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_END; 150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgUp) { 151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_PRIOR; 152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgDwn) { 153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_NEXT; 154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyTab) { 155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_TAB; 15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaNextTrack && 15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_NEXT_TRACK; 15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPlayPause && 16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PLAY_PAUSE; 16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPrevTrack && 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PREV_TRACK; 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaStop && 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_STOP; 168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); 171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= '0' && tokens[i][0] <= '9') { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 18758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't support Ctrl+Alt+foo see this article: 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On Mac Command can also be used in combination with Shift or on its own, 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a modifier. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (shift && !ctrl && !alt && !command)) { 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if ((key == ui::VKEY_MEDIA_NEXT_TRACK || 21058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PREV_TRACK || 21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PLAY_PAUSE || 21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_STOP) && 21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (shift || ctrl || alt || command)) { 21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBindingMediaKeyWithModifier, 21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) platform_key, 21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator); 21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return ui::Accelerator(); 22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(key, modifiers); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// platforms leave the shortcut untouched. 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NormalizeShortcutSuggestion(const std::string& suggestion, 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform) { 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool normalize = false; 230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform == values::kKeybindingPlatformMac) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform == values::kKeybindingPlatformDefault) { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!normalize) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return suggestion; 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(suggestion, '+', &tokens); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) 245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCommand; 246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (tokens[i] == values::kKeyMacCtrl) 247a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCtrl; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JoinString(tokens, '+'); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Command::Command() : global_(false) {} 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::Command(const std::string& command_name, 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& description, 2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& accelerator, 2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : command_name_(command_name), 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) description_(description), 2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_(global) { 263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 error; 26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::~Command() {} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Command::CommandPlatform() { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformWin; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformMac; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_CHROMEOS) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformChromeOs; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformLinux; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)ui::Accelerator Command::StringToAccelerator(const std::string& accelerator, 28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& command_name) { 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 error; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator parsed = 29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ParseImpl(accelerator, Command::CommandPlatform(), 0, 29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static 296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) { 297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::string shortcut; 298a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 299a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Ctrl and Alt are mutually exclusive. 300a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCtrlDown()) 301a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCtrl; 302a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (accelerator.IsAltDown()) 303a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyAlt; 304a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!shortcut.empty()) 305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 307a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCmdDown()) { 308a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCommand; 309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 310a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 312a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsShiftDown()) { 313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyShift; 314a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 315a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 316a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 317a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.key_code() >= ui::VKEY_0 && 318a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_9) { 319a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += '0' + (accelerator.key_code() - ui::VKEY_0); 320a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (accelerator.key_code() >= ui::VKEY_A && 321a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_Z) { 322a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += 'A' + (accelerator.key_code() - ui::VKEY_A); 323a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) switch (accelerator.key_code()) { 325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_COMMA: 326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyComma; 327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_PERIOD: 329a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPeriod; 330a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 331a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_UP: 332a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyUp; 333a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 334a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DOWN: 335a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDown; 336a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 337a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_LEFT: 338a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyLeft; 339a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 340a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_RIGHT: 341a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyRight; 342a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 343a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_INSERT: 344a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyIns; 345a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DELETE: 347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDel; 348a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 349a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_HOME: 350a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyHome; 351a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 352a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_END: 353a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyEnd; 354a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 355a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_PRIOR: 356a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgUp; 357a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 358a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_NEXT: 359a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgDwn; 360a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 361a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_TAB: 362a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyTab; 363a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 36458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_NEXT_TRACK: 36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaNextTrack; 36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 36758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PLAY_PAUSE: 36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPlayPause; 36958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 37058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PREV_TRACK: 37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPrevTrack; 37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_STOP: 37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaStop; 37558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 376a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) default: 377a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return ""; 378a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 379a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 380a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return shortcut; 381a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 382a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Command::IsMediaKey(const ui::Accelerator& accelerator) { 385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (accelerator.modifiers() != 0) 386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return (accelerator.key_code() == ui::VKEY_MEDIA_NEXT_TRACK || 389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_PREV_TRACK || 390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_PLAY_PAUSE || 391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_STOP); 392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 3947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Command::Parse(const base::DictionaryValue* command, 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name, 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* error) { 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!command_name.empty()); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 description; 40158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (IsNamedCommand(command_name)) { 402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!command->GetString(keys::kDescription, &description) || 403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description.empty()) { 404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kInvalidKeyBindingDescription, 406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::IntToString(index)); 407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We'll build up a map of platform-to-shortcut suggestions. 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<const std::string, std::string> SuggestionMap; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SuggestionMap suggestions; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First try to parse the |suggested_key| as a dictionary. 4167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::DictionaryValue* suggested_key_dict; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { 4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for (base::DictionaryValue::Iterator iter(*suggested_key_dict); 4197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) !iter.IsAtEnd(); iter.Advance()) { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For each item in the dictionary, extract the platforms specified. 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iter.value().GetAsString(&suggested_key_string) && 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found a platform, add it to the suggestions list. 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) suggestions[iter.key()] = suggested_key_string; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMissing); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No dictionary was found, fall back to using just a string, so developers 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't have to specify a dictionary if they just want to use one default 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for all platforms. 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If only a single string is provided, it must be default for all. 443a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = suggested_key_string; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 445a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = ""; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Check if this is a global or a regular shortcut. 4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global = false; 451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (FeatureSwitch::global_commands()->IsEnabled() && 452f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) chrome::VersionInfo::GetChannel() <= chrome::VersionInfo::CHANNEL_DEV) 453f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command->GetBoolean(keys::kGlobal, &global); 4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normalize the suggestions. 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SuggestionMap::iterator iter = suggestions.begin(); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != suggestions.end(); ++iter) { 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we normalize Ctrl to Command we must detect when the developer 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specified Command in the Default section, which will work on Mac after 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // normalization but only fail on other platforms when they try it out on 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other platforms, which is not what we want. 462a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (iter->first == values::kKeybindingPlatformDefault && 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->second.find("Command+") != std::string::npos) { 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCommandKeyNotSupported); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->first); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string platform = CommandPlatform(); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = platform; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = values::kKeybindingPlatformDefault; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) { 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingMissingPlatform, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // No platform specified and no fallback. Bail. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For developer convenience, we parse all the suggestions (and complain about 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors for platforms other than the current one) but use only what we need. 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<const std::string, std::string>::const_iterator iter = 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions.begin(); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; iter != suggestions.end(); ++iter) { 494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::Accelerator accelerator; 495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!iter->second.empty()) { 496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note that we pass iter->first to pretend we are on a platform we're not 497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on. 49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator = ParseImpl(iter->second, iter->first, index, 49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), error); 500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (accelerator.key_code() == ui::VKEY_UNKNOWN) { 50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error->empty()) { 50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 50358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBinding, 50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 50558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->first, 50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->second); 50758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 508c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter->first == key) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This platform is our platform, so grab this key. 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator_ = accelerator; 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name_ = command_name; 516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description_ = description; 5174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_ = global; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::DictionaryValue* Command::ToValue(const Extension* extension, 5247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool active) const { 5257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* extension_data = new base::DictionaryValue(); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 command_description; 5288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool extension_action = false; 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_name() == values::kBrowserActionCommandEvent || 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_name() == values::kPageActionCommandEvent) { 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE); 5338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_action = true; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = description(); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("description", command_description); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetBoolean("active", active); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("keybinding", accelerator().GetShortcutText()); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("command_name", command_name()); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("extension_id", extension->id()); 5428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_data->SetBoolean("global", global()); 5438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_data->SetBoolean("extension_action", extension_action); 5448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 5458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (FeatureSwitch::global_commands()->IsEnabled()) { 5468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(finnur): This is to make sure we don't show the config UI beyond 5478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // dev and will be removed when we launch. 5488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static bool stable_or_beta = 5498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) chrome::VersionInfo::GetChannel() >= chrome::VersionInfo::CHANNEL_BETA; 5508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_data->SetBoolean("scope_ui_visible", !stable_or_beta); 5518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extension_data; 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 557