diff --git a/widget/cocoa/TextInputHandler.h b/widget/cocoa/TextInputHandler.h index db5a20bb50d6..e31d6c5f0553 100644 --- a/widget/cocoa/TextInputHandler.h +++ b/widget/cocoa/TextInputHandler.h @@ -226,6 +226,26 @@ public: void InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent, const nsAString *aInsertString = nullptr); + /** + * WillDispatchKeyboardEvent() computes aKeyEvent.alternativeCharCodes and + * recompute aKeyEvent.charCode if it's necessary. + * + * @param aNativeKeyEvent A native key event for which you want to + * dispatch a Gecko key event. + * @param aInsertString If caller expects that the event will cause + * a character to be input (say in an editor), + * the caller should set this. Otherwise, + * if caller sets null to this, this method will + * compute the character to be input from + * characters of aNativeKeyEvent. + * @param aKeyEvent The result -- a Gecko key event initialized + * from the native key event. This must be + * eKeyPress event. + */ + void WillDispatchKeyboardEvent(NSEvent* aNativeKeyEvent, + const nsAString* aInsertString, + WidgetKeyboardEvent& aKeyEvent); + /** * ComputeGeckoKeyCode() returns Gecko keycode for aNativeKeyCode on current * keyboard layout. @@ -286,23 +306,34 @@ protected: uint32_t TranslateToChar(UInt32 aKeyCode, UInt32 aModifiers, UInt32 aKbType); /** - * InitKeyPressEvent() initializes aKeyEvent for aNativeKeyEvent. - * Don't call this method when aKeyEvent isn't eKeyPress. + * ComputeInsertString() computes string to be inserted with the key event. * - * @param aNativeKeyEvent A native key event for which you want to - * dispatch a Gecko key event. - * @param aInsertChar A character to be input in an editor by the - * event. - * @param aKeyEvent The result -- a Gecko key event initialized - * from the native key event. This must be - * eKeyPress event. - * @param aKbType A native Keyboard Type value. Typically, - * this is a result of ::LMGetKbdType(). + * @param aNativeKeyEvent The native key event which causes our keyboard + * event(s). + * @param aKeyEvent A Gecko key event which was partially + * initialized with aNativeKeyEvent. + * @param aInsertString The string to be inputting by aNativeKeyEvent. + * This should be specified by InsertText(). + * In other words, if the key event doesn't cause + * a call of InsertText(), this can be nullptr. + * @param aResult The string which should be set to charCode of + * keypress event(s). */ - void InitKeyPressEvent(NSEvent *aNativeKeyEvent, - char16_t aInsertChar, - WidgetKeyboardEvent& aKeyEvent, - UInt32 aKbType); + void ComputeInsertStringForCharCode(NSEvent* aNativeKeyEvent, + const WidgetKeyboardEvent& aKeyEvent, + const nsAString* aInsertString, + nsAString& aResult); + + /** + * IsPrintableKeyEvent() returns true if aNativeKeyEvent is caused by + * a printable key. Otherwise, returns false. + */ + bool IsPrintableKeyEvent(NSEvent* aNativeKeyEvent) const; + + /** + * GetKbdType() returns physical keyboard type. + */ + UInt32 GetKbdType() const; bool GetBoolProperty(const CFStringRef aKey); bool GetStringProperty(const CFStringRef aKey, CFStringRef &aStr); @@ -467,6 +498,9 @@ protected: { // Handling native key event NSEvent* mKeyEvent; + // String specified by InsertText(). This is not null only during a + // call of InsertText(). + nsAString* mInsertString; // Whether keydown event was consumed by web contents or chrome contents. bool mKeyDownHandled; // Whether keypress event was dispatched for mKeyEvent. @@ -517,6 +551,7 @@ protected: [mKeyEvent release]; mKeyEvent = nullptr; } + mInsertString = nullptr; mKeyDownHandled = false; mKeyPressDispatched = false; mKeyPressHandled = false; @@ -535,7 +570,7 @@ protected: }; /** - * Helper class for guaranteeing cleaning mCurrentKeyEvent + * Helper classes for guaranteeing cleaning mCurrentKeyEvent */ class AutoKeyEventStateCleaner { @@ -553,6 +588,23 @@ protected: RefPtr mHandler; }; + class MOZ_STACK_CLASS AutoInsertStringClearer + { + public: + explicit AutoInsertStringClearer(KeyEventState* aState) + : mState(aState) + { + } + ~AutoInsertStringClearer() + { + if (mState) { + mState->mInsertString = nullptr; + } + } + private: + KeyEventState* mState; + }; + /** * mCurrentKeyEvents stores all key events which are being processed. * When we call interpretKeyEvents, IME may generate other key events. @@ -616,6 +668,22 @@ protected: return mCurrentKeyEvents[mCurrentKeyEvents.Length() - 1]; } + struct KeyboardLayoutOverride final + { + int32_t mKeyboardLayout; + bool mOverrideEnabled; + + KeyboardLayoutOverride() : + mKeyboardLayout(0), mOverrideEnabled(false) + { + } + }; + + const KeyboardLayoutOverride& KeyboardLayoutOverrideRef() const + { + return mKeyboardOverride; + } + /** * IsPrintableChar() checks whether the unicode character is * a non-printable ASCII character or not. Note that this returns @@ -648,16 +716,6 @@ protected: static bool IsModifierKey(UInt32 aNativeKeyCode); private: - struct KeyboardLayoutOverride { - int32_t mKeyboardLayout; - bool mOverrideEnabled; - - KeyboardLayoutOverride() : - mKeyboardLayout(0), mOverrideEnabled(false) - { - } - }; - KeyboardLayoutOverride mKeyboardOverride; static int32_t sSecureEventInputCount; diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 132e2915f2a2..94bd60439225 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -753,6 +753,125 @@ TISInputSourceWrapper::Clear() mOverrideKeyboard = false; } +bool +TISInputSourceWrapper::IsPrintableKeyEvent(NSEvent* aNativeKeyEvent) const +{ + UInt32 nativeKeyCode = [aNativeKeyEvent keyCode]; + + bool isPrintableKey = !TextInputHandler::IsSpecialGeckoKey(nativeKeyCode); + if (isPrintableKey && + [aNativeKeyEvent type] != NSKeyDown && + [aNativeKeyEvent type] != NSKeyUp) { + NS_WARNING("Why the printable key doesn't cause NSKeyDown or NSKeyUp?"); + isPrintableKey = false; + } + return isPrintableKey; +} + +UInt32 +TISInputSourceWrapper::GetKbdType() const +{ + // If a keyboard layout override is set, we also need to force the keyboard + // type to something ANSI to avoid test failures on machines with JIS + // keyboards (since the pair of keyboard layout and physical keyboard type + // form the actual key layout). This assumes that the test setting the + // override was written assuming an ANSI keyboard. + return mOverrideKeyboard ? eKbdType_ANSI : ::LMGetKbdType(); +} + +void +TISInputSourceWrapper::ComputeInsertStringForCharCode( + NSEvent* aNativeKeyEvent, + const WidgetKeyboardEvent& aKeyEvent, + const nsAString* aInsertString, + nsAString& aResult) +{ + if (aInsertString) { + // If the caller expects that the aInsertString will be input, we shouldn't + // change it. + aResult = *aInsertString; + } else if (IsPrintableKeyEvent(aNativeKeyEvent)) { + // If IME is open, [aNativeKeyEvent characters] may be a character + // which will be appended to the composition string. However, especially, + // while IME is disabled, most users and developers expect the key event + // works as IME closed. So, we should compute the aResult with + // the ASCII capable keyboard layout. + // NOTE: Such keyboard layouts typically change the layout to its ASCII + // capable layout when Command key is pressed. And we don't worry + // when Control key is pressed too because it causes inputting + // control characters. + UInt32 nativeKeyCode = [aNativeKeyEvent keyCode]; + if (!aKeyEvent.IsMeta() && !aKeyEvent.IsControl() && IsOpenedIMEMode()) { + UInt32 state = + nsCocoaUtils::ConvertToCarbonModifier([aNativeKeyEvent modifierFlags]); + uint32_t ch = TranslateToChar(nativeKeyCode, state, GetKbdType()); + if (ch) { + aResult = ch; + } + } else { + // If the caller isn't sure what string will be input, let's use + // characters of NSEvent. + nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], aResult); + } + + // If control key is pressed and the eventChars is a non-printable control + // character, we should convert it to ASCII alphabet. + if (aKeyEvent.IsControl() && + !aResult.IsEmpty() && aResult[0] <= char16_t(26)) { + aResult = (aKeyEvent.IsShift() ^ aKeyEvent.IsCapsLocked()) ? + static_cast(aResult[0] + ('A' - 1)) : + static_cast(aResult[0] + ('a' - 1)); + } + // If Meta key is pressed, it may cause to switch the keyboard layout like + // Arabic, Russian, Hebrew, Greek and Dvorak-QWERTY. + else if (aKeyEvent.IsMeta() && + !(aKeyEvent.IsControl() || aKeyEvent.IsAlt())) { + UInt32 kbType = GetKbdType(); + UInt32 numLockState = + aKeyEvent.IsNumLocked() ? kEventKeyModifierNumLockMask : 0; + UInt32 capsLockState = aKeyEvent.IsCapsLocked() ? alphaLock : 0; + UInt32 shiftState = aKeyEvent.IsShift() ? shiftKey : 0; + uint32_t uncmdedChar = + TranslateToChar(nativeKeyCode, numLockState, kbType); + uint32_t cmdedChar = + TranslateToChar(nativeKeyCode, cmdKey | numLockState, kbType); + // If we can make a good guess at the characters that the user would + // expect this key combination to produce (with and without Shift) then + // use those characters. This also corrects for CapsLock. + uint32_t ch = 0; + if (uncmdedChar == cmdedChar) { + // The characters produced with Command seem similar to those without + // Command. + ch = TranslateToChar(nativeKeyCode, + shiftState | capsLockState | numLockState, kbType); + } else { + TISInputSourceWrapper USLayout("com.apple.keylayout.US"); + uint32_t uncmdedUSChar = + USLayout.TranslateToChar(nativeKeyCode, numLockState, kbType); + // If it looks like characters from US keyboard layout when Command key + // is pressed, we should compute a character in the layout. + if (uncmdedUSChar == cmdedChar) { + ch = USLayout.TranslateToChar(nativeKeyCode, + shiftState | capsLockState | numLockState, kbType); + } + } + + // If there is a more preferred character for the commanded key event, + // we should use it. + if (ch) { + aResult = ch; + } + } + } + + // Remove control characters which shouldn't be inputted on editor. + // XXX Currently, we don't find any cases inserting control characters with + // printable character. So, just checking first character is enough. + if (!aResult.IsEmpty() && IsControlChar(aResult[0])) { + aResult.Truncate(); + } +} + void TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent, WidgetKeyboardEvent& aKeyEvent, @@ -791,110 +910,11 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent, } aKeyEvent.refPoint = LayoutDeviceIntPoint(0, 0); + aKeyEvent.isChar = false; // XXX not used in XP level - // If a keyboard layout override is set, we also need to force the keyboard - // type to something ANSI to avoid test failures on machines with JIS - // keyboards (since the pair of keyboard layout and physical keyboard type - // form the actual key layout). This assumes that the test setting the - // override was written assuming an ANSI keyboard. - UInt32 kbType = mOverrideKeyboard ? eKbdType_ANSI : ::LMGetKbdType(); - + UInt32 kbType = GetKbdType(); UInt32 nativeKeyCode = [aNativeKeyEvent keyCode]; - bool isPrintableKey = !TextInputHandler::IsSpecialGeckoKey(nativeKeyCode); - if (isPrintableKey && - [aNativeKeyEvent type] != NSKeyDown && - [aNativeKeyEvent type] != NSKeyUp) { - NS_WARNING("Why the printable key doesn't cause NSKeyDown or NSKeyUp?"); - isPrintableKey = false; - } - - // Decide what string will be input. - nsAutoString insertString; - if (aInsertString) { - // If the caller expects that the aInsertString will be input, we shouldn't - // change it. - insertString = *aInsertString; - } else if (isPrintableKey) { - // If IME is open, [aNativeKeyEvent characters] may be a character - // which will be appended to the composition string. However, especially, - // while IME is disabled, most users and developers expect the key event - // works as IME closed. So, we should compute the insertString with - // the ASCII capable keyboard layout. - // NOTE: Such keyboard layouts typically change the layout to its ASCII - // capable layout when Command key is pressed. And we don't worry - // when Control key is pressed too because it causes inputting - // control characters. - if (!aKeyEvent.IsMeta() && !aKeyEvent.IsControl() && IsOpenedIMEMode()) { - UInt32 state = - nsCocoaUtils::ConvertToCarbonModifier([aNativeKeyEvent modifierFlags]); - uint32_t ch = TranslateToChar(nativeKeyCode, state, kbType); - if (ch) { - insertString = ch; - } - } else { - // If the caller isn't sure what string will be input, let's use - // characters of NSEvent. - nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], - insertString); - } - - // If control key is pressed and the eventChars is a non-printable control - // character, we should convert it to ASCII alphabet. - if (aKeyEvent.IsControl() && - !insertString.IsEmpty() && insertString[0] <= char16_t(26)) { - insertString = (aKeyEvent.IsShift() ^ aKeyEvent.IsCapsLocked()) ? - static_cast(insertString[0] + ('A' - 1)) : - static_cast(insertString[0] + ('a' - 1)); - } - // If Meta key is pressed, it may cause to switch the keyboard layout like - // Arabic, Russian, Hebrew, Greek and Dvorak-QWERTY. - else if (aKeyEvent.IsMeta() && - !(aKeyEvent.IsControl() || aKeyEvent.IsAlt())) { - UInt32 numLockState = - aKeyEvent.IsNumLocked() ? kEventKeyModifierNumLockMask : 0; - UInt32 capsLockState = aKeyEvent.IsCapsLocked() ? alphaLock : 0; - UInt32 shiftState = aKeyEvent.IsShift() ? shiftKey : 0; - uint32_t uncmdedChar = - TranslateToChar(nativeKeyCode, numLockState, kbType); - uint32_t cmdedChar = - TranslateToChar(nativeKeyCode, cmdKey | numLockState, kbType); - // If we can make a good guess at the characters that the user would - // expect this key combination to produce (with and without Shift) then - // use those characters. This also corrects for CapsLock. - uint32_t ch = 0; - if (uncmdedChar == cmdedChar) { - // The characters produced with Command seem similar to those without - // Command. - ch = TranslateToChar(nativeKeyCode, - shiftState | capsLockState | numLockState, kbType); - } else { - TISInputSourceWrapper USLayout("com.apple.keylayout.US"); - uint32_t uncmdedUSChar = - USLayout.TranslateToChar(nativeKeyCode, numLockState, kbType); - // If it looks like characters from US keyboard layout when Command key - // is pressed, we should compute a character in the layout. - if (uncmdedUSChar == cmdedChar) { - ch = USLayout.TranslateToChar(nativeKeyCode, - shiftState | capsLockState | numLockState, kbType); - } - } - - // If there is a more preferred character for the commanded key event, - // we should use it. - if (ch) { - insertString = ch; - } - } - } - - // Remove control characters which shouldn't be inputted on editor. - // XXX Currently, we don't find any cases inserting control characters with - // printable character. So, just checking first character is enough. - if (!insertString.IsEmpty() && IsControlChar(insertString[0])) { - insertString.Truncate(); - } - aKeyEvent.keyCode = ComputeGeckoKeyCode(nativeKeyCode, kbType, aKeyEvent.IsMeta()); @@ -949,23 +969,7 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent, this, OnOrOff(aKeyEvent.IsShift()), OnOrOff(aKeyEvent.IsControl()), OnOrOff(aKeyEvent.IsAlt()), OnOrOff(aKeyEvent.IsMeta()))); - if (aKeyEvent.mMessage == eKeyPress && - (isPrintableKey || !insertString.IsEmpty())) { - InitKeyPressEvent(aNativeKeyEvent, - insertString.IsEmpty() ? 0 : insertString[0], - aKeyEvent, kbType); - MOZ_ASSERT(!aKeyEvent.charCode || !IsControlChar(aKeyEvent.charCode), - "charCode must not be a control character"); - } else { - aKeyEvent.charCode = 0; - aKeyEvent.isChar = false; // XXX not used in XP level - - MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyEvent, keyCode=0x%X charCode=0x0", - this, aKeyEvent.keyCode)); - } - - if (isPrintableKey) { + if (IsPrintableKeyEvent(aNativeKeyEvent)) { aKeyEvent.mKeyNameIndex = KEY_NAME_INDEX_USE_STRING; // If insertText calls this method, let's use the string. if (aInsertString && !aInsertString->IsEmpty() && @@ -1032,46 +1036,56 @@ TISInputSourceWrapper::InitKeyEvent(NSEvent *aNativeKeyEvent, } void -TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, - char16_t aInsertChar, - WidgetKeyboardEvent& aKeyEvent, - UInt32 aKbType) +TISInputSourceWrapper::WillDispatchKeyboardEvent( + NSEvent* aNativeKeyEvent, + const nsAString* aInsertString, + WidgetKeyboardEvent& aKeyEvent) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - NS_ASSERTION(aKeyEvent.mMessage == eKeyPress, - "aKeyEvent must be eKeyPress event"); + UInt32 kbType = GetKbdType(); if (MOZ_LOG_TEST(gLog, LogLevel::Info)) { nsAutoString chars; nsCocoaUtils::GetStringForNSString([aNativeKeyEvent characters], chars); NS_ConvertUTF16toUTF8 utf8Chars(chars); - char16_t expectedChar = static_cast(aInsertChar); - NS_ConvertUTF16toUTF8 utf8ExpectedChar(&expectedChar, 1); + char16_t uniChar = static_cast(aKeyEvent.charCode); MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, aNativeKeyEvent=%p, " - "[aNativeKeyEvent characters]=\"%s\", aInsertChar=0x%X(%s), " - "aKeyEvent.mMessage=%s, aKbType=0x%X, IsOpenedIMEMode()=%s", - this, aNativeKeyEvent, utf8Chars.get(), aInsertChar, - utf8ExpectedChar.get(), GetGeckoKeyEventType(aKeyEvent), aKbType, - TrueOrFalse(IsOpenedIMEMode()))); + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " + "aNativeKeyEvent=%p, [aNativeKeyEvent characters]=\"%s\", " + "aKeyEvent={ mMessage=%s, charCode=0x%X(%s) }, kbType=0x%X, " + "IsOpenedIMEMode()=%s", + this, aNativeKeyEvent, utf8Chars.get(), + GetGeckoKeyEventType(aKeyEvent), aKeyEvent.charCode, + uniChar ? NS_ConvertUTF16toUTF8(&uniChar, 1).get() : "", + kbType, TrueOrFalse(IsOpenedIMEMode()))); } - aKeyEvent.isChar = true; // this is not a special key XXX not used in XP - aKeyEvent.charCode = aInsertChar; - if (aKeyEvent.charCode != 0) { - aKeyEvent.keyCode = 0; + nsAutoString insertStringForCharCode; + ComputeInsertStringForCharCode(aNativeKeyEvent, aKeyEvent, aInsertString, + insertStringForCharCode); + uint32_t charCode = + insertStringForCharCode.IsEmpty() ? 0 : insertStringForCharCode[0]; + if (aKeyEvent.mMessage == eKeyPress) { + aKeyEvent.charCode = charCode; + aKeyEvent.isChar = true; // this is not a special key XXX not used in XP + } else if (charCode) { + // If it's not a keypress event, we need to set alternative char code + // to charCode value for shortcut key event handlers. + AlternativeCharCode altCharCodes(0, 0); + if (!aKeyEvent.IsShift()) { + altCharCodes.mUnshiftedCharCode = charCode; + } else { + altCharCodes.mShiftedCharCode = charCode; + } + aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); } MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, " + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " "aKeyEvent.keyCode=0x%X, aKeyEvent.charCode=0x%X", this, aKeyEvent.keyCode, aKeyEvent.charCode)); - if (!aKeyEvent.IsControl() && !aKeyEvent.IsMeta() && !aKeyEvent.IsAlt()) { - return; - } - TISInputSourceWrapper USLayout("com.apple.keylayout.US"); bool isRomanKeyboardLayout = IsASCIICapable(); @@ -1087,30 +1101,30 @@ TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, } MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, " + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " "isRomanKeyboardLayout=%s, key=0x%X", - this, TrueOrFalse(isRomanKeyboardLayout), aKbType, key)); + this, TrueOrFalse(isRomanKeyboardLayout), kbType, key)); nsString str; // normal chars - uint32_t unshiftedChar = TranslateToChar(key, lockState, aKbType); + uint32_t unshiftedChar = TranslateToChar(key, lockState, kbType); UInt32 shiftLockMod = shiftKey | lockState; - uint32_t shiftedChar = TranslateToChar(key, shiftLockMod, aKbType); + uint32_t shiftedChar = TranslateToChar(key, shiftLockMod, kbType); // characters generated with Cmd key // XXX we should remove CapsLock state, which changes characters from // Latin to Cyrillic with Russian layout on 10.4 only when Cmd key // is pressed. UInt32 numState = (lockState & ~alphaLock); // only num lock state - uint32_t uncmdedChar = TranslateToChar(key, numState, aKbType); + uint32_t uncmdedChar = TranslateToChar(key, numState, kbType); UInt32 shiftNumMod = numState | shiftKey; - uint32_t uncmdedShiftChar = TranslateToChar(key, shiftNumMod, aKbType); - uint32_t uncmdedUSChar = USLayout.TranslateToChar(key, numState, aKbType); + uint32_t uncmdedShiftChar = TranslateToChar(key, shiftNumMod, kbType); + uint32_t uncmdedUSChar = USLayout.TranslateToChar(key, numState, kbType); UInt32 cmdNumMod = cmdKey | numState; - uint32_t cmdedChar = TranslateToChar(key, cmdNumMod, aKbType); + uint32_t cmdedChar = TranslateToChar(key, cmdNumMod, kbType); UInt32 cmdShiftNumMod = shiftKey | cmdNumMod; - uint32_t cmdedShiftChar = TranslateToChar(key, cmdShiftNumMod, aKbType); + uint32_t cmdedShiftChar = TranslateToChar(key, cmdShiftNumMod, kbType); // Is the keyboard layout changed by Cmd key? // E.g., Arabic, Russian, Hebrew, Greek and Dvorak-QWERTY. @@ -1129,7 +1143,7 @@ TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); } MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, " + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " "aKeyEvent.isMeta=%s, isDvorakQWERTY=%s, " "unshiftedChar=U+%X, shiftedChar=U+%X", this, OnOrOff(aKeyEvent.IsMeta()), TrueOrFalse(isDvorakQWERTY), @@ -1169,11 +1183,11 @@ TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, } else if (uncmdedUSChar == cmdedChar) { // It looks like characters from a US layout are provided when Command // is down. - uint32_t ch = USLayout.TranslateToChar(key, lockState, aKbType); + uint32_t ch = USLayout.TranslateToChar(key, lockState, kbType); if (ch) { cmdedChar = ch; } - ch = USLayout.TranslateToChar(key, shiftLockMod, aKbType); + ch = USLayout.TranslateToChar(key, shiftLockMod, kbType); if (ch) { cmdedShiftChar = ch; } @@ -1191,7 +1205,7 @@ TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); } MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, " + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " "hasCmdShiftOnlyChar=%s, isCmdSwitchLayout=%s, isDvorakQWERTY=%s, " "cmdedChar=U+%X, cmdedShiftChar=U+%X", this, TrueOrFalse(hasCmdShiftOnlyChar), TrueOrFalse(isDvorakQWERTY), @@ -1203,7 +1217,7 @@ TISInputSourceWrapper::InitKeyPressEvent(NSEvent *aNativeKeyEvent, aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); } MOZ_LOG(gLog, LogLevel::Info, - ("%p TISInputSourceWrapper::InitKeyPressEvent, " + ("%p TISInputSourceWrapper::WillDispatchKeyboardEvent, " "hasCmdShiftOnlyChar=%s, originalCmdedShiftChar=U+%X", this, TrueOrFalse(hasCmdShiftOnlyChar), originalCmdedShiftChar)); @@ -2122,6 +2136,12 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString, nsAutoString str; nsCocoaUtils::GetStringForNSString([aAttrString string], str); + + AutoInsertStringClearer clearer(currentKeyEvent); + if (currentKeyEvent) { + currentKeyEvent->mInsertString = &str; + } + if (!IsIMEComposing() && str.IsEmpty()) { // nothing to do if there is no content which can be removed. if (!isEditable) { @@ -2524,7 +2544,23 @@ IMEInputHandler::WillDispatchKeyboardEvent( uint32_t aIndexOfKeypress, void* aData) { - // TODO: Implement this later. + // If the keyboard event is not caused by a native key event, we can do + // nothing here. + if (!aData) { + return; + } + + KeyEventState* currentKeyEvent = static_cast(aData); + NSEvent* nativeEvent = currentKeyEvent->mKeyEvent; + nsAString* insertString = currentKeyEvent->mInsertString; + if (KeyboardLayoutOverrideRef().mOverrideEnabled) { + TISInputSourceWrapper tis; + tis.InitByLayoutID(KeyboardLayoutOverrideRef().mKeyboardLayout, true); + tis.WillDispatchKeyboardEvent(nativeEvent, insertString, aKeyboardEvent); + return; + } + TISInputSourceWrapper::CurrentInputSource(). + WillDispatchKeyboardEvent(nativeEvent, insertString, aKeyboardEvent); } void @@ -4260,16 +4296,11 @@ TextInputHandlerBase::IsNormalCharInputtingEvent( const WidgetKeyboardEvent& aKeyEvent) { // this is not character inputting event, simply. - if (!aKeyEvent.isChar || !aKeyEvent.charCode || aKeyEvent.IsMeta()) { + if (aKeyEvent.mNativeCharacters.IsEmpty() || + aKeyEvent.IsMeta()) { return false; } - // if this is unicode char inputting event, we don't need to check - // ctrl/alt/command keys - if (aKeyEvent.charCode > 0x7F) { - return true; - } - // ASCII chars should be inputted without ctrl/alt/command keys - return !aKeyEvent.IsControl() && !aKeyEvent.IsAlt(); + return !IsControlChar(aKeyEvent.mNativeCharacters[0]); } /* static */ bool diff --git a/widget/tests/test_keycodes.xul b/widget/tests/test_keycodes.xul index 265523da902e..4ce1dcf97e82 100644 --- a/widget/tests/test_keycodes.xul +++ b/widget/tests/test_keycodes.xul @@ -1162,7 +1162,7 @@ function* runKeyEventTests() modifiers:{}, chars:"7", unmodifiedChars:"7"}, nsIDOMKeyEvent.DOM_VK_7, "7", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7, - modifiers:{shiftKey:1}, chars:"\u0026;", unmodifiedChars:"\u0026;"}, + modifiers:{shiftKey:1}, chars:"\u0026", unmodifiedChars:"\u0026"}, nsIDOMKeyEvent.DOM_VK_7, "\u0026", SHOULD_DELIVER_ALL, KeyboardEvent.DOM_KEY_LOCATION_STANDARD); yield testKey({layout:KEYBOARD_LAYOUT_EN_US, keyCode:MAC_VK_ANSI_7, modifiers:{ctrlKey:1}, chars:"7", unmodifiedChars:"7"},