mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 12:47:42 +02:00
[eric] dictation: using dictation asks for the fn grant every time, not once per launch (ENG-360)
This commit is contained in:
@@ -482,15 +482,31 @@ function installVoiceHotkey(getMainWindow) {
|
||||
// but a running tap makes macOS list the app in that pane for the user to flip.
|
||||
ipcMain.handle('voice:request-hold-permission', () => {
|
||||
armNativeTiers();
|
||||
askForFnPermission();
|
||||
if (process.platform === 'darwin' && !tapProven) {
|
||||
try { systemPreferences.isTrustedAccessibilityClient(true); } catch (_) {}
|
||||
}
|
||||
return tapProven;
|
||||
});
|
||||
// Deliberately re-asked on every dictation attempt, not once per launch: armNativeTiers is
|
||||
// one-shot, so a user who was denied (or dismissed the prompt) could never be asked again, which
|
||||
// is how a permission you are willing to grant turns into a key that just never works.
|
||||
let lastFnAskMs = 0;
|
||||
const askForFnPermission = () => {
|
||||
if (process.platform !== 'darwin' || combo.special !== 'fn' || fnProc) return;
|
||||
const now = Date.now();
|
||||
if (now - lastFnAskMs < 10_000) return;
|
||||
lastFnAskMs = now;
|
||||
unusableNotified = false;
|
||||
startFnWatcher();
|
||||
};
|
||||
|
||||
// Fires the real TCC mic prompt BEFORE the first capture: with the entitlement present but no
|
||||
// prior grant, getUserMedia would still fail once and burn the user's first dictation attempt.
|
||||
ipcMain.handle('voice:request-mic-access', async () => {
|
||||
armNativeTiers();
|
||||
// Using dictation IS the intent that earns the fn prompt, every time, not just the first.
|
||||
askForFnPermission();
|
||||
if (process.platform !== 'darwin') return true;
|
||||
try {
|
||||
if (systemPreferences.getMediaAccessStatus('microphone') === 'granted') return true;
|
||||
|
||||
@@ -92,3 +92,28 @@ test('a key that starts working retracts its own warning', () => {
|
||||
assert.match(provenBlock, /lastHotkeyIssue = null/);
|
||||
assert.match(provenBlock, /voice:primary-usable/);
|
||||
});
|
||||
|
||||
// ---- Asking is part of the feature, not a one-shot side effect ----
|
||||
// Eric: "if the user clicks it, they should still ask for microphone permission and fn permissions".
|
||||
// armNativeTiers is one-shot, so a denied (or dismissed) grant could never be re-requested and the
|
||||
// key stayed dead for the life of the install even though the user was willing to grant it.
|
||||
|
||||
test('using dictation re-asks for the fn grant, not just the first time', () => {
|
||||
assert.match(hotkeySrc, /const askForFnPermission = \(\) => \{/);
|
||||
const micHandler = hotkeySrc.split("ipcMain.handle('voice:request-mic-access'")[1].slice(0, 300);
|
||||
assert.match(micHandler, /askForFnPermission\(\)/,
|
||||
'the mic prompt and the fn prompt are the same moment of intent');
|
||||
const holdHandler = hotkeySrc.split("ipcMain.handle('voice:request-hold-permission'")[1].slice(0, 300);
|
||||
assert.match(holdHandler, /askForFnPermission\(\)/);
|
||||
});
|
||||
|
||||
test('the re-ask is throttled so it cannot spawn a watcher per keystroke', () => {
|
||||
const fn = hotkeySrc.split('const askForFnPermission')[1].slice(0, 400);
|
||||
assert.match(fn, /lastFnAskMs/);
|
||||
assert.match(fn, /return;/);
|
||||
});
|
||||
|
||||
test('the intent path spawns WITHOUT --no-prompt, or nothing is ever asked', () => {
|
||||
const fn = hotkeySrc.split('const askForFnPermission')[1].slice(0, 400);
|
||||
assert.match(fn, /startFnWatcher\(\);/, 'a --no-prompt spawn here would silently never prompt');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user