Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support more accelerators in menu. #110

Merged
merged 9 commits into from Oct 21, 2013
4 changes: 2 additions & 2 deletions browser/default_app/main.js
@@ -1,15 +1,15 @@
var app = require('app');
var dialog = require('dialog');
var path = require('path');
var optimist = require('optimist');

// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
if (app.listeners('window-all-closed').length == 1)
app.quit();
});

process.argv.splice(1, 0, 'dummyScript');
var argv = require('optimist').argv;
var argv = optimist(process.argv.slice(1)).argv;

// Start the specified app if there is one specified in command line, otherwise
// start the default app.
Expand Down
205 changes: 138 additions & 67 deletions browser/ui/accelerator_util.cc
Expand Up @@ -4,6 +4,8 @@

#include "browser/ui/accelerator_util.h"

#include <stdio.h>

#include <string>

#include "base/string_util.h"
Expand All @@ -15,27 +17,79 @@ namespace accelerator_util {

namespace {

// Convert "Command" to "Ctrl" on non-Mac
std::string NormalizeShortcutSuggestion(const std::string& suggestion) {
#if defined(OS_MACOSX)
return suggestion;
#endif
// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
*shifted = false;
switch (c) {
case 8: case 0x7F: return ui::VKEY_BACK;
case 9: return ui::VKEY_TAB;
case 0xD: case 3: return ui::VKEY_RETURN;
case 0x1B: return ui::VKEY_ESCAPE;
case ' ': return ui::VKEY_SPACE;

std::string key;
std::vector<std::string> tokens;
base::SplitString(suggestion, '+', &tokens);
for (size_t i = 0; i < tokens.size(); i++) {
if (tokens[i] == "Command")
tokens[i] = "Ctrl";
case 'a': return ui::VKEY_A;
case 'b': return ui::VKEY_B;
case 'c': return ui::VKEY_C;
case 'd': return ui::VKEY_D;
case 'e': return ui::VKEY_E;
case 'f': return ui::VKEY_F;
case 'g': return ui::VKEY_G;
case 'h': return ui::VKEY_H;
case 'i': return ui::VKEY_I;
case 'j': return ui::VKEY_J;
case 'k': return ui::VKEY_K;
case 'l': return ui::VKEY_L;
case 'm': return ui::VKEY_M;
case 'n': return ui::VKEY_N;
case 'o': return ui::VKEY_O;
case 'p': return ui::VKEY_P;
case 'q': return ui::VKEY_Q;
case 'r': return ui::VKEY_R;
case 's': return ui::VKEY_S;
case 't': return ui::VKEY_T;
case 'u': return ui::VKEY_U;
case 'v': return ui::VKEY_V;
case 'w': return ui::VKEY_W;
case 'x': return ui::VKEY_X;
case 'y': return ui::VKEY_Y;
case 'z': return ui::VKEY_Z;

case ')': *shifted = true; case '0': return ui::VKEY_0;
case '!': *shifted = true; case '1': return ui::VKEY_1;
case '@': *shifted = true; case '2': return ui::VKEY_2;
case '#': *shifted = true; case '3': return ui::VKEY_3;
case '$': *shifted = true; case '4': return ui::VKEY_4;
case '%': *shifted = true; case '5': return ui::VKEY_5;
case '^': *shifted = true; case '6': return ui::VKEY_6;
case '&': *shifted = true; case '7': return ui::VKEY_7;
case '*': *shifted = true; case '8': return ui::VKEY_8;
case '(': *shifted = true; case '9': return ui::VKEY_9;

case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;

default: return ui::VKEY_UNKNOWN;
}
return JoinString(tokens, '+');
}

} // namespace

bool StringToAccelerator(const std::string& description,
ui::Accelerator* accelerator) {
std::string shortcut(NormalizeShortcutSuggestion(description));
if (!IsStringASCII(description)) {
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
return false;
}
std::string shortcut(StringToLowerASCII(description));

std::vector<std::string> tokens;
base::SplitString(shortcut, '+', &tokens);
Expand All @@ -48,72 +102,89 @@ bool StringToAccelerator(const std::string& description,
int modifiers = ui::EF_NONE;
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
for (size_t i = 0; i < tokens.size(); i++) {
if (tokens[i] == "Ctrl") {
// We use straight comparing instead of map because the accelerator tends
// to be correct and usually only uses few special tokens.
if (tokens[i].size() == 1) {
bool shifted = false;
key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
if (shifted)
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i] == "ctrl") {
modifiers |= ui::EF_CONTROL_DOWN;
} else if (tokens[i] == "Command") {
} else if (tokens[i] == "command") {
// The "Command" would be translated to "Ctrl" on platforms other than
// OS X.
#if defined(OS_MACOSX)
modifiers |= ui::EF_COMMAND_DOWN;
} else if (tokens[i] == "Alt") {
#else
modifiers |= ui::EF_CONTROL_DOWN;
#endif
} else if (tokens[i] == "alt") {
modifiers |= ui::EF_ALT_DOWN;
} else if (tokens[i] == "Shift") {
} else if (tokens[i] == "shift") {
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i].size() == 1) {
char token = tokens[i][0];

if (key != ui::VKEY_UNKNOWN) {
// Multiple key assignments.
key = ui::VKEY_UNKNOWN;
return false;
}
if (token >= 'A' && token <= 'Z') {
key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (token - 'A'));
} else if (token >= '0' && token <= '9') {
key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (token - '0'));
} else if (token >= '*' && token <= '/') {
// *+,-./
key = static_cast<ui::KeyboardCode>(
ui::VKEY_MULTIPLY + (token - '*'));
} else if (tokens[i] == "tab") {
key = ui::VKEY_TAB;
} else if (tokens[i] == "space") {
key = ui::VKEY_SPACE;
} else if (tokens[i] == "backspace") {
key = ui::VKEY_BACK;
} else if (tokens[i] == "delete") {
key = ui::VKEY_DELETE;
} else if (tokens[i] == "enter" || tokens[i] == "return") {
key = ui::VKEY_RETURN;
} else if (tokens[i] == "up") {
key = ui::VKEY_UP;
} else if (tokens[i] == "down") {
key = ui::VKEY_DOWN;
} else if (tokens[i] == "left") {
key = ui::VKEY_LEFT;
} else if (tokens[i] == "right") {
key = ui::VKEY_RIGHT;
} else if (tokens[i] == "home") {
key = ui::VKEY_HOME;
} else if (tokens[i] == "end") {
key = ui::VKEY_END;
} else if (tokens[i] == "pagedown") {
key = ui::VKEY_PRIOR;
} else if (tokens[i] == "pageup") {
key = ui::VKEY_NEXT;
} else if (tokens[i] == "esc") {
key = ui::VKEY_ESCAPE;
} else if (tokens[i] == "volumemute") {
key = ui::VKEY_VOLUME_MUTE;
} else if (tokens[i] == "volumeup") {
key = ui::VKEY_VOLUME_UP;
} else if (tokens[i] == "volumedown") {
key = ui::VKEY_VOLUME_DOWN;
} else if (tokens[i] == "medianexttrack") {
key = ui::VKEY_MEDIA_NEXT_TRACK;
} else if (tokens[i] == "mediaprevioustrack") {
key = ui::VKEY_MEDIA_PREV_TRACK;
} else if (tokens[i] == "mediastop") {
key = ui::VKEY_MEDIA_STOP;
} else if (tokens[i] == "mediaplaypause") {
key = ui::VKEY_MEDIA_PLAY_PAUSE;
} else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
// F1 - F24.
int n;
if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
} else {
switch (token) {
case ':':
case ';':
key = ui::VKEY_OEM_1;
break;
case '?':
case '/':
key = ui::VKEY_OEM_2;
break;
case '~':
case '`':
key = ui::VKEY_OEM_3;
break;
case '{':
case '[':
key = ui::VKEY_OEM_4;
break;
case '|':
case '\\':
key = ui::VKEY_OEM_5;
break;
case '}':
case ']':
key = ui::VKEY_OEM_6;
break;
case '\"':
case '\'':
key = ui::VKEY_OEM_7;
break;
default:
LOG(WARNING) << "Invalid accelerator character: " << tokens[i];
key = ui::VKEY_UNKNOWN;
return false;
}
LOG(WARNING) << tokens[i] << "is not available on keyboard";
return false;
}
} else {
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
return false;
}
}

if (key == ui::VKEY_UNKNOWN) {
LOG(WARNING) << "The accelerator doesn't contain a valid key";
return false;
}

*accelerator = ui::Accelerator(key, modifiers);
SetPlatformAccelerator(accelerator);
return true;
Expand Down