electron/shell/browser/api/electron_api_global_shortcut.cc
Charles Kerr 60c4c9fec6
chore: remove unused #includes (#42971)
* chore: iwyu buildflags.h

* chore: iwyu dictionary.h

* chore: iwyu arguments.h

* chore: iwyu values.h

* chore: iwyu compiler_specific.h

* chore: iwyu binder_map.h

* chore: iwyu <vector>

* chore: iwyu <set>

* chore: iwyu raw_ptr

* chore: iwyu gfx/canvas.h

* chore: iwyu gfx/color_utils.h

* chore: iwyu base/strings/stringprintf.h

* chore: iwyu base/task/thread_pool.h

* chore: iwyu base/no_destructor.h

* chore: iwyu base/path_service.h

* chore: iwyu base/files/file_pathh

* chore: iwyu base/strings/sys_string_conversions.h

* chore: iwyu base/logging.h

* chore: iwyu base/command_line.h

* chore: iwyu base/files/file_util.h

* chore: iwyu base/files/scoped_file.h

* chore: iwyu base/strings/utf_string_conversions.h

* chore: iwyu base/environment.h

* chore: iwyu base/scoped_observation.h

* chore: iwyu base/strings/string_split.h

* chore: iwyu base/strings/pattern.h

* chore: iwyu base/json/string_escape.h

* chore: iwyu base/json/json_reader.h

* chore: iwyu base/memory/singleton.h

* chore: iwyu base/observer_list.h

* chore: iwyu base/timer/timer.h

* fixup! chore: iwyu values.h

* chore: iwyu shell/browser/browser.h

* chore: iwyu base/stl_util.h

* chore: iwyu base/strings/string_util.h

* chore: iwyu shell/browser/javascript_environment.h

* chore: iwyu base/memory/ref_counted.h

* chore: iwyu base/environment.h

* chore: iwyu content/public/browser/browser_thread.h

* chore: remove unused typedef gin_helper::EventEmitter::ValueArray

* chore: iwyu gin/wrappable.h

* chore: iwyu shell/common/gin_helper/function_template_extensions.h

* chore: iwyu shell/common/gin_converters/login_item_settings_converter.h

* chore: iwyu shell/common/gin_helper/arguments.h

* chore: iwyu ui/gfx/skia_util.h

* chore: iwyu ui/gfx/geometry/rect.h

* chore: iwyu ui/gfx/image/image.h

* chore: iwyu base/strings/strcat.h

* chore: iwyu ui/native_theme/native_theme.h

* fixup! chore: iwyu shell/browser/javascript_environment.h

* fixup! chore: iwyu gfx/canvas.h

* fixup! chore: iwyu content/public/browser/browser_thread.h

* fixup! chore: iwyu ui/native_theme/native_theme.h

* fixup! chore: iwyu ui/native_theme/native_theme.h
2024-07-22 11:31:32 +02:00

188 lines
5.8 KiB
C++

// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/api/electron_api_global_shortcut.h"
#include <vector>
#include "base/containers/contains.h"
#include "extensions/common/command.h"
#include "gin/dictionary.h"
#include "gin/object_template_builder.h"
#include "shell/browser/api/electron_api_system_preferences.h"
#include "shell/browser/browser.h"
#include "shell/common/gin_converters/accelerator_converter.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/node_includes.h"
#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
using extensions::Command;
using extensions::GlobalShortcutListener;
namespace {
#if BUILDFLAG(IS_MAC)
bool RegisteringMediaKeyForUntrustedClient(const ui::Accelerator& accelerator) {
return Command::IsMediaKey(accelerator) &&
!electron::api::SystemPreferences::IsTrustedAccessibilityClient(false);
}
bool MapHasMediaKeys(
const std::map<ui::Accelerator, base::RepeatingClosure>& accelerator_map) {
auto media_key = std::find_if(
accelerator_map.begin(), accelerator_map.end(),
[](const auto& ac) { return Command::IsMediaKey(ac.first); });
return media_key != accelerator_map.end();
}
#endif
} // namespace
namespace electron::api {
gin::WrapperInfo GlobalShortcut::kWrapperInfo = {gin::kEmbedderNativeGin};
GlobalShortcut::GlobalShortcut(v8::Isolate* isolate) {}
GlobalShortcut::~GlobalShortcut() {
UnregisterAll();
}
void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
if (!base::Contains(accelerator_callback_map_, accelerator)) {
// This should never occur, because if it does, GlobalShortcutListener
// notifies us with wrong accelerator.
NOTREACHED();
}
accelerator_callback_map_[accelerator].Run();
}
bool GlobalShortcut::RegisterAll(
const std::vector<ui::Accelerator>& accelerators,
const base::RepeatingClosure& callback) {
if (!electron::Browser::Get()->is_ready()) {
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
.ThrowError("globalShortcut cannot be used before the app is ready");
return false;
}
std::vector<ui::Accelerator> registered;
for (auto& accelerator : accelerators) {
if (!Register(accelerator, callback)) {
// Unregister all shortcuts if any failed.
UnregisterSome(registered);
return false;
}
registered.push_back(accelerator);
}
return true;
}
bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
const base::RepeatingClosure& callback) {
if (!electron::Browser::Get()->is_ready()) {
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
.ThrowError("globalShortcut cannot be used before the app is ready");
return false;
}
#if BUILDFLAG(IS_MAC)
if (Command::IsMediaKey(accelerator)) {
if (RegisteringMediaKeyForUntrustedClient(accelerator))
return false;
GlobalShortcutListener::SetShouldUseInternalMediaKeyHandling(false);
}
#endif
if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(accelerator,
this)) {
return false;
}
accelerator_callback_map_[accelerator] = callback;
return true;
}
void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
if (!electron::Browser::Get()->is_ready()) {
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
.ThrowError("globalShortcut cannot be used before the app is ready");
return;
}
if (accelerator_callback_map_.erase(accelerator) == 0)
return;
#if BUILDFLAG(IS_MAC)
if (Command::IsMediaKey(accelerator) &&
!MapHasMediaKeys(accelerator_callback_map_)) {
GlobalShortcutListener::SetShouldUseInternalMediaKeyHandling(true);
}
#endif
GlobalShortcutListener::GetInstance()->UnregisterAccelerator(accelerator,
this);
}
void GlobalShortcut::UnregisterSome(
const std::vector<ui::Accelerator>& accelerators) {
for (auto& accelerator : accelerators) {
Unregister(accelerator);
}
}
bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) {
return base::Contains(accelerator_callback_map_, accelerator);
}
void GlobalShortcut::UnregisterAll() {
if (!electron::Browser::Get()->is_ready()) {
gin_helper::ErrorThrower(JavascriptEnvironment::GetIsolate())
.ThrowError("globalShortcut cannot be used before the app is ready");
return;
}
accelerator_callback_map_.clear();
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
}
// static
gin::Handle<GlobalShortcut> GlobalShortcut::Create(v8::Isolate* isolate) {
return gin::CreateHandle(isolate, new GlobalShortcut(isolate));
}
// static
gin::ObjectTemplateBuilder GlobalShortcut::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<GlobalShortcut>::GetObjectTemplateBuilder(isolate)
.SetMethod("registerAll", &GlobalShortcut::RegisterAll)
.SetMethod("register", &GlobalShortcut::Register)
.SetMethod("isRegistered", &GlobalShortcut::IsRegistered)
.SetMethod("unregister", &GlobalShortcut::Unregister)
.SetMethod("unregisterAll", &GlobalShortcut::UnregisterAll);
}
const char* GlobalShortcut::GetTypeName() {
return "GlobalShortcut";
}
} // namespace electron::api
namespace {
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
v8::Isolate* isolate = context->GetIsolate();
gin::Dictionary dict(isolate, exports);
dict.Set("globalShortcut", electron::api::GlobalShortcut::Create(isolate));
}
} // namespace
NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_global_shortcut, Initialize)