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" 126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/generated_resources.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.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 && 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_name != values::kBrowserActionCommandEvent; 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool DoesRequireModifier(const std::string& accelerator) { 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return accelerator != values::kKeyMediaNextTrack && 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPlayPause && 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaPrevTrack && 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator != values::kKeyMediaStop; 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::Accelerator ParseImpl(const std::string& accelerator, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform_key, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool should_parse_media_keys, 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* error) { 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) error->clear(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (platform_key != values::kKeybindingPlatformWin && 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformMac && 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformChromeOs && 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformLinux && 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key != values::kKeybindingPlatformDefault) { 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingUnknownPlatform, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(accelerator, '+', &tokens); 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (tokens.size() == 0 || 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (tokens.size() == 1 && DoesRequireModifier(accelerator)) || 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens.size() > 3) { 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, parse it into an accelerator. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int modifiers = ui::EF_NONE; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::KeyboardCode key = ui::VKEY_UNKNOWN; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_CONTROL_DOWN; 80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyCommand) { 81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform_key == values::kKeybindingPlatformMac) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either the developer specified Command+foo in the manifest for Mac or 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they specified Ctrl and it got normalized to Command (to get Ctrl on 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac the developer has to specify MacCtrl). Therefore we treat this 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as Command. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform_key == values::kKeybindingPlatformDefault) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we see "Command+foo" in the Default section it can mean two 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // things, depending on the platform: 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The developer specified "Ctrl+foo" for Default and it got normalized 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on Mac to "Command+foo". This is fine. Treat it as Command. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No other platform supports Command. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } else if (tokens[i] == values::kKeySearch) { 10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Search is a special modifier only on ChromeOS and maps to 'Command'. 10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (platform_key == values::kKeybindingPlatformChromeOs) { 10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) modifiers |= ui::EF_COMMAND_DOWN; 10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } else { 10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // No other platform supports Search. 10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) break; 10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyAlt) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_ALT_DOWN; 111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyShift) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) modifiers |= ui::EF_SHIFT_DOWN; 113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 || // A-Z, 0-9. 114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyComma || 115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPeriod || 116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyUp || 117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDown || 118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyLeft || 119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyRight || 120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyIns || 121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyDel || 122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyHome || 123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyEnd || 124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgUp || 125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] == values::kKeyPgDwn || 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyTab || 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaNextTrack || 12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPlayPause || 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaPrevTrack || 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) tokens[i] == values::kKeyMediaStop) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key != ui::VKEY_UNKNOWN) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Multiple key assignments. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyComma) { 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_COMMA; 139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPeriod) { 140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_OEM_PERIOD; 141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyUp) { 142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_UP; 143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDown) { 144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DOWN; 145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyLeft) { 146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_LEFT; 147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyRight) { 148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_RIGHT; 149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyIns) { 150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_INSERT; 151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyDel) { 152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_DELETE; 153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyHome) { 154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_HOME; 155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyEnd) { 156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_END; 157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgUp) { 158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_PRIOR; 159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyPgDwn) { 160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_NEXT; 161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i] == values::kKeyTab) { 162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) key = ui::VKEY_TAB; 16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaNextTrack && 16458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_NEXT_TRACK; 16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPlayPause && 16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PLAY_PAUSE; 16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaPrevTrack && 17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_PREV_TRACK; 17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (tokens[i] == values::kKeyMediaStop && 17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) should_parse_media_keys) { 17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key = ui::VKEY_MEDIA_STOP; 175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); 178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (tokens[i].size() == 1 && 179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i][0] >= '0' && tokens[i][0] <= '9') { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0')); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = ui::VKEY_UNKNOWN; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool alt = (modifiers & ui::EF_ALT_DOWN) != 0; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't support Ctrl+Alt+foo see this article: 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On Mac Command can also be used in combination with Shift or on its own, 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as a modifier. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) || 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (shift && !ctrl && !alt && !command)) { 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform_key, 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if ((key == ui::VKEY_MEDIA_NEXT_TRACK || 21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PREV_TRACK || 21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_PLAY_PAUSE || 21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) key == ui::VKEY_MEDIA_STOP) && 22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (shift || ctrl || alt || command)) { 22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBindingMediaKeyWithModifier, 22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) platform_key, 22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator); 22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return ui::Accelerator(); 22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 22858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::Accelerator(key, modifiers); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// platforms leave the shortcut untouched. 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NormalizeShortcutSuggestion(const std::string& suggestion, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& platform) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool normalize = false; 237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (platform == values::kKeybindingPlatformMac) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (platform == values::kKeybindingPlatformDefault) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normalize = true; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!normalize) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return suggestion; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<std::string> tokens; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SplitString(suggestion, '+', &tokens); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < tokens.size(); i++) { 251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (tokens[i] == values::kKeyCtrl) 252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCommand; 253a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (tokens[i] == values::kKeyMacCtrl) 254a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) tokens[i] = values::kKeyCtrl; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JoinString(tokens, '+'); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Command::Command() : global_(false) {} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::Command(const std::string& command_name, 264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& description, 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::string& accelerator, 2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : command_name_(command_name), 2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) description_(description), 2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_(global) { 270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 error; 27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0, 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Command::~Command() {} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Command::CommandPlatform() { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformWin; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformMac; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_CHROMEOS) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformChromeOs; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return values::kKeybindingPlatformLinux; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)ui::Accelerator Command::StringToAccelerator(const std::string& accelerator, 29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& command_name) { 295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 error; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator parsed = 29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ParseImpl(accelerator, Command::CommandPlatform(), 0, 29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), &error); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return parsed; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 302a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static 303a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) { 304a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::string shortcut; 305a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Ctrl and Alt are mutually exclusive. 307a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCtrlDown()) 308a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCtrl; 309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) else if (accelerator.IsAltDown()) 310a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyAlt; 311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!shortcut.empty()) 312a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 314a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsCmdDown()) { 31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(OS_CHROMEOS) 31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // Chrome OS treats the Search key like the Command key. 31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) shortcut += values::kKeySearch; 31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#else 319a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyCommand; 32003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif 321a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 322a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 323a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.IsShiftDown()) { 325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyShift; 326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeySeparator; 327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 329a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (accelerator.key_code() >= ui::VKEY_0 && 330a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_9) { 331a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += '0' + (accelerator.key_code() - ui::VKEY_0); 332a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (accelerator.key_code() >= ui::VKEY_A && 333a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) accelerator.key_code() <= ui::VKEY_Z) { 334a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += 'A' + (accelerator.key_code() - ui::VKEY_A); 335a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 336a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) switch (accelerator.key_code()) { 337a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_COMMA: 338a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyComma; 339a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 340a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_OEM_PERIOD: 341a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPeriod; 342a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 343a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_UP: 344a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyUp; 345a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DOWN: 347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDown; 348a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 349a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_LEFT: 350a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyLeft; 351a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 352a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_RIGHT: 353a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyRight; 354a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 355a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_INSERT: 356a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyIns; 357a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 358a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_DELETE: 359a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyDel; 360a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 361a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_HOME: 362a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyHome; 363a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 364a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_END: 365a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyEnd; 366a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 367a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_PRIOR: 368a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgUp; 369a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_NEXT: 371a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyPgDwn; 372a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 373a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case ui::VKEY_TAB: 374a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) shortcut += values::kKeyTab; 375a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_NEXT_TRACK: 37758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaNextTrack; 37858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 37958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PLAY_PAUSE: 38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPlayPause; 38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_PREV_TRACK: 38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaPrevTrack; 38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 38558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) case ui::VKEY_MEDIA_STOP: 38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) shortcut += values::kKeyMediaStop; 38758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) break; 388a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) default: 389a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return ""; 390a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 391a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 392a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return shortcut; 393a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 394a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static 396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool Command::IsMediaKey(const ui::Accelerator& accelerator) { 397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (accelerator.modifiers() != 0) 398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return false; 399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return (accelerator.key_code() == ui::VKEY_MEDIA_NEXT_TRACK || 401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_PREV_TRACK || 402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_PLAY_PAUSE || 403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) accelerator.key_code() == ui::VKEY_MEDIA_STOP); 404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Command::Parse(const base::DictionaryValue* command, 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& command_name, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* error) { 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!command_name.empty()); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 description; 41358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (IsNamedCommand(command_name)) { 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!command->GetString(keys::kDescription, &description) || 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description.empty()) { 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kInvalidKeyBindingDescription, 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::IntToString(index)); 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We'll build up a map of platform-to-shortcut suggestions. 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<const std::string, std::string> SuggestionMap; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SuggestionMap suggestions; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First try to parse the |suggested_key| as a dictionary. 4287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::DictionaryValue* suggested_key_dict; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { 4307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for (base::DictionaryValue::Iterator iter(*suggested_key_dict); 4317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) !iter.IsAtEnd(); iter.Advance()) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For each item in the dictionary, extract the platforms specified. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (iter.value().GetAsString(&suggested_key_string) && 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found a platform, add it to the suggestions list. 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) suggestions[iter.key()] = suggested_key_string; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMissing); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No dictionary was found, fall back to using just a string, so developers 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't have to specify a dictionary if they just want to use one default 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for all platforms. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string suggested_key_string; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !suggested_key_string.empty()) { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If only a single string is provided, it must be default for all. 455a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = suggested_key_string; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 457a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) suggestions[values::kKeybindingPlatformDefault] = ""; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Check if this is a global or a regular shortcut. 4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) bool global = false; 463116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch command->GetBoolean(keys::kGlobal, &global); 4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Normalize the suggestions. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (SuggestionMap::iterator iter = suggestions.begin(); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter != suggestions.end(); ++iter) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we normalize Ctrl to Command we must detect when the developer 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // specified Command in the Default section, which will work on Mac after 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // normalization but only fail on other platforms when they try it out on 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other platforms, which is not what we want. 472a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (iter->first == values::kKeybindingPlatformDefault && 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->second.find("Command+") != std::string::npos) { 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBinding, 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCommandKeyNotSupported); 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter->first); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string platform = CommandPlatform(); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string key = platform; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = values::kKeybindingPlatformDefault; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (suggestions.find(key) == suggestions.end()) { 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errors::kInvalidKeyBindingMissingPlatform, 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString(index), 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keys::kSuggestedKey, 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) platform); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // No platform specified and no fallback. Bail. 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For developer convenience, we parse all the suggestions (and complain about 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // errors for platforms other than the current one) but use only what we need. 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::map<const std::string, std::string>::const_iterator iter = 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suggestions.begin(); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; iter != suggestions.end(); ++iter) { 504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::Accelerator accelerator; 505c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!iter->second.empty()) { 506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Note that we pass iter->first to pretend we are on a platform we're not 507c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // on. 50858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) accelerator = ParseImpl(iter->second, iter->first, index, 50958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) IsNamedCommand(command_name), error); 510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (accelerator.key_code() == ui::VKEY_UNKNOWN) { 51158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error->empty()) { 51258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 51358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) errors::kInvalidKeyBinding, 51458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::IntToString(index), 51558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->first, 51658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) iter->second); 51758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (iter->first == key) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This platform is our platform, so grab this key. 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) accelerator_ = accelerator; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_name_ = command_name; 526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) description_ = description; 5274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) global_ = global; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::DictionaryValue* Command::ToValue(const Extension* extension, 5347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool active) const { 5357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::DictionaryValue* extension_data = new base::DictionaryValue(); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 command_description; 5388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool extension_action = false; 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_name() == values::kBrowserActionCommandEvent || 5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command_name() == values::kPageActionCommandEvent) { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE); 5438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_action = true; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_description = description(); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("description", command_description); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetBoolean("active", active); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("keybinding", accelerator().GetShortcutText()); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("command_name", command_name()); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_data->SetString("extension_id", extension->id()); 5528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_data->SetBoolean("global", global()); 5538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) extension_data->SetBoolean("extension_action", extension_action); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return extension_data; 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 558