From 0da4cca552c0a0ea89505a10d58dc9e7db1caede Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Wed, 26 Jan 2011 09:46:16 -0500 Subject: [PATCH] Implement 'timeout' and 'timeoutlen'. --HG-- branch : key-processing --- common/content/events.js | 157 ++++++++++++++++++--------------- common/locale/en-US/repeat.xml | 5 +- 2 files changed, 90 insertions(+), 72 deletions(-) diff --git a/common/content/events.js b/common/content/events.js index bd9f6802..cdc5f7c3 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -11,12 +11,14 @@ 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; @@ -31,9 +33,70 @@ 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); @@ -70,9 +133,7 @@ var ProcessorStack = Class("ProcessorStack", { dbg("ACTIONS: " + actions.length + " " + this.actions.length); dbg("PROCESSORS:", processors); - if (!processors.some(function (p) p.main.ownsBuffer)) - statusline.updateInputBuffer(processors.length ? this.buffer : ""); - + this._actions = actions; this.actions = actions.concat(this.actions); if (result === Events.KILL) @@ -87,43 +148,7 @@ var ProcessorStack = Class("ProcessorStack", { this.processors = processors; - if (processors.length) - result = Events.KILL; - else if (this.actions.length) { - if (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 && - 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(event); - - 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); - }); - return this.processors.length == 0; + return this.execute(result, options["timeout"] && options["timeoutlen"] === 0) } }); @@ -871,10 +896,7 @@ var Events = Module("events", { isContentNode: function isContentNode(node) { let win = (node.ownerDocument || node).defaultView || node; - for (; win; win = win.parent != win && win.parent) - if (win == content) - return true; - return false; + return XPCNativeWrapper(win).top == content; }, /** @@ -883,39 +905,24 @@ var Events = Module("events", { * * @returns {boolean} */ - waitForPageLoad: function () { + waitForPageLoad: function (time) { util.threadYield(true); // clear queue - if (buffer.loaded == 1) + if (buffer.loaded) return true; - const maxWaitTime = 25; + dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE); + + const maxWaitTime = (time || 25); let start = Date.now(); - let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option - let now; - while (now = Date.now(), now < end) { - util.threadYield(); + let end = start + (maxWaitTime * 1000); - if (!events.feedingKeys) - return false; - - if (buffer.loaded > 0) { - util.sleep(250); - break; - } - else - dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE); - } + util.waitFor(function () !events.feedingKeys || buffer.loaded || Date.now() > end); 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; }, @@ -1368,14 +1375,15 @@ var Events = Module("events", { }, { count: true }); - mappings.add([modes.MAIN], + mappings.add([modes.COMMAND], ["l", ""], "Wait for the current page to finish loading before continuing macro playback", - function () { - if (!events.waitForPageLoad()) { + function ({ count }) { + if (events.feedingKeys && !events.waitForPageLoad(count)) { util.interrupted = true; throw Error("Interrupted"); } - }); + }, + { count: true }); }, options: function () { options.add(["passkeys", "pk"], @@ -1396,9 +1404,18 @@ var Events = Module("events", { return values; } }); + options.add(["strictfocus", "sf"], "Prevent scripts from focusing input elements without user intervention", "boolean", true); + + options.add(["timeout", "to"], + "Whether to execute a shorter key command after a timeout when a longer command exists", + "boolean", true); + + options.add(["timeoutlen", "tm"], + "Maximum time to wait for a longer key command when a shorter command exists", + "number", 1000); }, sanitizer: function () { sanitizer.addItem("macros", { diff --git a/common/locale/en-US/repeat.xml b/common/locale/en-US/repeat.xml index 8070ce21..d9470eff 100644 --- a/common/locale/en-US/repeat.xml +++ b/common/locale/en-US/repeat.xml @@ -122,11 +122,12 @@ l]]> - l]]> + countl]]>

Wait for the current page to finish loading before resuming - playback. + playback. If count is given, wait no more than + count seconds. Otherwise wait no more than 25 seconds.