Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f51d761
ci: modernize GH pages workflow
HigherOrderLogic Oct 19, 2026
aee25c9
Redraw important hotkeys when hide-not-bound changes
YaLTeR Oct 20, 2026
e19df12
render: Skip unsupported framebuffer effects
greyxp1 Oct 19, 2026
66a03cf
config: Fix panic on a bind key with a null byte
YaLTeR Oct 23, 2026
807681c
tests: Make keyboard enter print order-indepentent
YaLTeR Oct 24, 2026
600ec86
config: Simplify and reconcile binds parsing
YaLTeR Oct 25, 2026
1b16c76
binds: allow bare modifier keys and Mod as bind triggers
JustinSpedding Sep 22, 2026
fc3d54d
input: use an enum for the keyboard intercept result
JustinSpedding Sep 23, 2026
5331880
input: support press and release bind actions
JustinSpedding Sep 23, 2026
73e9687
input: add find_pointer_bind()
JustinSpedding Sep 22, 2026
ab05d6d
input: support release actions on mouse buttons
JustinSpedding Sep 22, 2026
eb9e029
input: support release actions on tablet stylus buttons
JustinSpedding Sep 22, 2026
3c6e215
tests/binds: Print events before any ops too
YaLTeR Sep 23, 2026
9828c09
input: add press and release bind tests
JustinSpedding Sep 23, 2026
b345b12
wiki: document press and release bindings
JustinSpedding Sep 22, 2026
cbd94d1
input: avoid unnecessary Bind and Action clones
JustinSpedding Oct 18, 2026
75db0a3
Make generic-modifier-only binds press-order-independent
YaLTeR Oct 24, 2026
9aa245c
input: Refactor screenshot binds to work like others
YaLTeR Oct 26, 2026
5f23510
tests/binds: Add more not-currently-working layouts tests
YaLTeR Sep 28, 2026
447cf77
tests/binds: Add some more layouts tests
YaLTeR Oct 26, 2026
9d8f4f8
tests/binds: Add two more layouts tests
YaLTeR Oct 26, 2026
3ab862e
tests/binds: Add more layouts tests
YaLTeR Oct 27, 2026
1b1dc6d
input: Add Tracy span to find_bind()
YaLTeR Oct 27, 2026
ca8777d
input: Rename raw arg to key
YaLTeR Oct 27, 2026
2f15c28
input: Pass Modifiers instead of ModifiersState
YaLTeR Oct 27, 2026
3bc662c
input: Use Option<Keysym> for modified
YaLTeR Oct 27, 2026
cd45650
input: Check modified for hardcoded binds instead of raw
YaLTeR Oct 27, 2026
74bcbf1
input: Extract find() closure in find_bind()
YaLTeR Oct 27, 2026
fcbc971
input: Search for binds with modified, raw, and raw_ascii
YaLTeR Oct 27, 2026
b22eb84
backend/winit: Release held keys on lost focus
broli Oct 23, 2026
803462c
backend/winit: Hide host cursor in nested sessions by default
broli Oct 30, 2026
30fae8d
config: make expand home path util generic over span type
HigherOrderLogic Oct 19, 2026
a8cb0a3
config: return result when expand path instead of option
HigherOrderLogic Oct 20, 2026
2ffab3f
config: watch xkb config file for change
HigherOrderLogic Oct 20, 2026
417530f
input: Commit MRU on ForwardAndHandle
YaLTeR Oct 30, 2026
7dd8055
input: Handle hardcoded overview binds though make_binds_iter()
YaLTeR Oct 31, 2026
2ae55ff
input: Flatten if-else chain in should_intercept_key()
JustinSpedding Oct 29, 2026
a508e3b
input: Add pass-through property to binds
JustinSpedding Oct 29, 2026
157e11b
config/binds: Extract Trigger::is_scroll()
YaLTeR Oct 31, 2026
8e7b574
input: Pass through all keyboard release-only binds by default
YaLTeR Oct 31, 2026
71007e3
merge up to upstream commit 8e7b574
AmmoniumX Oct 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,10 @@ jobs:
with:
path: docs/wiki/

publish-docs:
build-docs:
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && (github.repository == 'niri-wm/niri' || github.repository == 'barrulus/biri')
needs:
- test
permissions:
contents: write
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
Expand All @@ -376,14 +374,23 @@ jobs:
- name: Generate rustdoc documentation
run: cargo doc --no-deps -p niri-ipc

- run: mkdir -p publish/niri_ipc
- run: cp -r ./target/doc/* ./publish/
- run: cp -r ./docs/site/* ./publish/
- run: |
mkdir -p publish/niri_ipc
cp -r ./target/doc/* ./publish/
cp -r ./docs/site/* ./publish/

- name: Deploy documentation
if: github.ref == 'refs/heads/main'
uses: peaceiris/actions-gh-pages@v4
- name: Upload pages artifact
uses: actions/upload-pages-artifact@v5
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./publish
force_orphan: true
path: ./publish

publish-docs:
runs-on: ubuntu-24.04
needs:
- build-docs
permissions:
id-token: write
pages: write
steps:
- name: Deploy artifact to GitHub Pages
uses: actions/deploy-pages@v5
13 changes: 13 additions & 0 deletions docs/wiki/Configuration:-Debug-Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ debug {
skip-cursor-only-updates-during-vrr
deactivate-unfocused-windows
disable-10bit-output
nested-show-host-cursor
}

binds {
Expand Down Expand Up @@ -399,3 +400,15 @@ binds {
Mod+Shift+Ctrl+D { debug-toggle-damage; }
}
```

### `nested-show-host-cursor`

<sup>Since: next release</sup>

Shows the host cursor when running niri as a nested window, on top of the nested niri cursor.

```kdl
debug {
nested-show-host-cursor
}
```
162 changes: 152 additions & 10 deletions docs/wiki/Configuration:-Key-Bindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ binds {
}
```

The hotkey consists of modifiers separated by `+` signs, followed by an XKB key name in the end.
The hotkey consists of modifiers separated by `+` signs, followed by a trigger key in the end.
The trigger key can be either an XKB key name or <sup>Since: next release</sup> a modifier.

Valid modifiers are:

Expand All @@ -31,6 +32,38 @@ Valid modifiers are:
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.

Specific left or right modifier keys like `Alt_L` or `Alt_R` can be used as triggers, but not as modifiers:

```kdl
binds {
// Valid:
Ctrl+Alt_L { spawn "alacritty"; }

// Invalid:
// Alt_L+Ctrl { spawn "alacritty"; }

// Also, this is equivalent to just Alt_L
// because Alt_L implies the Alt modifier:
Alt+Alt_L { spawn "the Alt here is unnecessary but allowed"; }
// This is the same:
// Alt_L { spawn "alacritty"; }
}
```

<sup>Since: next release</sup> Generic modifiers like `Shift` or `Alt` can be used as trigger keys.
Binds consisting only of generic modifiers do not depend on the order that you press them:

```kdl
binds {
// Will trigger both when pressing Alt then Shift, and Shift then Alt.
Alt+Shift { spawn "alacritty"; }

// The trigger is not a generic modifier, so
// you need to press it last. Only Ctrl then Left Shift will work.
Ctrl+Shift_L { spawn "alacritty"; }
}
```

<sup>Since: 25.05</sup> You can customize the `Mod` key [in the `input` section of the config](./Configuration:-Input.md#mod-key-mod-key-nested).

> [!TIP]
Expand All @@ -53,14 +86,25 @@ For this reason, most of the default keys use the `Mod` modifier.
> 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.
>
> Keep in mind that binding shifted keys requires spelling out Shift and the unshifted version of the key, according to your XKB layout.
> For example, on the US QWERTY layout, <kbd>&lt;</kbd> is on <kbd>Shift</kbd> + <kbd>,</kbd>, so to bind it, you spell out something like `Mod+Shift+Comma`.
> Keep in mind that binding a key requires spelling out the modifiers that you hold when typing it.
> So, symbols that you type while holding Shift need the Shift modifier in the corresponding binding.
> For example, on the US QWERTY layout, <kbd>&lt;</kbd> is on <kbd>Shift</kbd> + <kbd>,</kbd>, so to bind it, you spell out something like `Mod+Shift+Less` or `Mod+Shift+Comma` (just `Mod+Less` will not work).
>
> As another example, if you've configured the French [BÉPO](https://en.wikipedia.org/wiki/B%C3%89PO) XKB layout, your <kbd>&lt;</kbd> is on <kbd>AltGr</kbd> + <kbd>«</kbd>.
> <kbd>AltGr</kbd> is `ISO_Level3_Shift`, or equivalently `Mod5`, so to bind it, you spell out something like `Mod+Mod5+guillemotleft`.
> <kbd>AltGr</kbd> is `ISO_Level3_Shift`, or equivalently `Mod5`, so to bind it, you spell out something like `Mod+Mod5+Less` or `Mod+Mod5+guillemotleft`.
>
> When resolving latin keys, niri will search for the *first* configured XKB layout that has the latin key.
> So for example with US QWERTY and RU layouts configured, US QWERTY will be used for latin binds.
> When resolving ASCII (latin) keys, niri will search for the *first* configured XKB layout that has the ASCII key.
> So for example with US Colemak and RU layouts configured, US Colemak will be used for ASCII binds.
>
> Keys from the current layout have priority though.
> For example, if you have US QWERTY and Russian layouts, and both `Mod+Z` and `Mod+Cyrillic_ya` binds, then on Russian the `Mod+Cyrillic_ya` bind will trigger, while on US, the `Mod+Z` bind will trigger.
>
> Also, binds that spell out the typed character have priority over binds that spell out an unshifted character.
> For example, on US QWERTY, `Mod+Shift+At` will have priority over `Mod+Shift+2` if both are configured.
>
> <sup>Since: next release</sup> You used to need to spell out the *unshifted* version of the trigger key.
> So to bind <kbd>&lt;</kbd> on US QWERTY you could use only `Mod+Shift+Comma` (since <kbd>,</kbd> is the unshifted version of that key).
> This is no longer the case: you can spell out either version of the key.

<sup>Since: 0.1.8</sup> 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`:
Expand All @@ -81,6 +125,93 @@ binds {

This is mostly useful for the scroll bindings.

### Press and Release Bindings

<sup>Since: next release</sup>

Binds can be set to trigger on key press, on key release, or both.
By default, binds trigger on key press.
You can change it using `press {}` and `release {}` blocks:

```kdl
binds {
// Trigger on press (default behavior).
Mod+T { spawn "alacritty"; }

// Trigger on release.
// Press and release Mod by itself to open the overview.
Mod {
release { toggle-overview; }
}

// Trigger on both press and release with different actions.
//
// If the press action runs, the release action is guaranteed to run,
// no matter how you release the keys.
// You can safely use these binds for things like push-to-talk.
Control_R {
press { spawn "notify-send" "Enable push-to-talk"; }
release { spawn "notify-send" "Disable push-to-talk"; }
}

// Release binds trigger only if you don't press anything else in between.
// So, an Alt+Shift bind like this still lets you hit
// Alt+Shift+arrows and other shortcuts in applications.
Alt+Shift {
release { switch-layout "next"; }
}
}
```

Release bindings are especially useful when you want to bind a modifier key.
A normal press bind would effectively prevent you from having any other bind containing that modifier.

Release-only binds only trigger when you don't press anything else while holding it.
If you have a release-only `Mod` bind from the example above, and press any other key or mouse button while holding `Mod`, the bind will not trigger (the overview won't open).

In bindings with both press and release, the release action is guaranteed to trigger if the press action triggers.
So, your push-to-talk press-release binding will never get stuck pressed, no matter how you release the keys.

By default, any bind with both press and release action does not repeat.
You can explicitly set `repeat=true` if needed:

```kdl
binds {
// Doesn't repeat automatically
// because it has a release {} section.
Mod+Shift+Q repeat=true {
press { spawn "notify-send" "Pressed (repeating)"; }
release { spawn "notify-send" "Released"; }
}
}
```

By default, bound key presses/releases are not passed to applications.
You can set `pass-through=true` if you want applications to see the bound key:

```kdl
binds {
// Let applications see the Alt key presses/releases.
Alt pass-through=true {
press { spawn "notify-send" "Pressed"; }
release { spawn "notify-send" "Released"; }
}
}
```

Keyboard release-only bindings are passed through by default though.
You can set `pass-through=false` on those if you don't like that:

```kdl
binds {
// Do not pass Mod press/release event to applications.
// (They will still see the modifiers event.)
Mod pass-through=false {
release { toggle-overview; }
}
}
```

### Scroll Bindings

You can bind mouse wheel scroll ticks using the following syntax.
Expand Down Expand Up @@ -199,12 +330,23 @@ binds {
}
```

`press {}` and `release {}` blocks can also hold several actions each.

```kdl
binds {
Mod+P {
press { spawn "notify-send" "Recording"; spawn "pw-record" "/tmp/out.wav"; }
release { spawn "pkill" "pw-record"; }
}
}
```

Two limitations apply to multi-action binds:

- They never appear in the hotkey overlay, and `hotkey-overlay-title` has no effect on
them.
- `allow-when-locked=true` is accepted only when *every* action in the bind is `spawn`
or `spawn-sh`. Otherwise the flag would let a non-spawn action run from the lock
- A press or release with several actions never appears in the hotkey overlay, and
`hotkey-overlay-title` has no effect on it.
- `allow-when-locked=true` is accepted only when *every* action in the bind, on press
and on release, is `spawn` or `spawn-sh`. Otherwise the flag would let a non-spawn action run from the lock
screen.

If an action cannot run — for example a non-spawn action on a locked screen — it is
Expand Down
18 changes: 17 additions & 1 deletion docs/wiki/Configuration:-Recent-Windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,23 @@ recent-windows {
The recent windows binds have lower precedence than the [normal binds](./Configuration:-Key-Bindings.md), meaning that if you have <kbd>Alt</kbd><kbd>Tab</kbd> bound to something else in the normal binds, the `recent-windows` bind won't work.
In this case, you can remove the conflicting normal bind.

All binds in this section must have a modifier key like <kbd>Alt</kbd> or <kbd>Mod</kbd> because the recent windows switcher remains open only while you hold any modifier key.
All binds in this section must have a modifier key like <kbd>Alt</kbd> or <kbd>Mod</kbd> (that isn't the same as the trigger key) because the recent windows switcher remains open only while you hold any modifier key.

```kdl
recent-windows {
binds {
// Allowed: has a modifier, two keys.
Ctrl+Alt { next-window; }

// Not allowed: only a single key.
// Alt { next-window; }

// Not allowed: modifier matches the key
// (effectively only a single key).
// Alt+Alt_L { next-window; }
}
}
```

#### Bindings inside the switcher

Expand Down
8 changes: 6 additions & 2 deletions niri-config/src/animations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,12 @@ fn parse_custom_shader_path<S: knuffel::traits::ErrorSpan>(
for (name, val) in &spanned.properties {
if &***name == "path" {
let path_val = knuffel::traits::DecodeScalar::decode(val, ctx)?;
let Some(path) = expand_home_path(path_val, spanned, ctx) else {
continue;
let path = match expand_home_path(path_val, spanned, ctx) {
Ok(p) => p,
Err(e) => {
ctx.emit_error(e);
continue;
}
};

let includes = ctx.get::<Rc<RefCell<Includes>>>().unwrap();
Expand Down
Loading
Loading