From 877ab2210968ccbd2972dde7dca65f224f9a93ba Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 24 Apr 2013 12:49:47 +0900 Subject: [PATCH] Bug 842927 part.3 Implement D3E KeyboardEvent.key on Windows (Desktop) r=smaug+jimm --- widget/windows/KeyboardLayout.cpp | 94 +++++++++++++++++++++++-------- widget/windows/KeyboardLayout.h | 43 ++++++++++++-- widget/windows/nsWindow.cpp | 11 ++-- 3 files changed, 112 insertions(+), 36 deletions(-) diff --git a/widget/windows/KeyboardLayout.cpp b/widget/windows/KeyboardLayout.cpp index 1ea05bd2013c..cbbf4727913d 100644 --- a/widget/windows/KeyboardLayout.cpp +++ b/widget/windows/KeyboardLayout.cpp @@ -384,7 +384,8 @@ VirtualKey::FillKbdState(PBYTE aKbdState, NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout, nsWindow* aWindow, const MSG& aKeyOrCharMessage) : - mDOMKeyCode(0), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0) + mDOMKeyCode(0), mMessage(aKeyOrCharMessage.message), + mVirtualKeyCode(0), mOriginalVirtualKeyCode(0) { mScanCode = WinUtils::GetScanCode(aKeyOrCharMessage.lParam); mIsExtended = WinUtils::IsExtendedScanCode(aKeyOrCharMessage.lParam); @@ -392,7 +393,7 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout, // extended keys due to the API limitation. bool canComputeVirtualKeyCodeFromScanCode = (!mIsExtended || WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION); - switch (aKeyOrCharMessage.message) { + switch (mMessage) { case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: @@ -540,6 +541,8 @@ NativeKey::NativeKey(const KeyboardLayout& aKeyboardLayout, mDOMKeyCode = aKeyboardLayout.ConvertNativeKeyCodeToDOMKeyCode(mOriginalVirtualKeyCode); + mKeyNameIndex = + aKeyboardLayout.ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode); } UINT @@ -659,48 +662,66 @@ KeyboardLayout::IsDeadKey(uint8_t aVirtualKey, VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers())); } -UniCharsAndModifiers -KeyboardLayout::OnKeyDown(uint8_t aVirtualKey, - const ModifierKeyState& aModKeyState) +void +KeyboardLayout::InitNativeKey(NativeKey& aNativeKey, + const ModifierKeyState& aModKeyState) { if (mPendingKeyboardLayout) { LoadLayout(mPendingKeyboardLayout); } - int32_t virtualKeyIndex = GetKeyIndex(aVirtualKey); + uint8_t virtualKey = aNativeKey.GetOriginalVirtualKeyCode(); + int32_t virtualKeyIndex = GetKeyIndex(virtualKey); if (virtualKeyIndex < 0) { // Does not produce any printable characters, but still preserves the // dead-key state. - return UniCharsAndModifiers(); + return; } + bool isKeyDown = aNativeKey.IsKeyDownMessage(); uint8_t shiftState = VirtualKey::ModifiersToShiftState(aModKeyState.GetModifiers()); if (mVirtualKeys[virtualKeyIndex].IsDeadKey(shiftState)) { - if (mActiveDeadKey < 0) { - // Dead-key state activated. No characters generated. - mActiveDeadKey = aVirtualKey; - mDeadKeyShiftState = shiftState; - return UniCharsAndModifiers(); + if ((isKeyDown && mActiveDeadKey < 0) || + (!isKeyDown && mActiveDeadKey == virtualKey)) { + // First dead key event doesn't generate characters. + if (isKeyDown) { + // Dead-key state activated at keydown. + mActiveDeadKey = virtualKey; + mDeadKeyShiftState = shiftState; + } + UniCharsAndModifiers deadChars = + mVirtualKeys[virtualKeyIndex].GetNativeUniChars(shiftState); + NS_ASSERTION(deadChars.mLength == 1, + "dead key must generate only one character"); + aNativeKey.mKeyNameIndex = + WidgetUtils::GetDeadKeyNameIndex(deadChars.mChars[0]); + return; } // Dead-key followed by another dead-key. Reset dead-key state and // return both dead-key characters. int32_t activeDeadKeyIndex = GetKeyIndex(mActiveDeadKey); - UniCharsAndModifiers result = + UniCharsAndModifiers prevDeadChars = mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState); - result += mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); - DeactivateDeadKeyState(); - return result; + UniCharsAndModifiers newChars = + mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); + // But keypress events should be fired for each committed character. + aNativeKey.mCommittedCharsAndModifiers = prevDeadChars + newChars; + if (isKeyDown) { + DeactivateDeadKeyState(); + } + return; } UniCharsAndModifiers baseChars = mVirtualKeys[virtualKeyIndex].GetUniChars(shiftState); if (mActiveDeadKey < 0) { // No dead-keys are active. Just return the produced characters. - return baseChars; + aNativeKey.mCommittedCharsAndModifiers = baseChars; + return; } // Dead-key was active. See if pressed base character does produce @@ -712,20 +733,25 @@ KeyboardLayout::OnKeyDown(uint8_t aVirtualKey, if (compositeChar) { // Active dead-key and base character does produce exactly one // composite character. - UniCharsAndModifiers result; - result.Append(compositeChar, baseChars.mModifiers[0]); - DeactivateDeadKeyState(); - return result; + aNativeKey.mCommittedCharsAndModifiers.Append(compositeChar, + baseChars.mModifiers[0]); + if (isKeyDown) { + DeactivateDeadKeyState(); + } + return; } // There is no valid dead-key and base character combination. // Return dead-key character followed by base character. - UniCharsAndModifiers result = + UniCharsAndModifiers deadChars = mVirtualKeys[activeDeadKeyIndex].GetUniChars(mDeadKeyShiftState); - result += baseChars; - DeactivateDeadKeyState(); + // But keypress events should be fired for each committed character. + aNativeKey.mCommittedCharsAndModifiers = deadChars + baseChars; + if (isKeyDown) { + DeactivateDeadKeyState(); + } - return result; + return; } UniCharsAndModifiers @@ -1254,6 +1280,24 @@ KeyboardLayout::ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const return 0; } +KeyNameIndex +KeyboardLayout::ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const +{ + switch (aVirtualKey) { + +#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ + case aNativeKey: return aKeyNameIndex; + +#include "NativeKeyToDOMKeyName.h" + +#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX + + default: + return IsPrintableCharKey(aVirtualKey) ? KEY_NAME_INDEX_PrintableKey : + KEY_NAME_INDEX_Unidentified; + } +} + /***************************************************************************** * mozilla::widget::DeadKeyTable *****************************************************************************/ diff --git a/widget/windows/KeyboardLayout.h b/widget/windows/KeyboardLayout.h index b32f75c0b269..7584309ea71c 100644 --- a/widget/windows/KeyboardLayout.h +++ b/widget/windows/KeyboardLayout.h @@ -271,7 +271,8 @@ public: class NativeKey { public: NativeKey() : - mDOMKeyCode(0), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0), + mDOMKeyCode(0), mKeyNameIndex(KEY_NAME_INDEX_Unidentified), + mMessage(0), mVirtualKeyCode(0), mOriginalVirtualKeyCode(0), mScanCode(0), mIsExtended(false) { } @@ -281,25 +282,48 @@ public: const MSG& aKeyOrCharMessage); uint32_t GetDOMKeyCode() const { return mDOMKeyCode; } + KeyNameIndex GetKeyNameIndex() const { return mKeyNameIndex; } + const UniCharsAndModifiers& GetCommittedCharsAndModifiers() const + { + return mCommittedCharsAndModifiers; + } // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*. uint32_t GetKeyLocation() const; + UINT GetMessage() const { return mMessage; } + bool IsKeyDownMessage() const + { + return (mMessage == WM_KEYDOWN || mMessage == WM_SYSKEYDOWN); + } WORD GetScanCode() const { return mScanCode; } uint8_t GetVirtualKeyCode() const { return mVirtualKeyCode; } uint8_t GetOriginalVirtualKeyCode() const { return mOriginalVirtualKeyCode; } private: uint32_t mDOMKeyCode; + KeyNameIndex mKeyNameIndex; + + // The message which the instance was initialized with. + UINT mMessage; + // mVirtualKeyCode distinguishes left key or right key of modifier key. uint8_t mVirtualKeyCode; // mOriginalVirtualKeyCode doesn't distinguish left key or right key of // modifier key. However, if the given keycode is VK_PROCESS, it's resolved // to a keycode before it's handled by IME. uint8_t mOriginalVirtualKeyCode; + + // mCommittedChars indicates the inputted characters which is committed by + // the key. If dead key fail to composite a character, mCommittedChars + // indicates both the dead characters and the base characters. + UniCharsAndModifiers mCommittedCharsAndModifiers; + WORD mScanCode; bool mIsExtended; UINT GetScanCodeWithExtendedFlag() const; + + friend class KeyboardLayout; }; class KeyboardLayout @@ -357,12 +381,13 @@ public: const ModifierKeyState& aModKeyState) const; /** - * OnKeyDown() must be called when actually widget receives WM_KEYDOWN - * message. This method is stateful. This saves current dead key state - * and computes current inputted character(s). + * InitNativeKey() must be called when actually widget receives WM_KEYDOWN or + * WM_KEYUP. This method is stateful. This saves current dead key state at + * WM_KEYDOWN. Additionally, computes current inputted character(s) and set + * them to the aNativeKey. */ - UniCharsAndModifiers OnKeyDown(uint8_t aVirtualKey, - const ModifierKeyState& aModKeyState); + void InitNativeKey(NativeKey& aNativeKey, + const ModifierKeyState& aModKeyState); /** * LoadLayout() loads the keyboard layout. If aLoadLater is true, @@ -372,6 +397,12 @@ public: uint32_t ConvertNativeKeyCodeToDOMKeyCode(UINT aNativeKeyCode) const; + /** + * ConvertNativeKeyCodeToKeyNameIndex() returns KeyNameIndex value for + * non-printable keys (except some special keys like space key). + */ + KeyNameIndex ConvertNativeKeyCodeToKeyNameIndex(uint8_t aVirtualKey) const; + HKL GetLayout() const { return mPendingKeyboardLayout ? mPendingKeyboardLayout : mKeyboardLayout; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 33fe76391fdb..eec90bd7790b 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -3622,6 +3622,7 @@ void nsWindow::InitKeyEvent(nsKeyEvent& aKeyEvent, { nsIntPoint point(0, 0); InitEvent(aKeyEvent, &point); + aKeyEvent.mKeyNameIndex = aNativeKey.GetKeyNameIndex(); aKeyEvent.location = aNativeKey.GetKeyLocation(); aModKeyState.InitInputEvent(aKeyEvent); } @@ -5654,6 +5655,7 @@ LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched) // if a child window didn't handle it (for example Alt+Space in a content window) ModifierKeyState modKeyState; NativeKey nativeKey(gKbdLayout, this, aMsg); + gKbdLayout.InitNativeKey(nativeKey, modKeyState); return OnChar(aMsg, nativeKey, modKeyState, aEventDispatched); } @@ -6461,12 +6463,9 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg, nsFakeCharMessage* aFakeCharMessage) { NativeKey nativeKey(gKbdLayout, this, aMsg); - UINT virtualKeyCode = nativeKey.GetOriginalVirtualKeyCode(); + gKbdLayout.InitNativeKey(nativeKey, aModKeyState); UniCharsAndModifiers inputtingChars = - gKbdLayout.OnKeyDown(virtualKeyCode, aModKeyState); - - // Use only DOMKeyCode for XP processing. - // Use virtualKeyCode for gKbdLayout and native processing. + nativeKey.GetCommittedCharsAndModifiers(); uint32_t DOMKeyCode = nativeKey.GetDOMKeyCode(); #ifdef DEBUG @@ -6554,6 +6553,7 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg, return noDefault; } + UINT virtualKeyCode = nativeKey.GetOriginalVirtualKeyCode(); bool isDeadKey = gKbdLayout.IsDeadKey(virtualKeyCode, aModKeyState); EventFlags extraFlags; extraFlags.mDefaultPrevented = noDefault; @@ -6830,6 +6830,7 @@ LRESULT nsWindow::OnKeyUp(const MSG &aMsg, *aEventDispatched = true; nsKeyEvent keyupEvent(true, NS_KEY_UP, this); NativeKey nativeKey(gKbdLayout, this, aMsg); + gKbdLayout.InitNativeKey(nativeKey, aModKeyState); keyupEvent.keyCode = nativeKey.GetDOMKeyCode(); InitKeyEvent(keyupEvent, nativeKey, aModKeyState); // Set defaultPrevented of the key event if the VK_MENU is not a system key