diff --git a/atom/browser/api/atom_api_global_shortcut.cc b/atom/browser/api/atom_api_global_shortcut.cc index 4fc7532d9e346..8598c2f8a5503 100644 --- a/atom/browser/api/atom_api_global_shortcut.cc +++ b/atom/browser/api/atom_api_global_shortcut.cc @@ -6,15 +6,44 @@ #include +#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" +#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 (base::mac::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 +60,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 +69,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; diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h index bfd64e80159dc..37671a8e221c4 100644 --- a/atom/browser/api/atom_api_system_preferences.h +++ b/atom/browser/api/atom_api_system_preferences.h @@ -93,6 +93,8 @@ class SystemPreferences : public mate::EventEmitter mate::Arguments* args); void RemoveUserDefault(const std::string& name); bool IsSwipeTrackingFromScrollEventsEnabled(); + + static bool IsTrustedAccessibilityClient(bool prompt); #endif bool IsDarkMode(); bool IsInvertedColorScheme(); diff --git a/atom/browser/api/atom_api_system_preferences_mac.mm b/atom/browser/api/atom_api_system_preferences_mac.mm index 99fb216f5c48e..f26212968647e 100644 --- a/atom/browser/api/atom_api_system_preferences_mac.mm +++ b/atom/browser/api/atom_api_system_preferences_mac.mm @@ -308,6 +308,12 @@ } } +// 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)]; diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md index d0f48a6f8055c..802ef14a2ecb3 100644 --- a/docs/api/global-shortcut.md +++ b/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)