//go:build darwin
|
|
package permissions
|
|
/*
|
#cgo CFLAGS: -x objective-c
|
#cgo LDFLAGS: -framework ApplicationServices -framework AVFoundation
|
#include <ApplicationServices/ApplicationServices.h>
|
#import <AVFoundation/AVFoundation.h>
|
|
static int accessibilityGranted(void) {
|
return AXIsProcessTrusted() ? 1 : 0;
|
}
|
|
static void requestAccessibility(void) {
|
NSDictionary* opts = @{(__bridge NSString*)kAXTrustedCheckOptionPrompt: @YES};
|
AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts);
|
}
|
|
static int inputMonitoringGranted(void) {
|
return CGPreflightListenEventAccess() ? 1 : 0;
|
}
|
|
static void requestInputMonitoring(void) {
|
CGRequestListenEventAccess();
|
}
|
|
static int microphoneStatus(void) {
|
return (int)[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
|
}
|
|
static int requestMicrophone(void) {
|
__block int granted = 0;
|
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
|
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL ok) {
|
granted = ok ? 1 : 0;
|
dispatch_semaphore_signal(sem);
|
}];
|
dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC));
|
return granted;
|
}
|
*/
|
import "C"
|
|
import (
|
"os/exec"
|
"voicesnap/internal/startup"
|
)
|
|
// Statuses returns the current macOS privacy permission state.
|
func Statuses() []Status {
|
return []Status{
|
{
|
ID: IDMicrophone,
|
Granted: C.microphoneStatus() == 3,
|
State: microphoneState(int(C.microphoneStatus())),
|
Required: true,
|
},
|
{
|
ID: IDAccessibility,
|
Granted: C.accessibilityGranted() != 0,
|
State: grantedState(C.accessibilityGranted() != 0),
|
Required: true,
|
},
|
{
|
ID: IDInputMonitoring,
|
Granted: C.inputMonitoringGranted() != 0,
|
State: grantedState(C.inputMonitoringGranted() != 0),
|
Required: true,
|
},
|
{
|
ID: IDBackground,
|
Granted: startup.IsEnabled(),
|
State: enabledState(startup.IsEnabled()),
|
Required: false,
|
},
|
}
|
}
|
|
// Request asks macOS for a permission where a public prompt API exists,
|
// then opens the matching System Settings pane.
|
func Request(id string) {
|
switch id {
|
case IDMicrophone:
|
C.requestMicrophone()
|
openSettings(id)
|
case IDAccessibility:
|
C.requestAccessibility()
|
openSettings(id)
|
case IDInputMonitoring:
|
C.requestInputMonitoring()
|
openSettings(id)
|
case IDBackground:
|
_ = startup.SetEnabled(true)
|
openSettings(id)
|
}
|
}
|
|
func OpenSettings(id string) {
|
openSettings(id)
|
}
|
|
func microphoneState(status int) string {
|
switch status {
|
case 0:
|
return "notDetermined"
|
case 1:
|
return "restricted"
|
case 2:
|
return "denied"
|
case 3:
|
return "granted"
|
default:
|
return "unknown"
|
}
|
}
|
|
func grantedState(granted bool) string {
|
if granted {
|
return "granted"
|
}
|
return "denied"
|
}
|
|
func enabledState(enabled bool) string {
|
if enabled {
|
return "enabled"
|
}
|
return "disabled"
|
}
|
|
func openSettings(id string) {
|
url := "x-apple.systempreferences:com.apple.preference.security"
|
switch id {
|
case IDMicrophone:
|
url = "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone"
|
case IDAccessibility:
|
url = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
|
case IDInputMonitoring:
|
url = "x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent"
|
case IDBackground:
|
url = "x-apple.systempreferences:com.apple.LoginItems-Settings.extension"
|
}
|
_ = exec.Command("open", url).Start()
|
}
|