YaLTeR/niri

Putting several binds on the same key will show incorrect values in hotkey overlay

sodiboo opened this issue · 2 comments

The main cause of this issue is that when creating two binds of the same key, niri doesn't complain at all. Notably, it even remembers both binds after parsing. It then handles this inconsistently. The code is not necessarily broken, but the root cause is that this code is written under the incorrect assumptions that every key corresponds to at most one Bind (potentially zero, if unbound of course), and that every bind contains exactly one Action.

The hotkey overlay informs a user of the configured hotkeys, nonexhaustively. Mainly, it shows only one keybind per action. To do this, it searches for each action separately.

The actual keyboard handler will search for the key, and perform the first action it finds. This is not necessarily the keybind that the hotkey overlay shows for this action, which is fine, but what's not fine is that it's also not necessarily the action the hotkey overlay shows for this keybind, or even necessarily any action at all.

Here's a minimal config displaying two behaviours that i don't think are very intuitive.

binds {
    Mod+A { quit skip-confirmation=true; }
    Mod+A { spawn "alacritty"; }
    Mod+Y {}
    Mod+Y { spawn "fuzzel"; }
    Mod+Q { quit; }
}

Pretend you are a user who does not remember their config. The overlay is a quick reminder of what each button does, right?

image

Niri does elide "redundant" keybinds. It's expected that there may be more keybinds not listed.

This user, who knows how the hotkey overlay works, knows that at least the following binds exist:

  • Mod+Q will exit niri
  • Mod+A will spawn a terminal
  • Mod+Y will spawn an application launcher

Mod+Q really does work as they expect! It will close niri. Nothing strange there.

They want to get something done, so they press Mod+Y and nothing happens. Niri does not perform the action it promised. They cannot launch applications.

This is an advanced user who is comfortable with the terminal, so they figure they can figure out what's happening here. So they press Mod+A, as the hotkey overlay told them. Niri performs the wrong action. Our user is confused as to why they have been sent back to their login manager.

A related problem stemming from the same root cause is that you can currently bind multiple actions in the same block, like so:

binds {
    Mod+A { spawn "alacritty"; spawn "fuzzel"; }
}

In this case, niri just ignores the second action in the block completely. It never appears in hotkey overlays, and it is never executed. The same interactions with duplicate binds can still occur, though.

System Information

  • niri version: niri 0.1.2 (niri-flake at 494e98c)

I actually have been considering the multiple single bind, multiple action problem.

As a user and someone just farting around in rust and never having had much of a C background just Java I didn't know where to go and whether to post.

I really wish it could just be that ";" was "end of command" && "logical OR" such that if the first command failed or was unable to act, the second command could act. My example would be:

Mod+Left comes to the first stack in the second workspace on my right and then seamlessly moves to the next visible workspace on my left. (i.e from right to left monitor).

The above could apply to window movement as well.

It also means you could bind window close to a key and have it fallback to kill the process if that fails.

Guess I just wanted to through my 2-cents worth in. I'll continue futz around on my own copy of Niri with this goal.

I really wish it could just be that ";" was "end of command"

Well, the ; in the syntax is really just KDL for "end of node". A linebreak works just the same, but ; is required if there are more tokens on the same line. But yeah, i understand what you mean; that we could define several commands in succession.

"logical OR" such that if the first command failed or was unable to act, the second command could act.

This does seem like an interesting idea. Maybe make a feature request? Ultimately, this issue is about the currently incorrect parsing of binds. I don't necessarily think it should always be that only one bind can be assigned per key; but that's just straight up how it is at the moment, even though the config parser would seem to suggest otherwise (because, it does not parse what the rest of the code expects)

Mod+Left comes to the first stack in the second workspace on my right and then seamlessly moves to the next visible workspace on my left. (i.e from right to left monitor).

The above could apply to window movement as well.

It also means you could bind window close to a key and have it fallback to kill the process if that fails.

This is definitely an interesting idea, and also, honestly, that movement should maybe just be a built in bind. But in general, i do think some of these would be better served by improving the capabilities of niri msg, so that it can output information about the action it just performed. Then, you could script whatever you want, with any kind of logic, as long as the appropriate inputs to this logic is actually emitted by niri msg