Skip to content

Commit

Permalink
fix(macos): properly handle accessibility permission
Browse files Browse the repository at this point in the history
  • Loading branch information
Hazer committed Dec 23, 2024
1 parent 129abd8 commit f8fda7f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/platform/macos/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <chrono>
#include <mach/mach.h>

#include "misc.h"

#include "src/display_device.h"
#include "src/logging.h"
#include "src/platform/common.h"
Expand Down Expand Up @@ -227,6 +229,11 @@ const KeyCodeMap kKeyCodesMap[] = {
};
// clang-format on

/**
* Used to avoid spamming permission requests when the user receives an input event
*/
bool accessibility_permission_requested;

int
keysym(int keycode) {
KeyCodeMap key_map {};
Expand All @@ -243,12 +250,36 @@ const KeyCodeMap kKeyCodesMap[] = {
return temp_map->mac_keycode;
}

std::string
default_accessibility_log_msg() {
return "Accessibility permission is not enabled,"
" please enable sunshine in "
"[System Settings > Privacy & Security > Privacy > Accessibility]"
", then please restart Sunshine for it to take effect";
}

void
print_accessibility_status(const bool is_keyboard_event, const bool release) {
if (!release) return;

if (!has_accessibility_permission()) {
if (!accessibility_permission_requested) {
accessibility_permission_requested = true;
request_accessibility_permission();
}
BOOST_LOG(info) << "Received " << (is_keyboard_event ? "keyboard" : "mouse") << " event but "
<< default_accessibility_log_msg();
}
}

void
keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags) {
auto key = keysym(modcode);

BOOST_LOG(debug) << "got keycode: 0x"sv << std::hex << modcode << ", translated to: 0x" << std::hex << key << ", release:" << release;

print_accessibility_status(true, release);

if (key < 0) {
return;
}
Expand Down Expand Up @@ -439,6 +470,8 @@ const KeyCodeMap kKeyCodesMap[] = {
return;
}

print_accessibility_status(false, release);

macos_input->mouse_down[mac_button] = !release;

// if the last mouse down was less than MULTICLICK_DELAY_MS, we send a double click event
Expand Down Expand Up @@ -539,6 +572,11 @@ const KeyCodeMap kKeyCodesMap[] = {

const auto macos_input = static_cast<macos_input_t *>(result.get());

accessibility_permission_requested = false;
if (request_accessibility_permission()) {
BOOST_LOG(info) << default_accessibility_log_msg() << ", to allow mouse clicks and keyboard inputs.";
}

// Default to main display
macos_input->display = CGMainDisplayID();

Expand Down
14 changes: 14 additions & 0 deletions src/platform/macos/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
namespace platf {
bool
is_screen_capture_allowed();

/**
* Prompts the user for Accessibility permission
* @return returns true if requested permission, false if already has permission
*/
bool
request_accessibility_permission();

/**
* Checks for Accessibility permission
* @return returns true if sunshine has Accessibility permission enabled
*/
bool
has_accessibility_permission();
}

namespace dyn {
Expand Down
18 changes: 18 additions & 0 deletions src/platform/macos/misc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#define __APPLE_USE_RFC_3542 1
#endif

#include <Carbon/Carbon.h>

#include <Foundation/Foundation.h>
#include <arpa/inet.h>
#include <dlfcn.h>
Expand Down Expand Up @@ -566,6 +568,22 @@ operator bool() override {
create_high_precision_timer() {
return std::make_unique<macos_high_precision_timer>();
}

bool
request_accessibility_permission() {
NSDictionary* options = @{static_cast<id> (kAXTrustedCheckOptionPrompt): @YES};
return !AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef> (options));
}

bool
has_accessibility_permission() {
NSDictionary* options = @{static_cast<id> (kAXTrustedCheckOptionPrompt): @NO};
// We use kAXTrustedCheckOptionPrompt == NO here,
// instead of using XIsProcessTrusted(),
// because this will update the accessibility list with sunshine current path
return AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef> (options));
}

} // namespace platf

namespace dyn {
Expand Down

0 comments on commit f8fda7f

Please sign in to comment.