Skip to content

Commit 96505cc

Browse files
committed
fix(macos): properly handle accessibility permission
1 parent af8ef23 commit 96505cc

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

src/platform/macos/input.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <chrono>
99
#include <mach/mach.h>
1010

11+
#include "misc.h"
12+
1113
#include "src/logging.h"
1214
#include "src/platform/common.h"
1315
#include "src/utility.h"
@@ -226,6 +228,11 @@ const KeyCodeMap kKeyCodesMap[] = {
226228
};
227229
// clang-format on
228230

231+
/**
232+
* Used to avoid spamming permission requests when the user receives an input event
233+
*/
234+
bool accessibility_permission_requested;
235+
229236
int
230237
keysym(int keycode) {
231238
KeyCodeMap key_map {};
@@ -242,12 +249,36 @@ const KeyCodeMap kKeyCodesMap[] = {
242249
return temp_map->mac_keycode;
243250
}
244251

252+
std::string
253+
default_accessibility_log_msg() {
254+
return "Accessibility permission is not enabled,"
255+
" please enable sunshine in "
256+
"[System Settings > Privacy & Security > Privacy > Accessibility]"
257+
", then please restart Sunshine for it to take effect";
258+
}
259+
260+
void
261+
print_accessibility_status(const bool is_keyboard_event, const bool release) {
262+
if (!release) return;
263+
264+
if (!has_accessibility_permission()) {
265+
if (!accessibility_permission_requested) {
266+
accessibility_permission_requested = true;
267+
request_accessibility_permission();
268+
}
269+
BOOST_LOG(info) << "Received " << (is_keyboard_event ? "keyboard" : "mouse") << " event but "
270+
<< default_accessibility_log_msg();
271+
}
272+
}
273+
245274
void
246275
keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags) {
247276
auto key = keysym(modcode);
248277

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

280+
print_accessibility_status(true, release);
281+
251282
if (key < 0) {
252283
return;
253284
}
@@ -437,6 +468,8 @@ const KeyCodeMap kKeyCodesMap[] = {
437468
BOOST_LOG(warning) << "Unsupported mouse button for MacOS: "sv << button;
438469
return;
439470
}
471+
472+
print_accessibility_status(false, release);
440473

441474
macos_input->mouse_down[mac_button] = !release;
442475

@@ -538,6 +571,11 @@ const KeyCodeMap kKeyCodesMap[] = {
538571

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

574+
accessibility_permission_requested = false;
575+
if (request_accessibility_permission()) {
576+
BOOST_LOG(info) << default_accessibility_log_msg() << ", to allow mouse clicks and keyboard inputs.";
577+
}
578+
541579
// Default to main display
542580
macos_input->display = CGMainDisplayID();
543581

src/platform/macos/misc.h

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@
1111
namespace platf {
1212
bool
1313
is_screen_capture_allowed();
14+
15+
/**
16+
* Prompts the user for Accessibility permission
17+
* @return returns true if requested permission, false if already has permission
18+
*/
19+
bool
20+
request_accessibility_permission();
21+
22+
/**
23+
* Checks for Accessibility permission
24+
* @return returns true if sunshine has Accessibility permission enabled
25+
*/
26+
bool
27+
has_accessibility_permission();
1428
}
1529

1630
namespace dyn {

src/platform/macos/misc.mm

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#define __APPLE_USE_RFC_3542 1
99
#endif
1010

11+
#include <Carbon/Carbon.h>
12+
1113
#include <Foundation/Foundation.h>
1214
#include <arpa/inet.h>
1315
#include <dlfcn.h>
@@ -538,6 +540,21 @@
538540

539541
return std::make_unique<qos_t>(sockfd, reset_options);
540542
}
543+
544+
bool
545+
request_accessibility_permission() {
546+
NSDictionary* options = @{static_cast<id>(kAXTrustedCheckOptionPrompt): @YES};
547+
return !AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef>(options));
548+
}
549+
550+
bool
551+
has_accessibility_permission() {
552+
NSDictionary* options = @{static_cast<id>(kAXTrustedCheckOptionPrompt): @NO};
553+
// We use kAXTrustedCheckOptionPrompt == NO here,
554+
// instead of using XIsProcessTrusted(),
555+
// because this will update the accessibility list with sunshine current path
556+
return AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef>(options));
557+
}
541558

542559
std::string
543560
get_host_name() {

0 commit comments

Comments
 (0)