From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- widget/cocoa/NativeKeyBindings.mm | 292 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 widget/cocoa/NativeKeyBindings.mm (limited to 'widget/cocoa/NativeKeyBindings.mm') 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(@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(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 bindingCommands; + nsCocoaUtils::GetCommandsFromKeyEvent(cocoaEvent, bindingCommands); + + MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info, + ("%p NativeKeyBindings::KeyPress, bindingCommands=%u", + this, bindingCommands.Length())); + + AutoTArray 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(mSelectorToCommand.Get( + reinterpret_cast(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 -- cgit v1.2.3