diff --git a/README.md b/README.md index abf4ee5..dcc8e9f 100644 --- a/README.md +++ b/README.md @@ -39,17 +39,13 @@ After installing, launch **WIS Free V3** from the application launcher or run `w ### Global shortcut -On current GNOME, KDE Plasma, and other desktops that implement the XDG GlobalShortcuts portal, set the shortcut in WIS Free V3 Settings. The desktop may ask you to approve or change the shortcut. - -If the portal is unavailable on your desktop, use the **Fallback System Shortcut** command shown in Settings: +Linux uses your desktop environment's custom shortcut feature as the primary global shortcut method. Copy the **Linux System Shortcut** command shown in Settings and bind it to your preferred key combination: - GNOME: **Settings -> Keyboard -> Custom Shortcuts** - KDE Plasma: **System Settings -> Shortcuts -> Command/URL** That command toggles recording: one press starts and the next press stops. It is shell-quoted automatically, including when the app is installed in a path containing spaces. It also works from a cold start because it uses `--action=toggle`. -Set `WISFREE_USE_PORTAL_HOTKEY=0` before launching the app only to deliberately disable portal shortcuts and use the fallback command instead. - ### Direct typing with ydotool WIS Free V3 uses `ydotool` to type transcriptions into the active application. This works on both Wayland and X11, but it needs the persistent `ydotoold` service. @@ -156,7 +152,7 @@ With no flag, the script builds both formats and therefore requires both `dpkg-d | Symptom | What to check | | --- | --- | | The package installed but the app will not launch | Install it with `apt install ./file.deb` or `dnf install ./file.rpm` so runtime libraries are resolved. Launch `wis-free-v3` from a terminal once to see any loader error. | -| The shortcut does nothing | Configure the portal shortcut in Settings. If your desktop rejects it, use the fallback command displayed there. | +| The shortcut does nothing | Copy the Linux System Shortcut command from Settings and bind it in your desktop's custom shortcut settings. | | Transcription completes but text is not inserted | Open Settings and complete the ydotool setup. Check `systemctl --user status ydotool.service`. | | `ydotoold socket not found` | Enable the user service, then log out/in once only if the service still cannot access `/dev/uinput`. | | The app runs but no tray icon appears on GNOME | Install and enable the AppIndicator extension. | diff --git a/app.go b/app.go index c0fb33e..ca7c6b5 100644 --- a/app.go +++ b/app.go @@ -25,19 +25,19 @@ import ( // App struct type App struct { - ctx context.Context - audioRecorder *recorder.AudioRecorder - hotkeyListener *hotkey.Listener - transcriber *transcriber.Client - config *config.Config - overlay platform.Overlay - recordingPath string - recording int32 - isQuitting bool - wasMediaPlaying bool - whisperManager *whisper.Manager - tempDir string - transcribing int32 // atomic: 1 = transcription in progress, prevents concurrent + ctx context.Context + audioRecorder *recorder.AudioRecorder + hotkeyListener *hotkey.Listener + transcriber *transcriber.Client + config *config.Config + overlay platform.Overlay + recordingPath string + recording int32 + isQuitting bool + wasMediaPlaying bool + whisperManager *whisper.Manager + tempDir string + transcribing int32 // atomic: 1 = transcription in progress, prevents concurrent } // NewApp creates a new App application struct @@ -468,37 +468,25 @@ func (a *App) SaveSettings(settings map[string]interface{}) string { } } if val, ok := settings["shortcut"].(string); ok { - _, _, modOnly, ok := hotkey.ParseShortcut(val) - if !ok { - logger.Error("Invalid shortcut: %s (rejected)", val) - return "Invalid shortcut - use modifiers plus a key (e.g. ctrl+k), or modifier-only on Windows (e.g. ctrl+win)" - } - if modOnly && runtime.GOOS != "windows" { - return "Modifier-only shortcuts (like ctrl+win) are only supported on Windows" - } - - a.config.Shortcut = val - // Hot-swap the listener on every platform. Linux uses the XDG - // GlobalShortcuts portal when the desktop implements it and otherwise - // exposes the custom-command fallback in Settings. - if a.hotkeyListener != nil { - a.hotkeyListener.UpdateShortcut(val) + if runtime.GOOS == "linux" { + logger.Info("Ignoring in-app shortcut recording on Linux; use the desktop custom-shortcut command shown in Settings") } else { - a.hotkeyListener = hotkey.NewListener(val, a.StartRecording, a.StopRecording) - if runtime.GOOS != "windows" { - a.hotkeyListener.SetRegistrationErrorCallback(func(err error) { - logger.Error("Linux hotkey registration failed: %v", err) - // Show notification for hotkey registration failures - go func() { - time.Sleep(500 * time.Millisecond) - if a.overlay != nil { - a.overlay.Show("Shortcut registration failed. Use the command shown in Settings for a desktop shortcut.") - } - logger.Info("HOTKEY SETUP: Portal failed. Add a custom GNOME/KDE shortcut with: wisp-open --action=toggle") - }() - }) + _, _, modOnly, ok := hotkey.ParseShortcut(val) + if !ok { + logger.Error("Invalid shortcut: %s (rejected)", val) + return "Invalid shortcut - use modifiers plus a key (e.g. ctrl+k), or modifier-only on Windows (e.g. ctrl+win)" + } + if modOnly && runtime.GOOS != "windows" { + return "Modifier-only shortcuts (like ctrl+win) are only supported on Windows" + } + + a.config.Shortcut = val + if a.hotkeyListener != nil { + a.hotkeyListener.UpdateShortcut(val) + } else { + a.hotkeyListener = hotkey.NewListener(val, a.StartRecording, a.StopRecording) + a.hotkeyListener.Start() } - a.hotkeyListener.Start() } } if val, ok := settings["whisper_model"].(string); ok { @@ -652,37 +640,19 @@ func (a *App) startupHeadless() { } } - // Ensure desktop integration for Wayland portals + // Ensure desktop integration for Linux custom shortcuts and tray metadata. if err := platform.EnsureDesktopFile(tray.DefaultIconBytes()); err != nil { logger.Error("Failed to ensure desktop file: %v", err) } - // Initialize Hotkey Listener - if shouldStartBuiltInHotkeyListener() { + // Linux uses the desktop custom-shortcut command shown in Settings instead + // of an in-app global hotkey backend. Other platforms keep their native + // listeners. + if runtime.GOOS != "linux" { a.hotkeyListener = hotkey.NewListener(a.config.Shortcut, a.StartRecording, a.StopRecording) - if runtime.GOOS != "windows" { - a.hotkeyListener.SetRegistrationErrorCallback(func(err error) { - logger.Error("Linux hotkey registration failed: %v", err) - // Always show an error notification when portal registration fails - // so the user knows to use the fallback method - go func() { - // Show notification immediately via tray if available - if err != nil { - logger.Error("Portal hotkey error (will show notification): %v", err) - } - // Also try to show overlay if window is visible - time.Sleep(500 * time.Millisecond) - if a.overlay != nil { - a.overlay.Show("Shortcut registration failed. Use the command shown in Settings for a desktop shortcut.") - } - // Log a clear instruction for the fallback method - logger.Info("HOTKEY SETUP: Portal failed. Add a custom GNOME/KDE shortcut with: wisp-open --action=toggle") - }() - }) - } a.hotkeyListener.Start() } else { - logger.Info("Linux portal hotkey disabled via WISFREE_USE_PORTAL_HOTKEY=0; use the command shown in Settings for a desktop shortcut") + logger.Info("Linux shortcut setup uses the command shown in Settings; configure it in GNOME/KDE custom shortcuts") } logger.Info("Components initialized successfully!") @@ -690,16 +660,6 @@ func (a *App) startupHeadless() { logger.Info("Basic app components loaded, continuing startup...") } -func shouldStartBuiltInHotkeyListener() bool { - if runtime.GOOS != "linux" { - return true - } - // The portal is the safest cross-desktop implementation on modern Linux. - // WISFREE_USE_PORTAL_HOTKEY=0 remains an escape hatch for desktops with a - // broken portal; Settings always provides a custom-shortcut fallback. - return os.Getenv("WISFREE_USE_PORTAL_HOTKEY") != "0" -} - // Shutdown cleans up resources func (a *App) Shutdown(ctx context.Context) { if a.hotkeyListener != nil { diff --git a/frontend/index.html b/frontend/index.html index 66adbbe..81e1503 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -39,7 +39,7 @@
Get your free key at console.groq.com/keys
- +Uses the desktop GlobalShortcuts portal when available. Press the key combination you want to use to start/stop recording (e.g. alt+z, ctrl+shift+space). Modifier-only combos like ctrl+alt are supported only on Windows.
+Windows and macOS can listen for this shortcut directly. Modifier-only combos like ctrl+alt are supported only on Windows.