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, a=ritu
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 26 Aug 2016 22:12:58 +0900
changeset 347996 9731047ebbfa20df44816f7874f57bc8eef9f318
parent 347995 82eb0241b83c35f4031525d50e651008c647633a
child 347997 87c57eedbd7f0f4b45c5b421b4a9d434025c0570
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato, ritu
bugs1293505
milestone50.0a2
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, a=ritu 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
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
--- 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);
   }
 
   /**