Bug 1293505 part.1 NativeKey should treat a key message as printable key's when the key message is followed by a printable char message r=m_kato
Some keyboard utilities for Windows can change non-printable keys to printable keys. Therefore, if a keydown message is followed by one or more char message whose wParam isn't a control character, NativeKey should treat it as a printable key's event.
MozReview-Commit-ID: HoFbz5Zafeh
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -690,16 +690,17 @@ NativeKey::NativeKey(nsWindowBase* aWidg
, mModKeyState(aModKeyState)
, mVirtualKeyCode(0)
, mOriginalVirtualKeyCode(0)
, mShiftedLatinChar(0)
, mUnshiftedLatinChar(0)
, mScanCode(0)
, mIsExtended(false)
, mIsDeadKey(false)
+ , mIsFollowedByNonControlCharMessage(false)
, mFakeCharMsgs(aFakeCharMsgs && aFakeCharMsgs->Length() ?
aFakeCharMsgs : nullptr)
{
MOZ_ASSERT(aWidget);
MOZ_ASSERT(mDispatcher);
KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
mKeyboardLayout = keyboardLayout->GetLayout();
if (aOverrideKeyboardLayout && mKeyboardLayout != aOverrideKeyboardLayout) {
@@ -874,28 +875,35 @@ NativeKey::NativeKey(nsWindowBase* aWidg
}
if (!mVirtualKeyCode) {
mVirtualKeyCode = mOriginalVirtualKeyCode;
}
mDOMKeyCode =
keyboardLayout->ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode);
- mKeyNameIndex =
+ // Be aware, keyboard utilities can change non-printable keys to printable
+ // keys. In such case, we should make the key value as a printable key.
+ mIsFollowedByNonControlCharMessage =
+ IsKeyDownMessage() && IsFollowedByNonControlCharMessage();
+ mKeyNameIndex = mIsFollowedByNonControlCharMessage ?
+ KEY_NAME_INDEX_USE_STRING :
keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
mCodeNameIndex =
KeyboardLayout::ConvertScanCodeToCodeNameIndex(
GetScanCodeWithExtendedFlag());
keyboardLayout->InitNativeKey(*this, mModKeyState);
mIsDeadKey =
(IsFollowedByDeadCharMessage() ||
keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
- mIsPrintableKey = KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
+ mIsPrintableKey =
+ mKeyNameIndex == KEY_NAME_INDEX_USE_STRING ||
+ KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
if (IsKeyDownMessage()) {
// Compute some strings which may be inputted by the key with various
// modifier state if this key event won't cause text input actually.
// They will be used for setting mAlternativeCharCodes in the callback
// method which will be called by TextEventDispatcher.
if (NeedsToHandleWithoutFollowingCharMessages()) {
ComputeInputtingStringWithKeyboardLayout();
@@ -1050,16 +1058,34 @@ NativeKey::IsFollowedByDeadCharMessage()
PM_NOREMOVE | PM_NOYIELD)) {
return false;
}
}
return IsDeadCharMessage(nextMsg);
}
bool
+NativeKey::IsFollowedByNonControlCharMessage() const
+{
+ MSG nextMsg;
+ if (mFakeCharMsgs) {
+ nextMsg = mFakeCharMsgs->ElementAt(0).GetCharMsg(mMsg.hwnd);
+ } else if (IsKeyMessageOnPlugin()) {
+ return false;
+ } else {
+ if (!WinUtils::PeekMessage(&nextMsg, mMsg.hwnd, WM_KEYFIRST, WM_KEYLAST,
+ PM_NOREMOVE | PM_NOYIELD)) {
+ return false;
+ }
+ }
+ return nextMsg.message == WM_CHAR &&
+ !IsControlChar(static_cast<char16_t>(nextMsg.wParam));
+}
+
+bool
NativeKey::IsIMEDoingKakuteiUndo() const
{
// Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
// ---------------------------------------------------------------------------
// WM_KEYDOWN * n (wParam = VK_BACK, lParam = 0x1)
// WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
// WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
// WM_IME_COMPOSITION * 1 (wParam = 0x0, lParam = 0x1BF)
@@ -1838,16 +1864,23 @@ NativeKey::NeedsToHandleWithoutFollowing
}
// If inputting two or more characters, should be dispatched after removing
// whole following char messages.
if (mCommittedCharsAndModifiers.mLength > 1) {
return true;
}
+ // If keydown message is followed by WM_CHAR whose wParam isn't a control
+ // character, we should dispatch keypress event with the char message
+ // even with any modifier state.
+ if (mIsFollowedByNonControlCharMessage) {
+ return false;
+ }
+
// If any modifier keys which may cause printable keys becoming non-printable
// are not pressed, we don't need special handling for the key.
if (!mModKeyState.IsControl() && !mModKeyState.IsAlt() &&
!mModKeyState.IsWin()) {
return false;
}
// If the key event causes dead key event, we don't need to dispatch keypress
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -300,16 +300,20 @@ private:
// mIsPrintableKey is true if the key may be a printable key without
// any modifier keys. Otherwise, false.
// Please note that the event may not cause any text input even if this
// is true. E.g., it might be dead key state or Ctrl key may be pressed.
bool mIsPrintableKey;
// mIsOverridingKeyboardLayout is true if the instance temporarily overriding
// keyboard layout with specified by the constructor.
bool mIsOverridingKeyboardLayout;
+ // mIsFollowedByNonControlCharMessage may be true when mMsg is a keydown
+ // message. When the keydown message is followed by a char message, this
+ // is true.
+ bool mIsFollowedByNonControlCharMessage;
nsTArray<FakeCharMsg>* mFakeCharMsgs;
// When a keydown event is dispatched at handling WM_APPCOMMAND, the computed
// virtual keycode is set to this. Even if we consume WM_APPCOMMAND message,
// Windows may send WM_KEYDOWN and WM_KEYUP message for them.
// At that time, we should not dispatch key events for them.
static uint8_t sDispatchedKeyOfAppCommand;
@@ -407,16 +411,17 @@ private:
{
return IsSysCharMessage(aMSG.message);
}
bool IsSysCharMessage(UINT aMessage) const
{
return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
}
bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
+ bool IsFollowedByNonControlCharMessage() const;
bool IsFollowedByDeadCharMessage() const;
bool IsKeyMessageOnPlugin() const
{
return (mMsg.message == MOZ_WM_KEYDOWN ||
mMsg.message == MOZ_WM_KEYUP);
}
/**