-
-
Notifications
You must be signed in to change notification settings - Fork 145
Configuration: Key Bindings
Key bindings are declared in the binds {}
section of the config.
Note
This is one of the few sections that does not get automatically filled with defaults if you omit it, so make sure to copy it from the default config.
Each bind is a hotkey followed by one action enclosed in curly brackets. For example:
binds {
Mod+Left { focus-column-left; }
Super+Alt+L { spawn "swaylock"; }
}
The hotkey consists of modifiers separated by +
signs, followed by an XKB key name in the end.
Valid modifiers are:
-
Ctrl
orControl
; -
Shift
; -
Alt
; -
Super
orWin
; -
ISO_Level3_Shift
orMod5
—this is the AltGr key on certain layouts; -
ISO_Level5_Shift
: can be used with an xkb lv5 option likelv5:caps_switch
; -
Mod
.
Mod
is a special modifier that is equal to Super
when running niri on a TTY, and to Alt
when running niri as a nested winit window.
This way, you can test niri in a window without causing too many conflicts with the host compositor's key bindings.
For this reason, most of the default keys use the Mod
modifier.
Tip
To find an XKB name for a particular key, you may use a program like wev
.
Open it from a terminal and press the key that you want to detect. In the terminal, you will see output like this:
[14: wl_keyboard] key: serial: 757775; time: 44940343; key: 113; state: 1 (pressed)
sym: Left (65361), utf8: ''
[14: wl_keyboard] key: serial: 757776; time: 44940432; key: 113; state: 0 (released)
sym: Left (65361), utf8: ''
[14: wl_keyboard] key: serial: 757777; time: 44940753; key: 114; state: 1 (pressed)
sym: Right (65363), utf8: ''
[14: wl_keyboard] key: serial: 757778; time: 44940846; key: 114; state: 0 (released)
sym: Right (65363), utf8: ''
Here, look at sym: Left
and sym: Right
: these are the key names.
I was pressing the left and the right arrow in this example.
Since: 0.1.8 Binds will repeat by default (i.e. holding down a bind will make it trigger repeatedly).
You can disable that for specific binds with repeat=false
:
binds {
Mod+T repeat=false { spawn "alacritty"; }
}
Binds can also have a cooldown, which will rate-limit the bind and prevent it from repeatedly triggering too quickly.
binds {
Mod+T cooldown-ms=500 { spawn "alacritty"; }
}
This is mostly useful for the scroll bindings.
You can bind mouse wheel scroll ticks using the following syntax.
These binds will change direction based on the natural-scroll
setting.
binds {
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
Mod+WheelScrollRight { focus-column-right; }
Mod+WheelScrollLeft { focus-column-left; }
}
Similarly, you can bind touchpad scroll "ticks". Touchpad scrolling is continuous, so for these binds it is split into discrete intervals based on distance travelled.
These binds are also affected by touchpad's natural-scroll
, so these example binds are "inverted", since niri has natural-scroll
enabled for touchpads by default.
binds {
Mod+TouchpadScrollDown { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.02+"; }
Mod+TouchpadScrollUp { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.02-"; }
}
Both mouse wheel and touchpad scroll binds will prevent applications from receiving any scroll events when their modifiers are held down.
For example, if you have a Mod+WheelScrollDown
bind, then while holding Mod
, all mouse wheel scrolling will be consumed by niri.
Since: 25.01
You can bind mouse clicks using the following syntax.
binds {
Mod+MouseLeft { close-window; }
Mod+MouseRight { close-window; }
Mod+MouseMiddle { close-window; }
Mod+MouseForward { close-window; }
Mod+MouseBack { close-window; }
}
Mouse clicks operate on the window that was focused at the time of the click, not the window you're clicking.
Note that binding Mod+MouseLeft
or Mod+MouseRight
will override the corresponding gesture (moving or resizing the window).
Every action that you can bind is also available for programmatic invocation via niri msg action
.
Run niri msg action
to get a full list of actions along with their short descriptions.
Here are a few actions that benefit from more explanation.
Run a program.
spawn
accepts a path to the program binary as the first argument, followed by arguments to the program.
For example:
binds {
// Run alacritty.
Mod+T { spawn "alacritty"; }
// Run `wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+`.
XF86AudioRaiseVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"; }
}
Tip
Since: 0.1.5
Spawn bindings have a special allow-when-locked=true
property that makes them work even while the session is locked:
binds {
// This mute bind will work even when the session is locked.
XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
}
Currently, niri does not use a shell to run commands, which means that you need to manually separate arguments.
binds {
// Correct: every argument is in its own quotes.
Mod+T { spawn "alacritty" "-e" "/usr/bin/fish"; }
// Wrong: will interpret the whole `alacritty -e /usr/bin/fish` string as the binary path.
Mod+D { spawn "alacritty -e /usr/bin/fish"; }
// Wrong: will pass `-e /usr/bin/fish` as one argument, which alacritty won't understand.
Mod+Q { spawn "alacritty" "-e /usr/bin/fish"; }
}
This also means that you cannot expand environment variables or ~
.
If you need this, you can run the command through a shell manually.
binds {
// Wrong: no shell expansion here. These strings will be passed literally to the program.
Mod+T { spawn "grim" "-o" "$MAIN_OUTPUT" "~/screenshot.png"; }
// Correct: run this through a shell manually so that it can expand the arguments.
// Note that the entire command is passed as a SINGLE argument,
// because shell will do its own argument splitting by whitespace.
Mod+D { spawn "sh" "-c" "grim -o $MAIN_OUTPUT ~/screenshot.png"; }
// You can also use a shell to run multiple commands,
// use pipes, process substitution, and so on.
Mod+Q { spawn "sh" "-c" "notify-send clipboard \"$(wl-paste)\""; }
}
As a special case, niri will expand ~
to the home directory only at the beginning of the program name.
binds {
// This will work: one ~ at the very beginning.
Mod+T { spawn "~/scripts/do-something.sh"; }
}
Exit niri after showing a confirmation dialog to avoid accidentally triggering it.
binds {
Mod+Shift+E { quit; }
}
If you want to skip the confirmation dialog, set the flag like so:
binds {
Mod+Shift+E { quit skip-confirmation=true; }
}
Since: 0.1.6
Freeze the screen for a brief moment then crossfade to the new contents.
binds {
Mod+Return { do-screen-transition; }
}
This action is mainly useful to trigger from scripts changing the system theme or style (between light and dark for example). It makes transitions like this, where windows change their style one by one, look smooth and synchronized.
For example, using the GNOME color scheme setting:
niri msg action do-screen-transition
dconf write /org/gnome/desktop/interface/color-scheme "\"prefer-dark\""
By default, the screen is frozen for 250 ms to give windows time to redraw, before the crossfade. You can set this delay like this:
binds {
Mod+Return { do-screen-transition delay-ms=100; }
}
Or, in scripts:
niri msg action do-screen-transition --delay-ms 100
- Getting Started
- Example systemd Setup
- Important Software
- Floating Windows
- Layer‐Shell Components
- IPC,
niri msg
- Application-Specific Issues
- Xwayland
- Gestures
- Packaging niri
- FAQ