mirror of
https://github.com/jahruz67/wisp-open.git
synced 2026-08-08 18:14:08 +00:00
feat: implement enhanced Linux hotkey handling and add command copying functionality
This commit is contained in:
@@ -632,25 +632,36 @@ func (a *App) startupHeadless() {
|
||||
}
|
||||
|
||||
// Initialize Hotkey Listener
|
||||
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)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
if a.overlay != nil {
|
||||
a.overlay.Show("Shortcut registration failed. Please add a custom system shortcut calling 'wis-free-v3 --action=toggle' as a fallback.")
|
||||
}
|
||||
}()
|
||||
})
|
||||
if shouldStartBuiltInHotkeyListener() {
|
||||
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)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
if a.overlay != nil {
|
||||
a.overlay.Show("Shortcut registration failed. Add a custom system shortcut with the command shown in Settings.")
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
a.hotkeyListener.Start()
|
||||
} else {
|
||||
logger.Info("Linux portal hotkey disabled; use the --press command from Settings for GNOME shortcuts")
|
||||
}
|
||||
a.hotkeyListener.Start()
|
||||
|
||||
logger.Info("Components initialized successfully!")
|
||||
|
||||
logger.Info("Basic app components loaded, continuing startup...")
|
||||
}
|
||||
|
||||
func shouldStartBuiltInHotkeyListener() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
return true
|
||||
}
|
||||
return os.Getenv("WISFREE_USE_PORTAL_HOTKEY") == "1"
|
||||
}
|
||||
|
||||
// Shutdown cleans up resources
|
||||
func (a *App) Shutdown(ctx context.Context) {
|
||||
if a.hotkeyListener != nil {
|
||||
|
||||
+3
File diff suppressed because one or more lines are too long
-3
File diff suppressed because one or more lines are too long
Vendored
+4
-4
@@ -6,7 +6,7 @@
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<title>Wisp Settings</title>
|
||||
|
||||
<script type="module" crossorigin src="/assets/index.fbf781c1.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index.3a064eef.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.6e77aa4d.css">
|
||||
</head>
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
<button onclick="copyLinuxPressCommand()">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">GNOME: Settings -> Keyboard -> Custom Shortcuts -> Add a shortcut using the copied command.</p>
|
||||
<p class="hint">KDE: System Settings -> Shortcuts -> Command/URL -> Add a shortcut using the copied command.</p>
|
||||
<p class="hint">GNOME: Settings -> Keyboard -> Custom Shortcuts -> Add a shortcut with the copied command.</p>
|
||||
<p class="hint">KDE: System Settings -> Shortcuts -> Command/URL -> Add a shortcut with the copied command.</p>
|
||||
</div>
|
||||
|
||||
<!-- Microphone -->
|
||||
@@ -189,4 +189,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+30
-2
@@ -333,7 +333,16 @@
|
||||
const settings = await window.go.main.App.GetSettings();
|
||||
|
||||
document.getElementById('apiKey').value = settings.api_key || '';
|
||||
document.getElementById('shortcutInput').value = settings.shortcut || 'alt+z';
|
||||
const shortcutInput = document.getElementById('shortcutInput');
|
||||
if (shortcutInput) {
|
||||
shortcutInput.value = settings.shortcut || 'alt+z';
|
||||
}
|
||||
if (settings.linux_press_mode) {
|
||||
const section = document.getElementById('linuxPressSection');
|
||||
const cmdInput = document.getElementById('linuxPressCommand');
|
||||
if (section) section.style.display = 'block';
|
||||
if (cmdInput) cmdInput.value = settings.linux_press_command || '';
|
||||
}
|
||||
document.getElementById('whisperModel').value = settings.whisper_model || 'whisper-large-v3-turbo';
|
||||
document.getElementById('aiModel').value = settings.ai_model || 'llama-3.3-70b-versatile';
|
||||
document.getElementById('aiPrompt').value = settings.ai_prompt || '';
|
||||
@@ -407,6 +416,25 @@
|
||||
showSaveStatus('Prompt saved');
|
||||
};
|
||||
|
||||
window.copyLinuxPressCommand = async function () {
|
||||
const cmdInput = document.getElementById('linuxPressCommand');
|
||||
if (!cmdInput) return;
|
||||
|
||||
const command = cmdInput.value || '';
|
||||
try {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
await navigator.clipboard.writeText(command);
|
||||
} else {
|
||||
cmdInput.focus();
|
||||
cmdInput.select();
|
||||
document.execCommand('copy');
|
||||
}
|
||||
showSaveStatus('Command copied');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy Linux command:', err);
|
||||
}
|
||||
};
|
||||
|
||||
window.toggleStartup = async function () {
|
||||
await window.go.main.App.ToggleStartup(document.getElementById('startupToggle').checked);
|
||||
};
|
||||
@@ -560,4 +588,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+72
-15
@@ -13,9 +13,21 @@ import (
|
||||
const linuxPressAddr = "127.0.0.1:9876"
|
||||
|
||||
var (
|
||||
linuxPressMu sync.Mutex
|
||||
linuxPressTimer *time.Timer
|
||||
linuxPressRecording bool
|
||||
linuxPressMu sync.Mutex
|
||||
linuxPressReleaseTimer *time.Timer
|
||||
linuxPressDetectTimer *time.Timer
|
||||
linuxPressRecording bool
|
||||
linuxPressHoldMode bool
|
||||
linuxPressDetectingHold bool
|
||||
)
|
||||
|
||||
const (
|
||||
// GNOME custom shortcuts commonly auto-repeat while the key is held.
|
||||
// If we see a second ping quickly, treat the shortcut as push-to-talk.
|
||||
linuxPressHoldDetectWindow = 1200 * time.Millisecond
|
||||
|
||||
// Once hold mode is confirmed, lack of fresh pings means the key was released.
|
||||
linuxPressReleaseGrace = 450 * time.Millisecond
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -58,22 +70,36 @@ func (a *App) startLinuxPressDaemon() {
|
||||
|
||||
if !linuxPressRecording {
|
||||
linuxPressRecording = true
|
||||
linuxPressHoldMode = false
|
||||
linuxPressDetectingHold = true
|
||||
go a.StartRecording()
|
||||
}
|
||||
|
||||
if linuxPressTimer != nil {
|
||||
linuxPressTimer.Stop()
|
||||
}
|
||||
|
||||
linuxPressTimer = time.AfterFunc(300*time.Millisecond, func() {
|
||||
linuxPressMu.Lock()
|
||||
defer linuxPressMu.Unlock()
|
||||
if linuxPressRecording {
|
||||
linuxPressRecording = false
|
||||
go a.StopRecording()
|
||||
if linuxPressDetectTimer != nil {
|
||||
linuxPressDetectTimer.Stop()
|
||||
}
|
||||
})
|
||||
linuxPressDetectTimer = time.AfterFunc(linuxPressHoldDetectWindow, func() {
|
||||
linuxPressMu.Lock()
|
||||
defer linuxPressMu.Unlock()
|
||||
linuxPressDetectingHold = false
|
||||
})
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
if linuxPressDetectingHold || linuxPressHoldMode {
|
||||
linuxPressHoldMode = true
|
||||
linuxPressDetectingHold = false
|
||||
if linuxPressDetectTimer != nil {
|
||||
linuxPressDetectTimer.Stop()
|
||||
linuxPressDetectTimer = nil
|
||||
}
|
||||
resetLinuxPressReleaseTimer(a)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
stopLinuxPressRecording(a)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
|
||||
@@ -81,3 +107,34 @@ func (a *App) startLinuxPressDaemon() {
|
||||
_ = http.ListenAndServe(linuxPressAddr, mux)
|
||||
}()
|
||||
}
|
||||
|
||||
func resetLinuxPressReleaseTimer(a *App) {
|
||||
if linuxPressReleaseTimer != nil {
|
||||
linuxPressReleaseTimer.Stop()
|
||||
}
|
||||
|
||||
linuxPressReleaseTimer = time.AfterFunc(linuxPressReleaseGrace, func() {
|
||||
linuxPressMu.Lock()
|
||||
defer linuxPressMu.Unlock()
|
||||
if linuxPressRecording && linuxPressHoldMode {
|
||||
stopLinuxPressRecording(a)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func stopLinuxPressRecording(a *App) {
|
||||
if linuxPressReleaseTimer != nil {
|
||||
linuxPressReleaseTimer.Stop()
|
||||
linuxPressReleaseTimer = nil
|
||||
}
|
||||
if linuxPressDetectTimer != nil {
|
||||
linuxPressDetectTimer.Stop()
|
||||
linuxPressDetectTimer = nil
|
||||
}
|
||||
if linuxPressRecording {
|
||||
linuxPressRecording = false
|
||||
linuxPressHoldMode = false
|
||||
linuxPressDetectingHold = false
|
||||
go a.StopRecording()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user