Skip to content

Add com.openwhispr.App D-Bus endpoint for global shortcuts on Linux#1024

Open
sochotnicky wants to merge 3 commits into
OpenWhispr:mainfrom
sochotnicky:wayland-force-dbus
Open

Add com.openwhispr.App D-Bus endpoint for global shortcuts on Linux#1024
sochotnicky wants to merge 3 commits into
OpenWhispr:mainfrom
sochotnicky:wayland-force-dbus

Conversation

@sochotnicky

@sochotnicky sochotnicky commented Jun 30, 2026

Copy link
Copy Markdown

Adds a com.openwhispr.App session D-Bus endpoint for global shortcuts on Linux, since Electron's globalShortcut can't register hotkeys on many Wayland compositors (e.g. Sway). GNOME already drove shortcuts through this D-Bus interface; this extracts it into one shared, compositor-agnostic service and makes it available everywhere.

  • dbusToggleService.js (new): single owner of com.openwhispr.App and its methods — Toggle/ToggleAgent/ToggleMeeting/ToggleVoiceAgent (tap) plus StartDictation/StopDictation (push-to-talk).
  • Universal on Linux: the endpoint starts on every session (X11 + Wayland). Each desktop layers its own keybinding auto-registration on top and routes through it — GNOME gsettings, Hyprland hyprctl, wlroots manual dbus-send binds; KDE/X11 keep their native mechanism with the bus additionally available.
  • gnomeShortcut.js / hyprlandShortcut.js: reduced to keybinding registrars (Hyprland's duplicate bus/interface removed).
  • Having the bus up does not force tap-to-talk — X11 keeps globalShortcut + push-to-talk.
  • Push-to-talk needs a compositor that can bind key release (Sway bindsym --release, Hyprland bindr).
  • Docs: CLAUDE.md §15a.

Wayland has no portable global-hotkey API, and Electron's globalShortcut can't
register hotkeys on wlroots compositors (e.g. Sway). Expose a session-bus
service, com.openwhispr.App, whose four no-arg methods map to the app's actions;
the user binds keys in their compositor to dbus-send those methods.

- dbusToggleService.js: compositor-agnostic owner of the com.openwhispr.App
  service and its Toggle/ToggleAgent/ToggleMeeting/ToggleVoiceAgent methods.
  Single source of truth for the interface; no gsettings/compositor logic.
- gnomeShortcut.js: composes DBusToggleService instead of carrying its own
  duplicate interface; GNOME gsettings behavior and public API unchanged.
- hotkeyManager.js: auto-enables the endpoint and skips compositor key
  registration on Linux Wayland sessions with no native integration (not
  GNOME/KDE/Hyprland — e.g. Sway). Secondary slots (agent/voiceAgent/meeting)
  wire their callbacks to the matching D-Bus methods, and isUsingNativeShortcut()
  reports true so the UI forces tap-to-talk (a single dbus-send can't express
  push/release).
- main.js: wire agent/voiceAgent/meeting callbacks so all methods work even with
  no in-app hotkey configured.
- Document in CLAUDE.md (section 15a).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Toggle* methods are momentary (one fire = tap), so they can't express
push-to-talk. Add a StartDictation/StopDictation pair to the com.openwhispr.App
D-Bus interface: bind key-press to StartDictation and key-release to StopDictation
in the compositor (Sway `bindsym` + `bindsym --release`) for hold-to-talk.

- dbusToggleService: StartDictation/StopDictation methods + setters
- hotkeyManager.setDbusToggleCallbacks: accept startDictation/stopDictation
- main.js: wire them to windowManager.startWindowsPushToTalk() /
  handleWindowsPushKeyUp() — the same PTT primitives the native key listener uses
  (show panel, start after a short hold, stop/hide on release); captures the
  target PID on start so paste can refocus
- CLAUDE.md §15a: document the methods and the Sway press/release bindings

Works independent of the app's activation mode, since the compositor drives
start/stop explicitly. GNOME/KDE native shortcuts are press-only, so PTT is a
wlroots (Sway/Hyprland) capability.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sochotnicky sochotnicky force-pushed the wayland-force-dbus branch from ee5b775 to 4f1a118 Compare July 1, 2026 06:12
The bus is desktop-agnostic, but it was only created on GNOME (via
GnomeShortcutManager) and wlroots (initializeDbusEndpoint), Hyprland ran a second
duplicate Toggle-only service, and KDE/X11 never brought it up. Decouple bus
ownership from desktop detection: start ONE shared DBusToggleService on every
Linux session; each desktop keeps only its keybinding auto-registration on top.

- hotkeyManager: `ensureDbusEndpoint()` starts the single shared service on any
  Linux session (X11 + Wayland), before the DE branches. `registerSlot()` and
  `setDbusToggleCallbacks()` now wire callbacks to the shared endpoint whenever it
  exists (additive), then layer the DE-specific registration. GNOME/Hyprland init
  gate on the shared endpoint being up and fall back to globalShortcut otherwise.
- gnomeShortcut: drop bus ownership (initDBusService / dbusService / callback
  setters) — gsettings-only now.
- hyprlandShortcut: drop its duplicate bus + interface — hyprctl-only now (bonus:
  secondary Toggle* methods now work on Hyprland via the shared bus).
- Keep `useDbus` reserved for "D-Bus is the *primary* mechanism" (wlroots), so
  merely having the endpoint up does NOT flip isUsingNativeShortcut() — X11 keeps
  globalShortcut + push-to-talk.
- CLAUDE.md §15a rewritten: endpoint is universal; desktops layer keybinding
  registration on top.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sochotnicky sochotnicky changed the title Add com.openwhispr.App D-Bus endpoint for shortcuts on non-standard Wayland sessions Add com.openwhispr.App D-Bus endpoint for global shortcuts on Linux Jul 1, 2026
@sochotnicky

Copy link
Copy Markdown
Author

I think in theory the whole Hyprland could be changed as well since it seems to support Global shortcuts: https://wiki.hypr.land/Configuring/Basics/Binds/#global-keybinds

But I left that alone

@gabrielste1n gabrielste1n requested a review from xAlcahest July 3, 2026 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant