summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/NativeKeyBindings.mm
diff options
context:
space:
mode:
Diffstat (limited to 'widget/cocoa/NativeKeyBindings.mm')
-rw-r--r--widget/cocoa/NativeKeyBindings.mm605
1 files changed, 605 insertions, 0 deletions
diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm
new file mode 100644
index 0000000000..d3e5983259
--- /dev/null
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -0,0 +1,605 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "NativeKeyBindings.h"
+
+#include "nsTArray.h"
+#include "nsCocoaUtils.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/NativeKeyBindingsType.h"
+#include "mozilla/TextEvents.h"
+#include "mozilla/WritingModes.h"
+
+#import <Cocoa/Cocoa.h>
+#import <Carbon/Carbon.h>
+
+namespace mozilla {
+namespace widget {
+
+static LazyLogModule gNativeKeyBindingsLog("NativeKeyBindings");
+
+NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
+NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
+
+// static
+NativeKeyBindings* NativeKeyBindings::GetInstance(NativeKeyBindingsType aType) {
+ switch (aType) {
+ case NativeKeyBindingsType::SingleLineEditor:
+ if (!sInstanceForSingleLineEditor) {
+ sInstanceForSingleLineEditor = new NativeKeyBindings();
+ sInstanceForSingleLineEditor->Init(aType);
+ }
+ return sInstanceForSingleLineEditor;
+ case NativeKeyBindingsType::MultiLineEditor:
+ case NativeKeyBindingsType::RichTextEditor:
+ if (!sInstanceForMultiLineEditor) {
+ sInstanceForMultiLineEditor = new NativeKeyBindings();
+ sInstanceForMultiLineEditor->Init(aType);
+ }
+ return sInstanceForMultiLineEditor;
+ default:
+ MOZ_CRASH("Not implemented");
+ return nullptr;
+ }
+}
+
+// static
+void NativeKeyBindings::Shutdown() {
+ delete sInstanceForSingleLineEditor;
+ sInstanceForSingleLineEditor = nullptr;
+ delete sInstanceForMultiLineEditor;
+ sInstanceForMultiLineEditor = nullptr;
+}
+
+NativeKeyBindings::NativeKeyBindings() {}
+
+inline objc_selector* ToObjcSelectorPtr(SEL aSel) { return reinterpret_cast<objc_selector*>(aSel); }
+#define SEL_TO_COMMAND(aSel, aCommand) \
+ mSelectorToCommand.InsertOrUpdate(ToObjcSelectorPtr(@selector(aSel)), aCommand)
+
+void NativeKeyBindings::Init(NativeKeyBindingsType aType) {
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::Init", this));
+
+ // Many selectors have a one-to-one mapping to a Gecko command. Those mappings
+ // are registered in mSelectorToCommand.
+
+ // Selectors from NSResponder's "Responding to Action Messages" section and
+ // from NSText's "Action Methods for Editing" section
+
+ // TODO: Improves correctness of left / right meaning
+ // TODO: Add real paragraph motions
+
+ // SEL_TO_COMMAND(cancelOperation:, );
+ // SEL_TO_COMMAND(capitalizeWord:, );
+ // SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
+ // SEL_TO_COMMAND(changeCaseOfLetter:, );
+ // SEL_TO_COMMAND(complete:, );
+ SEL_TO_COMMAND(copy:, Command::Copy);
+ // SEL_TO_COMMAND(copyFont:, );
+ // SEL_TO_COMMAND(copyRuler:, );
+ SEL_TO_COMMAND(cut:, Command::Cut);
+ SEL_TO_COMMAND(delete:, Command::Delete);
+ SEL_TO_COMMAND(deleteBackward:, Command::DeleteCharBackward);
+ // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
+ SEL_TO_COMMAND(deleteForward:, Command::DeleteCharForward);
+
+ // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
+ SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
+ SEL_TO_COMMAND(deleteToBeginningOfParagraph:, Command::DeleteToBeginningOfLine);
+ SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine);
+ SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
+ // SEL_TO_COMMAND(deleteToMark:, );
+
+ SEL_TO_COMMAND(deleteWordBackward:, Command::DeleteWordBackward);
+ SEL_TO_COMMAND(deleteWordForward:, Command::DeleteWordForward);
+ // SEL_TO_COMMAND(indent:, );
+ // SEL_TO_COMMAND(insertBacktab:, );
+ // SEL_TO_COMMAND(insertContainerBreak:, );
+ // SEL_TO_COMMAND(insertLineBreak:, );
+ // SEL_TO_COMMAND(insertNewline:, );
+ // SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
+ // SEL_TO_COMMAND(insertParagraphSeparator:, );
+ // SEL_TO_COMMAND(insertTab:, );
+ // SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
+ // SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
+ // SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
+ // SEL_TO_COMMAND(lowercaseWord:, );
+ SEL_TO_COMMAND(moveBackward:, Command::CharPrevious);
+ SEL_TO_COMMAND(moveBackwardAndModifySelection:, Command::SelectCharPrevious);
+ if (aType == NativeKeyBindingsType::SingleLineEditor) {
+ SEL_TO_COMMAND(moveDown:, Command::EndLine);
+ } else {
+ SEL_TO_COMMAND(moveDown:, Command::LineNext);
+ }
+ SEL_TO_COMMAND(moveDownAndModifySelection:, Command::SelectLineNext);
+ SEL_TO_COMMAND(moveForward:, Command::CharNext);
+ SEL_TO_COMMAND(moveForwardAndModifySelection:, Command::SelectCharNext);
+ SEL_TO_COMMAND(moveLeft:, Command::CharPrevious);
+ SEL_TO_COMMAND(moveLeftAndModifySelection:, Command::SelectCharPrevious);
+ SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, Command::SelectBeginLine);
+ SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, Command::SelectEndLine);
+ SEL_TO_COMMAND(moveRight:, Command::CharNext);
+ SEL_TO_COMMAND(moveRightAndModifySelection:, Command::SelectCharNext);
+ SEL_TO_COMMAND(moveToBeginningOfDocument:, Command::MoveTop);
+ SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:, Command::SelectTop);
+ SEL_TO_COMMAND(moveToBeginningOfLine:, Command::BeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:, Command::SelectBeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfParagraph:, Command::BeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:, Command::SelectBeginLine);
+ SEL_TO_COMMAND(moveToEndOfDocument:, Command::MoveBottom);
+ SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, Command::SelectBottom);
+ SEL_TO_COMMAND(moveToEndOfLine:, Command::EndLine);
+ SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, Command::SelectEndLine);
+ SEL_TO_COMMAND(moveToEndOfParagraph:, Command::EndLine);
+ SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, Command::SelectEndLine);
+ SEL_TO_COMMAND(moveToLeftEndOfLine:, Command::BeginLine);
+ SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, Command::SelectBeginLine);
+ SEL_TO_COMMAND(moveToRightEndOfLine:, Command::EndLine);
+ SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, Command::SelectEndLine);
+ if (aType == NativeKeyBindingsType::SingleLineEditor) {
+ SEL_TO_COMMAND(moveUp:, Command::BeginLine);
+ } else {
+ SEL_TO_COMMAND(moveUp:, Command::LinePrevious);
+ }
+ SEL_TO_COMMAND(moveUpAndModifySelection:, Command::SelectLinePrevious);
+ SEL_TO_COMMAND(moveWordBackward:, Command::WordPrevious);
+ SEL_TO_COMMAND(moveWordBackwardAndModifySelection:, Command::SelectWordPrevious);
+ SEL_TO_COMMAND(moveWordForward:, Command::WordNext);
+ SEL_TO_COMMAND(moveWordForwardAndModifySelection:, Command::SelectWordNext);
+ SEL_TO_COMMAND(moveWordLeft:, Command::WordPrevious);
+ SEL_TO_COMMAND(moveWordLeftAndModifySelection:, Command::SelectWordPrevious);
+ SEL_TO_COMMAND(moveWordRight:, Command::WordNext);
+ SEL_TO_COMMAND(moveWordRightAndModifySelection:, Command::SelectWordNext);
+ SEL_TO_COMMAND(pageDown:, Command::MovePageDown);
+ SEL_TO_COMMAND(pageDownAndModifySelection:, Command::SelectPageDown);
+ SEL_TO_COMMAND(pageUp:, Command::MovePageUp);
+ SEL_TO_COMMAND(pageUpAndModifySelection:, Command::SelectPageUp);
+ SEL_TO_COMMAND(paste:, Command::Paste);
+ // SEL_TO_COMMAND(pasteFont:, );
+ // SEL_TO_COMMAND(pasteRuler:, );
+ SEL_TO_COMMAND(scrollLineDown:, Command::ScrollLineDown);
+ SEL_TO_COMMAND(scrollLineUp:, Command::ScrollLineUp);
+ SEL_TO_COMMAND(scrollPageDown:, Command::ScrollPageDown);
+ SEL_TO_COMMAND(scrollPageUp:, Command::ScrollPageUp);
+ SEL_TO_COMMAND(scrollToBeginningOfDocument:, Command::ScrollTop);
+ SEL_TO_COMMAND(scrollToEndOfDocument:, Command::ScrollBottom);
+ SEL_TO_COMMAND(selectAll:, Command::SelectAll);
+ // selectLine: is complex, see KeyDown
+ if (aType == NativeKeyBindingsType::SingleLineEditor) {
+ SEL_TO_COMMAND(selectParagraph:, Command::SelectAll);
+ }
+ // SEL_TO_COMMAND(selectToMark:, );
+ // selectWord: is complex, see KeyDown
+ // SEL_TO_COMMAND(setMark:, );
+ // SEL_TO_COMMAND(showContextHelp:, );
+ // SEL_TO_COMMAND(supplementalTargetForAction:sender:, );
+ // SEL_TO_COMMAND(swapWithMark:, );
+ // SEL_TO_COMMAND(transpose:, );
+ // SEL_TO_COMMAND(transposeWords:, );
+ // SEL_TO_COMMAND(uppercaseWord:, );
+ // SEL_TO_COMMAND(yank:, );
+}
+
+#undef SEL_TO_COMMAND
+
+void NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
+ const Maybe<WritingMode>& aWritingMode,
+ nsTArray<CommandInt>& aCommands) {
+ MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
+ MOZ_ASSERT(aCommands.IsEmpty());
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p NativeKeyBindings::GetEditCommands", this));
+
+ // Recover the current event, which should always be the key down we are
+ // responding to.
+
+ NSEvent* cocoaEvent = reinterpret_cast<NSEvent*>(aEvent.mNativeKeyEvent);
+
+ if (!cocoaEvent || [cocoaEvent type] != NSEventTypeKeyDown) {
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this));
+
+ return;
+ }
+
+ if (aWritingMode.isSome() && aEvent.NeedsToRemapNavigationKey() &&
+ aWritingMode.ref().IsVertical()) {
+ NSEvent* originalEvent = cocoaEvent;
+
+ // TODO: Use KeyNameIndex rather than legacy keyCode.
+ uint32_t remappedGeckoKeyCode = aEvent.GetRemappedKeyCode(aWritingMode.ref());
+ uint32_t remappedCocoaKeyCode = 0;
+ switch (remappedGeckoKeyCode) {
+ case NS_VK_UP:
+ remappedCocoaKeyCode = kVK_UpArrow;
+ break;
+ case NS_VK_DOWN:
+ remappedCocoaKeyCode = kVK_DownArrow;
+ break;
+ case NS_VK_LEFT:
+ remappedCocoaKeyCode = kVK_LeftArrow;
+ break;
+ case NS_VK_RIGHT:
+ remappedCocoaKeyCode = kVK_RightArrow;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Add a case for the new remapped key");
+ return;
+ }
+ unichar ch = nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(remappedGeckoKeyCode);
+ NSString* chars = [[[NSString alloc] initWithCharacters:&ch length:1] autorelease];
+ cocoaEvent = [NSEvent keyEventWithType:[originalEvent type]
+ location:[originalEvent locationInWindow]
+ modifierFlags:[originalEvent modifierFlags]
+ timestamp:[originalEvent timestamp]
+ windowNumber:[originalEvent windowNumber]
+ context:nil
+ characters:chars
+ charactersIgnoringModifiers:chars
+ isARepeat:[originalEvent isARepeat]
+ keyCode:remappedCocoaKeyCode];
+ }
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::GetEditCommands, interpreting", this));
+
+ AutoTArray<KeyBindingsCommand, 2> bindingCommands;
+ nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::GetEditCommands, bindingCommands=%zu", this,
+ bindingCommands.Length()));
+
+ for (uint32_t i = 0; i < bindingCommands.Length(); i++) {
+ SEL selector = bindingCommands[i].selector;
+
+ if (MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
+ NSString* selectorString = NSStringFromSelector(selector);
+ nsAutoString nsSelectorString;
+ nsCocoaUtils::GetStringForNSString(selectorString, nsSelectorString);
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::GetEditCommands, selector=%s", this,
+ NS_LossyConvertUTF16toASCII(nsSelectorString).get()));
+ }
+
+ AppendEditCommandsForSelector(ToObjcSelectorPtr(selector), aCommands);
+ }
+
+ LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommands");
+}
+
+void NativeKeyBindings::AppendEditCommandsForSelector(objc_selector* aSelector,
+ nsTArray<CommandInt>& aCommands) const {
+ // Try to find a simple mapping in the hashtable
+ Command geckoCommand = Command::DoNothing;
+ if (mSelectorToCommand.Get(aSelector, &geckoCommand) && geckoCommand != Command::DoNothing) {
+ aCommands.AppendElement(static_cast<CommandInt>(geckoCommand));
+ } else if (aSelector == ToObjcSelectorPtr(@selector(selectLine:))) {
+ // This is functional, but Cocoa's version is direction-less in that
+ // selection direction is not determined until some future directed action
+ // is taken. See bug 282097, comment 79 for more details.
+ aCommands.AppendElement(static_cast<CommandInt>(Command::BeginLine));
+ aCommands.AppendElement(static_cast<CommandInt>(Command::SelectEndLine));
+ } else if (aSelector == ToObjcSelectorPtr(@selector(selectWord:))) {
+ // This is functional, but Cocoa's version is direction-less in that
+ // selection direction is not determined until some future directed action
+ // is taken. See bug 282097, comment 79 for more details.
+ aCommands.AppendElement(static_cast<CommandInt>(Command::WordPrevious));
+ aCommands.AppendElement(static_cast<CommandInt>(Command::SelectWordNext));
+ }
+}
+
+void NativeKeyBindings::LogEditCommands(const nsTArray<CommandInt>& aCommands,
+ const char* aDescription) const {
+ if (!MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
+ return;
+ }
+
+ if (aCommands.IsEmpty()) {
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, ("%p %s, no edit commands", this, aDescription));
+ return;
+ }
+
+ for (CommandInt commandInt : aCommands) {
+ Command geckoCommand = static_cast<Command>(commandInt);
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p %s, command=%s", this, aDescription,
+ WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
+ }
+}
+
+// static
+void NativeKeyBindings::GetEditCommandsForTests(NativeKeyBindingsType aType,
+ const WidgetKeyboardEvent& aEvent,
+ const Maybe<WritingMode>& aWritingMode,
+ nsTArray<CommandInt>& aCommands) {
+ MOZ_DIAGNOSTIC_ASSERT(aEvent.IsTrusted());
+
+ // The following mapping is checked on Big Sur. Some of them are defined in:
+ // https://support.apple.com/en-us/HT201236#text
+ NativeKeyBindings* instance = NativeKeyBindings::GetInstance(aType);
+ if (NS_WARN_IF(!instance)) {
+ return;
+ }
+ switch (aWritingMode.isSome() ? aEvent.GetRemappedKeyNameIndex(aWritingMode.ref())
+ : aEvent.mKeyNameIndex) {
+ case KEY_NAME_INDEX_USE_STRING:
+ if (!aEvent.IsControl() || aEvent.IsAlt() || aEvent.IsMeta()) {
+ break;
+ }
+ switch (aEvent.PseudoCharCode()) {
+ case 'a':
+ case 'A':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:))
+ : ToObjcSelectorPtr(@selector(moveToBeginningOfParagraphAndModifySelection:)),
+ aCommands);
+ break;
+ case 'b':
+ case 'B':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveBackward:))
+ : ToObjcSelectorPtr(@selector(moveBackwardAndModifySelection:)),
+ aCommands);
+ break;
+ case 'd':
+ case 'D':
+ if (!aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
+ aCommands);
+ }
+ break;
+ case 'e':
+ case 'E':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToEndOfParagraph:))
+ : ToObjcSelectorPtr(@selector(moveToEndOfParagraphAndModifySelection:)),
+ aCommands);
+ break;
+ case 'f':
+ case 'F':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveForward:))
+ : ToObjcSelectorPtr(@selector(moveForwardAndModifySelection:)),
+ aCommands);
+ break;
+ case 'h':
+ case 'H':
+ if (!aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
+ aCommands);
+ }
+ break;
+ case 'k':
+ case 'K':
+ if (!aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(deleteToEndOfParagraph:)), aCommands);
+ }
+ break;
+ case 'n':
+ case 'N':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
+ : ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
+ aCommands);
+ break;
+ case 'p':
+ case 'P':
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
+ : ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
+ aCommands);
+ break;
+ default:
+ break;
+ }
+ break;
+ case KEY_NAME_INDEX_Backspace:
+ if (aEvent.IsMeta()) {
+ if (aEvent.IsAlt() || aEvent.IsControl()) {
+ break;
+ }
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(deleteToBeginningOfLine:)), aCommands);
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ // Shift and Control are ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordBackward:)),
+ aCommands);
+ break;
+ }
+ if (aEvent.IsControl()) {
+ if (aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(deleteBackwardByDecomposingPreviousCharacter:)),
+ aCommands);
+ }
+ break;
+ }
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteBackward:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_Delete:
+ if (aEvent.IsControl() || aEvent.IsMeta()) {
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteWordForward:)),
+ aCommands);
+ break;
+ }
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(deleteForward:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_PageDown:
+ if (aEvent.IsControl() || aEvent.IsMeta()) {
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageDown:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageDown:))
+ : ToObjcSelectorPtr(@selector(pageDownAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_PageUp:
+ if (aEvent.IsControl() || aEvent.IsMeta()) {
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ // Shift is ignored.
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(pageUp:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollPageUp:))
+ : ToObjcSelectorPtr(@selector(pageUpAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_Home:
+ if (aEvent.IsAlt() || aEvent.IsControl() || aEvent.IsMeta()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(scrollToBeginningOfDocument:))
+ : ToObjcSelectorPtr(@selector(moveToBeginningOfDocumentAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_End:
+ if (aEvent.IsAlt() || aEvent.IsControl() || aEvent.IsMeta()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(scrollToEndOfDocument:))
+ : ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_ArrowLeft:
+ if (aEvent.IsAlt()) {
+ break;
+ }
+ if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToLeftEndOfLine:))
+ : ToObjcSelectorPtr(@selector(moveToLeftEndOfLineAndModifySelection:)),
+ aCommands);
+ break;
+ }
+ if (aEvent.IsControl()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveLeft:))
+ : ToObjcSelectorPtr(@selector(moveLeftAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_ArrowRight:
+ if (aEvent.IsAlt()) {
+ break;
+ }
+ if (aEvent.IsMeta() || (aEvent.IsControl() && aEvent.IsShift())) {
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToRightEndOfLine:))
+ : ToObjcSelectorPtr(@selector(moveToRightEndOfLineAndModifySelection:)),
+ aCommands);
+ break;
+ }
+ if (aEvent.IsControl()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveRight:))
+ : ToObjcSelectorPtr(@selector(moveRightAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_ArrowUp:
+ if (aEvent.IsControl()) {
+ break;
+ }
+ if (aEvent.IsMeta()) {
+ if (aEvent.IsAlt()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToBeginningOfDocument:))
+ : ToObjcSelectorPtr(@selector(moveToBegginingOfDocumentAndModifySelection:)),
+ aCommands);
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ if (!aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveBackward:)),
+ aCommands);
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(moveToBeginningOfParagraph:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(moveParagraphBackwardAndModifySelection:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveUp:))
+ : ToObjcSelectorPtr(@selector(moveUpAndModifySelection:)),
+ aCommands);
+ break;
+ case KEY_NAME_INDEX_ArrowDown:
+ if (aEvent.IsControl()) {
+ break;
+ }
+ if (aEvent.IsMeta()) {
+ if (aEvent.IsAlt()) {
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift()
+ ? ToObjcSelectorPtr(@selector(moveToEndOfDocument:))
+ : ToObjcSelectorPtr(@selector(moveToEndOfDocumentAndModifySelection:)),
+ aCommands);
+ break;
+ }
+ if (aEvent.IsAlt()) {
+ if (!aEvent.IsShift()) {
+ instance->AppendEditCommandsForSelector(ToObjcSelectorPtr(@selector(moveForward:)),
+ aCommands);
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(moveToEndOfParagraph:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ ToObjcSelectorPtr(@selector(moveParagraphForwardAndModifySelection:)), aCommands);
+ break;
+ }
+ instance->AppendEditCommandsForSelector(
+ !aEvent.IsShift() ? ToObjcSelectorPtr(@selector(moveDown:))
+ : ToObjcSelectorPtr(@selector(moveDownAndModifySelection:)),
+ aCommands);
+ break;
+ default:
+ break;
+ }
+
+ instance->LogEditCommands(aCommands, "NativeKeyBindings::GetEditCommandsForTests");
+}
+
+} // namespace widget
+} // namespace mozilla