mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 10:15:41 +00:00
872f694c63
Now, nsIWidget::ExecuteNativeKeyBinding() isn't used by anybody for executing edit commands. Instead, they need array of edit commands for the key combination. So, the method should be renamed to GetEditCommands() and just return edit commands as an array. MozReview-Commit-ID: 4G0B1lJ8Lbe --HG-- extra : rebase_source : 4a5829281d59677c773950c34d91a1cd8074d243
283 lines
11 KiB
Plaintext
283 lines
11 KiB
Plaintext
/* -*- 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/SizePrintfMacros.h"
|
|
#include "mozilla/TextEvents.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 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)
|
|
{
|
|
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
|
|
|
|
void
|
|
NativeKeyBindings::GetEditCommands(const WidgetKeyboardEvent& aEvent,
|
|
nsTArray<CommandInt>& aCommands)
|
|
{
|
|
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] != NSKeyDown) {
|
|
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
|
("%p NativeKeyBindings::GetEditCommands, no Cocoa key down event", this));
|
|
|
|
return;
|
|
}
|
|
|
|
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=%" PRIuSIZE,
|
|
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()));
|
|
}
|
|
|
|
// Try to find a simple mapping in the hashtable
|
|
CommandInt geckoCommand =
|
|
mSelectorToCommand.Get(reinterpret_cast<struct objc_selector*>(selector));
|
|
|
|
if (geckoCommand) {
|
|
aCommands.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.
|
|
aCommands.AppendElement(CommandBeginLine);
|
|
aCommands.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.
|
|
aCommands.AppendElement(CommandWordPrevious);
|
|
aCommands.AppendElement(CommandSelectWordNext);
|
|
}
|
|
}
|
|
|
|
if (!MOZ_LOG_TEST(gNativeKeyBindingsLog, LogLevel::Info)) {
|
|
return;
|
|
}
|
|
|
|
if (aCommands.IsEmpty()) {
|
|
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
|
("%p NativeKeyBindings::GetEditCommands, handled=false", this));
|
|
return;
|
|
}
|
|
|
|
for (CommandInt commandInt : aCommands) {
|
|
Command geckoCommand = static_cast<Command>(commandInt);
|
|
MOZ_LOG(gNativeKeyBindingsLog, LogLevel::Info,
|
|
("%p NativeKeyBindings::GetEditCommands, command=%s",
|
|
this, WidgetKeyboardEvent::GetCommandStr(geckoCommand)));
|
|
}
|
|
}
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|