niri accepts lowercase and mixed-case key names such as mod+shift+m, so the grep in the conflict check must ignore case too. strings comes from binutils, which is now said in the docs. Refs #45
5.5 KiB
niri and Dank Material Shell
Dictation on the niri Wayland compositor, including sessions running Dank Material Shell (DMS). There is no compositor-specific code: activation reuses the standard external triggers over D-Bus, and the tray is the standard StatusNotifier item.
Prerequisites
- Install Voculinux first: INSTALL.md.
- Open Settings → Shortcuts and turn on External Activation (Desktop
Shortcut). The built-in key listener stops, and a running instance
answers these triggers on the session bus (
com.voculinux.Voculinux):
voculinux --toggle # start if idle, stop if active
voculinux --start # start voice typing
voculinux --stop # stop voice typing
Keybind: toggle once per press
Either paste the bind below into the binds {} section of
~/.config/niri/config.kdl, or copy the ready-made include file and
reference it (easier to keep across config edits):
mkdir -p ~/.config/niri
cp resources/niri/voculinux.kdl ~/.config/niri/voculinux.kdl
then near the top of ~/.config/niri/config.kdl:
include "~/.config/niri/voculinux.kdl"
The shipped bind:
binds {
Mod+Shift+M repeat=false hotkey-overlay-title="Toggle Voculinux dictation" {
spawn "voculinux" "--toggle";
}
}
repeat=false is what makes it toggle once per press: without it, holding
the key repeats the spawn and toggles dictation back off before you let go.
Mod+Shift+M was free in niri's stock binds and in Dank Material Shell's
binds when this was written. To use another key, check it first (below).
The bind's title shows in niri's hotkey overlay (Mod+Shift+Slash). The
include file's commented --start / --stop variants use Mod+Shift+S and
Mod+Shift+X, which were free in the same way.
A key is either a compositor bind or an in-app Voculinux shortcut — never both. With External Activation on, do not keep the same key configured under Settings → Shortcuts; with it off, remove the niri bind. A key claimed on both sides fires twice: the compositor toggles over D-Bus while the internal listener fires on its own.
Check a key before you bind it
niri validate rejects a key bound twice inside one binds {} block, but
not a key bound in two blocks: a bind in your include file and one in
dms/binds.kdl both pass validation with no warning. So validation cannot
tell you whether a key is free. Check with grep, against your own config and
niri's stock binds. Run this before you copy the include file, or your own
toggle bind will match:
KEY_RE='(Mod|Super)\+Shift\+M([[:space:]{]|$)' # the key you want to check
grep -rniE --include='*.kdl' "$KEY_RE" ~/.config/niri/
strings "$(command -v niri)" | grep -iE "^[[:space:]]*(//[[:space:]]*)?$KEY_RE"
Matching ignores case, because niri also accepts mod+shift+m. strings
comes from binutils. The first command searches your config. ~/.config/niri/ holds
config.kdl and the DMS-managed dms/binds.kdl, which config.kdl
includes. --include='*.kdl' skips the binds.kdl.pre-* backups. If you
include files from elsewhere, add their paths. The second command searches
the stock defaults embedded in the niri binary. Commented lines match too, so
a hit can be a bind you have commented out. No output from either command
means the key is free. For a hit, remove or move the other bind, because niri does not warn
about a key bound in two places. Mod and Super are both checked because
niri reads Mod as Super on a TTY.
First dictation
There is no permission prompt on niri. The RemoteDesktop portal is never
used there, because no portal backend implements it, so your first dictation
types straight into the focused window through wtype with nothing to approve
or deny. Do not pin portal as a niri recommendation. IBus is excluded on
niri as well. The GNOME and KDE first-run behaviour is described in
USER_GUIDE.md.
Hold-to-talk stays in the app
A compositor bind only sends the key press; it never sees the release, so it can only toggle dictation. Push-to-talk (hold Right Alt, release to stop) keeps working only through the built-in Voculinux shortcut. This pack ships plain press binds only, so if you dictate with hold-to-talk, leave the in-app shortcut in place for it and use the niri bind for toggle.
Flatpak
voculinux is not on the host PATH from a sandbox, so bind the host D-Bus
call instead (same toggle, no extra sandbox spawned per press). The include
file carries a commented-out gdbus variant; background and the exact
command live under Running without device
access.
Tray under Dank Material Shell
Not yet observed on hardware: the StatusNotifier watcher bus name (or
names) DMS owns will be recorded with ticket #32, the hardware acceptance
run. The tray probe (_check_status_notifier_watcher in
src/vocalinux/ui/tray_indicator.py) currently accepts only
org.kde.StatusNotifierWatcher, and no probe code changed in this ticket.
The observation to record on #32, with a DMS session running:
busctl --user list | grep -i -E 'watcher|statusnotifier'
If DMS owns only org.freedesktop.StatusNotifierWatcher, the probe is
widened to accept both watcher names so no false missing-tray warning
appears, with behaviour tests covering both names. If
org.kde.StatusNotifierWatcher is present, the current probe stands and
the recorded output closes the question.