Browse Source

fix: don't register some shortcuts without accessibility (#16276)

Shelley Vohr 6 years ago
parent
commit
8f629a2f31

+ 36 - 1
atom/browser/api/atom_api_global_shortcut.cc

@@ -6,15 +6,45 @@
 
 #include <string>
 
+#include "atom/browser/api/atom_api_system_preferences.h"
 #include "atom/common/native_mate_converters/accelerator_converter.h"
 #include "atom/common/native_mate_converters/callback.h"
 #include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "native_mate/dictionary.h"
 
 #include "atom/common/node_includes.h"
+#include "atom/common/platform_util.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
 
 using extensions::GlobalShortcutListener;
 
+namespace {
+
+#if defined(OS_MACOSX)
+bool RegisteringMediaKeyForUntrustedClient(const ui::Accelerator& accelerator) {
+  if (platform_util::IsAtLeastOS10_14()) {
+    constexpr ui::KeyboardCode mediaKeys[] = {
+        ui::VKEY_MEDIA_PLAY_PAUSE, ui::VKEY_MEDIA_NEXT_TRACK,
+        ui::VKEY_MEDIA_PREV_TRACK, ui::VKEY_MEDIA_STOP};
+
+    if (std::find(std::begin(mediaKeys), std::end(mediaKeys),
+                  accelerator.key_code()) != std::end(mediaKeys)) {
+      bool trusted =
+          atom::api::SystemPreferences::IsTrustedAccessibilityClient(false);
+      if (!trusted)
+        return true;
+    }
+  }
+  return false;
+}
+#endif
+
+}  // namespace
+
 namespace atom {
 
 namespace api {
@@ -31,7 +61,7 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
   if (accelerator_callback_map_.find(accelerator) ==
       accelerator_callback_map_.end()) {
     // This should never occur, because if it does, GlobalGlobalShortcutListener
-    // notifes us with wrong accelerator.
+    // notifies us with wrong accelerator.
     NOTREACHED();
     return;
   }
@@ -40,6 +70,11 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
 
 bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
                               const base::Closure& callback) {
+#if defined(OS_MACOSX)
+  if (RegisteringMediaKeyForUntrustedClient(accelerator))
+    return false;
+#endif
+
   if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(accelerator,
                                                                   this)) {
     return false;

+ 2 - 0
atom/browser/api/atom_api_system_preferences.h

@@ -93,6 +93,8 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences>
                       mate::Arguments* args);
   void RemoveUserDefault(const std::string& name);
   bool IsSwipeTrackingFromScrollEventsEnabled();
+
+  static bool IsTrustedAccessibilityClient(bool prompt);
 #endif
   bool IsDarkMode();
   bool IsInvertedColorScheme();

+ 6 - 0
atom/browser/api/atom_api_system_preferences_mac.mm

@@ -308,6 +308,12 @@ void SystemPreferences::SetUserDefault(const std::string& name,
   }
 }
 
+// static
+bool SystemPreferences::IsTrustedAccessibilityClient(bool prompt) {
+  NSDictionary* options = @{(id)kAXTrustedCheckOptionPrompt : @(prompt)};
+  return AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
+}
+
 void SystemPreferences::RemoveUserDefault(const std::string& name) {
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
   [defaults removeObjectForKey:base::SysUTF8ToNSString(name)];

+ 1 - 0
atom/common/platform_util.h

@@ -60,6 +60,7 @@ void Beep();
 #if defined(OS_MACOSX)
 bool GetLoginItemEnabled();
 void SetLoginItemEnabled(bool enabled);
+bool IsAtLeastOS10_14();
 #endif
 
 }  // namespace platform_util

+ 7 - 0
atom/common/platform_util_mac.mm

@@ -8,6 +8,8 @@
 #import <Cocoa/Cocoa.h>
 #import <ServiceManagement/ServiceManagement.h>
 
+#include "atom/common/platform_util.h"
+
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -18,6 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "net/base/mac/url_conversions.h"
+#include "third_party/WebKit/Source/platform/mac/VersionUtilMac.h"
 #include "url/gurl.h"
 
 namespace {
@@ -166,6 +169,10 @@ void OpenExternal(const GURL& url,
                  });
 }
 
+bool IsAtLeastOS10_14() {
+  return blink::internal::MacOSXMinorVersion() >= 14;
+}
+
 bool MoveItemToTrash(const base::FilePath& full_path) {
   NSString* path_string = base::SysUTF8ToNSString(full_path.value());
   BOOL status = [[NSFileManager defaultManager]

+ 8 - 0
docs/api/global-shortcut.md

@@ -54,6 +54,14 @@ When the accelerator is already taken by other applications, this call will
 silently fail. This behavior is intended by operating systems, since they don't
 want applications to fight for global shortcuts.
 
+The following accelerators will not be registered successfully on macOS 10.14 Mojave unless
+the app has been authorized as a [trusted accessibility client](https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html):
+
+* "Media Play/Pause"
+* "Media Next Track"
+* "Media Previous Track"
+* "Media Stop"
+
 ### `globalShortcut.isRegistered(accelerator)`
 
 * `accelerator` [Accelerator](accelerator.md)