Bug 1403759 - part 2: Handle edit/selection commands like insertNewline: in TextInputHandler::HandleCommand() r=m_kato

Let's make TextInputHandler::HandleCommand() handle other
commands which are caused by Backspace, Delete, Tab, ArrowUp,
ArrowDown, ArrowRight, ArrowLeft, PageUp, PageDown, Home, End
and Escape keys with various modifiers.

This patch makes Korean users can do most key operation in
editor even with composing Hangul character.

Note that this patch has a hack for cancelOperation: command.
The command is typically fired for Escape key press.  However,
it's also fired for Command + Period.  Unfortunately, this
behavior is really odd if subclass of NSResponder implements
|void cancelOperation:(id)sender|.  If it's implemented,
Cocoa doesn't call its |void keyDown:(NSEvent)theEvent|.
Instead, it calls only |void doCommandBySelector:(SEL)aSelector|
and |void cancelOperation:(id)sender| when Command + Period is
pressed.  Therefore, we cannot dispatch keydown nor keypress
event for this key combination if we implement it.  Therefore,
this patch doesn't implement the method but handle it in
doCommandBySelector even though the super class of ChildView
cannot handle the command with this path.

MozReview-Commit-ID: 4hS23SiwNJv

--HG--
extra : rebase_source : 38ac1ea494b5f786ecd5c9327efbacd460b59faf
This commit is contained in:
Masayuki Nakano 2017-12-02 14:53:10 +09:00
Родитель d7ecd695d3
Коммит af6a1c5d37
6 изменённых файлов: 719 добавлений и 22 удалений

Просмотреть файл

@ -4,9 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * 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 aName The name useful in C++ of the command.
* @param aCommandStr The command string in JS. * @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(BeginLine, cmd_beginLine)
@ -52,3 +55,8 @@ NS_DEFINE_COMMAND(SelectWordNext, cmd_selectWordNext)
NS_DEFINE_COMMAND(SelectWordPrevious, cmd_selectWordPrevious) NS_DEFINE_COMMAND(SelectWordPrevious, cmd_selectWordPrevious)
NS_DEFINE_COMMAND(WordNext, cmd_wordNext) NS_DEFINE_COMMAND(WordNext, cmd_wordNext)
NS_DEFINE_COMMAND(WordPrevious, cmd_wordPrevious) 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)

Просмотреть файл

@ -114,6 +114,7 @@ enum CodeNameIndex : CodeNameIndexType
const nsCString ToString(CodeNameIndex aCodeNameIndex); const nsCString ToString(CodeNameIndex aCodeNameIndex);
#define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName #define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName
#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , Command##aName
typedef int8_t CommandInt; typedef int8_t CommandInt;
enum Command : CommandInt enum Command : CommandInt
@ -123,6 +124,7 @@ enum Command : CommandInt
#include "mozilla/CommandList.h" #include "mozilla/CommandList.h"
}; };
#undef NS_DEFINE_COMMAND #undef NS_DEFINE_COMMAND
#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
const char* ToChar(Command aCommand); const char* ToChar(Command aCommand);

Просмотреть файл

@ -97,10 +97,14 @@ ToChar(Command aCommand)
#define NS_DEFINE_COMMAND(aName, aCommandStr) \ #define NS_DEFINE_COMMAND(aName, aCommandStr) \
case Command##aName: \ case Command##aName: \
return "Command" #aName; return "Command" #aName;
#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) \
case Command##aName: \
return "Command" #aName;
#include "mozilla/CommandList.h" #include "mozilla/CommandList.h"
#undef NS_DEFINE_COMMAND #undef NS_DEFINE_COMMAND
#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
default: default:
return "illegal command value"; return "illegal command value";
@ -1164,11 +1168,13 @@ WidgetKeyboardEvent::GetCodeNameIndex(const nsAString& aCodeValue)
WidgetKeyboardEvent::GetCommandStr(Command aCommand) WidgetKeyboardEvent::GetCommandStr(Command aCommand)
{ {
#define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName)
static const char* const kCommands[] = { static const char* const kCommands[] = {
"" // CommandDoNothing "" // CommandDoNothing
#include "mozilla/CommandList.h" #include "mozilla/CommandList.h"
}; };
#undef NS_DEFINE_COMMAND #undef NS_DEFINE_COMMAND
#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands), MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands),
"Illegal command enumeration value"); "Illegal command enumeration value");

Просмотреть файл

@ -627,14 +627,141 @@ protected:
return !mKeyDownHandled && !mKeyPressHandled; return !mKeyDownHandled && !mKeyPressHandled;
} }
bool IsEnterKeyEvent() const bool IsProperKeyEvent(Command aCommand) const
{ {
if (NS_WARN_IF(!mKeyEvent)) { if (NS_WARN_IF(!mKeyEvent)) {
return false; return false;
} }
KeyNameIndex keyNameIndex = KeyNameIndex keyNameIndex =
TISInputSourceWrapper::ComputeGeckoKeyNameIndex([mKeyEvent keyCode]); 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, void InitKeyEvent(TextInputHandlerBase* aHandler,
@ -1161,8 +1288,12 @@ public:
/** /**
* Handles aCommand. This may cause dispatching an eKeyPress event. * 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. * doCommandBySelector event handler.

Просмотреть файл

@ -2350,13 +2350,13 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
NS_OBJC_END_TRY_ABORT_BLOCK; NS_OBJC_END_TRY_ABORT_BLOCK;
} }
void bool
TextInputHandler::HandleCommand(Command aCommand) TextInputHandler::HandleCommand(Command aCommand)
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
if (Destroyed()) { if (Destroyed()) {
return; return false;
} }
KeyEventState* currentKeyEvent = GetCurrentKeyEvent(); KeyEventState* currentKeyEvent = GetCurrentKeyEvent();
@ -2377,9 +2377,9 @@ TextInputHandler::HandleCommand(Command aCommand)
currentKeyEvent ? currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mCompositionDispatched) : "N/A")); 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()) { if (currentKeyEvent && !currentKeyEvent->CanHandleCommand()) {
return; return false;
} }
// If it's in composition, we cannot dispatch keypress event. // If it's in composition, we cannot dispatch keypress event.
@ -2402,8 +2402,52 @@ TextInputHandler::HandleCommand(Command aCommand)
currentKeyEvent->mCompositionDispatched = true; currentKeyEvent->mCompositionDispatched = true;
} }
[lineBreaker release]; [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: default:
break; break;
} }
@ -2415,7 +2459,7 @@ TextInputHandler::HandleCommand(Command aCommand)
MOZ_LOG(gLog, LogLevel::Error, MOZ_LOG(gLog, LogLevel::Error,
("%p, IMEInputHandler::HandleCommand, " ("%p, IMEInputHandler::HandleCommand, "
"FAILED, due to BeginNativeInputTransaction() failure", this)); "FAILED, due to BeginNativeInputTransaction() failure", this));
return; return false;
} }
// TODO: If it's not appropriate keypress but user customized the OS // TODO: If it's not appropriate keypress but user customized the OS
@ -2428,7 +2472,7 @@ TextInputHandler::HandleCommand(Command aCommand)
// Otherwise, we should adjust Control, Option and Command state since // Otherwise, we should adjust Control, Option and Command state since
// editor may behave differently if some of them are active. // editor may behave differently if some of them are active.
bool dispatchFakeKeyPress = bool dispatchFakeKeyPress =
!(currentKeyEvent && currentKeyEvent->IsEnterKeyEvent() && !(currentKeyEvent && currentKeyEvent->IsProperKeyEvent(aCommand) &&
currentKeyEvent->CanDispatchKeyPressEvent()); currentKeyEvent->CanDispatchKeyPressEvent());
WidgetKeyboardEvent keypressEvent(true, eKeyPress, widget); WidgetKeyboardEvent keypressEvent(true, eKeyPress, widget);
@ -2464,8 +2508,205 @@ TextInputHandler::HandleCommand(Command aCommand)
} }
break; 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: default:
return; return false;
} }
} }
@ -2486,20 +2727,26 @@ TextInputHandler::HandleCommand(Command aCommand)
currentKeyEvent->mKeyPressHandled = keyPressHandled; currentKeyEvent->mKeyPressHandled = keyPressHandled;
currentKeyEvent->mKeyPressDispatched = keyPressDispatched; currentKeyEvent->mKeyPressDispatched = keyPressDispatched;
} }
return; return true;
} }
// If keypress event isn't dispatched as expected, we should fallback to // If keypress event isn't dispatched as expected, we should fallback to
// using composition events. // using composition events.
NSAttributedString* lineBreaker = if (aCommand == CommandInsertLineBreak ||
[[NSAttributedString alloc] initWithString:@"\n"]; aCommand == CommandInsertParagraph) {
InsertTextAsCommittingComposition(lineBreaker, nullptr); NSAttributedString* lineBreaker =
if (currentKeyEvent) { [[NSAttributedString alloc] initWithString:@"\n"];
currentKeyEvent->mCompositionDispatched = true; 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 bool
@ -2567,7 +2814,26 @@ TextInputHandler::DoCommandBySelector(const char* aSelector)
// Korean IME sends "insertNewline:" when committing existing composition // Korean IME sends "insertNewline:" when committing existing composition
// with Enter key press. In such case, the key operation has been consumed // 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. // 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;
} }

Просмотреть файл

@ -5599,6 +5599,290 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
} }
} }
- (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 - (void)flagsChanged:(NSEvent*)theEvent
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;