Bug 855975 part.9 Move keypress events dispatcher of nsWindow::OnKeyDown() to widget::NativeKey::DispatchKeyPressEventsWithKeyboardLayout() r=jimm
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 29 May 2013 15:34:48 +0900
changeset 133236 60420c75c496793fc1c994920b519ae0ea0feff3
parent 133235 269686777a14c7843f8f4d950009465665a5e681
child 133237 13350f2b2f04f0d8b6de3bb1b927696214294806
push id28671
push usermasayuki@d-toybox.com
push dateWed, 29 May 2013 06:35:17 +0000
treeherdermozilla-inbound@57461a161f93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs855975
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 855975 part.9 Move keypress events dispatcher of nsWindow::OnKeyDown() to widget::NativeKey::DispatchKeyPressEventsWithKeyboardLayout() r=jimm
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
widget/windows/nsWindow.cpp
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -869,16 +869,180 @@ NativeKey::HandleKeyUpMessage(bool* aEve
   nsKeyEvent keyupEvent(true, NS_KEY_UP, mWidget);
   InitKeyEvent(keyupEvent, mModKeyState);
   if (aEventDispatched) {
     *aEventDispatched = true;
   }
   return DispatchKeyEvent(keyupEvent, &mMsg);
 }
 
+bool
+NativeKey::DispatchKeyPressEventsWithKeyboardLayout(
+                        const UniCharsAndModifiers& aInputtingChars,
+                        const EventFlags& aExtraFlags) const
+{
+  MOZ_ASSERT(mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN);
+
+  KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
+
+  UniCharsAndModifiers inputtingChars(aInputtingChars);
+  UniCharsAndModifiers shiftedChars;
+  UniCharsAndModifiers unshiftedChars;
+  uint32_t shiftedLatinChar = 0;
+  uint32_t unshiftedLatinChar = 0;
+
+  if (!KeyboardLayout::IsPrintableCharKey(mVirtualKeyCode)) {
+    inputtingChars.Clear();
+  }
+
+  if (mModKeyState.IsControl() ^ mModKeyState.IsAlt()) {
+    ModifierKeyState capsLockState(
+                       mModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
+
+    unshiftedChars =
+      keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
+    capsLockState.Set(MODIFIER_SHIFT);
+    shiftedChars =
+      keyboardLayout->GetUniCharsAndModifiers(mVirtualKeyCode, capsLockState);
+
+    // The current keyboard cannot input alphabets or numerics,
+    // we should append them for Shortcut/Access keys.
+    // E.g., for Cyrillic keyboard layout.
+    capsLockState.Unset(MODIFIER_SHIFT);
+    WidgetUtils::GetLatinCharCodeForKeyCode(mDOMKeyCode,
+                                            capsLockState.GetModifiers(),
+                                            &unshiftedLatinChar,
+                                            &shiftedLatinChar);
+
+    // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
+    if (shiftedLatinChar) {
+      // If the produced characters of the key on current keyboard layout
+      // are same as computed Latin characters, we shouldn't append the
+      // Latin characters to alternativeCharCode.
+      if (unshiftedLatinChar == unshiftedChars.mChars[0] &&
+          shiftedLatinChar == shiftedChars.mChars[0]) {
+        shiftedLatinChar = unshiftedLatinChar = 0;
+      }
+    } else if (unshiftedLatinChar) {
+      // If the shiftedLatinChar is 0, the keyCode doesn't produce
+      // alphabet character.  At that time, the character may be produced
+      // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
+      // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
+      // Shift key but with Shift key, it produces '%'.
+      // If the unshiftedLatinChar is produced by the key on current
+      // keyboard layout, we shouldn't append it to alternativeCharCode.
+      if (unshiftedLatinChar == unshiftedChars.mChars[0] ||
+          unshiftedLatinChar == shiftedChars.mChars[0]) {
+        unshiftedLatinChar = 0;
+      }
+    }
+
+    // If the charCode is not ASCII character, we should replace the
+    // charCode with ASCII character only when Ctrl is pressed.
+    // But don't replace the charCode when the charCode is not same as
+    // unmodified characters. In such case, Ctrl is sometimes used for a
+    // part of character inputting key combination like Shift.
+    if (mModKeyState.IsControl()) {
+      uint32_t ch =
+        mModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar;
+      if (ch &&
+          (!inputtingChars.mLength ||
+           inputtingChars.UniCharsCaseInsensitiveEqual(
+             mModKeyState.IsShift() ? shiftedChars : unshiftedChars))) {
+        inputtingChars.Clear();
+        inputtingChars.Append(ch, mModKeyState.GetModifiers());
+      }
+    }
+  }
+
+  if (inputtingChars.IsEmpty() &&
+      shiftedChars.IsEmpty() && unshiftedChars.IsEmpty()) {
+    nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
+    keypressEvent.mFlags.Union(aExtraFlags);
+    keypressEvent.keyCode = mDOMKeyCode;
+    InitKeyEvent(keypressEvent, mModKeyState);
+    return (DispatchKeyEvent(keypressEvent) || aExtraFlags.mDefaultPrevented);
+  }
+
+  uint32_t longestLength =
+    std::max(inputtingChars.mLength,
+             std::max(shiftedChars.mLength, unshiftedChars.mLength));
+  uint32_t skipUniChars = longestLength - inputtingChars.mLength;
+  uint32_t skipShiftedChars = longestLength - shiftedChars.mLength;
+  uint32_t skipUnshiftedChars = longestLength - unshiftedChars.mLength;
+  UINT keyCode = !inputtingChars.mLength ? mDOMKeyCode : 0;
+  bool defaultPrevented = aExtraFlags.mDefaultPrevented;
+  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  < inputtingChars.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(inputtingChars.mModifiers[cnt - skipUniChars]);
+      }
+      uniChar = inputtingChars.mChars[cnt - skipUniChars];
+    }
+    if (skipShiftedChars <= cnt)
+      shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars];
+    if (skipUnshiftedChars <= cnt)
+      unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars];
+    nsAutoTArray<nsAlternativeCharCode, 5> altArray;
+
+    if (shiftedChar || unshiftedChar) {
+      nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
+      altArray.AppendElement(chars);
+    }
+    if (cnt == longestLength - 1) {
+      if (unshiftedLatinChar || shiftedLatinChar) {
+        nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
+        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.
+      PRUnichar 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 != unshiftedChars.mChars[0] &&
+          charForOEMKeyCode != shiftedChars.mChars[0] &&
+          charForOEMKeyCode != unshiftedLatinChar &&
+          charForOEMKeyCode != shiftedLatinChar) {
+        nsAlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
+        altArray.AppendElement(OEMChars);
+      }
+    }
+
+    nsKeyEvent keypressEvent(true, NS_KEY_PRESS, mWidget);
+    keypressEvent.mFlags.Union(aExtraFlags);
+    keypressEvent.charCode = uniChar;
+    keypressEvent.alternativeCharCodes.AppendElements(altArray);
+    InitKeyEvent(keypressEvent, modKeyState);
+    defaultPrevented = (DispatchKeyEvent(keypressEvent) || defaultPrevented);
+  }
+
+  return defaultPrevented;
+}
+
 /*****************************************************************************
  * mozilla::widget::KeyboardLayout
  *****************************************************************************/
 
 KeyboardLayout* KeyboardLayout::sInstance = nullptr;
 nsIIdleServiceInternal* KeyboardLayout::sIdleService = nullptr;
 
 // static
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -135,16 +135,17 @@ struct UniCharsAndModifiers
   UniCharsAndModifiers operator+(const UniCharsAndModifiers& aOther) const;
   UniCharsAndModifiers& operator+=(const UniCharsAndModifiers& aOther);
 
   /**
    * Append a pair of unicode character and the final modifier.
    */
   void Append(PRUnichar aUniChar, Modifiers aModifiers);
   void Clear() { mLength = 0; }
+  bool IsEmpty() const { return !mLength; }
 
   void FillModifiers(Modifiers aModifiers);
 
   bool UniCharsEqual(const UniCharsAndModifiers& aOther) const;
   bool UniCharsCaseInsensitiveEqual(const UniCharsAndModifiers& aOther) const;
 
   nsString ToString() const { return nsString(mChars, mLength); }
 };
@@ -327,16 +328,24 @@ public:
   /**
    * Dispatches the key event.  Returns true if the event is consumed.
    * Otherwise, false.
    */
   bool DispatchKeyEvent(nsKeyEvent& aKeyEvent,
                         const MSG* aMsgSentToPlugin = nullptr) const;
 
   /**
+   * DispatchKeyPressEventsWithKeyboardLayout() dispatches keypress event(s)
+   * with the information provided by KeyboardLayout class.
+   */
+  bool DispatchKeyPressEventsWithKeyboardLayout(
+                        const UniCharsAndModifiers& aInputtingChars,
+                        const EventFlags& aExtraFlags) const;
+
+  /**
    * Dspatces keydown event.  Retrns true if the event is consumed.
    * Otherwise, false.
    */
   bool DispatchKeyDownEvent(bool* aEventDispatched = nullptr) const;
 
   /**
    * Handles WM_CHAR message or WM_SYSCHAR message.  The instance must be
    * initialized with WM_KEYDOWN, WM_SYSKEYDOWN or them.
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6592,165 +6592,19 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
     // See bug 314130.
     return PluginHasFocus() && noDefault;
   }
 
   if (isDeadKey) {
     return PluginHasFocus() && noDefault;
   }
 
-  UniCharsAndModifiers shiftedChars;
-  UniCharsAndModifiers unshiftedChars;
-  uint32_t shiftedLatinChar = 0;
-  uint32_t unshiftedLatinChar = 0;
-
-  if (!KeyboardLayout::IsPrintableCharKey(virtualKeyCode)) {
-    inputtingChars.Clear();
-  }
-
-  if (aModKeyState.IsControl() ^ aModKeyState.IsAlt()) {
-    widget::ModifierKeyState capsLockState(
-      aModKeyState.GetModifiers() & MODIFIER_CAPSLOCK);
-    unshiftedChars =
-      keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
-    capsLockState.Set(MODIFIER_SHIFT);
-    shiftedChars =
-      keyboardLayout->GetUniCharsAndModifiers(virtualKeyCode, capsLockState);
-
-    // The current keyboard cannot input alphabets or numerics,
-    // we should append them for Shortcut/Access keys.
-    // E.g., for Cyrillic keyboard layout.
-    capsLockState.Unset(MODIFIER_SHIFT);
-    WidgetUtils::GetLatinCharCodeForKeyCode(DOMKeyCode,
-                                            capsLockState.GetModifiers(),
-                                            &unshiftedLatinChar,
-                                            &shiftedLatinChar);
-
-    // If the shiftedLatinChar isn't 0, the key code is NS_VK_[A-Z].
-    if (shiftedLatinChar) {
-      // If the produced characters of the key on current keyboard layout
-      // are same as computed Latin characters, we shouldn't append the
-      // Latin characters to alternativeCharCode.
-      if (unshiftedLatinChar == unshiftedChars.mChars[0] &&
-          shiftedLatinChar == shiftedChars.mChars[0]) {
-        shiftedLatinChar = unshiftedLatinChar = 0;
-      }
-    } else if (unshiftedLatinChar) {
-      // If the shiftedLatinChar is 0, the keyCode doesn't produce
-      // alphabet character.  At that time, the character may be produced
-      // with Shift key.  E.g., on French keyboard layout, NS_VK_PERCENT
-      // key produces LATIN SMALL LETTER U WITH GRAVE (U+00F9) without
-      // Shift key but with Shift key, it produces '%'.
-      // If the unshiftedLatinChar is produced by the key on current
-      // keyboard layout, we shouldn't append it to alternativeCharCode.
-      if (unshiftedLatinChar == unshiftedChars.mChars[0] ||
-          unshiftedLatinChar == shiftedChars.mChars[0]) {
-        unshiftedLatinChar = 0;
-      }
-    }
-
-    // If the charCode is not ASCII character, we should replace the
-    // charCode with ASCII character only when Ctrl is pressed.
-    // But don't replace the charCode when the charCode is not same as
-    // unmodified characters. In such case, Ctrl is sometimes used for a
-    // part of character inputting key combination like Shift.
-    if (aModKeyState.IsControl()) {
-      uint32_t ch =
-        aModKeyState.IsShift() ? shiftedLatinChar : unshiftedLatinChar;
-      if (ch &&
-          (!inputtingChars.mLength ||
-           inputtingChars.UniCharsCaseInsensitiveEqual(
-             aModKeyState.IsShift() ? shiftedChars : unshiftedChars))) {
-        inputtingChars.Clear();
-        inputtingChars.Append(ch, aModKeyState.GetModifiers());
-      }
-    }
-  }
-
-  if (inputtingChars.mLength ||
-      shiftedChars.mLength || unshiftedChars.mLength) {
-    uint32_t num = std::max(inputtingChars.mLength,
-                          std::max(shiftedChars.mLength, unshiftedChars.mLength));
-    uint32_t skipUniChars = num - inputtingChars.mLength;
-    uint32_t skipShiftedChars = num - shiftedChars.mLength;
-    uint32_t skipUnshiftedChars = num - unshiftedChars.mLength;
-    UINT keyCode = !inputtingChars.mLength ? DOMKeyCode : 0;
-    for (uint32_t cnt = 0; cnt < num; cnt++) {
-      uint16_t uniChar, shiftedChar, unshiftedChar;
-      uniChar = shiftedChar = unshiftedChar = 0;
-      ModifierKeyState modKeyState(aModKeyState);
-      if (skipUniChars <= cnt) {
-        if (cnt - skipUniChars  < inputtingChars.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(inputtingChars.mModifiers[cnt - skipUniChars]);
-        }
-        uniChar = inputtingChars.mChars[cnt - skipUniChars];
-      }
-      if (skipShiftedChars <= cnt)
-        shiftedChar = shiftedChars.mChars[cnt - skipShiftedChars];
-      if (skipUnshiftedChars <= cnt)
-        unshiftedChar = unshiftedChars.mChars[cnt - skipUnshiftedChars];
-      nsAutoTArray<nsAlternativeCharCode, 5> altArray;
-
-      if (shiftedChar || unshiftedChar) {
-        nsAlternativeCharCode chars(unshiftedChar, shiftedChar);
-        altArray.AppendElement(chars);
-      }
-      if (cnt == num - 1) {
-        if (unshiftedLatinChar || shiftedLatinChar) {
-          nsAlternativeCharCode chars(unshiftedLatinChar, shiftedLatinChar);
-          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.
-        PRUnichar charForOEMKeyCode = 0;
-        switch (virtualKeyCode) {
-          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 != unshiftedChars.mChars[0] &&
-            charForOEMKeyCode != shiftedChars.mChars[0] &&
-            charForOEMKeyCode != unshiftedLatinChar &&
-            charForOEMKeyCode != shiftedLatinChar) {
-          nsAlternativeCharCode OEMChars(charForOEMKeyCode, charForOEMKeyCode);
-          altArray.AppendElement(OEMChars);
-        }
-      }
-
-      nsKeyEvent keypressEvent(true, NS_KEY_PRESS, this);
-      keypressEvent.mFlags.Union(extraFlags);
-      keypressEvent.charCode = uniChar;
-      keypressEvent.alternativeCharCodes.AppendElements(altArray);
-      nativeKey.InitKeyEvent(keypressEvent, modKeyState);
-      nativeKey.DispatchKeyEvent(keypressEvent);
-    }
-  } else {
-    nsKeyEvent keypressEvent(true, NS_KEY_PRESS, this);
-    keypressEvent.mFlags.Union(extraFlags);
-    keypressEvent.keyCode = DOMKeyCode;
-    nativeKey.InitKeyEvent(keypressEvent, aModKeyState);
-    nativeKey.DispatchKeyEvent(keypressEvent);
-  }
-
-  return noDefault;
+  return static_cast<LRESULT>(
+    nativeKey.DispatchKeyPressEventsWithKeyboardLayout(inputtingChars,
+                                                       extraFlags));
 }
 
 void
 nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, uint32_t aModifiers)
 {
   for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) {
     const uint32_t* map = sModifierKeyMap[i];
     if (aModifiers & map[0]) {