feat: add MenuItem.userAccelerator property (#26682)

* feat: add MenuItem.userAccelerator property

This allows folks to read the user-assigned accelerator that macOS users can provide in system preferences. Useful for showing in-app shortcut help dialogs, you need to know if the accelerator you provided is not being used in favor of a user assigned one.

* chore: update syntax

* chore: add safety check for command index being -1
This commit is contained in:
Samuel Attard 2021-06-29 16:28:16 -07:00 committed by GitHub
parent 3e69985b76
commit da9261497e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 9 deletions

View file

@ -212,7 +212,7 @@ void Menu::Clear() {
model_->Clear();
}
int Menu::GetIndexOfCommandId(int command_id) {
int Menu::GetIndexOfCommandId(int command_id) const {
return model_->GetIndexOfCommandId(command_id);
}
@ -299,6 +299,9 @@ v8::Local<v8::ObjectTemplate> Menu::FillObjectTemplate(
.SetMethod("closePopupAt", &Menu::ClosePopupAt)
#if DCHECK_IS_ON()
.SetMethod("getAcceleratorTextAt", &Menu::GetAcceleratorTextAtForTesting)
#endif
#if defined(OS_MAC)
.SetMethod("_getUserAcceleratorAt", &Menu::GetUserAcceleratorAt)
#endif
.Build();
}

View file

@ -68,6 +68,7 @@ class Menu : public gin::Wrappable<Menu>,
bool GetSharingItemForCommandId(
int command_id,
ElectronMenuModel::SharingItem* item) const override;
v8::Local<v8::Value> GetUserAcceleratorAt(int command_id) const;
#endif
void ExecuteCommand(int command_id, int event_flags) override;
void OnMenuWillShow(ui::SimpleMenuModel* source) override;
@ -108,7 +109,7 @@ class Menu : public gin::Wrappable<Menu>,
void SetToolTip(int index, const std::u16string& toolTip);
void SetRole(int index, const std::u16string& role);
void Clear();
int GetIndexOfCommandId(int command_id);
int GetIndexOfCommandId(int command_id) const;
int GetItemCount() const;
int GetCommandIdAt(int index) const;
std::u16string GetLabelAt(int index) const;

View file

@ -16,12 +16,31 @@
#include "content/public/browser/web_contents.h"
#include "shell/browser/native_window.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "shell/common/keyboard_util.h"
#include "shell/common/node_includes.h"
namespace {
static scoped_nsobject<NSMenu> applicationMenu_;
ui::Accelerator GetAcceleratorFromKeyEquivalentAndModifierMask(
NSString* key_equivalent,
NSUInteger modifier_mask) {
absl::optional<char16_t> shifted_char;
ui::KeyboardCode code = electron::KeyboardCodeFromStr(
base::SysNSStringToUTF8(key_equivalent), &shifted_char);
int modifiers = 0;
if (modifier_mask & NSEventModifierFlagShift)
modifiers |= ui::EF_SHIFT_DOWN;
if (modifier_mask & NSEventModifierFlagControl)
modifiers |= ui::EF_CONTROL_DOWN;
if (modifier_mask & NSEventModifierFlagOption)
modifiers |= ui::EF_ALT_DOWN;
if (modifier_mask & NSEventModifierFlagCommand)
modifiers |= ui::EF_COMMAND_DOWN;
return ui::Accelerator(code, modifiers);
}
} // namespace
namespace electron {
@ -52,6 +71,32 @@ void MenuMac::PopupAt(BaseWindow* window,
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(popup));
}
v8::Local<v8::Value> Menu::GetUserAcceleratorAt(int command_id) const {
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
if (![NSMenuItem usesUserKeyEquivalents])
return v8::Null(isolate);
auto controller = base::scoped_nsobject<ElectronMenuController>(
[[ElectronMenuController alloc] initWithModel:model()
useDefaultAccelerator:NO]);
int command_index = GetIndexOfCommandId(command_id);
if (command_index == -1)
return v8::Null(isolate);
base::scoped_nsobject<NSMenuItem> item =
[controller makeMenuItemForIndex:command_index fromModel:model()];
if ([[item userKeyEquivalent] length] == 0)
return v8::Null(isolate);
NSString* user_key_equivalent = [item keyEquivalent];
NSUInteger user_modifier_mask = [item keyEquivalentModifierMask];
ui::Accelerator accelerator = GetAcceleratorFromKeyEquivalentAndModifierMask(
user_key_equivalent, user_modifier_mask);
return gin::ConvertToV8(isolate, accelerator.GetShortcutText());
}
void MenuMac::PopupOnUI(const base::WeakPtr<NativeWindow>& native_window,
int32_t window_id,
int x,