diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp index 3e2128ba6f88..1680ec9f5a45 100644 --- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -1533,7 +1533,7 @@ NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const // keypress for almost all keys if (NeedsToHandleWithoutFollowingCharMessages()) { return (DispatchPluginEventsAndDiscardsCharMessages() || - DispatchKeyPressEventsWithKeyboardLayout()); + DispatchKeyPressEventsWithoutCharMessage()); } MSG followingCharMsg; @@ -1560,7 +1560,7 @@ NativeKey::HandleKeyDownMessage(bool* aEventDispatched) const return false; } - return DispatchKeyPressEventsWithKeyboardLayout(); + return DispatchKeyPressEventsWithoutCharMessage(); } bool @@ -2159,113 +2159,125 @@ NativeKey::ComputeInputtingStringWithKeyboardLayout() } bool -NativeKey::DispatchKeyPressEventsWithKeyboardLayout() const +NativeKey::DispatchKeyPressEventsWithoutCharMessage() const { MOZ_ASSERT(IsKeyDownMessage()); MOZ_ASSERT(!mIsDeadKey); - if (mInputtingStringAndModifiers.IsEmpty() && - mShiftedString.IsEmpty() && mUnshiftedString.IsEmpty()) { - nsresult rv = mDispatcher->BeginNativeInputTransaction(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return true; - } - - WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget); - keypressEvent.keyCode = mDOMKeyCode; - nsEventStatus status = InitKeyEvent(keypressEvent, mModKeyState); - mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status, - const_cast(this)); - return status == nsEventStatus_eConsumeNoDefault; + nsresult rv = mDispatcher->BeginNativeInputTransaction(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; } + WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget); + if (mInputtingStringAndModifiers.IsEmpty() && + mShiftedString.IsEmpty() && mUnshiftedString.IsEmpty()) { + keypressEvent.keyCode = mDOMKeyCode; + } + nsEventStatus status = InitKeyEvent(keypressEvent, mModKeyState); + mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status, + const_cast(this)); + return status == nsEventStatus_eConsumeNoDefault; +} + +void +NativeKey::WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent, + uint32_t aIndex) +{ uint32_t longestLength = std::max(mInputtingStringAndModifiers.mLength, std::max(mShiftedString.mLength, mUnshiftedString.mLength)); uint32_t skipUniChars = longestLength - mInputtingStringAndModifiers.mLength; uint32_t skipShiftedChars = longestLength - mShiftedString.mLength; uint32_t skipUnshiftedChars = longestLength - mUnshiftedString.mLength; - bool defaultPrevented = false; - for (uint32_t cnt = 0; cnt < longestLength; cnt++) { - uint16_t uniChar, shiftedChar, unshiftedChar; - uniChar = shiftedChar = unshiftedChar = 0; - ModifierKeyState modKeyState(mModKeyState); - if (skipUniChars <= cnt) { - if (cnt - skipUniChars < mInputtingStringAndModifiers.mLength) { - // If key in combination with Alt and/or Ctrl produces a different - // character than without them then do not report these flags - // because it is separate keyboard layout shift state. If dead-key - // and base character does not produce a valid composite character - // then both produced dead-key character and following base - // character may have different modifier flags, too. - modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | - MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK); - modKeyState.Set( - mInputtingStringAndModifiers.mModifiers[cnt - skipUniChars]); - } - uniChar = mInputtingStringAndModifiers.mChars[cnt - skipUniChars]; - } - if (skipShiftedChars <= cnt) - shiftedChar = mShiftedString.mChars[cnt - skipShiftedChars]; - if (skipUnshiftedChars <= cnt) - unshiftedChar = mUnshiftedString.mChars[cnt - skipUnshiftedChars]; - AutoTArray altArray; + if (aIndex >= longestLength) { + return; + } - if (shiftedChar || unshiftedChar) { - AlternativeCharCode chars(unshiftedChar, shiftedChar); + nsTArray& altArray = aKeyboardEvent.alternativeCharCodes; + + uint16_t shiftedChar = 0, unshiftedChar = 0; + if (skipUniChars <= aIndex) { + // XXX Modifying modifier state of aKeyboardEvent is illegal, but no way + // to set different modifier state per keypress event except this + // hack. Note that ideally, dead key should cause composition events + // instead of keypress events, though. + if (aIndex - skipUniChars < mInputtingStringAndModifiers.mLength) { + ModifierKeyState modKeyState(mModKeyState); + // If key in combination with Alt and/or Ctrl produces a different + // character than without them then do not report these flags + // because it is separate keyboard layout shift state. If dead-key + // and base character does not produce a valid composite character + // then both produced dead-key character and following base + // character may have different modifier flags, too. + modKeyState.Unset(MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | + MODIFIER_ALTGRAPH | MODIFIER_CAPSLOCK); + modKeyState.Set( + mInputtingStringAndModifiers.mModifiers[aIndex - skipUniChars]); + modKeyState.InitInputEvent(aKeyboardEvent); + } + uint16_t uniChar = + mInputtingStringAndModifiers.mChars[aIndex - skipUniChars]; + if (aKeyboardEvent.mMessage == eKeyPress) { + // charCode is set from mKeyValue but e.g., when Ctrl key is pressed, + // the value should indicate an ASCII character for backward + // compatibility instead of inputting character without the modifiers. + aKeyboardEvent.charCode = uniChar; + MOZ_ASSERT(!aKeyboardEvent.keyCode); + } else if (uniChar) { + // If the event is not keypress event, we should set charCode as + // first alternative char code since the char code value is necessary + // for shortcut key handlers at looking for a proper handler. + AlternativeCharCode chars(0, 0); + if (!aKeyboardEvent.IsShift()) { + chars.mUnshiftedCharCode = uniChar; + } else { + chars.mShiftedCharCode = uniChar; + } altArray.AppendElement(chars); } - if (cnt == longestLength - 1) { - if (mUnshiftedLatinChar || mShiftedLatinChar) { - AlternativeCharCode chars(mUnshiftedLatinChar, mShiftedLatinChar); - altArray.AppendElement(chars); - } - - // Typically, following virtual keycodes are used for a key which can - // input the character. However, these keycodes are also used for - // other keys on some keyboard layout. E.g., in spite of Shift+'1' - // inputs '+' on Thai keyboard layout, a key which is at '=/+' - // key on ANSI keyboard layout is VK_OEM_PLUS. Native applications - // handle it as '+' key if Ctrl key is pressed. - char16_t charForOEMKeyCode = 0; - switch (mVirtualKeyCode) { - case VK_OEM_PLUS: charForOEMKeyCode = '+'; break; - case VK_OEM_COMMA: charForOEMKeyCode = ','; break; - case VK_OEM_MINUS: charForOEMKeyCode = '-'; break; - case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break; - } - if (charForOEMKeyCode && - charForOEMKeyCode != mUnshiftedString.mChars[0] && - charForOEMKeyCode != mShiftedString.mChars[0] && - charForOEMKeyCode != mUnshiftedLatinChar && - charForOEMKeyCode != mShiftedLatinChar) { - AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode); - altArray.AppendElement(OEMChars); - } - } - - - nsresult rv = mDispatcher->BeginNativeInputTransaction(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return true; - } - - // We should optimize this with improving TextEventDispatcher later. - WidgetKeyboardEvent keypressEvent(true, eKeyPress, mWidget); - keypressEvent.charCode = uniChar; - keypressEvent.alternativeCharCodes.AppendElements(altArray); - nsEventStatus status = InitKeyEvent(keypressEvent, modKeyState); - mDispatcher->MaybeDispatchKeypressEvents(keypressEvent, status, - const_cast(this)); - defaultPrevented = - (status == nsEventStatus_eConsumeNoDefault || defaultPrevented); - - if (mWidget->Destroyed()) { - return true; - } } - return defaultPrevented; + if (skipShiftedChars <= aIndex) { + shiftedChar = mShiftedString.mChars[aIndex - skipShiftedChars]; + } + if (skipUnshiftedChars <= aIndex) { + unshiftedChar = mUnshiftedString.mChars[aIndex - skipUnshiftedChars]; + } + + if (shiftedChar || unshiftedChar) { + AlternativeCharCode chars(unshiftedChar, shiftedChar); + altArray.AppendElement(chars); + } + + if (aIndex == longestLength - 1) { + if (mUnshiftedLatinChar || mShiftedLatinChar) { + AlternativeCharCode chars(mUnshiftedLatinChar, mShiftedLatinChar); + altArray.AppendElement(chars); + } + + // Typically, following virtual keycodes are used for a key which can + // input the character. However, these keycodes are also used for + // other keys on some keyboard layout. E.g., in spite of Shift+'1' + // inputs '+' on Thai keyboard layout, a key which is at '=/+' + // key on ANSI keyboard layout is VK_OEM_PLUS. Native applications + // handle it as '+' key if Ctrl key is pressed. + char16_t charForOEMKeyCode = 0; + switch (mVirtualKeyCode) { + case VK_OEM_PLUS: charForOEMKeyCode = '+'; break; + case VK_OEM_COMMA: charForOEMKeyCode = ','; break; + case VK_OEM_MINUS: charForOEMKeyCode = '-'; break; + case VK_OEM_PERIOD: charForOEMKeyCode = '.'; break; + } + if (charForOEMKeyCode && + charForOEMKeyCode != mUnshiftedString.mChars[0] && + charForOEMKeyCode != mShiftedString.mChars[0] && + charForOEMKeyCode != mUnshiftedLatinChar && + charForOEMKeyCode != mShiftedLatinChar) { + AlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode); + altArray.AppendElement(OEMChars); + } + } } bool diff --git a/widget/windows/KeyboardLayout.h b/widget/windows/KeyboardLayout.h index 900feb909445..8e2858c40caa 100644 --- a/widget/windows/KeyboardLayout.h +++ b/widget/windows/KeyboardLayout.h @@ -269,6 +269,13 @@ public: */ bool HandleAppCommandMessage() const; + /** + * Callback of TextEventDispatcherListener::WillDispatchKeyboardEvent(). + * This method sets alternative char codes of aKeyboardEvent. + */ + void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyboardEvent, + uint32_t aIndex); + private: RefPtr mWidget; RefPtr mDispatcher; @@ -476,10 +483,11 @@ private: bool DispatchCommandEvent(uint32_t aEventCommand) const; /** - * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s) - * with the information provided by KeyboardLayout class. + * DispatchKeyPressEventsWithoutCharMessage() dispatches keypress event(s) + * without char messages. So, this should be used only when there are no + * following char messages. */ - bool DispatchKeyPressEventsWithKeyboardLayout() const; + bool DispatchKeyPressEventsWithoutCharMessage() const; /** * Remove all following WM_CHAR, WM_SYSCHAR and WM_DEADCHAR messages for the diff --git a/widget/windows/WinTextEventDispatcherListener.cpp b/widget/windows/WinTextEventDispatcherListener.cpp index b15afca80aba..7ea20f59e222 100644 --- a/widget/windows/WinTextEventDispatcherListener.cpp +++ b/widget/windows/WinTextEventDispatcherListener.cpp @@ -3,6 +3,7 @@ * 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 "KeyboardLayout.h" #include "mozilla/TextEventDispatcher.h" #include "mozilla/widget/IMEData.h" #include "nsWindow.h" @@ -68,7 +69,8 @@ WinTextEventDispatcherListener::WillDispatchKeyboardEvent( uint32_t aIndexOfKeypress, void* aData) { - // TODO: Implement this method later. + static_cast(aData)-> + WillDispatchKeyboardEvent(aKeyboardEvent, aIndexOfKeypress); } } // namespace widget