summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/NativeKeyBindings.mm
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /widget/cocoa/NativeKeyBindings.mm
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'widget/cocoa/NativeKeyBindings.mm')
-rw-r--r--widget/cocoa/NativeKeyBindings.mm292
1 files changed, 292 insertions, 0 deletions
diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm
new file mode 100644
index 000000000..2f4ecadff
--- /dev/null
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -0,0 +1,292 @@
+/* -*- 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/TextEvents.h"
+
+namespace mozilla {
+namespace widget {
+
+PRLogModuleInfo* gNativeKeyBindingsLog = nullptr;
+
+NativeKeyBindings* NativeKeyBindings::sInstanceForSingleLineEditor = nullptr;
+NativeKeyBindings* NativeKeyBindings::sInstanceForMultiLineEditor = nullptr;
+
+// static
+NativeKeyBindings*
+NativeKeyBindings::GetInstance(NativeKeyBindingsType aType)
+{
+ switch (aType) {
+ case nsIWidget::NativeKeyBindingsForSingleLineEditor:
+ if (!sInstanceForSingleLineEditor) {
+ sInstanceForSingleLineEditor = new NativeKeyBindings();
+ sInstanceForSingleLineEditor->Init(aType);
+ }
+ return sInstanceForSingleLineEditor;
+ case nsIWidget::NativeKeyBindingsForMultiLineEditor:
+ case nsIWidget::NativeKeyBindingsForRichTextEditor:
+ 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()
+{
+}
+
+#define SEL_TO_COMMAND(aSel, aCommand) \
+ mSelectorToCommand.Put( \
+ reinterpret_cast<struct objc_selector *>(@selector(aSel)), aCommand)
+
+void
+NativeKeyBindings::Init(NativeKeyBindingsType aType)
+{
+ if (!gNativeKeyBindingsLog) {
+ gNativeKeyBindingsLog = PR_NewLogModule("NativeKeyBindings");
+ }
+
+ 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:, CommandCopy);
+ // SEL_TO_COMMAND(copyFont:, );
+ // SEL_TO_COMMAND(copyRuler:, );
+ SEL_TO_COMMAND(cut:, CommandCut);
+ SEL_TO_COMMAND(delete:, CommandDelete);
+ SEL_TO_COMMAND(deleteBackward:, CommandDeleteCharBackward);
+ // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
+ SEL_TO_COMMAND(deleteForward:, CommandDeleteCharForward);
+
+ // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
+ SEL_TO_COMMAND(deleteToBeginningOfLine:, CommandDeleteToBeginningOfLine);
+ SEL_TO_COMMAND(deleteToBeginningOfParagraph:, CommandDeleteToBeginningOfLine);
+ SEL_TO_COMMAND(deleteToEndOfLine:, CommandDeleteToEndOfLine);
+ SEL_TO_COMMAND(deleteToEndOfParagraph:, CommandDeleteToEndOfLine);
+ // SEL_TO_COMMAND(deleteToMark:, );
+
+ SEL_TO_COMMAND(deleteWordBackward:, CommandDeleteWordBackward);
+ SEL_TO_COMMAND(deleteWordForward:, CommandDeleteWordForward);
+ // 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:, CommandCharPrevious);
+ SEL_TO_COMMAND(moveBackwardAndModifySelection:, CommandSelectCharPrevious);
+ if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
+ SEL_TO_COMMAND(moveDown:, CommandEndLine);
+ } else {
+ SEL_TO_COMMAND(moveDown:, CommandLineNext);
+ }
+ SEL_TO_COMMAND(moveDownAndModifySelection:, CommandSelectLineNext);
+ SEL_TO_COMMAND(moveForward:, CommandCharNext);
+ SEL_TO_COMMAND(moveForwardAndModifySelection:, CommandSelectCharNext);
+ SEL_TO_COMMAND(moveLeft:, CommandCharPrevious);
+ SEL_TO_COMMAND(moveLeftAndModifySelection:, CommandSelectCharPrevious);
+ SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:,
+ CommandSelectBeginLine);
+ SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, CommandSelectEndLine);
+ SEL_TO_COMMAND(moveRight:, CommandCharNext);
+ SEL_TO_COMMAND(moveRightAndModifySelection:, CommandSelectCharNext);
+ SEL_TO_COMMAND(moveToBeginningOfDocument:, CommandMoveTop);
+ SEL_TO_COMMAND(moveToBeginningOfDocumentAndModifySelection:,
+ CommandSelectTop);
+ SEL_TO_COMMAND(moveToBeginningOfLine:, CommandBeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:,
+ CommandSelectBeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfParagraph:, CommandBeginLine);
+ SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:,
+ CommandSelectBeginLine);
+ SEL_TO_COMMAND(moveToEndOfDocument:, CommandMoveBottom);
+ SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, CommandSelectBottom);
+ SEL_TO_COMMAND(moveToEndOfLine:, CommandEndLine);
+ SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, CommandSelectEndLine);
+ SEL_TO_COMMAND(moveToEndOfParagraph:, CommandEndLine);
+ SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, CommandSelectEndLine);
+ SEL_TO_COMMAND(moveToLeftEndOfLine:, CommandBeginLine);
+ SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:,
+ CommandSelectBeginLine);
+ SEL_TO_COMMAND(moveToRightEndOfLine:, CommandEndLine);
+ SEL_TO_COMMAND(moveToRightEndOfLineAndModifySelection:, CommandSelectEndLine);
+ if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
+ SEL_TO_COMMAND(moveUp:, CommandBeginLine);
+ } else {
+ SEL_TO_COMMAND(moveUp:, CommandLinePrevious);
+ }
+ SEL_TO_COMMAND(moveUpAndModifySelection:, CommandSelectLinePrevious);
+ SEL_TO_COMMAND(moveWordBackward:, CommandWordPrevious);
+ SEL_TO_COMMAND(moveWordBackwardAndModifySelection:,
+ CommandSelectWordPrevious);
+ SEL_TO_COMMAND(moveWordForward:, CommandWordNext);
+ SEL_TO_COMMAND(moveWordForwardAndModifySelection:, CommandSelectWordNext);
+ SEL_TO_COMMAND(moveWordLeft:, CommandWordPrevious);
+ SEL_TO_COMMAND(moveWordLeftAndModifySelection:, CommandSelectWordPrevious);
+ SEL_TO_COMMAND(moveWordRight:, CommandWordNext);
+ SEL_TO_COMMAND(moveWordRightAndModifySelection:, CommandSelectWordNext);
+ SEL_TO_COMMAND(pageDown:, CommandMovePageDown);
+ SEL_TO_COMMAND(pageDownAndModifySelection:, CommandSelectPageDown);
+ SEL_TO_COMMAND(pageUp:, CommandMovePageUp);
+ SEL_TO_COMMAND(pageUpAndModifySelection:, CommandSelectPageUp);
+ SEL_TO_COMMAND(paste:, CommandPaste);
+ // SEL_TO_COMMAND(pasteFont:, );
+ // SEL_TO_COMMAND(pasteRuler:, );
+ SEL_TO_COMMAND(scrollLineDown:, CommandScrollLineDown);
+ SEL_TO_COMMAND(scrollLineUp:, CommandScrollLineUp);
+ SEL_TO_COMMAND(scrollPageDown:, CommandScrollPageDown);
+ SEL_TO_COMMAND(scrollPageUp:, CommandScrollPageUp);
+ SEL_TO_COMMAND(scrollToBeginningOfDocument:, CommandScrollTop);
+ SEL_TO_COMMAND(scrollToEndOfDocument:, CommandScrollBottom);
+ SEL_TO_COMMAND(selectAll:, CommandSelectAll);
+ // selectLine: is complex, see KeyDown
+ if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
+ SEL_TO_COMMAND(selectParagraph:, CommandSelectAll);
+ }
+ // 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
+
+bool
+NativeKeyBindings::Execute(const WidgetKeyboardEvent& aEvent,
+ DoCommandCallback aCallback,
+ void* aCallbackData)
+{
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress", 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] != NSKeyDown) {
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, no Cocoa key down event", this));
+
+ return false;
+ }
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, interpreting", this));
+
+ AutoTArray<KeyBindingsCommand, 2> bindingCommands;
+ nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands);
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, bindingCommands=%u",
+ this, bindingCommands.Length()));
+
+ AutoTArray<Command, 4> geckoCommands;
+
+ 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::KeyPress, selector=%s",
+ this, NS_LossyConvertUTF16toASCII(nsSelectorString).get()));
+ }
+
+ // Try to find a simple mapping in the hashtable
+ Command geckoCommand = static_cast<Command>(mSelectorToCommand.Get(
+ reinterpret_cast<struct objc_selector*>(selector)));
+
+ if (geckoCommand) {
+ geckoCommands.AppendElement(geckoCommand);
+ } else if (selector == @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.
+ geckoCommands.AppendElement(CommandBeginLine);
+ geckoCommands.AppendElement(CommandSelectEndLine);
+ } else if (selector == @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.
+ geckoCommands.AppendElement(CommandWordPrevious);
+ geckoCommands.AppendElement(CommandSelectWordNext);
+ }
+ }
+
+ if (geckoCommands.IsEmpty()) {
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, handled=false", this));
+
+ return false;
+ }
+
+ for (uint32_t i = 0; i < geckoCommands.Length(); i++) {
+ Command geckoCommand = geckoCommands[i];
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, command=%s",
+ this, WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
+
+ // Execute the Gecko command
+ aCallback(geckoCommand, aCallbackData);
+ }
+
+ MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
+ ("%p NativeKeyBindings::KeyPress, handled=true", this));
+
+ return true;
+}
+
+} // namespace widget
+} // namespace mozilla