diff --git a/alert/alert_darwin.go b/alert/alert_darwin.go index 5f90f7a..86ea092 100644 --- a/alert/alert_darwin.go +++ b/alert/alert_darwin.go @@ -4,7 +4,15 @@ package alert import "os/exec" -func Show(msg string) { +func Error(msg string) { + show(msg, "stop") +} + +func Warn(msg string) { + show(msg, "caution") +} + +func show(msg, icon string) { exec.Command("osascript", "-e", - `display dialog "`+msg+`" with title "Zee" buttons {"OK"} default button "OK" with icon stop`).Run() + `display dialog "`+msg+`" with title "Zee" buttons {"OK"} default button "OK" with icon `+icon).Run() } diff --git a/alert/alert_other.go b/alert/alert_other.go index 267a265..974a544 100644 --- a/alert/alert_other.go +++ b/alert/alert_other.go @@ -2,4 +2,5 @@ package alert -func Show(_ string) {} +func Error(_ string) {} +func Warn(_ string) {} diff --git a/clipboard/clipboard_darwin.go b/clipboard/clipboard_darwin.go index 94d2ec7..49a74e5 100644 --- a/clipboard/clipboard_darwin.go +++ b/clipboard/clipboard_darwin.go @@ -1,5 +1,15 @@ package clipboard +/* +#cgo LDFLAGS: -framework ApplicationServices -framework CoreFoundation +#include + +static int testAccessibility() { + return AXIsProcessTrusted(); +} +*/ +import "C" + import ( "sync" @@ -27,3 +37,7 @@ func Paste() error { kb.HasSuper(true) // Cmd+V on macOS return kb.Launching() } + +func CheckAccessibility() bool { + return C.testAccessibility() == 1 +} diff --git a/clipboard/clipboard_linux.go b/clipboard/clipboard_linux.go index a54ce03..80dad22 100644 --- a/clipboard/clipboard_linux.go +++ b/clipboard/clipboard_linux.go @@ -159,3 +159,5 @@ func Paste() error { } return syn() } + +func CheckAccessibility() bool { return true } diff --git a/main.go b/main.go index 89c7e3f..b2a39c4 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ var version = "dev" func fatal(msg string, args ...any) { s := fmt.Sprintf(msg, args...) fmt.Fprintln(os.Stderr, s) - alert.Show(s) + alert.Error(s) os.Exit(1) } @@ -183,13 +183,12 @@ func run() { // Resolve log directory early logPath, err := log.ResolveDir(*logPathFlag) if err != nil { - fmt.Fprintf(os.Stderr, "Error: failed to resolve log directory: %v\n", err) - os.Exit(1) + fatal("Failed to resolve log directory: %v", err) } log.SetDir(logPath) if err := log.EnsureDir(); err != nil { - fmt.Fprintf(os.Stderr, "Warning: could not create log directory: %v\n", err) + log.Warnf("could not create log directory: %v", err) } crashPath := filepath.Join(log.Dir(), "crash_log.txt") @@ -232,8 +231,7 @@ func run() { case "mp3@16", "mp3@64", "flac": activeFormat = *formatFlag default: - fmt.Printf("Error: unknown format %q (use mp3@16, mp3@64, or flac)\n", *formatFlag) - os.Exit(1) + fatal("Unknown format %q (use mp3@16, mp3@64, or flac)", *formatFlag) } if streamEnabled && *formatFlag != "mp3@16" { @@ -253,8 +251,7 @@ func run() { if *setupFlag && *deviceFlag == "" { ctx, err := audio.NewContext() if err != nil { - fmt.Printf("Error initializing audio: %v\n", err) - os.Exit(1) + fatal("Error initializing audio: %v", err) } if dev, _ := selectDevice(ctx); dev != nil { *deviceFlag = dev.Name @@ -265,7 +262,7 @@ func run() { if *debugFlag { log.SetTranscribeEnabled(*debugTranscribeFlag) if err := log.Init(); err != nil { - fmt.Fprintf(os.Stderr, "Warning: could not init logging: %v\n", err) + alert.Warn("Debug logging will not work.\n\n" + err.Error()) } else { log.SessionStart(activeTranscriber.Name(), activeFormat, activeFormat) } @@ -288,8 +285,12 @@ func run() { if autoPaste { if err := clipboard.Init(); err != nil { - fmt.Printf("Warning: paste init failed: %v\n", err) - fmt.Println("Fix with: sudo chmod 660 /dev/uinput && sudo chgrp input /dev/uinput") + log.Warnf("paste init failed: %v", err) + alert.Warn("Auto-paste will not work.\n\n" + err.Error()) + } + if !clipboard.CheckAccessibility() { + log.Warnf("accessibility permission missing or stale") + alert.Warn("Auto-paste requires Accessibility permission.\n\nGrant access to Zee.app (or your terminal app if running from CLI) in:\nSystem Settings → Privacy & Security → Accessibility") } } @@ -313,9 +314,7 @@ func run() { } else if *setupFlag { selectedDevice, err = selectDevice(ctx) if err != nil { - log.Warnf("device selection failed: %v", err) - fmt.Printf("Warning: device selection failed: %v\n", err) - fmt.Println("Falling back to default device") + log.Warnf("device selection failed: %v — falling back to default", err) selectedDevice = nil } }