js: key bindings: ensure priorities for same-key bindings

Previously, if a script bound the same key more than once to different
functions (without removing the older bindings first), then pressing
the key triggered any of the bound functions arbitrarily[1].

Now the newest binding for the same key is always the active one.

If the newest binding is then removed - the second-newest will become
active, etc. (same mechanism as before, except that the active key
was not always the newest).

[1] The order was implementation-defined, however `for (name in obj)'
    happens to iterate. With mujs that's currently alhabetic order,
    and name is from mp.add_[forced_]key_binding(key, name...)
    or generated internally if name is not provided. So a binding with
    higher alphabetic `name' value had priority over lower name value.
This commit is contained in:
Avi Halachmi (:avih) 2021-07-21 13:29:27 +03:00
parent 1d1d1fbff9
commit 7f4841ff39
1 changed files with 14 additions and 4 deletions

View File

@ -276,9 +276,18 @@ function dispatch_key_binding(name, state, key_name) {
var binds_tid = 0; // flush timer id. actual id's are always true-thy
mp.flush_key_bindings = function flush_key_bindings() {
function prioritized_inputs(arr) {
return arr.sort(function(a, b) { return a.id > b.id })
.map(function(bind) { return bind.input });
}
var def = [], forced = [];
for (var n in binds) // Array.join() will later skip undefined .input
(binds[n].forced ? forced : def).push(binds[n].input);
for (var n in binds)
if (binds[n].input)
(binds[n].forced ? forced : def).push(binds[n]);
// newer bindings for the same key override/hide older ones
def = prioritized_inputs(def);
forced = prioritized_inputs(forced);
var sect = "input_" + mp.script_name;
mp.commandv("define-section", sect, def.join("\n"), "default");
@ -306,13 +315,14 @@ function add_binding(forced, key, name, fn, opts) {
fn = name;
name = false;
}
if (!name)
name = "__keybinding" + next_bid++; // new unique binding name
var key_data = {forced: forced};
switch (typeof opts) { // merge opts into key_data
case "string": key_data[opts] = true; break;
case "object": for (var o in opts) key_data[o] = opts[o];
}
key_data.id = next_bid++;
if (!name)
name = "__keybinding" + key_data.id; // new unique binding name
if (key_data.complex) {
mp.register_script_message(name, function msg_cb() {