-
Notifications
You must be signed in to change notification settings - Fork 0
Desktop Integration
Voice Input does not grab keys. Hyprland runs small client commands that connect to the daemon control socket.
The installed snippet is:
source = ~/.local/share/voice-input/omarchy-hyprland-snippet.confIts default controls form one adjacent F-key group. The snippet does not alter Omarchy's stock Super+Ctrl+X Voxtype shortcut:
binddp = , F8, Cancel voice input, exec, voice-input record cancel
binddp = , F9, Toggle voice input, exec, voice-input record toggle
binddp = , F10, Restart active voice input, exec, voice-input record restartF10 is one daemon restart action: it discards and restarts an active recording and is ignored while idle. Do not replace it with a shell-level cancel && start sequence.
Toggle is the robust choice when release events are unreliable. Each accepted recording control is tagged with the daemon's current idle generation. Completing or cancelling a session advances that generation, so an older control that was queued behind finalization cannot act on the following idle/session generation; elapsed queue time is diagnostic only.
For push-to-talk, replace the F9 toggle with paired press and release bindings:
bind = , F9, exec, voice-input record start
bindr = , F9, exec, voice-input record stopThe release must reach Hyprland. If release is unreliable, return to toggle. hotkey.mode does not install a binding by itself; it affects generated output from:
voice-input setup hyprlandCancel without output, or restart an active session as one control action:
voice-input record cancel
voice-input record restartrecord restart reports success only after the replacement recording starts; when there is no active session, it returns an ignored-idle response.
The primary HUD is a separate service:
systemctl --user status voice-input-hud.service
systemctl --user restart voice-input-hud.serviceThe unit runs:
/usr/bin/qs --no-duplicate --path ~/.local/share/voice-input/quickshell
It sets XDG_RUNTIME_DIR=%t, loads the installation-compiled shaders/wavy-halo.frag.qsb, creates one PanelWindow variant per screen, displays only on the focused Hyprland monitor, uses the overlay layer, requests no keyboard focus, ignores exclusive-zone layout, and subtracts its complete input mask so it is click-through.
HUD placement is global configuration interpreted relative to the focused monitor: bottom-left, bottom-center, or bottom-right, the bottom margin, and X/Y offsets are applied within that monitor's current geometry. Changing focus moves visibility to the corresponding screen variant. Screen variants follow Quickshell's live screen list, and focused-monitor matching uses stable monitor names so focus changes, monitor removal/reconnection, and hot-plugged displays do not leave the HUD attached to a stale monitor object.
$XDG_RUNTIME_DIR/voice-input/state.json
$XDG_RUNTIME_DIR/voice-input/waveform.sock
One shared StateStore.qml serves all screen variants. It polls the daemon's atomically replaced JSON state every 50 ms during active phases and every 100 ms while idle, strictly validates the complete snapshot, rejects stale/malformed/partial snapshots, and updates the UI with one whole-object assignment. The shared Quickshell local socket independently receives newline-delimited waveform frames, enforces bounded framing plus the complete field/range/session/sequence schema, and atomically replaces the waveform frame only after validation; it reconnects after 400 ms when disconnected. There is no per-screen fallback poll. Long transcript display uses a four-line viewport anchored to the newest text, with an edge fade over older content.
The top-edge halo uses one frequency-envelope renderer across the active pipeline. Listening displays the twelve live microphone bands during speech and a calm virtual spectrum with processing-scale reach before speech and during pauses. Finalizing, Refining, and Sending share one continuously advancing virtual-band animation; their transitions change only color through a whole-halo crossfade, without resetting geometry, motion phase, cadence, or brightness or introducing a moving color boundary. An end-of-session waveform reset does not clear the final live frame until the runtime snapshot reaches idle. Listening hands that frame to Finalizing through a short fade to roughly five percent halo visibility and back, while the capsule itself remains visible. Transition progress is reset synchronously with the phase change rather than on the next animation frame, so the target processing profile cannot flash before the crossfade.
An integrated status row occupies additional space inside the bottom of the same capsule, leaving the transcript viewport unchanged. Its left side maps runtime phases to Arming, Listening, Finalizing, Refining, Sending, or Error; its right side shows effective recording time as MM:SS. The daemon starts that clock only when capture and ASR are ready and the phase enters recording, then freezes it when stop is accepted. Finalization and later stages retain the frozen duration, so arming and processing delays are excluded.
The HUD is exclusively Quickshell and remains independent from recognition:
- restarting the daemon does not restart Quickshell;
- a HUD crash does not stop ASR/output;
-
[hud].enabled = falsehides the HUD surface while the resident service can remain running; stop/disablevoice-input-hud.serviceto remove the process; - each state snapshot carries
hud_enabled,hud_margin_bottom,hud_height,hud_position,hud_offset_x, andhud_offset_y, and Quickshell honors those values.
Quickshell watches:
~/.config/omarchy/current/theme/colors.toml
It maps accent, foreground, color3, color5, and color1 to phase colors and retains built-in colors if the file cannot be read or parsed. This theme file is optional.
The current position and offsets live in config and runtime state:
voice-input hud position bottom-left
voice-input hud move right
voice-input hud move up 12
voice-input hud center
voice-input hud reset-
moveuses[hud].nudge_stepunless an amount is given. - Positive X moves right; positive Y raises the HUD.
-
centerselects bottom-center and clears X only. -
resetselects bottom-center and clears both offsets.
Suggested optional bindings:
bind = SUPER CTRL ALT, left, exec, voice-input hud move left
bind = SUPER CTRL ALT, right, exec, voice-input hud move right
bind = SUPER CTRL ALT, up, exec, voice-input hud move up
bind = SUPER CTRL ALT, down, exec, voice-input hud move down
bind = SUPER CTRL ALT, c, exec, voice-input hud centerSettings is a second Quickshell configuration, separate from the resident HUD:
~/.local/share/voice-input/quickshell-settings
Open it with:
voice-input settingsThe command first uses non-secret Quickshell IPC to activate an existing voiceInputSettings instance. Otherwise it starts:
/usr/bin/qs --daemonize --no-duplicate --path ~/.local/share/voice-input/quickshell-settings
This configuration creates a regular FloatingWindow, not a layer-shell panel, and exits when the window closes. It is on demand and has no systemd unit. The supplied Hyprland snippet floats and centers the Voice Input Settings client so the compositor honors its requested 900 × 620 utility-window size instead of tiling it across the workspace.
The full-height navigation opens Overview, Speech, Refinement, Output, Appearance, and Hotkey & state. Overview shows a read-only local service report and summaries of the current Speech, Refinement, Output, and Appearance configuration. Detail pages use flat desktop-form sections with clear dividers instead of a dashboard of nested cards. Provider-specific fields appear conditionally, and technical fields remain available in expandable Advanced sections on the relevant pages; no configuration field is discarded when hidden. The header provides an unsaved-change indicator, a language menu, a Reload settings overflow action, and Close.
Speech exposes the complete experimental Audio3 workflow: a separate acknowledgement gate, Regional/Custom routing and region, language hints, heartbeat, recognition presets and Custom controls, dynamic vocabulary, Native final-pass policy, and Streaming/Native endpoints, models, and timeout fields in Advanced. Selecting Audio3 alone does not acknowledge or enable the experiment. Save & restart validates and persists the full draft, updates requested credentials, and then asks systemd to restart voice-input.service; a persistence success and a credential/restart failure are reported as separate outcomes. It does not restart the resident HUD or the Settings window.
Its QML starts one dedicated Rust child backend and communicates only through protocol-version-1 NDJSON over inherited stdin/stdout; QML does not write TOML or credentials directly. Each request has a 30-second response deadline. Responses are capped at 2 MiB and accepted only after strict envelope and method-specific validation. A timeout, malformed/oversized/unexpected response, or backend exit invalidates pending operations and restarts the child with exponential delays from 250 ms up to 8 seconds, for at most six automatic attempts. Only a validated response resets that failure count; after the limit, Reload settings makes one manual attempt. These child-backend restarts do not imply that voice-input.service restarted or that a timed-out save failed—Settings reports that the operation may have completed, so reload before retrying. runtime.get returns only allowlisted service and runtime metadata for Overview; it is independent from configuration save state and does not claim provider connectivity.
The supplied JSONC fragment defines custom/voice-input:
voice-input setup waybarIts command is:
voice-input status --follow --format json --extended
status --follow checks state every 250 ms and prints only when the payload changes. The snippet maps phase classes to icons, opens Settings on right click, and opens the model setup wizard on left click.
Merge the object into your Waybar configuration and add custom/voice-input to the desired module list. The setup command prints a fragment; it does not edit an existing Waybar file or restart Waybar.
At recording start, the CLI asks Hyprland whether the active window is XWayland and passes a hint to the daemon. At output time the daemon queries again. If either the captured hint or current target says XWayland, it takes the XWayland route.
| Target | Clipboard provider | Paste shortcut |
|---|---|---|
| Wayland | wl-copy |
Hyprland dispatch sendshortcut
|
| XWayland | xclip |
xdotool |
All text uses the paste route regardless of length or legacy output.mode values. On native Wayland, both the transient transcript and restored clipboard payload are written with the wl-copy --sensitive hint. Only compatible clipboard managers are expected to keep those payloads out of history and avoid reordering them. The XWayland xclip route has no equivalent sensitive hint. The daemon backs up and restores the target clipboard around the paste operation and never creates a per-character synthetic keymap.
Hyprland discovery first tries the command socket and falls back to hyprctl. It can import HYPRLAND_INSTANCE_SIGNATURE, WAYLAND_DISPLAY, DISPLAY, and XDG_RUNTIME_DIR from the systemd user-manager environment. If a service cannot see the session, update that environment from your graphical-session startup and restart the service rather than hard-coding another user's runtime path.
See also: Troubleshooting · Configuration
English Home · 简体中文首页 · Source repository · MIT License
Voice Input is an independent community project. HUD and Settings require Quickshell 0.3+. Review Security and Privacy before enabling remote ASR, LLM refinement, pre-roll, agent context, or replacing credentials in Settings.
Voice Input 是独立的社区项目。HUD 和 Settings 需要 Quickshell 0.3 或更高版本。启用远程 ASR、LLM refinement、pre-roll、Agent 上下文,或者在 Settings 中替换 credential 前,请阅读安全与隐私。