author | Masayuki Nakano <masayuki@d-toybox.com> |
Sat, 02 Dec 2017 14:53:10 +0900 | |
changeset 394978 | afc17c7465c2371b7ba0f50c92ec065c099e9fd3 |
parent 394977 | f5039cf4ead7e14b067052ab1ecff2277ecbeace |
child 394979 | 793d2834b3e3c2d1411216740161f1735f5fa70d |
push id | 97987 |
push user | nerli@mozilla.com |
push date | Tue, 05 Dec 2017 13:52:50 +0000 |
treeherder | mozilla-inbound@8842dba7396b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | m_kato |
bugs | 1403759 |
milestone | 59.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/widget/CommandList.h +++ b/widget/CommandList.h @@ -1,17 +1,20 @@ /* -*- 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/. */ /** - * Define NS_DEFIVE_COMMAND(aName, aCommandStr) before including this. + * Define NS_DEFINE_COMMAND(aName, aCommandStr) before including this. * @param aName The name useful in C++ of the command. * @param aCommandStr The command string in JS. + * + * Define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) before including this. + * @param aName The name useful in C++ of the command. */ NS_DEFINE_COMMAND(BeginLine, cmd_beginLine) NS_DEFINE_COMMAND(CharNext, cmd_charNext) NS_DEFINE_COMMAND(CharPrevious, cmd_charPrevious) NS_DEFINE_COMMAND(Copy, cmd_copy) NS_DEFINE_COMMAND(Cut, cmd_cut) NS_DEFINE_COMMAND(Delete, cmd_delete) @@ -47,8 +50,13 @@ NS_DEFINE_COMMAND(SelectLineNext, NS_DEFINE_COMMAND(SelectLinePrevious, cmd_selectLinePrevious) NS_DEFINE_COMMAND(SelectPageDown, cmd_selectPageDown) NS_DEFINE_COMMAND(SelectPageUp, cmd_selectPageUp) NS_DEFINE_COMMAND(SelectTop, cmd_selectTop) NS_DEFINE_COMMAND(SelectWordNext, cmd_selectWordNext) NS_DEFINE_COMMAND(SelectWordPrevious, cmd_selectWordPrevious) NS_DEFINE_COMMAND(WordNext, cmd_wordNext) NS_DEFINE_COMMAND(WordPrevious, cmd_wordPrevious) + +NS_DEFINE_COMMAND_NO_EXEC_COMMAND(CancelOperation) +NS_DEFINE_COMMAND_NO_EXEC_COMMAND(Complete) +NS_DEFINE_COMMAND_NO_EXEC_COMMAND(InsertBacktab) +NS_DEFINE_COMMAND_NO_EXEC_COMMAND(InsertTab)
--- a/widget/EventForwards.h +++ b/widget/EventForwards.h @@ -109,25 +109,27 @@ enum CodeNameIndex : CodeNameIndexType CODE_NAME_INDEX_USE_STRING }; #undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME const nsCString ToString(CodeNameIndex aCodeNameIndex); #define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName +#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , Command##aName typedef int8_t CommandInt; enum Command : CommandInt { CommandDoNothing #include "mozilla/CommandList.h" }; #undef NS_DEFINE_COMMAND +#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND const char* ToChar(Command aCommand); } // namespace mozilla /** * All header files should include this header instead of *Events.h. */
--- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -92,20 +92,24 @@ ToChar(Command aCommand) return "CommandDoNothing"; } switch (aCommand) { #define NS_DEFINE_COMMAND(aName, aCommandStr) \ case Command##aName: \ return "Command" #aName; +#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) \ + case Command##aName: \ + return "Command" #aName; #include "mozilla/CommandList.h" #undef NS_DEFINE_COMMAND +#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND default: return "illegal command value"; } } const nsCString GetDOMKeyCodeName(uint32_t aKeyCode) @@ -1159,21 +1163,23 @@ WidgetKeyboardEvent::GetCodeNameIndex(co sCodeNameIndexHashtable->Get(aCodeValue, &result); return result; } /* static */ const char* WidgetKeyboardEvent::GetCommandStr(Command aCommand) { #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr +#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) static const char* const kCommands[] = { "" // CommandDoNothing #include "mozilla/CommandList.h" }; #undef NS_DEFINE_COMMAND +#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands), "Illegal command enumeration value"); return kCommands[aCommand]; } /* static */ uint32_t WidgetKeyboardEvent::ComputeLocationFromCodeValue(CodeNameIndex aCodeNameIndex)
--- a/widget/cocoa/TextInputHandler.h +++ b/widget/cocoa/TextInputHandler.h @@ -622,24 +622,151 @@ protected: return !mKeyPressDispatched && !IsDefaultPrevented(); } bool CanHandleCommand() const { return !mKeyDownHandled && !mKeyPressHandled; } - bool IsEnterKeyEvent() const + bool IsProperKeyEvent(Command aCommand) const { if (NS_WARN_IF(!mKeyEvent)) { return false; } KeyNameIndex keyNameIndex = TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode]); - return keyNameIndex == KEY_NAME_INDEX_Enter; + Modifiers modifiers = + nsCocoaUtils::ModifiersForEvent(mKeyEvent) & (MODIFIER_SHIFT | + MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + switch (aCommand) { + case CommandInsertLineBreak: + return keyNameIndex == KEY_NAME_INDEX_Enter && + modifiers == MODIFIER_CONTROL; + case CommandInsertParagraph: + return keyNameIndex == KEY_NAME_INDEX_Enter && + modifiers == MODIFIER_NONE; + case CommandDeleteCharBackward: + return keyNameIndex == KEY_NAME_INDEX_Backspace && + modifiers == MODIFIER_NONE; + case CommandDeleteToBeginningOfLine: + return keyNameIndex == KEY_NAME_INDEX_Backspace && + modifiers == MODIFIER_META; + case CommandDeleteWordBackward: + return keyNameIndex == KEY_NAME_INDEX_Backspace && + modifiers == MODIFIER_ALT; + case CommandDeleteCharForward: + return keyNameIndex == KEY_NAME_INDEX_Delete && + modifiers == MODIFIER_NONE; + case CommandDeleteWordForward: + return keyNameIndex == KEY_NAME_INDEX_Delete && + modifiers == MODIFIER_ALT; + case CommandInsertTab: + return keyNameIndex == KEY_NAME_INDEX_Tab && + modifiers == MODIFIER_NONE; + case CommandInsertBacktab: + return keyNameIndex == KEY_NAME_INDEX_Tab && + modifiers == MODIFIER_SHIFT; + case CommandCharNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == MODIFIER_NONE; + case CommandSelectCharNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == MODIFIER_SHIFT; + case CommandWordNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == MODIFIER_ALT; + case CommandSelectWordNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == (MODIFIER_ALT | MODIFIER_SHIFT); + case CommandEndLine: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == MODIFIER_META; + case CommandSelectEndLine: + return keyNameIndex == KEY_NAME_INDEX_ArrowRight && + modifiers == (MODIFIER_META | MODIFIER_SHIFT); + case CommandCharPrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == MODIFIER_NONE; + case CommandSelectCharPrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == MODIFIER_SHIFT; + case CommandWordPrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == MODIFIER_ALT; + case CommandSelectWordPrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == (MODIFIER_ALT | MODIFIER_SHIFT); + case CommandBeginLine: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == MODIFIER_META; + case CommandSelectBeginLine: + return keyNameIndex == KEY_NAME_INDEX_ArrowLeft && + modifiers == (MODIFIER_META | MODIFIER_SHIFT); + case CommandLinePrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowUp && + modifiers == MODIFIER_NONE; + case CommandSelectLinePrevious: + return keyNameIndex == KEY_NAME_INDEX_ArrowUp && + modifiers == MODIFIER_SHIFT; + case CommandMoveTop: + return keyNameIndex == KEY_NAME_INDEX_ArrowUp && + modifiers == MODIFIER_META; + case CommandSelectTop: + return (keyNameIndex == KEY_NAME_INDEX_ArrowUp && + modifiers == (MODIFIER_META | MODIFIER_SHIFT)) || + (keyNameIndex == KEY_NAME_INDEX_Home && + modifiers == MODIFIER_SHIFT); + case CommandLineNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowDown && + modifiers == MODIFIER_NONE; + case CommandSelectLineNext: + return keyNameIndex == KEY_NAME_INDEX_ArrowDown && + modifiers == MODIFIER_SHIFT; + case CommandMoveBottom: + return keyNameIndex == KEY_NAME_INDEX_ArrowDown && + modifiers == MODIFIER_META; + case CommandSelectBottom: + return (keyNameIndex == KEY_NAME_INDEX_ArrowDown && + modifiers == (MODIFIER_META | MODIFIER_SHIFT)) || + (keyNameIndex == KEY_NAME_INDEX_End && + modifiers == MODIFIER_SHIFT); + case CommandScrollPageUp: + return keyNameIndex == KEY_NAME_INDEX_PageUp && + modifiers == MODIFIER_NONE; + case CommandSelectPageUp: + return keyNameIndex == KEY_NAME_INDEX_PageUp && + modifiers == MODIFIER_SHIFT; + case CommandScrollPageDown: + return keyNameIndex == KEY_NAME_INDEX_PageDown && + modifiers == MODIFIER_NONE; + case CommandSelectPageDown: + return keyNameIndex == KEY_NAME_INDEX_PageDown && + modifiers == MODIFIER_SHIFT; + case CommandScrollBottom: + return keyNameIndex == KEY_NAME_INDEX_End && + modifiers == MODIFIER_NONE; + case CommandScrollTop: + return keyNameIndex == KEY_NAME_INDEX_Home && + modifiers == MODIFIER_NONE; + case CommandCancelOperation: + return (keyNameIndex == KEY_NAME_INDEX_Escape && + (modifiers == MODIFIER_NONE || + modifiers == MODIFIER_SHIFT)) || + ([mKeyEvent keyCode] == kVK_ANSI_Period && + modifiers == MODIFIER_META); + case CommandComplete: + return keyNameIndex == KEY_NAME_INDEX_Escape && + (modifiers == MODIFIER_ALT || + modifiers == (MODIFIER_ALT | MODIFIER_SHIFT)); + default: + return false; + } } void InitKeyEvent(TextInputHandlerBase* aHandler, WidgetKeyboardEvent& aKeyEvent); /** * GetUnhandledString() returns characters of the event which have not been * handled with InsertText() yet. For example, if there is a composition @@ -1156,18 +1283,22 @@ public: * @param aReplacementRange The range which will be replaced with the * aAttrString instead of current selection. */ void InsertText(NSAttributedString *aAttrString, NSRange* aReplacementRange = nullptr); /** * Handles aCommand. This may cause dispatching an eKeyPress event. + * + * @param aCommand The command which receives from Cocoa. + * @return true if this handles the command even if it does + * nothing actually. Otherwise, false. */ - void HandleCommand(Command aCommand); + bool HandleCommand(Command aCommand); /** * doCommandBySelector event handler. * * @param aSelector A selector of the command. * @return TRUE if the command is consumed. Otherwise, * FALSE. */
--- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -2345,23 +2345,23 @@ TextInputHandler::InsertText(NSAttribute if (currentKeyEvent) { currentKeyEvent->mKeyPressHandled = keyPressHandled; currentKeyEvent->mKeyPressDispatched = keyPressDispatched; } NS_OBJC_END_TRY_ABORT_BLOCK; } -void +bool TextInputHandler::HandleCommand(Command aCommand) { - NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; if (Destroyed()) { - return; + return false; } KeyEventState* currentKeyEvent = GetCurrentKeyEvent(); MOZ_LOG(gLog, LogLevel::Info, ("%p TextInputHandler::HandleCommand, " "aCommand=%s, IsIMEComposing()=%s, " "keyevent=%p, keydownHandled=%s, keypressDispatched=%s, " @@ -2372,19 +2372,19 @@ TextInputHandler::HandleCommand(Command TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A", currentKeyEvent ? TrueOrFalse(currentKeyEvent->mKeyPressDispatched) : "N/A", currentKeyEvent ? TrueOrFalse(currentKeyEvent->mCausedOtherKeyEvents) : "N/A", currentKeyEvent ? TrueOrFalse(currentKeyEvent->mCompositionDispatched) : "N/A")); - // If "insertNewline:" command shouldn't be handled, let's ignore it. + // The command shouldn't be handled, let's ignore it. if (currentKeyEvent && !currentKeyEvent->CanHandleCommand()) { - return; + return false; } // If it's in composition, we cannot dispatch keypress event. // Therefore, we should use different approach or give up to handle // the command. if (IsIMEComposing()) { switch (aCommand) { case CommandInsertLineBreak: @@ -2397,43 +2397,87 @@ TextInputHandler::HandleCommand(Command // NSKeyDown event or should insert it with committing composition. NSAttributedString* lineBreaker = [[NSAttributedString alloc] initWithString:@"\n"]; InsertTextAsCommittingComposition(lineBreaker, nullptr); if (currentKeyEvent) { currentKeyEvent->mCompositionDispatched = true; } [lineBreaker release]; - return; + return true; } + case CommandDeleteCharBackward: + case CommandDeleteCharForward: + case CommandDeleteToBeginningOfLine: + case CommandDeleteWordBackward: + case CommandDeleteWordForward: + // Don't remove any contents during composition. + return false; + case CommandInsertTab: + case CommandInsertBacktab: + // Don't move focus during composition. + return false; + case CommandCharNext: + case CommandSelectCharNext: + case CommandWordNext: + case CommandSelectWordNext: + case CommandEndLine: + case CommandSelectEndLine: + case CommandCharPrevious: + case CommandSelectCharPrevious: + case CommandWordPrevious: + case CommandSelectWordPrevious: + case CommandBeginLine: + case CommandSelectBeginLine: + case CommandLinePrevious: + case CommandSelectLinePrevious: + case CommandMoveTop: + case CommandLineNext: + case CommandSelectLineNext: + case CommandMoveBottom: + case CommandSelectBottom: + case CommandSelectPageUp: + case CommandSelectPageDown: + case CommandScrollBottom: + case CommandScrollTop: + // Don't move selection during composition. + return false; + case CommandCancelOperation: + case CommandComplete: + // Don't handle Escape key by ourselves during composition. + return false; + case CommandScrollPageUp: + case CommandScrollPageDown: + // Allow to scroll. + break; default: break; } } RefPtr<nsChildView> widget(mWidget); nsresult rv = mDispatcher->BeginNativeInputTransaction(); if (NS_WARN_IF(NS_FAILED(rv))) { MOZ_LOG(gLog, LogLevel::Error, ("%p, IMEInputHandler::HandleCommand, " "FAILED, due to BeginNativeInputTransaction() failure", this)); - return; + return false; } // TODO: If it's not appropriate keypress but user customized the OS // settings to do the command with other key, we should just set // command to the keypress event and it should be handled as // the key press in editor. // If it's handling actual key event and hasn't cause any composition // events nor other key events, we should expose actual modifier state. // Otherwise, we should adjust Control, Option and Command state since // editor may behave differently if some of them are active. bool dispatchFakeKeyPress = - !(currentKeyEvent && currentKeyEvent->IsEnterKeyEvent() && + !(currentKeyEvent && currentKeyEvent->IsProperKeyEvent(aCommand) && currentKeyEvent->CanDispatchKeyPressEvent()); WidgetKeyboardEvent keypressEvent(true, eKeyPress, widget); if (!dispatchFakeKeyPress) { // If we're acutally handling a key press, we should dispatch // the keypress event as-is. currentKeyEvent->InitKeyEvent(this, keypressEvent); } else { @@ -2459,18 +2503,215 @@ TextInputHandler::HandleCommand(Command MODIFIER_META); if (aCommand == CommandInsertLineBreak) { // In default settings, Ctrl + Enter causes insertLineBreak command. // So, let's make Ctrl state active of the keypress event. keypressEvent.mModifiers |= MODIFIER_CONTROL; } break; } + case CommandDeleteCharBackward: + case CommandDeleteToBeginningOfLine: + case CommandDeleteWordBackward: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_BACK; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_Backspace; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandDeleteToBeginningOfLine) { + keypressEvent.mModifiers |= MODIFIER_META; + } else if (aCommand == CommandDeleteWordBackward) { + keypressEvent.mModifiers |= MODIFIER_ALT; + } + break; + } + case CommandDeleteCharForward: + case CommandDeleteWordForward: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_DELETE; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_Delete; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandDeleteWordForward) { + keypressEvent.mModifiers |= MODIFIER_ALT; + } + break; + } + case CommandCharNext: + case CommandSelectCharNext: + case CommandWordNext: + case CommandSelectWordNext: + case CommandEndLine: + case CommandSelectEndLine: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_RIGHT; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_ArrowRight; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectCharNext || + aCommand == CommandSelectWordNext || + aCommand == CommandSelectEndLine) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + if (aCommand == CommandWordNext || + aCommand == CommandSelectWordNext) { + keypressEvent.mModifiers |= MODIFIER_ALT; + } + if (aCommand == CommandEndLine || + aCommand == CommandSelectEndLine) { + keypressEvent.mModifiers |= MODIFIER_META; + } + break; + } + case CommandCharPrevious: + case CommandSelectCharPrevious: + case CommandWordPrevious: + case CommandSelectWordPrevious: + case CommandBeginLine: + case CommandSelectBeginLine: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_LEFT; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_ArrowLeft; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectCharPrevious || + aCommand == CommandSelectWordPrevious || + aCommand == CommandSelectBeginLine) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + if (aCommand == CommandWordPrevious || + aCommand == CommandSelectWordPrevious) { + keypressEvent.mModifiers |= MODIFIER_ALT; + } + if (aCommand == CommandBeginLine || + aCommand == CommandSelectBeginLine) { + keypressEvent.mModifiers |= MODIFIER_META; + } + break; + } + case CommandLinePrevious: + case CommandSelectLinePrevious: + case CommandMoveTop: + case CommandSelectTop: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_UP; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_ArrowUp; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectLinePrevious || + aCommand == CommandSelectTop) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + if (aCommand == CommandMoveTop || + aCommand == CommandSelectTop) { + keypressEvent.mModifiers |= MODIFIER_META; + } + break; + } + case CommandLineNext: + case CommandSelectLineNext: + case CommandMoveBottom: + case CommandSelectBottom: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_DOWN; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_ArrowDown; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectLineNext || + aCommand == CommandSelectBottom) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + if (aCommand == CommandMoveBottom || + aCommand == CommandSelectBottom) { + keypressEvent.mModifiers |= MODIFIER_META; + } + break; + } + case CommandScrollPageUp: + case CommandSelectPageUp: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_PAGE_UP; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_PageUp; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectPageUp) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + break; + } + case CommandScrollPageDown: + case CommandSelectPageDown: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_PAGE_DOWN; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_PageDown; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandSelectPageDown) { + keypressEvent.mModifiers |= MODIFIER_SHIFT; + } + break; + } + case CommandScrollBottom: + case CommandScrollTop: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + if (aCommand == CommandScrollBottom) { + keypressEvent.mKeyCode = NS_VK_END; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_End; + } else { + keypressEvent.mKeyCode = NS_VK_HOME; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_Home; + } + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + break; + } + case CommandCancelOperation: + case CommandComplete: { + NSEvent* keyEvent = + currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr; + nsCocoaUtils::InitInputEvent(keypressEvent, keyEvent); + keypressEvent.mKeyCode = NS_VK_ESCAPE; + keypressEvent.mKeyNameIndex = KEY_NAME_INDEX_Escape; + keypressEvent.mModifiers &= ~(MODIFIER_CONTROL | + MODIFIER_ALT | + MODIFIER_META); + if (aCommand == CommandComplete) { + keypressEvent.mModifiers |= MODIFIER_ALT; + } + break; + } default: - return; + return false; } } nsEventStatus status = nsEventStatus_eIgnore; bool keyPressDispatched = mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status, currentKeyEvent); bool keyPressHandled = (status == nsEventStatus_eConsumeNoDefault); @@ -2481,30 +2722,36 @@ TextInputHandler::HandleCommand(Command // Record the keypress event state only when it dispatched actual Enter // keypress event because in other cases, the keypress event just a // messenger. E.g., if it's caused by different key, keypress event for // the actual key should be dispatched. if (!dispatchFakeKeyPress && currentKeyEvent) { currentKeyEvent->mKeyPressHandled = keyPressHandled; currentKeyEvent->mKeyPressDispatched = keyPressDispatched; } - return; + return true; } // If keypress event isn't dispatched as expected, we should fallback to // using composition events. - NSAttributedString* lineBreaker = - [[NSAttributedString alloc] initWithString:@"\n"]; - InsertTextAsCommittingComposition(lineBreaker, nullptr); - if (currentKeyEvent) { - currentKeyEvent->mCompositionDispatched = true; + if (aCommand == CommandInsertLineBreak || + aCommand == CommandInsertParagraph) { + NSAttributedString* lineBreaker = + [[NSAttributedString alloc] initWithString:@"\n"]; + InsertTextAsCommittingComposition(lineBreaker, nullptr); + if (currentKeyEvent) { + currentKeyEvent->mCompositionDispatched = true; + } + [lineBreaker release]; + return true; } - [lineBreaker release]; - - NS_OBJC_END_TRY_ABORT_BLOCK; + + return false; + + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); } bool TextInputHandler::DoCommandBySelector(const char* aSelector) { RefPtr<nsChildView> widget(mWidget); KeyEventState* currentKeyEvent = GetCurrentKeyEvent(); @@ -2562,17 +2809,36 @@ TextInputHandler::DoCommandBySelector(co return true; } // If the key operation didn't cause keypress event or caused keypress event // but not prevented its default, we need to honor the command. For example, // Korean IME sends "insertNewline:" when committing existing composition // with Enter key press. In such case, the key operation has been consumed // by the committing composition but we still need to handle the command. - return Destroyed() || !currentKeyEvent->CanHandleCommand(); + if (Destroyed() || !currentKeyEvent->CanHandleCommand()) { + return true; + } + + // cancelOperation: command is fired after Escape or Command + Period. + // However, if ChildView implements cancelOperation:, calling + // [[ChildView super] doCommandBySelector:aSelector] when Command + Period + // causes only a call of [ChildView cancelOperation:sender]. I.e., + // [ChildView keyDown:theEvent] becomes to be never called. For avoiding + // this odd behavior, we need to handle the command before super class of + // ChildView only when current key event is proper event to fire Escape + // keypress event. + if (!strcmp(aSelector, "cancelOperatiorn:") && currentKeyEvent && + currentKeyEvent->IsProperKeyEvent(CommandCancelOperation)) { + return HandleCommand(CommandCancelOperation); + } + + // Otherwise, we've not handled the command yet. Propagate the command + // to the super class of ChildView. + return false; } #pragma mark - /****************************************************************************** *
--- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -5594,16 +5594,300 @@ GetIntegerDeltaForEvent(NSEvent* aEvent) - (void)insertLineBreak:(id)sender { // Ctrl + Enter in the default settings. if (mTextInputHandler) { mTextInputHandler->HandleCommand(CommandInsertLineBreak); } } +- (void) deleteBackward:(id)sender +{ + // Backspace in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteCharBackward); + } +} + +- (void) deleteBackwardByDecomposingPreviousCharacter:(id)sender +{ + // Ctrl + Backspace in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteCharBackward); + } +} + +- (void) deleteWordBackward:(id)sender +{ + // Alt + Backspace in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteWordBackward); + } +} + +- (void) deleteToBeginningOfBackward:(id)sender +{ + // Command + Backspace in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteToBeginningOfLine); + } +} + +- (void) deleteForward:(id)sender +{ + // Delete in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteCharForward); + } +} + +- (void) deleteWordForward:(id)sender +{ + // Alt + Delete in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandDeleteWordForward); + } +} + +- (void) insertTab:(id)sender +{ + // Tab in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandInsertTab); + } +} + +- (void) insertBacktab:(id)sender +{ + // Shift + Tab in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandInsertBacktab); + } +} + +- (void) moveRight:(id)sender +{ + // RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandCharNext); + } +} + +- (void) moveRightAndModifySelection:(id)sender +{ + // Shift + RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectCharNext); + } +} + +- (void) moveWordRight:(id)sender +{ + // Alt + RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandWordNext); + } +} + +- (void) moveWordRightAndModifySelection:(id)sender +{ + // Alt + Shift + RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectWordNext); + } +} + +- (void) moveToRightEndOfLine:(id)sender +{ + // Command + RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandEndLine); + } +} + +- (void) moveToRightEndOfLineAndModifySelection:(id)sender +{ + // Command + Shift + RightArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectEndLine); + } +} + +- (void) moveLeft:(id)sender +{ + // LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandCharPrevious); + } +} + +- (void) moveLeftAndModifySelection:(id)sender +{ + // Shift + LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectCharPrevious); + } +} + +- (void) moveWordLeft:(id)sender +{ + // Alt + LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandWordPrevious); + } +} + +- (void) moveWordLeftAndModifySelection:(id)sender +{ + // Alt + Shift + LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectWordPrevious); + } +} + +- (void) moveToLeftEndOfLine:(id)sender +{ + // Command + LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandBeginLine); + } +} + +- (void) moveToLeftEndOfLineAndModifySelection:(id)sender +{ + // Command + Shift + LeftArrow in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectBeginLine); + } +} + +- (void) moveUp:(id)sender +{ + // ArrowUp in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandLinePrevious); + } +} + +- (void) moveUpAndModifySelection:(id)sender +{ + // Shift + ArrowUp in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectLinePrevious); + } +} + +- (void) moveToBeginningOfDocument:(id)sender +{ + // Command + ArrowUp in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandMoveTop); + } +} + +- (void) moveToBeginningOfDocumentAndModifySelection:(id)sender +{ + // Command + Shift + ArrowUp or Shift + Home in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectTop); + } +} + +- (void) moveDown:(id)sender +{ + // ArrowDown in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandLineNext); + } +} + +- (void) moveDownAndModifySelection:(id)sender +{ + // Shift + ArrowDown in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectLineNext); + } +} + +- (void) moveToEndOfDocument:(id)sender +{ + // Command + ArrowDown in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandMoveBottom); + } +} + +- (void) moveToEndOfDocumentAndModifySelection:(id)sender +{ + // Command + Shift + ArrowDown or Shift + End in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectBottom); + } +} + +- (void) scrollPageUp:(id)sender +{ + // PageUp in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandScrollPageUp); + } +} + +- (void) pageUpAndModifySelection:(id)sender +{ + // Shift + PageUp in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectPageUp); + } +} + +- (void) scrollPageDown:(id)sender +{ + // PageDown in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandScrollPageDown); + } +} + +- (void) pageDownAndModifySelection:(id)sender +{ + // Shift + PageDown in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandSelectPageDown); + } +} + +- (void) scrollToEndOfDocument:(id)sender +{ + // End in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandScrollBottom); + } +} + +- (void) scrollToBeginningOfDocument:(id)sender +{ + // Home in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandScrollTop); + } +} + +// XXX Don't decleare nor implement calcelOperation: because it +// causes not calling keyDown: for Command + Period. +// We need to handle it from doCommandBySelector:. + +- (void) complete:(id)sender +{ + // Alt + Escape or Alt + Shift + Escape in the default settings. + if (mTextInputHandler) { + mTextInputHandler->HandleCommand(CommandComplete); + } +} + - (void)flagsChanged:(NSEvent*)theEvent { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_ENSURE_TRUE(mGeckoChild, ); nsAutoRetainCocoaObject kungFuDeathGrip(self); mTextInputHandler->HandleFlagsChanged(theEvent);