diff --git a/src/components/SettingsPage.tsx b/src/components/SettingsPage.tsx
index ed930f3b1..4a06bb1f9 100644
--- a/src/components/SettingsPage.tsx
+++ b/src/components/SettingsPage.tsx
@@ -1030,7 +1030,7 @@ export default function SettingsPage({ activeSection = "general" }: SettingsPage
title: t("settingsPage.permissions.resetAccessibility.title"),
description: message,
onConfirm: () => {
- permissionsHook.openAccessibilitySettings();
+ permissionsHook.requestAccessibilityPermission();
},
});
};
@@ -3324,8 +3324,7 @@ EOF`,
description={t("settingsPage.permissions.microphoneDescription")}
granted={permissionsHook.micPermissionGranted}
onRequest={permissionsHook.requestMicPermission}
- buttonText={t("settingsPage.permissions.test")}
- onOpenSettings={permissionsHook.openMicPrivacySettings}
+ buttonText={t("settingsPage.permissions.grantAccess")}
/>
{platform === "darwin" && (
@@ -3335,9 +3334,8 @@ EOF`,
title={t("settingsPage.permissions.accessibilityTitle")}
description={t("settingsPage.permissions.accessibilityDescription")}
granted={permissionsHook.accessibilityPermissionGranted}
- onRequest={permissionsHook.testAccessibilityPermission}
- buttonText={t("settingsPage.permissions.testAndGrant")}
- onOpenSettings={permissionsHook.openAccessibilitySettings}
+ onRequest={permissionsHook.requestAccessibilityPermission}
+ buttonText={t("settingsPage.permissions.grantAccess")}
/>
{systemAudio.mode === "native" && (
)}
diff --git a/src/components/ui/PermissionCard.tsx b/src/components/ui/PermissionCard.tsx
index 3413f0fbc..161644492 100644
--- a/src/components/ui/PermissionCard.tsx
+++ b/src/components/ui/PermissionCard.tsx
@@ -1,5 +1,5 @@
import { Button } from "./button";
-import { Check, ExternalLink, LucideIcon, Settings } from "lucide-react";
+import { Check, LucideIcon } from "lucide-react";
import { cn } from "../lib/utils";
interface PermissionCardProps {
@@ -9,9 +9,7 @@ interface PermissionCardProps {
granted: boolean;
onRequest: () => void;
buttonText?: string;
- onOpenSettings?: () => void;
badge?: string;
- openSettingsText?: string;
hint?: string;
}
@@ -22,9 +20,7 @@ export default function PermissionCard({
granted,
onRequest,
buttonText = "Grant Access",
- onOpenSettings,
badge,
- openSettingsText,
hint,
}: PermissionCardProps) {
return (
@@ -38,7 +34,6 @@ export default function PermissionCard({
)}
>
- {/* Icon container */}
- {/* Content */}
{title}
@@ -67,36 +61,13 @@ export default function PermissionCard({
{description}
- {/* Actions - only when not granted */}
{!granted && (
-
- {onOpenSettings && openSettingsText ? (
-
- ) : (
- <>
-
- {onOpenSettings && (
-
- )}
- >
- )}
-
+
)}
- {/* Troubleshooting hint */}
{hint && !granted && (
{hint}
)}
diff --git a/src/components/ui/PermissionsSection.tsx b/src/components/ui/PermissionsSection.tsx
index 607375a13..9f4df7434 100644
--- a/src/components/ui/PermissionsSection.tsx
+++ b/src/components/ui/PermissionsSection.tsx
@@ -11,7 +11,6 @@ interface PermissionsSectionProps {
granted: boolean;
mode: "native" | "unsupported";
request: () => Promise
;
- openSettings: () => Promise;
};
}
@@ -29,7 +28,7 @@ export default function PermissionsSection({ permissions, systemAudio }: Permiss
description={t("onboarding.permissions.microphoneDescription")}
granted={permissions.micPermissionGranted}
onRequest={permissions.requestMicPermission}
- buttonText={t("onboarding.permissions.grant")}
+ buttonText={t("onboarding.permissions.grantAccess")}
/>
{isMacOS && (
@@ -39,10 +38,8 @@ export default function PermissionsSection({ permissions, systemAudio }: Permiss
title={t("onboarding.permissions.accessibilityTitle")}
description={t("onboarding.permissions.accessibilityDescription")}
granted={permissions.accessibilityPermissionGranted}
- onRequest={permissions.testAccessibilityPermission}
- buttonText={t("onboarding.permissions.testAndGrant")}
- onOpenSettings={permissions.openAccessibilitySettings}
- openSettingsText={t("onboarding.permissions.openSystemSettings")}
+ onRequest={permissions.requestAccessibilityPermission}
+ buttonText={t("onboarding.permissions.grantAccess")}
badge={t("onboarding.permissions.recommended")}
hint={
permissions.accessibilityTroubleshooting
@@ -57,8 +54,7 @@ export default function PermissionsSection({ permissions, systemAudio }: Permiss
description={t("onboarding.permissions.systemAudioDescription")}
granted={systemAudio.granted}
onRequest={systemAudio.request}
- buttonText={t("onboarding.permissions.grant")}
- onOpenSettings={systemAudio.openSettings}
+ buttonText={t("onboarding.permissions.grantAccess")}
badge={t("onboarding.permissions.optional")}
/>
)}
diff --git a/src/helpers/audioTapManager.js b/src/helpers/audioTapManager.js
index 25f7950cd..29e797282 100644
--- a/src/helpers/audioTapManager.js
+++ b/src/helpers/audioTapManager.js
@@ -11,7 +11,7 @@ const ARCH_CPU_TYPE = {
const DEFAULT_SAMPLE_RATE = 24000;
const DEFAULT_CHUNK_MS = 100;
const START_TIMEOUT_MS = 3000;
-const REQUEST_TIMEOUT_MS = 15000;
+const REQUEST_TIMEOUT_MS = 60000;
const STOP_TIMEOUT_MS = 5000;
function compareVersions(left, right) {
diff --git a/src/helpers/clipboard.js b/src/helpers/clipboard.js
index 0d3d0e51e..c436d76f2 100644
--- a/src/helpers/clipboard.js
+++ b/src/helpers/clipboard.js
@@ -162,9 +162,7 @@ class ClipboardManager {
}
const possiblePaths = [
- ...(process.resourcesPath
- ? [path.join(process.resourcesPath, "bin", "nircmd.exe")]
- : []),
+ ...(process.resourcesPath ? [path.join(process.resourcesPath, "bin", "nircmd.exe")] : []),
path.join(__dirname, "..", "..", "resources", "bin", "nircmd.exe"),
path.join(process.cwd(), "resources", "bin", "nircmd.exe"),
];
diff --git a/src/helpers/hotkeyManager.js b/src/helpers/hotkeyManager.js
index 0b5f12983..96600ff25 100644
--- a/src/helpers/hotkeyManager.js
+++ b/src/helpers/hotkeyManager.js
@@ -211,9 +211,7 @@ class HotkeyManager {
slot.accelerator = null;
this.slots.set(slotName, slot);
- debugLogger.log(
- `[HotkeyManager] KDE slot "${slotName}" set to "${hotkey}"`
- );
+ debugLogger.log(`[HotkeyManager] KDE slot "${slotName}" set to "${hotkey}"`);
return { success: true, hotkey };
}
@@ -483,7 +481,11 @@ class HotkeyManager {
}
async initializeKDEShortcuts(callback) {
- if (process.platform !== "linux" || !KDEShortcutManager.isWayland() || !KDEShortcutManager.isKDE()) {
+ if (
+ process.platform !== "linux" ||
+ !KDEShortcutManager.isWayland() ||
+ !KDEShortcutManager.isKDE()
+ ) {
return false;
}
@@ -606,9 +608,7 @@ class HotkeyManager {
const success = await this.kdeManager.registerKeybinding(hotkey, "dictation", callback);
if (success) {
this.currentHotkey = hotkey;
- debugLogger.log(
- `[HotkeyManager] KDE hotkey "${hotkey}" registered successfully`
- );
+ debugLogger.log(`[HotkeyManager] KDE hotkey "${hotkey}" registered successfully`);
} else {
debugLogger.log(
"[HotkeyManager] KDE keybinding failed, falling back to globalShortcut"
diff --git a/src/helpers/ipcHandlers.js b/src/helpers/ipcHandlers.js
index 8d6c32a19..754899242 100644
--- a/src/helpers/ipcHandlers.js
+++ b/src/helpers/ipcHandlers.js
@@ -2066,12 +2066,14 @@ class IPCHandlers {
return { granted: true, status: "granted", mode: "unsupported" };
}
- if (this.audioTapManager?.isSupported()) {
- const status = systemPreferences.getMediaAccessStatus("screen");
- return { granted: status === "granted", status, mode: "native" };
+ if (!this.audioTapManager?.isSupported()) {
+ return { granted: false, status: "unsupported", mode: "unsupported" };
}
- return { granted: false, status: "unsupported", mode: "unsupported" };
+ const screenStatus = systemPreferences.getMediaAccessStatus("screen");
+ const tapStatus = this.audioTapManager.getPermissionStatus();
+ const granted = screenStatus === "granted" || tapStatus === "granted";
+ return { granted, status: granted ? "granted" : screenStatus, mode: "native" };
});
ipcMain.handle("request-system-audio-access", async () => {
@@ -2083,16 +2085,24 @@ class IPCHandlers {
return { granted: false, status: "unsupported", mode: "unsupported" };
}
- const status = systemPreferences.getMediaAccessStatus("screen");
- if (status === "granted") {
+ const screenStatus = systemPreferences.getMediaAccessStatus("screen");
+ if (screenStatus === "granted") {
return { granted: true, status: "granted", mode: "native" };
}
- // Permission not yet granted — open System Settings so the user can toggle it manually.
- // Unlike microphone, macOS does not show a system prompt for screen/audio recording;
- // the user must enable it in System Settings.
+ // Probe the binary — AudioHardwareCreateProcessTap triggers the native consent dialog
+ try {
+ const result = await this.audioTapManager.requestAccess();
+ if (result.granted) {
+ return { granted: true, status: "granted", mode: "native" };
+ }
+ } catch {
+ // Falls through to opening System Settings
+ }
+
+ // Fallback for older macOS or if the native prompt was denied
await openSystemSettings("systemAudio");
- return { granted: false, status, mode: "native" };
+ return { granted: false, status: screenStatus, mode: "native" };
});
// Auth: clear all session cookies for sign-out.
@@ -2487,7 +2497,13 @@ class IPCHandlers {
{ ref: "_meetingSystemStreaming", secret: secrets[1], source: "system" },
];
} else {
- pairs = [{ ref: "_meetingMicStreaming", secret: await fetchRealtimeToken(event, options), source: "mic" }];
+ pairs = [
+ {
+ ref: "_meetingMicStreaming",
+ secret: await fetchRealtimeToken(event, options),
+ source: "mic",
+ },
+ ];
}
for (const { ref, source } of pairs) {
diff --git a/src/helpers/kdeShortcut.js b/src/helpers/kdeShortcut.js
index 9ebf01864..e1d511030 100644
--- a/src/helpers/kdeShortcut.js
+++ b/src/helpers/kdeShortcut.js
@@ -25,23 +25,75 @@ const QT_MODIFIERS = {
};
const QT_KEYS = {
- a: 0x41, b: 0x42, c: 0x43, d: 0x44, e: 0x45, f: 0x46, g: 0x47, h: 0x48,
- i: 0x49, j: 0x4a, k: 0x4b, l: 0x4c, m: 0x4d, n: 0x4e, o: 0x4f, p: 0x50,
- q: 0x51, r: 0x52, s: 0x53, t: 0x54, u: 0x55, v: 0x56, w: 0x57, x: 0x58,
- y: 0x59, z: 0x5a,
- 0: 0x30, 1: 0x31, 2: 0x32, 3: 0x33, 4: 0x34,
- 5: 0x35, 6: 0x36, 7: 0x37, 8: 0x38, 9: 0x39,
- f1: 0x01000030, f2: 0x01000031, f3: 0x01000032, f4: 0x01000033,
- f5: 0x01000034, f6: 0x01000035, f7: 0x01000036, f8: 0x01000037,
- f9: 0x01000038, f10: 0x01000039, f11: 0x0100003a, f12: 0x0100003b,
- space: 0x20, tab: 0x01000001, escape: 0x01000000, backspace: 0x01000003,
- enter: 0x01000005, return: 0x01000004,
- insert: 0x01000006, delete: 0x01000007,
- home: 0x01000010, end: 0x01000011,
- pageup: 0x01000016, pagedown: 0x01000017,
- up: 0x01000013, down: 0x01000015, left: 0x01000012, right: 0x01000014,
- "`": 0x60, grave: 0x60,
- print: 0x01000009, scrolllock: 0x01000026, pause: 0x01000008,
+ a: 0x41,
+ b: 0x42,
+ c: 0x43,
+ d: 0x44,
+ e: 0x45,
+ f: 0x46,
+ g: 0x47,
+ h: 0x48,
+ i: 0x49,
+ j: 0x4a,
+ k: 0x4b,
+ l: 0x4c,
+ m: 0x4d,
+ n: 0x4e,
+ o: 0x4f,
+ p: 0x50,
+ q: 0x51,
+ r: 0x52,
+ s: 0x53,
+ t: 0x54,
+ u: 0x55,
+ v: 0x56,
+ w: 0x57,
+ x: 0x58,
+ y: 0x59,
+ z: 0x5a,
+ 0: 0x30,
+ 1: 0x31,
+ 2: 0x32,
+ 3: 0x33,
+ 4: 0x34,
+ 5: 0x35,
+ 6: 0x36,
+ 7: 0x37,
+ 8: 0x38,
+ 9: 0x39,
+ f1: 0x01000030,
+ f2: 0x01000031,
+ f3: 0x01000032,
+ f4: 0x01000033,
+ f5: 0x01000034,
+ f6: 0x01000035,
+ f7: 0x01000036,
+ f8: 0x01000037,
+ f9: 0x01000038,
+ f10: 0x01000039,
+ f11: 0x0100003a,
+ f12: 0x0100003b,
+ space: 0x20,
+ tab: 0x01000001,
+ escape: 0x01000000,
+ backspace: 0x01000003,
+ enter: 0x01000005,
+ return: 0x01000004,
+ insert: 0x01000006,
+ delete: 0x01000007,
+ home: 0x01000010,
+ end: 0x01000011,
+ pageup: 0x01000016,
+ pagedown: 0x01000017,
+ up: 0x01000013,
+ down: 0x01000015,
+ left: 0x01000012,
+ right: 0x01000014,
+ "`": 0x60,
+ grave: 0x60,
+ print: 0x01000009,
+ scrolllock: 0x01000026,
+ pause: 0x01000008,
};
const COMPONENT_NAME = "openwhispr";
@@ -92,10 +144,7 @@ class KDEShortcutManager {
try {
this.bus = dbusModule.sessionBus();
- const proxy = await this.bus.getProxyObject(
- "org.kde.kglobalaccel",
- "/kglobalaccel"
- );
+ const proxy = await this.bus.getProxyObject("org.kde.kglobalaccel", "/kglobalaccel");
this.kglobalaccel = proxy.getInterface("org.kde.KGlobalAccel");
debugLogger.log("[KDEShortcut] Connected to KGlobalAccel D-Bus");
@@ -113,10 +162,7 @@ class KDEShortcutManager {
try {
const componentPath = `/component/${COMPONENT_NAME}`;
- const proxy = await this.bus.getProxyObject(
- "org.kde.kglobalaccel",
- componentPath
- );
+ const proxy = await this.bus.getProxyObject("org.kde.kglobalaccel", componentPath);
const iface = proxy.getInterface("org.kde.kglobalaccel.Component");
iface.on("globalShortcutPressed", (componentUnique, shortcutUnique, timestamp) => {
@@ -124,12 +170,15 @@ class KDEShortcutManager {
// Tested on KDE Plasma 6 (Fedora 43): signal sends the actionFriendly
// name ("OpenWhispr") not the actionUnique ("dictation"). The fallback
// maps friendly names back to slot names.
- const callback = this.callbacks.get(shortcutUnique)
- || this._findCallbackByFriendlyName(shortcutUnique);
+ const callback =
+ this.callbacks.get(shortcutUnique) || this._findCallbackByFriendlyName(shortcutUnique);
if (callback) {
callback();
} else {
- debugLogger.log("[KDEShortcut] No callback found for", { shortcutUnique, registered: [...this.callbacks.keys()] });
+ debugLogger.log("[KDEShortcut] No callback found for", {
+ shortcutUnique,
+ registered: [...this.callbacks.keys()],
+ });
}
});
@@ -168,12 +217,7 @@ class KDEShortcutManager {
}
// actionId: [componentUnique, componentFriendly, actionUnique, actionFriendly]
- const actionId = [
- COMPONENT_NAME,
- "OpenWhispr",
- slotName,
- `OpenWhispr ${slotName}`,
- ];
+ const actionId = [COMPONENT_NAME, "OpenWhispr", slotName, `OpenWhispr ${slotName}`];
try {
// Register action then set shortcut
@@ -186,7 +230,9 @@ class KDEShortcutManager {
// Start listening for press events on the component
const listening = await this._listenForComponent();
if (!listening) {
- debugLogger.log(`[KDEShortcut] Keybinding registered but listener failed for "${slotName}"`);
+ debugLogger.log(
+ `[KDEShortcut] Keybinding registered but listener failed for "${slotName}"`
+ );
return false;
}
@@ -206,12 +252,7 @@ class KDEShortcutManager {
async unregisterKeybinding(slotName = "dictation") {
if (!this.kglobalaccel) return;
- const actionId = [
- COMPONENT_NAME,
- "OpenWhispr",
- slotName,
- `OpenWhispr ${slotName}`,
- ];
+ const actionId = [COMPONENT_NAME, "OpenWhispr", slotName, `OpenWhispr ${slotName}`];
try {
await this.kglobalaccel.unRegister(actionId);
@@ -237,7 +278,9 @@ class KDEShortcutManager {
Promise.allSettled(promises).finally(() => {
if (this.bus) {
- try { this.bus.disconnect(); } catch {}
+ try {
+ this.bus.disconnect();
+ } catch {}
this.bus = null;
this.kglobalaccel = null;
this.componentProxy = null;
diff --git a/src/helpers/meetingDetectionEngine.js b/src/helpers/meetingDetectionEngine.js
index e6aec1398..69bcdf806 100644
--- a/src/helpers/meetingDetectionEngine.js
+++ b/src/helpers/meetingDetectionEngine.js
@@ -202,7 +202,11 @@ class MeetingDetectionEngine {
}
} catch (error) {
this._meetingModeActive = false;
- debugLogger.error("Error handling notification response", { error: error?.message, detectionId, action }, "meeting");
+ debugLogger.error(
+ "Error handling notification response",
+ { error: error?.message, detectionId, action },
+ "meeting"
+ );
} finally {
this.windowManager.dismissMeetingNotification();
}
diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts
index d1f18f38b..e17f36a2e 100644
--- a/src/hooks/usePermissions.ts
+++ b/src/hooks/usePermissions.ts
@@ -15,11 +15,10 @@ export interface UsePermissionsReturn {
accessibilityTroubleshooting: boolean;
requestMicPermission: () => Promise;
- testAccessibilityPermission: () => Promise;
+ requestAccessibilityPermission: () => Promise;
checkPasteToolsAvailability: () => Promise;
openMicPrivacySettings: () => Promise;
openSoundInputSettings: () => Promise;
- openAccessibilitySettings: () => Promise;
setMicPermissionGranted: (granted: boolean) => void;
setAccessibilityPermissionGranted: (granted: boolean) => void;
}
@@ -128,7 +127,6 @@ export const usePermissions = (
const [isCheckingPasteTools, setIsCheckingPasteTools] = useState(false);
const [accessibilityTroubleshooting, setAccessibilityTroubleshooting] = useState(false);
const accessibilityPollCount = useRef(0);
- const hasPromptedAccessibility = useRef(false);
const openSystemSettings = useCallback(
async (
@@ -171,19 +169,6 @@ export const usePermissions = (
[openSystemSettings]
);
- const openAccessibilitySettings = useCallback(async () => {
- // On first click, trigger the macOS system prompt to create a TCC entry
- if (!hasPromptedAccessibility.current) {
- hasPromptedAccessibility.current = true;
- try {
- await window.electronAPI?.promptAccessibilityPermission?.();
- } catch {
- // Ignore — falls through to opening System Settings
- }
- }
- await openSystemSettings("accessibility", window.electronAPI?.openAccessibilitySettings);
- }, [openSystemSettings]);
-
const requestMicPermission = useCallback(async () => {
if (!navigator?.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
const message = t("hooks.permissions.micUnavailable");
@@ -254,6 +239,46 @@ export const usePermissions = (
}
}, [setAccessibilityPermissionGranted]);
+ const requestAccessibilityPermission = useCallback(async () => {
+ const platform = getPlatform();
+
+ if (platform === "darwin") {
+ // Check if already granted
+ const alreadyGranted = await window.electronAPI?.checkAccessibilityPermission?.(true);
+ if (alreadyGranted) {
+ setAccessibilityPermissionGranted(true);
+ return;
+ }
+
+ // Trigger the macOS TCC prompt (creates entry in System Settings)
+ try {
+ const granted = await window.electronAPI?.promptAccessibilityPermission?.();
+ if (granted) {
+ setAccessibilityPermissionGranted(true);
+ return;
+ }
+ } catch {
+ // Falls through to opening System Settings
+ }
+
+ // Open System Settings for manual toggle
+ await openSystemSettings("accessibility", window.electronAPI?.openAccessibilitySettings);
+ return;
+ }
+
+ // On Windows, PowerShell SendKeys is always available
+ if (platform === "win32") {
+ setAccessibilityPermissionGranted(true);
+ return;
+ }
+
+ // On Linux, auto-paste is optional — grant regardless of paste tool availability
+ if (platform === "linux") {
+ await checkPasteToolsAvailability();
+ setAccessibilityPermissionGranted(true);
+ }
+ }, [openSystemSettings, checkPasteToolsAvailability, setAccessibilityPermissionGranted]);
+
// Check paste tools on mount
useEffect(() => {
checkPasteToolsAvailability();
@@ -305,97 +330,6 @@ export const usePermissions = (
return () => clearInterval(interval);
}, [accessibilityPermissionGranted, setAccessibilityPermissionGranted]);
- const testAccessibilityPermission = useCallback(async () => {
- const platform = getPlatform();
-
- // On macOS, actually test the accessibility permission
- if (platform === "darwin") {
- try {
- await window.electronAPI.pasteText(t("hooks.permissions.accessibilityTestText"));
- setAccessibilityPermissionGranted(true);
- } catch (err) {
- logger.error("Accessibility permission test failed:", err);
- if (showAlertDialog) {
- showAlertDialog({
- title: t("hooks.permissions.titles.accessibilityNeeded"),
- description: t("hooks.permissions.descriptions.accessibilityNeeded"),
- });
- } else {
- alert(t("hooks.permissions.alerts.accessibilityNeeded"));
- }
- }
- return;
- }
-
- // On Windows, PowerShell SendKeys is always available
- if (platform === "win32") {
- setAccessibilityPermissionGranted(true);
- if (showAlertDialog) {
- showAlertDialog({
- title: t("hooks.permissions.titles.readyToGo"),
- description: t("hooks.permissions.descriptions.windowsReady"),
- });
- }
- return;
- }
-
- // On Linux, check if paste tools are available
- if (platform === "linux") {
- const result = await checkPasteToolsAvailability();
-
- if (result?.available) {
- setAccessibilityPermissionGranted(true);
- if (showAlertDialog) {
- const method = result.method || t("hooks.permissions.labels.defaultPasteTool");
- const methodLabel =
- result.isWayland && method === "xdotool"
- ? t("hooks.permissions.labels.xdotoolXwayland")
- : method;
- showAlertDialog({
- title: t("hooks.permissions.titles.readyToGo"),
- description: t("hooks.permissions.descriptions.linuxReadyWithMethod", {
- method: methodLabel,
- }),
- });
- }
- } else {
- // Don't block, but inform the user
- const isWayland = result?.isWayland;
- const xwaylandAvailable = result?.xwaylandAvailable;
- const recommendedTool = result?.recommendedInstall;
- const installCmd =
- recommendedTool === "wtype"
- ? "sudo dnf install wtype # Fedora\nsudo apt install wtype # Debian/Ubuntu"
- : "sudo apt install xdotool # Debian/Ubuntu/Mint\nsudo dnf install xdotool # Fedora";
-
- if (showAlertDialog) {
- if (isWayland && !xwaylandAvailable && !recommendedTool) {
- showAlertDialog({
- title: t("hooks.permissions.titles.waylandClipboardMode"),
- description: t("hooks.permissions.descriptions.waylandClipboardMode"),
- });
- } else {
- const waylandNote = isWayland
- ? recommendedTool === "wtype"
- ? t("hooks.permissions.notes.waylandWtype")
- : t("hooks.permissions.notes.waylandXwaylandOnly")
- : "";
- showAlertDialog({
- title: t("hooks.permissions.titles.optionalPasteTool"),
- description: t("hooks.permissions.descriptions.optionalPasteTool", {
- tool: recommendedTool || t("hooks.permissions.labels.defaultPasteTool"),
- installCmd,
- waylandNote,
- }),
- });
- }
- }
- // Still allow proceeding - this is optional
- setAccessibilityPermissionGranted(true);
- }
- }
- }, [showAlertDialog, checkPasteToolsAvailability, setAccessibilityPermissionGranted, t]);
-
return {
micPermissionGranted,
accessibilityPermissionGranted,
@@ -404,11 +338,10 @@ export const usePermissions = (
isCheckingPasteTools,
accessibilityTroubleshooting,
requestMicPermission,
- testAccessibilityPermission,
+ requestAccessibilityPermission,
checkPasteToolsAvailability,
openMicPrivacySettings,
openSoundInputSettings,
- openAccessibilitySettings,
setMicPermissionGranted,
setAccessibilityPermissionGranted,
};
diff --git a/src/locales/de/translation.json b/src/locales/de/translation.json
index 332515e4b..9134726f4 100644
--- a/src/locales/de/translation.json
+++ b/src/locales/de/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Mikrofon",
"microphoneDescription": "Nimmt Ihre Stimme für die Transkription auf",
"grant": "Erteilen",
+ "grantAccess": "Zugriff gewähren",
"accessibilityTitle": "Bedienungshilfen",
- "accessibilityDescription": "In Systemeinstellungen aktivieren",
+ "accessibilityDescription": "Ermöglicht das automatische Einfügen transkribierter Texte in jede App",
"testAndGrant": "Testen & erteilen",
"requiredForApp": "Erforderlich, damit OpenWhispr funktioniert",
"microphoneRequired": "Mikrofonzugriff erforderlich",
@@ -1335,6 +1336,7 @@
"optional": "Optional",
"systemAudioTitle": "Systemaudio",
"systemAudioDescription": "Nimmt den Ton anderer Teilnehmer aus Anrufen und Meetings auf",
+ "grantAccess": "Zugriff gewähren",
"test": "Testen",
"testAndGrant": "Testen & erteilen",
"title": "Berechtigungen",
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index f87322023..ec47cd742 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Microphone",
"microphoneDescription": "Captures your voice for transcription",
"grant": "Grant",
+ "grantAccess": "Grant Access",
"accessibilityTitle": "Accessibility",
- "accessibilityDescription": "Enable in System Settings by toggling it on",
+ "accessibilityDescription": "Allows auto-pasting transcribed text into any app",
"testAndGrant": "Test & Grant",
"requiredForApp": "Required for OpenWhispr to work",
"microphoneRequired": "Microphone access required",
@@ -1383,6 +1384,7 @@
"optional": "Optional",
"systemAudioTitle": "System Audio",
"systemAudioDescription": "Captures other participants' audio from calls and meetings",
+ "grantAccess": "Grant Access",
"test": "Test",
"testAndGrant": "Test & Grant",
"title": "Permissions",
diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json
index baeee075b..91f60ea1c 100644
--- a/src/locales/es/translation.json
+++ b/src/locales/es/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Micrófono",
"microphoneDescription": "Captura tu voz para la transcripción",
"grant": "Conceder",
+ "grantAccess": "Conceder acceso",
"accessibilityTitle": "Accesibilidad",
- "accessibilityDescription": "Actívalo en Ajustes del Sistema",
+ "accessibilityDescription": "Permite pegar automáticamente el texto transcrito en cualquier aplicación",
"testAndGrant": "Probar y conceder",
"requiredForApp": "Necesario para que OpenWhispr funcione",
"microphoneRequired": "Se requiere acceso al micrófono",
@@ -1335,6 +1336,7 @@
"optional": "Opcional",
"systemAudioTitle": "Audio del Sistema",
"systemAudioDescription": "Captura el audio de otros participantes en llamadas y reuniones",
+ "grantAccess": "Conceder acceso",
"test": "Probar",
"testAndGrant": "Probar y conceder",
"title": "Permisos",
diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json
index de02ec63c..36c6f02db 100644
--- a/src/locales/fr/translation.json
+++ b/src/locales/fr/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Microphone",
"microphoneDescription": "Capture votre voix pour la transcription",
"grant": "Autoriser",
+ "grantAccess": "Accorder l'accès",
"accessibilityTitle": "Accessibilité",
- "accessibilityDescription": "Activez dans les Réglages Système",
+ "accessibilityDescription": "Permet de coller automatiquement le texte transcrit dans n'importe quelle application",
"testAndGrant": "Tester et autoriser",
"requiredForApp": "Nécessaire pour le bon fonctionnement d'OpenWhispr",
"microphoneRequired": "Accès microphone requis",
@@ -1335,6 +1336,7 @@
"optional": "Facultatif",
"systemAudioTitle": "Audio Système",
"systemAudioDescription": "Capture l'audio des autres participants lors d'appels et de réunions",
+ "grantAccess": "Accorder l'accès",
"test": "Tester",
"testAndGrant": "Tester et autoriser",
"title": "Permissions",
diff --git a/src/locales/it/translation.json b/src/locales/it/translation.json
index 96f3e6b79..9b0d20064 100644
--- a/src/locales/it/translation.json
+++ b/src/locales/it/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Microfono",
"microphoneDescription": "Cattura la tua voce per la trascrizione",
"grant": "Concedi",
+ "grantAccess": "Concedi accesso",
"accessibilityTitle": "Accessibilità",
- "accessibilityDescription": "Attiva nelle Impostazioni di Sistema",
+ "accessibilityDescription": "Permette di incollare automaticamente il testo trascritto in qualsiasi app",
"testAndGrant": "Testa e concedi",
"requiredForApp": "Necessario per usare OpenWhispr",
"microphoneRequired": "Accesso al microfono richiesto",
@@ -1335,6 +1336,7 @@
"optional": "Facoltativo",
"systemAudioTitle": "Audio di Sistema",
"systemAudioDescription": "Cattura l'audio degli altri partecipanti durante chiamate e riunioni",
+ "grantAccess": "Concedi accesso",
"test": "Test",
"testAndGrant": "Testa e concedi",
"title": "Permessi",
diff --git a/src/locales/ja/translation.json b/src/locales/ja/translation.json
index abe86df3c..e05ed8811 100644
--- a/src/locales/ja/translation.json
+++ b/src/locales/ja/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "マイク",
"microphoneDescription": "文字起こしのためにあなたの声を録音します",
"grant": "許可",
+ "grantAccess": "アクセスを許可",
"accessibilityTitle": "アクセシビリティ",
- "accessibilityDescription": "システム設定でオンに切り替えてください",
+ "accessibilityDescription": "文字起こしテキストを任意のアプリに自動貼り付けします",
"testAndGrant": "テストして許可",
"requiredForApp": "OpenWhispr の動作に必要です",
"microphoneRequired": "マイクへのアクセスが必要です",
@@ -1335,6 +1336,7 @@
"optional": "任意",
"systemAudioTitle": "システムオーディオ",
"systemAudioDescription": "通話や会議で他の参加者の音声を録音します",
+ "grantAccess": "アクセスを許可",
"test": "テスト",
"testAndGrant": "テストして許可",
"title": "権限",
diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json
index 14bca2e7a..f032757a0 100644
--- a/src/locales/pt/translation.json
+++ b/src/locales/pt/translation.json
@@ -129,8 +129,9 @@
"microphoneTitle": "Microfone",
"microphoneDescription": "Captura a sua voz para transcrição",
"grant": "Conceder",
+ "grantAccess": "Conceder acesso",
"accessibilityTitle": "Acessibilidade",
- "accessibilityDescription": "Ative nas Configurações do Sistema",
+ "accessibilityDescription": "Permite colar automaticamente o texto transcrito em qualquer aplicativo",
"testAndGrant": "Testar e conceder",
"requiredForApp": "Necessário para o OpenWhispr funcionar",
"microphoneRequired": "Acesso ao microfone necessário",
@@ -1307,6 +1308,7 @@
"optional": "Opcional",
"systemAudioTitle": "Áudio do Sistema",
"systemAudioDescription": "Captura o áudio dos outros participantes em chamadas e reuniões",
+ "grantAccess": "Conceder acesso",
"test": "Testar",
"testAndGrant": "Testar e conceder",
"title": "Permissões",
diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json
index 167b1c81a..7d11631f9 100644
--- a/src/locales/ru/translation.json
+++ b/src/locales/ru/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "Микрофон",
"microphoneDescription": "Записывает ваш голос для транскрипции",
"grant": "Предоставить",
+ "grantAccess": "Предоставить доступ",
"accessibilityTitle": "Универсальный доступ",
- "accessibilityDescription": "Включите в Системных настройках",
+ "accessibilityDescription": "Позволяет автоматически вставлять транскрибированный текст в любое приложение",
"testAndGrant": "Проверить и предоставить",
"requiredForApp": "Необходимо для работы OpenWhispr",
"microphoneRequired": "Требуется доступ к микрофону",
@@ -1335,6 +1336,7 @@
"optional": "Необязательно",
"systemAudioTitle": "Системное аудио",
"systemAudioDescription": "Записывает аудио других участников звонков и совещаний",
+ "grantAccess": "Предоставить доступ",
"test": "Тест",
"testAndGrant": "Проверить и предоставить",
"title": "Разрешения",
diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json
index 0115def16..188a5c885 100644
--- a/src/locales/zh-CN/translation.json
+++ b/src/locales/zh-CN/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "麦克风",
"microphoneDescription": "录制您的声音用于转录",
"grant": "授权",
+ "grantAccess": "授予访问权限",
"accessibilityTitle": "辅助功能",
- "accessibilityDescription": "在系统设置中开启此权限",
+ "accessibilityDescription": "允许将转录文本自动粘贴到任何应用程序",
"testAndGrant": "测试并授权",
"requiredForApp": "OpenWhispr 运行所必需的权限",
"microphoneRequired": "需要麦克风访问权限",
@@ -1335,6 +1336,7 @@
"optional": "可选",
"systemAudioTitle": "系统音频",
"systemAudioDescription": "录制通话和会议中其他参与者的音频",
+ "grantAccess": "授予访问权限",
"test": "测试",
"testAndGrant": "测试并授权",
"title": "权限",
diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json
index 0447dd8b8..9fe0164ed 100644
--- a/src/locales/zh-TW/translation.json
+++ b/src/locales/zh-TW/translation.json
@@ -157,8 +157,9 @@
"microphoneTitle": "麥克風",
"microphoneDescription": "錄製您的聲音用於轉錄",
"grant": "授權",
+ "grantAccess": "授予存取權限",
"accessibilityTitle": "輔助使用",
- "accessibilityDescription": "在系統設定中開啟此權限",
+ "accessibilityDescription": "允許將轉錄文字自動貼上到任何應用程式",
"testAndGrant": "測試並授權",
"requiredForApp": "OpenWhispr 運作所需",
"microphoneRequired": "需要麥克風存取權限",
@@ -1335,6 +1336,7 @@
"optional": "可選",
"systemAudioTitle": "系統音訊",
"systemAudioDescription": "錄製通話和會議中其他參與者的音訊",
+ "grantAccess": "授予存取權限",
"test": "測試",
"testAndGrant": "測試並授權",
"title": "權限",