Finalize current keymapping work:

- catchup with latest changes to pilot/keys.js
- the textinput adds a event.addCommandKeyEvent(...) to the input
- the onTextInput and onCommandKey event sent by the textinput are forwareded to the edtior which
  then forwards the input to the keybinding, which handles the input based on the current inputMode.
- the current inputMode can get changed by setting the setting "inputMode". Currently there are the
  modes "vim" and "emacs". If the inputMode doesn't match, the "default" mode is used.
This commit is contained in:
Julian Viereck 2010-12-31 18:32:53 +01:00
commit 3ebd2865ea
6 changed files with 95 additions and 94 deletions

View file

@ -253,7 +253,7 @@ canon.addCommand({
canon.addCommand({ canon.addCommand({
name: "inserttext", name: "inserttext",
exec: function(env, args, request) { exec: function(env, args, request) {
env.editor.onTextInput(lang.stringRepeat(args.text || "", env.editor.insert(lang.stringRepeat(args.text || "",
args.times || 1)); args.times || 1));
} }
}); });

View file

@ -54,7 +54,7 @@ var Editor =function(renderer, doc) {
this.renderer = renderer; this.renderer = renderer;
this.textInput = new TextInput(container, this); this.textInput = new TextInput(container, this);
this.keyBinding = new KeyBinding(container, this); this.keyBinding = new KeyBinding(this);
var self = this; var self = this;
event.addListener(container, "mousedown", function(e) { event.addListener(container, "mousedown", function(e) {
setTimeout(function() {self.focus();}); setTimeout(function() {self.focus();});
@ -403,7 +403,7 @@ var Editor =function(renderer, doc) {
} }
}; };
this.onTextInput = function(text) { this.insert = function(text) {
if (this.$readOnly) if (this.$readOnly)
return; return;
@ -480,6 +480,14 @@ var Editor =function(renderer, doc) {
_self.renderer.scrollCursorIntoView(); _self.renderer.scrollCursorIntoView();
}); });
}); });
}
this.onTextInput = function(text) {
this.keyBinding.onTextInput(text);
};
this.onCommandKey = function(e, hashId, keyCode) {
this.keyBinding.onCommandKey(e, hashId, keyCode);
}; };
this.$overwrite = false; this.$overwrite = false;

View file

@ -39,102 +39,45 @@
define(function(require, exports, module) { define(function(require, exports, module) {
var useragent = require("pilot/useragent"); var useragent = require("pilot/useragent");
var keyUtil = require("pilot/keys");
var event = require("pilot/event"); var event = require("pilot/event");
var settings = require("pilot/settings").settings;
var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_mac = require("ace/conf/keybindings/default_mac").bindings;
var default_win = require("ace/conf/keybindings/default_win").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings;
var canon = require("pilot/canon"); var canon = require("pilot/canon");
require("ace/commands/default_commands"); require("ace/commands/default_commands");
var vim_mode = require("ace/mode/vim"); var inputModes = {
var emacs_mode = require("ace/mode/emacs"); vim: require("ace/mode/vim"),
emacs: require("ace/mode/emacs")
var KeyBinding = function(element, editor, config) {
this.setConfig(config);
var data = { };
var _self = this;
event.addKeyListener(element, function(e) {
// opera on mac swaps ctrl and meta keys
if (useragent.isOpera && useragent.isMac)
var hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0);
else
var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
console.log(hashId, e.keyCode);
var key;
var keyCode = e.keyCode;
// TODO: Pressing the command key on Chrome/Mac causes the keyCode
// to be 91, which is the "[" character, without pressing this actually.
// Invastigate more further and make a proper work around.
if (hashId & 8 && keyCode == 91) {
key = "";
} else {
key = (_self.keyNames[e.keyCode] ||
String.fromCharCode(e.keyCode)).toLowerCase();
}
var toExecute;
if (true) {
var toExecute =
// vim_mode.handleKeyboard(data, hashId, key, e);
emacs_mode.handleKeyboard(data, hashId, key, e);
}
// If there is nothing to execute yet, then use the default keymapping.
if (!toExecute) {
toExecute = {
command: (_self.config.reverse[hashId] || {})[key]
}; };
}
// If there is something to execute, then go for it. var KeyBinding = function(editor, config) {
if (toExecute) { this.$editor = editor;
var success = canon.exec(toExecute.command, this.$data = { };
{editor: editor}, toExecute.args); this.setConfig(config);
if (success) {
return event.stopEvent(e); // PROBLEM: When this file is loaded via require.js, the types are already
} // declaired, BUT the startup() function is not called in pilot/types/basic.
} // Therefore the settings are not declaired. As a workaround, the setting
}); // is declaired when the KeyBinding is created.
var InputModeSetting = {
name: "inputMode",
description: "Which input mode do you want to use?",
type: "text",
defaultValue: "standard"
};
this.$inputMode = null;
settings.addSetting(InputModeSetting);
settings.getSetting("inputMode").addEventListener("change", function(e) {
this.$inputMode = inputModes[e.value];
this.$data = { };
}.bind(this));
}; };
(function() { (function() {
this.keyMods = {"ctrl": 1, "alt": 2, "option" : 2, "shift": 4, "meta": 8, "command": 8};
this.keyNames = {
"8" : "Backspace",
"9" : "Tab",
"13" : "Enter",
"27" : "Esc",
"32" : "Space",
"33" : "PageUp",
"34" : "PageDown",
"35" : "End",
"36" : "Home",
"37" : "Left",
"38" : "Up",
"39" : "Right",
"40" : "Down",
"45" : "Insert",
"46" : "Delete",
"107": "+",
"112": "F1",
"113": "F2",
"114": "F3",
"115": "F4",
"116": "F5",
"117": "F6",
"118": "F7",
"119": "F8",
"120": "F9",
"121": "F10",
"122": "F11",
"123": "F12"
};
function splitSafe(s, separator, limit, bLowerCase) { function splitSafe(s, separator, limit, bLowerCase) {
return (bLowerCase && s.toLowerCase() || s) return (bLowerCase && s.toLowerCase() || s)
.replace(/(?:^\s+|\n|\s+$)/g, "") .replace(/(?:^\s+|\n|\s+$)/g, "")
@ -149,8 +92,8 @@ var KeyBinding = function(element, editor, config) {
l = parts.length; l = parts.length;
for (; i < l; ++i) { for (; i < l; ++i) {
if (this.keyMods[parts[i]]) if (keyUtil.KEY_MODS[parts[i]])
hashId = hashId | this.keyMods[parts[i]]; hashId = hashId | keyUtil.KEY_MODS[parts[i]];
else else
key = parts[i] || "-"; //when empty, the splitSafe removed a '-' key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
} }
@ -184,6 +127,47 @@ var KeyBinding = function(element, editor, config) {
this.config.reverse = objectReverse.call(this, this.config, "|"); this.config.reverse = objectReverse.call(this, this.config, "|");
}; };
this.onCommandKey = function(e, hashId, keyCode) {
key = (keyUtil[keyCode] ||
String.fromCharCode(keyCode)).toLowerCase();
var toExecute;
if (this.$inputMode) {
toExecute =
this.$inputMode.handleKeyboard(this.$data, hashId, key, e);
}
// If there is nothing to execute yet, then use the default keymapping.
if (!toExecute) {
toExecute = {
command: (this.config.reverse[hashId] || {})[key]
};
}
// If there is something to execute, then go for it.
if (toExecute) {
var success = canon.exec(toExecute.command,
{editor: this.$editor}, toExecute.args);
if (success) {
return event.stopEvent(e);
}
}
};
this.onTextInput = function(text) {
if (this.$inputMode) {
var toExecute =
this.$inputMode.handleKeyboard(this.$data, 0, text, {});
var success = canon.exec(toExecute.command,
{editor: this.$editor}, toExecute.args);
if (success) {
return;
}
}
this.$editor.insert(text);
}
}).call(KeyBinding.prototype); }).call(KeyBinding.prototype);
exports.KeyBinding = KeyBinding; exports.KeyBinding = KeyBinding;

View file

@ -37,6 +37,10 @@
define(function(require, exports, module) { define(function(require, exports, module) {
// If you're developing a new keymapping and want to get an idea what's going
// on, then enable debugging.
var DEBUG = false;
function KeyboardStateMapper(keymapping) { function KeyboardStateMapper(keymapping) {
this.keymapping = this.$buildKeymappingRegex(keymapping); this.keymapping = this.$buildKeymappingRegex(keymapping);
} }
@ -172,7 +176,9 @@ KeyboardStateMapper.prototype = {
result.command = "null"; result.command = "null";
} }
if (DEBUG) {
console.log("KeyboardStateMapper#find", binding); console.log("KeyboardStateMapper#find", binding);
}
return true; return true;
}); });
@ -191,7 +197,9 @@ KeyboardStateMapper.prototype = {
var symbolicName = r.symbolicName; var symbolicName = r.symbolicName;
r = this.$find(data, buffer, symbolicName, hashId, key); r = this.$find(data, buffer, symbolicName, hashId, key);
if (DEBUG) {
console.log("KeyboardStateMapper#match", buffer, symbolicName, r); console.log("KeyboardStateMapper#match", buffer, symbolicName, r);
}
return r; return r;
} }

View file

@ -114,6 +114,7 @@ var TextInput = function(parentNode, host) {
setTimeout(sendText, 0); setTimeout(sendText, 0);
}; };
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
event.addListener(text, "keypress", onTextInput); event.addListener(text, "keypress", onTextInput);
event.addListener(text, "textInput", onTextInput); event.addListener(text, "textInput", onTextInput);
event.addListener(text, "paste", onTextInput); event.addListener(text, "paste", onTextInput);

@ -1 +1 @@
Subproject commit 36c55c39e8ede94e964364e01ab5308f3f51c2eb Subproject commit cd074fd37a02bc40300aa7b120d395525767b156