mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-04 19:14:12 +01:00
Back out most of the changes accidentally merged from key-processing.
--HG-- extra : rebase_source : a00510584f7e13917f8496e15b7dd36852d98ea7
This commit is contained in:
@@ -11,17 +11,15 @@
|
||||
var ProcessorStack = Class("ProcessorStack", {
|
||||
init: function (mode, hives, keyModes) {
|
||||
this.main = mode.main;
|
||||
this._actions = [];
|
||||
this.actions = [];
|
||||
this.buffer = "";
|
||||
this.events = [];
|
||||
|
||||
this.processors = keyModes.map(function (m) hives.map(function (h) KeyProcessor(m, h)))
|
||||
.flatten().array;
|
||||
this.ownsBuffer = !this.processors.some(function (p) p.main.ownsBuffer);
|
||||
|
||||
for (let [i, input] in Iterator(this.processors)) {
|
||||
let params = input.main.params;
|
||||
let params = input.main == mode.main ? mode.params : input.main.params;
|
||||
if (params.preExecute)
|
||||
input.preExecute = params.preExecute;
|
||||
if (params.postExecute)
|
||||
@@ -33,70 +31,9 @@ var ProcessorStack = Class("ProcessorStack", {
|
||||
}
|
||||
},
|
||||
|
||||
notify: function () {
|
||||
this.execute(Events.KILL, true);
|
||||
},
|
||||
|
||||
execute: function execute(result, force) {
|
||||
|
||||
if (force && this.actions.length)
|
||||
this.processors.length = 0;
|
||||
|
||||
if (this.ownsBuffer)
|
||||
statusline.updateInputBuffer(this.processors.length ? this.buffer : "");
|
||||
|
||||
if (this.processors.length) {
|
||||
result = Events.KILL;
|
||||
if (this.actions.length && options["timeout"])
|
||||
this.timer = services.Timer(this, options["timeoutlen"], services.Timer.TYPE_ONE_SHOT);
|
||||
}
|
||||
else if (this.actions.length) {
|
||||
if (this._actions.length == 0) {
|
||||
dactyl.beep();
|
||||
events.feedingKeys = false;
|
||||
}
|
||||
|
||||
for (var res = this.actions[0]; callable(res);)
|
||||
res = res();
|
||||
result = res === Events.PASS ? Events.PASS : Events.KILL;
|
||||
}
|
||||
else if (result !== Events.KILL && !this.actions.length &&
|
||||
this.processors.some(function (p) !p.main.passUnknown)) {
|
||||
result = Events.KILL;
|
||||
dactyl.beep();
|
||||
events.feedingKeys = false;
|
||||
}
|
||||
else if (result === undefined)
|
||||
result = Events.PASS;
|
||||
|
||||
if (result !== Events.PASS)
|
||||
Events.kill(this.events[this.events.length - 1]);
|
||||
|
||||
if (result === Events.PASS || result === Events.ABORT)
|
||||
this.events.filter(function (e) e.getPreventDefault())
|
||||
.forEach(function (event, i) {
|
||||
let elem = event.originalTarget;
|
||||
if (event.originalTarget) {
|
||||
let doc = elem.ownerDocument || elem.document || elem;
|
||||
let evt = events.create(doc, event.type, event);
|
||||
events.dispatch(elem, evt, { skipmap: true, isMacro: true, isReplay: true });
|
||||
}
|
||||
else if (i > 0)
|
||||
events.events.keypress.call(events, event);
|
||||
});
|
||||
|
||||
if (force && this.processors.length === 0)
|
||||
events.processor = null;
|
||||
|
||||
return this.processors.length == 0;
|
||||
},
|
||||
|
||||
process: function process(event) {
|
||||
function dbg() {}
|
||||
|
||||
if (this.timer)
|
||||
this.timer.cancel();
|
||||
|
||||
let key = events.toString(event);
|
||||
this.events.push(event);
|
||||
|
||||
@@ -133,7 +70,9 @@ var ProcessorStack = Class("ProcessorStack", {
|
||||
dbg("ACTIONS: " + actions.length + " " + this.actions.length);
|
||||
dbg("PROCESSORS:", processors);
|
||||
|
||||
this._actions = actions;
|
||||
if (!processors.some(function (p) p.main.ownsBuffer))
|
||||
statusline.updateInputBuffer(processors.length ? this.buffer : "");
|
||||
|
||||
this.actions = actions.concat(this.actions);
|
||||
|
||||
if (result === Events.KILL)
|
||||
@@ -148,7 +87,41 @@ var ProcessorStack = Class("ProcessorStack", {
|
||||
|
||||
this.processors = processors;
|
||||
|
||||
return this.execute(result, options["timeout"] && options["timeoutlen"] === 0)
|
||||
if (processors.length)
|
||||
result = Events.KILL;
|
||||
else if (this.actions.length) {
|
||||
if (actions.length == 0)
|
||||
dactyl.beep();
|
||||
|
||||
if (modes.replaying && !events.waitForPageLoad())
|
||||
result = Events.KILL;
|
||||
else {
|
||||
for (var res = this.actions[0]; callable(res);)
|
||||
res = res();
|
||||
result = res === Events.PASS ? Events.PASS : Events.KILL;
|
||||
}
|
||||
}
|
||||
else if (result !== Events.KILL && processors.some(function (p) !p.main.passUnknown)) {
|
||||
result = Events.KILL;
|
||||
dactyl.beep();
|
||||
}
|
||||
else if (result === undefined)
|
||||
result = Events.PASS;
|
||||
|
||||
if (result !== Events.PASS)
|
||||
Events.kill(event);
|
||||
|
||||
if (result === Events.PASS || result === Events.ABORT)
|
||||
this.events.filter(function (e) e.getPreventDefault())
|
||||
.forEach(function (event, i) {
|
||||
if (event.originalTarget) {
|
||||
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
|
||||
events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true });
|
||||
}
|
||||
else if (i > 0)
|
||||
events.events.keypress.call(events, event);
|
||||
});
|
||||
return this.processors.length == 0;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -184,13 +157,12 @@ var KeyProcessor = Class("KeyProcessor", {
|
||||
return this.onKeyPress(event);
|
||||
},
|
||||
|
||||
execute: function execute(map, args)
|
||||
let (self = this)
|
||||
execute: function execute(map)
|
||||
let (self = this, args = arguments)
|
||||
function execute() {
|
||||
if (self.preExecute)
|
||||
self.preExecute.apply(self, args);
|
||||
let res = map.execute.call(map, update({ self: self.main.params.mappingSelf || self.main.mappingSelf || map },
|
||||
args))
|
||||
let res = map.execute.apply(map, Array.slice(args, 1));
|
||||
if (self.postExecute)
|
||||
self.postExecute.apply(self, args);
|
||||
return res;
|
||||
@@ -515,7 +487,6 @@ var Events = Module("events", {
|
||||
util.threadYield(1, true);
|
||||
|
||||
for (let [, evt_obj] in Iterator(events.fromString(keys))) {
|
||||
let now = Date.now();
|
||||
for (let type in values(["keydown", "keyup", "keypress"])) {
|
||||
let evt = update({}, evt_obj, { type: type });
|
||||
|
||||
@@ -616,14 +587,9 @@ var Events = Module("events", {
|
||||
* of x.
|
||||
*
|
||||
* @param {string} keys Messy form.
|
||||
* @param {boolean} unknownOk Whether unknown keys are passed
|
||||
* through rather than being converted to <lt>keyname>.
|
||||
* @default false
|
||||
* @returns {string} Canonical form.
|
||||
*/
|
||||
canonicalKeys: function (keys, unknownOk) {
|
||||
if (arguments.length === 1)
|
||||
unknownOk = true;
|
||||
return events.fromString(keys, unknownOk).map(events.closure.toString).join("");
|
||||
},
|
||||
|
||||
@@ -678,17 +644,11 @@ var Events = Module("events", {
|
||||
* <S-@> where @ is a non-case-changeable, non-space character.
|
||||
*
|
||||
* @param {string} keys The string to parse.
|
||||
* @param {boolean} unknownOk Whether unknown keys are passed
|
||||
* through rather than being converted to <lt>keyname>.
|
||||
* @default false
|
||||
* @returns {Array[Object]}
|
||||
*/
|
||||
fromString: function (input, unknownOk) {
|
||||
|
||||
if (arguments.length === 1)
|
||||
unknownOk = true;
|
||||
|
||||
let out = [];
|
||||
|
||||
let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g");
|
||||
let match;
|
||||
while ((match = re.exec(input))) {
|
||||
@@ -895,7 +855,10 @@ var Events = Module("events", {
|
||||
|
||||
isContentNode: function isContentNode(node) {
|
||||
let win = (node.ownerDocument || node).defaultView || node;
|
||||
return XPCNativeWrapper(win).top == content;
|
||||
for (; win; win = win.parent != win && win.parent)
|
||||
if (win == content)
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -904,24 +867,39 @@ var Events = Module("events", {
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
waitForPageLoad: function (time) {
|
||||
waitForPageLoad: function () {
|
||||
util.threadYield(true); // clear queue
|
||||
|
||||
if (buffer.loaded)
|
||||
if (buffer.loaded == 1)
|
||||
return true;
|
||||
|
||||
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
|
||||
|
||||
const maxWaitTime = (time || 25);
|
||||
const maxWaitTime = 25;
|
||||
let start = Date.now();
|
||||
let end = start + (maxWaitTime * 1000);
|
||||
let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option
|
||||
let now;
|
||||
while (now = Date.now(), now < end) {
|
||||
util.threadYield();
|
||||
|
||||
util.waitFor(function () !events.feedingKeys || buffer.loaded || Date.now() > end);
|
||||
if (!events.feedingKeys)
|
||||
return false;
|
||||
|
||||
if (buffer.loaded > 0) {
|
||||
util.sleep(250);
|
||||
break;
|
||||
}
|
||||
else
|
||||
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
|
||||
}
|
||||
commandline.clear();
|
||||
|
||||
// TODO: allow macros to be continued when page does not fully load with an option
|
||||
if (!buffer.loaded)
|
||||
dactyl.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped.");
|
||||
|
||||
// sometimes the input widget had focus when replaying a macro
|
||||
// maybe this call should be moved somewhere else?
|
||||
// dactyl.focusContent(true);
|
||||
|
||||
return buffer.loaded;
|
||||
},
|
||||
|
||||
@@ -1014,8 +992,7 @@ var Events = Module("events", {
|
||||
*/
|
||||
|
||||
input: function onInput(event) {
|
||||
if ("dactylKeyPress" in event.originalTarget)
|
||||
delete event.originalTarget.dactylKeyPress;
|
||||
delete event.originalTarget.dactylKeyPress;
|
||||
},
|
||||
|
||||
// this keypress handler gets always called first, even if e.g.
|
||||
@@ -1039,17 +1016,18 @@ var Events = Module("events", {
|
||||
let duringFeed = this.duringFeed || [];
|
||||
this.duringFeed = [];
|
||||
try {
|
||||
if (this.feedingEvent)
|
||||
if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) {
|
||||
for (let [k, v] in Iterator(this.feedingEvent))
|
||||
if (!(k in event))
|
||||
event[k] = v;
|
||||
this.feedingEvent = null;
|
||||
this.feedingEvent = null;
|
||||
}
|
||||
|
||||
let key = events.toString(event);
|
||||
if (!key)
|
||||
return null;
|
||||
|
||||
if (modes.recording && !event.isReplay)
|
||||
if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key)))
|
||||
events._macroKeys.push(key);
|
||||
|
||||
// feedingKeys needs to be separate from interrupted so
|
||||
@@ -1057,6 +1035,8 @@ var Events = Module("events", {
|
||||
// interrupting whatever it's started and a real <C-c>
|
||||
// interrupting our playback.
|
||||
if (events.feedingKeys && !event.isMacro) {
|
||||
if (!event.originalTarget)
|
||||
util.dumpStack();
|
||||
if (key == "<C-c>") {
|
||||
events.feedingKeys = false;
|
||||
if (modes.replaying) {
|
||||
@@ -1106,8 +1086,7 @@ var Events = Module("events", {
|
||||
|
||||
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
|
||||
|
||||
let main = { __proto__: mode.main, params: mode.params };
|
||||
let keyModes = array([mode.params.keyModes, main, mode.main.allBases]).flatten().compact();
|
||||
let keyModes = array([mode.params.keyModes, mode.main, mode.main.allBases]).flatten().compact();
|
||||
|
||||
this.processor = ProcessorStack(mode, hives, keyModes);
|
||||
}
|
||||
@@ -1189,6 +1168,10 @@ var Events = Module("events", {
|
||||
// access to the real focus target
|
||||
// Huh? --djk
|
||||
onFocusChange: function onFocusChange(event) {
|
||||
// command line has its own focus change handler
|
||||
if (modes.main == modes.COMMAND_LINE)
|
||||
return;
|
||||
|
||||
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
|
||||
|
||||
let win = window.document.commandDispatcher.focusedWindow;
|
||||
@@ -1210,7 +1193,7 @@ var Events = Module("events", {
|
||||
}
|
||||
|
||||
if (Events.isInputElement(elem)) {
|
||||
if (!modes.main.input)
|
||||
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
|
||||
modes.push(modes.INSERT);
|
||||
|
||||
if (hasHTMLDocument(win))
|
||||
@@ -1224,7 +1207,7 @@ var Events = Module("events", {
|
||||
if (modes.main == modes.VISUAL && elem.selectionEnd == elem.selectionStart)
|
||||
modes.pop();
|
||||
|
||||
if (!modes.main.input)
|
||||
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
|
||||
if (options["insertmode"])
|
||||
modes.push(modes.INSERT);
|
||||
else {
|
||||
@@ -1330,59 +1313,39 @@ var Events = Module("events", {
|
||||
};
|
||||
},
|
||||
mappings: function () {
|
||||
mappings.add(modes.MAIN,
|
||||
["<C-z>", "<pass-all-keys>"], "Temporarily ignore all " + config.appName + " key bindings",
|
||||
mappings.add(modes.all,
|
||||
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
|
||||
function () { modes.push(modes.PASS_THROUGH); });
|
||||
|
||||
mappings.add(modes.MAIN,
|
||||
["<C-v>", "<pass-next-key>"], "Pass through next key",
|
||||
mappings.add(modes.all,
|
||||
["<C-v>"], "Pass through next key",
|
||||
function () {
|
||||
if (modes.main == modes.QUOTE)
|
||||
return Events.PASS;
|
||||
modes.push(modes.QUOTE);
|
||||
});
|
||||
|
||||
mappings.add(modes.BASE,
|
||||
mappings.add(modes.all,
|
||||
["<Nop>"], "Do nothing",
|
||||
function () {});
|
||||
|
||||
// macros
|
||||
mappings.add([modes.COMMAND],
|
||||
["q", "<record-macro>"], "Record a key sequence into a macro",
|
||||
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
|
||||
["q"], "Record a key sequence into a macro",
|
||||
function ({ arg }) {
|
||||
events._macroKeys.pop();
|
||||
events[modes.recording ? "finishRecording" : "startRecording"](arg);
|
||||
},
|
||||
{ get arg() !modes.recording });
|
||||
|
||||
mappings.add([modes.COMMAND],
|
||||
["@", "<play-macro>"], "Play a macro",
|
||||
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
|
||||
["@"], "Play a macro",
|
||||
function ({ arg, count }) {
|
||||
count = Math.max(count, 1);
|
||||
while (count-- && events.playMacro(arg))
|
||||
;
|
||||
},
|
||||
{ arg: true, count: true });
|
||||
|
||||
mappings.add([modes.COMMAND],
|
||||
["<A-m>s", "<sleep>"], "Sleep for {count} milliseconds before continuing macro playback",
|
||||
function ({ command, count }) {
|
||||
let now = Date.now();
|
||||
dactyl.assert(count, "Count required for " + command);
|
||||
if (events.feedingKeys)
|
||||
util.sleep(count);
|
||||
},
|
||||
{ count: true });
|
||||
|
||||
mappings.add([modes.COMMAND],
|
||||
["<A-m>l", "<wait-for-page-load>"], "Wait for the current page to finish loading before continuing macro playback",
|
||||
function ({ count }) {
|
||||
if (events.feedingKeys && !events.waitForPageLoad(count)) {
|
||||
util.interrupted = true;
|
||||
throw Error("Interrupted");
|
||||
}
|
||||
},
|
||||
{ count: true });
|
||||
},
|
||||
options: function () {
|
||||
options.add(["passkeys", "pk"],
|
||||
@@ -1403,18 +1366,9 @@ var Events = Module("events", {
|
||||
return values;
|
||||
}
|
||||
});
|
||||
|
||||
options.add(["strictfocus", "sf"],
|
||||
"Prevent scripts from focusing input elements without user intervention",
|
||||
"boolean", true);
|
||||
|
||||
options.add(["timeout", "tmo"],
|
||||
"Whether to execute a shorter key command after a timeout when a longer command exists",
|
||||
"boolean", true);
|
||||
|
||||
options.add(["timeoutlen", "tmol"],
|
||||
"Maximum time (milliseconds) to wait for a longer key command when a shorter one exists",
|
||||
"number", 1000);
|
||||
},
|
||||
sanitizer: function () {
|
||||
sanitizer.addItem("macros", {
|
||||
|
||||
Reference in New Issue
Block a user