Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Use windows-specific keybindings on linux #2331

Merged
merged 9 commits into from
Dec 13, 2012
33 changes: 11 additions & 22 deletions src/base-config/keyboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
],
"edit.selectLine": [
{
"key": "Ctrl-L",
"platform": "win"
"key": "Ctrl-L"
},
{
"key": "Ctrl-L",
Expand All @@ -47,8 +46,7 @@
],
"edit.findNext": [
{
"key": "F3",
"platform": "win"
"key": "F3"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this file, in cases where the key bindings on mac are different from win/linux, the order is always generic first, followed by platform:mac. These can be specified in either order (and this file just happens to be organized that way), correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct

{
"key": "Cmd-G",
Expand All @@ -57,8 +55,7 @@
],
"edit.findPrevious": [
{
"key": "Shift-F3",
"platform": "win"
"key": "Shift-F3"
},
{
"key": "Cmd-Shift-G",
Expand All @@ -67,8 +64,7 @@
],
"edit.replace": [
{
"key": "Ctrl-H",
"platform": "win"
"key": "Ctrl-H"
},
{
"key": "Cmd-Alt-F",
Expand Down Expand Up @@ -96,8 +92,7 @@
"edit.lineUp": [
{
"key": "Ctrl-Shift-Up",
"displayKey": "Ctrl-Shift-↑",
"platform": "win"
"displayKey": "Ctrl-Shift-↑"
},
{
"key": "Cmd-Ctrl-Up",
Expand All @@ -108,8 +103,7 @@
"edit.lineDown": [
{
"key": "Ctrl-Shift-Down",
"displayKey": "Ctrl-Shift-↓",
"platform": "win"
"displayKey": "Ctrl-Shift-↓"
},
{
"key": "Cmd-Ctrl-Down",
Expand Down Expand Up @@ -150,8 +144,7 @@
],
"navigate.gotoLine": [
{
"key": "Ctrl-G",
"platform": "win"
"key": "Ctrl-G"
},
{
"key": "Cmd-L",
Expand All @@ -163,8 +156,7 @@
],
"navigate.nextDoc": [
{
"key": "Ctrl-Tab",
"platform": "win"
"key": "Ctrl-Tab"
},
{
"key": "Ctrl-Tab",
Expand All @@ -173,8 +165,7 @@
],
"navigate.prevDoc": [
{
"key": "Ctrl-Shift-Tab",
"platform": "win"
"key": "Ctrl-Shift-Tab"
},
{
"key": "Ctrl-Shift-Tab",
Expand All @@ -198,8 +189,7 @@
],
"debug.showDeveloperTools": [
{
"key": "F12",
"platform": "win"
"key": "F12"
},
{
"key": "Cmd-Opt-I",
Expand All @@ -208,8 +198,7 @@
],
"debug.refreshWindow": [
{
"key": "F5",
"platform": "win"
"key": "F5"
},
{
"key": "Cmd-R",
Expand Down
167 changes: 114 additions & 53 deletions src/command/KeyBindingManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ define(function (require, exports, module) {
* Takes a keyboard event and translates it into a key in a key map
*/
function _translateKeyboardEvent(event) {
var hasMacCtrl = (brackets.platform === "win") ? false : (event.ctrlKey),
hasCtrl = (brackets.platform === "win") ? (event.ctrlKey) : (event.metaKey),
var hasMacCtrl = (brackets.platform === "mac") ? (event.ctrlKey) : false,
hasCtrl = (brackets.platform !== "mac") ? (event.ctrlKey) : (event.metaKey),
hasAlt = (event.altKey),
hasShift = (event.shiftKey),
key = String.fromCharCode(event.keyCode);
Expand Down Expand Up @@ -298,13 +298,51 @@ define(function (require, exports, module) {
return (_keyMap[key] !== undefined);
}

/**
* Remove a key binding from _keymap
*
* @param {!string} key - a key-description string that may or may not be normalized.
* @param {?string} platform - OS from which to remove the binding (all platforms if unspecified)
*/
function removeBinding(key, platform) {
if (!key || ((platform !== null) && (platform !== undefined) && (platform !== brackets.platform))) {
return;
}

var normalizedKey = normalizeKeyDescriptorString(key);

if (!normalizedKey) {
console.log("Fail to nomalize " + key);
} else if (_isKeyAssigned(normalizedKey)) {
var binding = _keyMap[normalizedKey],
command = CommandManager.get(binding.commandID),
bindings = _commandMap[binding.commandID];

// delete key binding record
delete _keyMap[normalizedKey];

if (bindings) {
// delete mapping from command to key binding
_commandMap[binding.commandID] = bindings.filter(function (b) {
return (b.key !== normalizedKey);
});

if (command) {
$(command).triggerHandler("keyBindingRemoved", [{key: normalizedKey, displayKey: binding.displayKey}]);
}
}
}
}

/**
* @private
*
* @param {string} commandID
* @param {string|{{key: string, displayKey: string}}} keyBinding - a single shortcut.
* @param {?string} platform - undefined indicates all platforms
* @return {?{key: string, displayKey:String}} Returns a record for valid key bindings
* @return {?{key: string, displayKey:String}} Returns a record for valid key bindings.
* Returns null when key binding platform does not match, binding does not normalize,
* or is already assigned.
*/
function _addBinding(commandID, keyBinding, platform) {
var key,
Expand All @@ -315,11 +353,6 @@ define(function (require, exports, module) {
targetPlatform = explicitPlatform || brackets.platform,
command;

// skip if this binding doesn't match the current platform
if (targetPlatform !== brackets.platform) {
return null;
}

key = (keyBinding.key) || keyBinding;
if (brackets.platform === "mac" && explicitPlatform === undefined) {
key = key.replace("Ctrl", "Cmd");
Expand All @@ -342,6 +375,50 @@ define(function (require, exports, module) {
return null;
}

// for cross-platform compatibility
if (brackets.platform !== "mac" &&
brackets.platform !== "win") {
if (explicitPlatform === "win") {
// windows-only key bindings are used as the default binding
// only if a default binding wasn't already defined
var existing = _keyMap[normalized];

// search for a generic or platform-specific binding if it
// already exists
if (existing &&
(!existing.explicitPlatform || existing.explicitPlatform === brackets.platform)) {
// do not clobber existing binding with windows-only binding
return null;
}

// target this windows binding for the current platform
targetPlatform = brackets.platform;
} else if (!explicitPlatform || (explicitPlatform === brackets.platform)) {
// if adding a generic binding or a binding for the current
// platform, clobber any windows bindings that may have been
// installed
var existingBindings = _commandMap[commandID] || [],
bindingsToDelete = [];

// filter out windows-only bindings in _commandMap
existingBindings.forEach(function (binding) {
if (binding.explicitPlatform === "win") {
bindingsToDelete.push(binding);
}
});

// delete windows-only bindings in _keyMap
bindingsToDelete.forEach(function (binding) {
removeBinding(binding.key);
});
}
}

// skip if this binding doesn't match the current platform
if (targetPlatform !== brackets.platform) {
return null;
}

// optional display-friendly string (e.g. CMD-+ instead of CMD-=)
normalizedDisplay = (keyBinding.displayKey) ? normalizeKeyDescriptorString(keyBinding.displayKey) : normalized;

Expand All @@ -350,11 +427,21 @@ define(function (require, exports, module) {
_commandMap[commandID] = [];
}

result = {key: normalized, displayKey: normalizedDisplay};
result = {
key : normalized,
displayKey : normalizedDisplay,
explicitPlatform : explicitPlatform
};

_commandMap[commandID].push(result);

// 1-to-1 key binding to commandID
_keyMap[normalized] = {commandID: commandID, key: normalized, displayKey: normalizedDisplay};
_keyMap[normalized] = {
commandID : commandID,
key : normalized,
displayKey : normalizedDisplay,
explicitPlatform : explicitPlatform
};

// notify listeners
command = CommandManager.get(commandID);
Expand Down Expand Up @@ -404,12 +491,16 @@ define(function (require, exports, module) {
* Add one or more key bindings to a particular Command.
*
* @param {!string} commandID
* @param {?({key: string, displayKey: string} | Array.<{key: string, displayKey: string, platform: string}>)} keyBindings - a single key binding
* or an array of keybindings. Example: "Shift-Cmd-F". Mac and Win key equivalents are automatically
* mapped to each other. Use displayKey property to display a different string (e.g. "CMD+" instead of "CMD=").
* @param {?string} platform - the target OS of the keyBindings either "mac" or "win". If undefined, all platforms will use
* the key binding. Ignored if keyBindings is passed an Array.
* @return {{key: string, displayKey:String}|Array.<{key: string, displayKey:String}>} Returns record(s) for valid key binding(s)
* @param {?({key: string, displayKey: string} | Array.<{key: string, displayKey: string, platform: string}>)} keyBindings
* a single key binding or an array of keybindings. Example:
* "Shift-Cmd-F". Mac and Win key equivalents are automatically
* mapped to each other. Use displayKey property to display a different
* string (e.g. "CMD+" instead of "CMD=").
* @param {?string} platform - the target OS of the keyBindings either
* "mac", "win" or "linux". If undefined, all platforms not explicitly
* defined will use the key binding.
* @return {{key: string, displayKey:String}|Array.<{key: string, displayKey:String}>}
* Returns record(s) for valid key binding(s)
*/
function addBinding(commandID, keyBindings, platform) {
if ((commandID === null) || (commandID === undefined) || !keyBindings) {
Expand All @@ -424,7 +515,8 @@ define(function (require, exports, module) {
var keyBinding;
results = [];

keyBindings.forEach(function (keyBindingRequest) {
keyBindings.forEach(function addSingleBinding(keyBindingRequest) {
// attempt to add keybinding
keyBinding = _addBinding(commandID, keyBindingRequest, keyBindingRequest.platform);

if (keyBinding) {
Expand All @@ -437,42 +529,6 @@ define(function (require, exports, module) {

return results;
}

/**
* Remove a key binding from _keymap
*
* @param {!string} key - a key-description string that may or may not be normalized.
* @param {?string} platform - OS from which to remove the binding (all platforms if unspecified)
*/
function removeBinding(key, platform) {
if (!key || ((platform !== null) && (platform !== undefined) && (platform !== brackets.platform))) {
return;
}

var normalizedKey = normalizeKeyDescriptorString(key);

if (!normalizedKey) {
console.log("Fail to nomalize " + key);
} else if (_isKeyAssigned(normalizedKey)) {
var binding = _keyMap[normalizedKey],
command = CommandManager.get(binding.commandID),
bindings = _commandMap[binding.commandID];

// delete key binding record
delete _keyMap[normalizedKey];

if (bindings) {
// delete mapping from command to key binding
_commandMap[binding.commandID] = bindings.filter(function (b) {
return (b.key !== normalizedKey);
});

if (command) {
$(command).triggerHandler("keyBindingRemoved", [{key: normalizedKey, displayKey: binding.displayKey}]);
}
}
}
}

/**
* Retrieve key bindings currently associated with a command
Expand All @@ -485,6 +541,11 @@ define(function (require, exports, module) {
return bindings || [];
}

/**
* Adds default key bindings when commands are registered to CommandManager
* @param {$.Event} event jQuery event
* @param {Command} command Newly registered command
*/
function _handleCommandRegistered(event, command) {
var commandId = command.getID(),
defaults = KeyboardPrefs[commandId];
Expand Down
Loading