[Win] Update KeyboardEvent as per the latest specification
authorHironori.Fujii@sony.com <Hironori.Fujii@sony.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Nov 2019 05:18:54 +0000 (05:18 +0000)
committerHironori.Fujii@sony.com <Hironori.Fujii@sony.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Nov 2019 05:18:54 +0000 (05:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202183

Reviewed by Ross Kirsling.

Source/WebCore:

Add 'key' and 'code' properties of KeyboardEvent for Windows. The
implementation is copied from Chromium for Windows.

For implementing 'key' properties, ToUnicodeEx API is used to
convert a virtual key code to a character information.
Unfortunately, ToUnicodeEx alters the stored previous typed dead
key in the driver, it can't be used for each key event. So,
ToUnicodeEx is used to convert all virtual keys with all modifier
combinations beforehand.

This change turns on ENABLE_KEYBOARD_KEY_ATTRIBUTE and
ENABLE_KEYBOARD_CODE_ATTRIBUTE macros for all ports. A follow-up
patch will remove the macros.

Existing tests covers.

* PlatformWin.cmake:
* platform/win/KeyEventWin.cpp:
(WebCore::windowsKeyNames):
(WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
* platform/win/WindowsKeyNames.cpp: Added.
(hasControlAndAlt):
(getModifierFlags):
(nonPrintableVirtualKeyToDomKey):
(WindowsKeyNames::WindowsKeyNames):
(WindowsKeyNames::domKeyFromLParam):
(singleCharacterString):
(WindowsKeyNames::domKeyFromChar):
(WindowsKeyNames::domCodeFromLParam):
(WindowsKeyNames::updateLayout):
* platform/win/WindowsKeyNames.h: Added.

Source/WebKit:

* Shared/WebEvent.h:
* Shared/WebKeyboardEvent.cpp:
(WebKit::WebKeyboardEvent::WebKeyboardEvent):
* Shared/win/WebEventFactory.cpp:
(WebKit::windowsKeyNames):
(WebKit::WebEventFactory::createWebKeyboardEvent):

Source/WTF:

* wtf/FeatureDefines.h:

LayoutTests:

* platform/win/TestExpectations:
* platform/wincairo/TestExpectations:
Unskipped fast/events/arrow-keys-on-body.html, fast/events/keyboardevent-key.html, and fast/events/key-events-in-input-text.html.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252873 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/win/TestExpectations
LayoutTests/platform/wincairo/TestExpectations
Source/WTF/ChangeLog
Source/WTF/wtf/FeatureDefines.h
Source/WebCore/ChangeLog
Source/WebCore/PlatformWin.cmake
Source/WebCore/platform/win/KeyEventWin.cpp
Source/WebCore/platform/win/WindowsKeyNames.cpp [new file with mode: 0644]
Source/WebCore/platform/win/WindowsKeyNames.h [new file with mode: 0644]
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebEvent.h
Source/WebKit/Shared/WebKeyboardEvent.cpp
Source/WebKit/Shared/win/WebEventFactory.cpp

index e6fc2a9..878dbcc 100644 (file)
@@ -1,3 +1,14 @@
+2019-11-25  Fujii Hironori  <Hironori.Fujii@sony.com>
+
+        [Win] Update KeyboardEvent as per the latest specification
+        https://bugs.webkit.org/show_bug.cgi?id=202183
+
+        Reviewed by Ross Kirsling.
+
+        * platform/win/TestExpectations:
+        * platform/wincairo/TestExpectations:
+        Unskipped fast/events/arrow-keys-on-body.html, fast/events/keyboardevent-key.html, and fast/events/key-events-in-input-text.html.
+
 2019-11-25  Zan Dobersek  <zdobersek@igalia.com>  and  Chris Lord <clord@igalia.com>
 
         Basic OffscreenCanvas functionality
index 929307d..514c884 100644 (file)
@@ -3234,7 +3234,6 @@ fast/dom/HTMLMeterElement/meter-styles.html [ Failure ]
 fast/dom/HTMLProgressElement/progress-bar-value-pseudo-element.html [ Failure ]
 fast/dom/Window/get-set-properties.html [ Failure ]
 fast/dom/Window/window-lookup-precedence.html [ Failure ]
-fast/events/arrow-keys-on-body.html [ Failure ]
 fast/events/before-input-events-prevent-drag-and-drop.html [ Failure ]
 fast/events/constructors/keyboard-event-constructor.html [ Failure ]
 fast/events/constructors/overconstrained-error-event-constructor.html [ Failure ]
@@ -3245,9 +3244,7 @@ fast/events/ime-composition-events-001.html [ Failure ]
 fast/events/ime-compositionend-on-selection-change.html [ Failure ]
 fast/events/input-events-paste-rich-datatransfer.html [ Failure ]
 fast/events/key-events-in-input-button.html [ Failure ]
-fast/events/key-events-in-input-text.html [ Failure ]
 fast/events/keyboardevent-code.html [ Failure ]
-fast/events/keyboardevent-key.html [ Failure ]
 fast/events/updateLayoutForHitTest.html [ Failure ]
 fast/events/wheelevent-basic.html [ Failure ]
 fast/forms/listbox-respects-padding-bottom.html [ Failure ]
index 77d3eec..1c98179 100644 (file)
@@ -1636,7 +1636,6 @@ fast/css/will-change/will-change-creates-stacking-context-inline.html [ ImageOnl
 fast/css/will-change/will-change-creates-stacking-context.html [ ImageOnlyFailure ]
 fast/dom/adopt-attribute-crash.svg [ Failure ]
 fast/dom/navigator-property-gc-after-frame-detach.html [ Failure ]
-fast/events/arrow-keys-on-body.html [ Failure ]
 fast/events/attempt-scroll-with-no-scrollbars.html [ Failure ]
 fast/events/autoscroll-when-input-is-offscreen.html [ Skip ] # UIScript
 fast/events/autoscroll-with-software-keyboard.html [ Skip ] # UIScript
@@ -1672,9 +1671,7 @@ fast/events/input-event-insert-replacement.html [ Skip ] # UIScript
 fast/events/input-events-paste-data.html [ Pass Failure ]
 fast/events/input-events-paste-rich-datatransfer.html [ Failure ]
 fast/events/key-events-in-input-button.html [ Failure ]
-fast/events/key-events-in-input-text.html [ Failure ]
 fast/events/keyboardevent-code.html [ Failure ]
-fast/events/keyboardevent-key.html [ Failure ]
 fast/events/keydown-numpad-keys.html [ Failure ]
 fast/events/mouse-cursor-image-set.html [ Failure ]
 fast/events/mouseover-button.html [ Failure ]
index 50303f7..7cf52ff 100644 (file)
@@ -1,5 +1,14 @@
 2019-11-25  Fujii Hironori  <Hironori.Fujii@sony.com>
 
+        [Win] Update KeyboardEvent as per the latest specification
+        https://bugs.webkit.org/show_bug.cgi?id=202183
+
+        Reviewed by Ross Kirsling.
+
+        * wtf/FeatureDefines.h:
+
+2019-11-25  Fujii Hironori  <Hironori.Fujii@sony.com>
+
         Add DefaultHash<OptionSet<T>> and HashTrait<OptionSet<T>> specializations
         https://bugs.webkit.org/show_bug.cgi?id=204562
 
index 5238e79..864df46 100644 (file)
@@ -751,11 +751,11 @@ the public iOS SDK. See <https://webkit.org/b/179167>. */
 #endif
 
 #if !defined(ENABLE_KEYBOARD_KEY_ATTRIBUTE)
-#define ENABLE_KEYBOARD_KEY_ATTRIBUTE 0
+#define ENABLE_KEYBOARD_KEY_ATTRIBUTE 1
 #endif
 
 #if !defined(ENABLE_KEYBOARD_CODE_ATTRIBUTE)
-#define ENABLE_KEYBOARD_CODE_ATTRIBUTE 0
+#define ENABLE_KEYBOARD_CODE_ATTRIBUTE 1
 #endif
 
 #if !defined(ENABLE_DATA_INTERACTION)
index ddd4bf2..fbcccc0 100644 (file)
@@ -1,3 +1,42 @@
+2019-11-25  Fujii Hironori  <Hironori.Fujii@sony.com>
+
+        [Win] Update KeyboardEvent as per the latest specification
+        https://bugs.webkit.org/show_bug.cgi?id=202183
+
+        Reviewed by Ross Kirsling.
+
+        Add 'key' and 'code' properties of KeyboardEvent for Windows. The
+        implementation is copied from Chromium for Windows.
+
+        For implementing 'key' properties, ToUnicodeEx API is used to
+        convert a virtual key code to a character information.
+        Unfortunately, ToUnicodeEx alters the stored previous typed dead
+        key in the driver, it can't be used for each key event. So,
+        ToUnicodeEx is used to convert all virtual keys with all modifier
+        combinations beforehand.
+
+        This change turns on ENABLE_KEYBOARD_KEY_ATTRIBUTE and
+        ENABLE_KEYBOARD_CODE_ATTRIBUTE macros for all ports. A follow-up
+        patch will remove the macros.
+
+        Existing tests covers.
+
+        * PlatformWin.cmake:
+        * platform/win/KeyEventWin.cpp:
+        (WebCore::windowsKeyNames):
+        (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
+        * platform/win/WindowsKeyNames.cpp: Added.
+        (hasControlAndAlt):
+        (getModifierFlags):
+        (nonPrintableVirtualKeyToDomKey):
+        (WindowsKeyNames::WindowsKeyNames):
+        (WindowsKeyNames::domKeyFromLParam):
+        (singleCharacterString):
+        (WindowsKeyNames::domKeyFromChar):
+        (WindowsKeyNames::domCodeFromLParam):
+        (WindowsKeyNames::updateLayout):
+        * platform/win/WindowsKeyNames.h: Added.
+
 2019-11-25  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][IFC] Use FontCascade::spaceWidth to measure single or collapsed whitespace content
index 10206fe..d1fd4eb 100644 (file)
@@ -107,6 +107,7 @@ list(APPEND WebCore_SOURCES
     platform/win/WheelEventWin.cpp
     platform/win/WidgetWin.cpp
     platform/win/WindowMessageBroadcaster.cpp
+    platform/win/WindowsKeyNames.cpp
 
     rendering/RenderThemeWin.cpp
 )
@@ -142,6 +143,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/win/WebCoreTextRenderer.h
     platform/win/WindowMessageBroadcaster.h
     platform/win/WindowMessageListener.h
+    platform/win/WindowsKeyNames.h
     platform/win/WindowsTouch.h
 )
 
index b2356c5..4473768 100644 (file)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "PlatformKeyboardEvent.h"
 
+#include "WindowsKeyNames.h"
 #include <windows.h>
 #include <wtf/ASCIICType.h>
 #include <wtf/HexNumber.h>
@@ -218,10 +219,18 @@ static inline String singleCharacterString(UChar c)
     return String(&c, 1);
 }
 
+static WindowsKeyNames& windowsKeyNames()
+{
+    static NeverDestroyed<WindowsKeyNames> keyNames;
+    return keyNames;
+}
+
 PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, Type type, bool systemKey)
     : PlatformEvent(type, GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT, GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT, GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT, false, WallTime::fromRawSeconds(::GetTickCount() * 0.001))
     , m_text((type == PlatformEvent::Char) ? singleCharacterString(code) : String())
     , m_unmodifiedText((type == PlatformEvent::Char) ? singleCharacterString(code) : String())
+    , m_key(type == PlatformEvent::Char ? windowsKeyNames().domKeyFromChar(code) : windowsKeyNames().domKeyFromLParam(keyData))
+    , m_code(windowsKeyNames().domCodeFromLParam(keyData))
     , m_keyIdentifier((type == PlatformEvent::Char) ? String() : keyIdentifierForWindowsKeyCode(code))
     , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? windowsKeycodeWithLocation(code, keyData) : 0)
     , m_autoRepeat(HIWORD(keyData) & KF_REPEAT)
diff --git a/Source/WebCore/platform/win/WindowsKeyNames.cpp b/Source/WebCore/platform/win/WindowsKeyNames.cpp
new file mode 100644 (file)
index 0000000..d3d45d9
--- /dev/null
@@ -0,0 +1,534 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright (C) 2019 Sony Interactive Entertainment Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "WindowsKeyNames.h"
+
+namespace WebCore {
+
+enum class WindowsKeyNames::KeyModifier : uint8_t {
+    Shift = 1 << 0,
+    Control = 1 << 1,
+    Alt = 1 << 2,
+    CapsLock = 1 << 3,
+};
+
+static void setModifierState(BYTE* keyboardState, WindowsKeyNames::KeyModifierSet modifiers)
+{
+    // According to MSDN GetKeyState():
+    // 1. If the high-order bit is 1, the key is down; otherwise, it is up.
+    // 2. If the low-order bit is 1, the key is toggled. A key, such as the
+    //    CAPS LOCK key, is toggled if it is turned on. The key is off and
+    //    untoggled if the low-order bit is 0.
+    // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301.aspx
+    if (modifiers.contains(WindowsKeyNames::KeyModifier::Shift))
+        keyboardState[VK_SHIFT] |= 0x80;
+
+    if (modifiers.contains(WindowsKeyNames::KeyModifier::Control))
+        keyboardState[VK_CONTROL] |= 0x80;
+
+    if (modifiers.contains(WindowsKeyNames::KeyModifier::Alt))
+        keyboardState[VK_MENU] |= 0x80;
+
+    if (modifiers.contains(WindowsKeyNames::KeyModifier::CapsLock))
+        keyboardState[VK_CAPITAL] |= 0x01;
+}
+
+static bool hasControlAndAlt(WindowsKeyNames::KeyModifierSet modifiers)
+{
+    return modifiers.containsAll({ WindowsKeyNames::KeyModifier::Control, WindowsKeyNames::KeyModifier::Alt });
+}
+
+// This table must be sorted by 'virtualKey' for binary search.
+constexpr struct NonPrintableKeyEntry {
+    int virtualKey;
+    ASCIILiteral domKey;
+} cNonPrintableKeyMap[] = {
+    { VK_CANCEL, "Cancel"_s },
+    { VK_BACK, "Backspace"_s },
+    { VK_TAB, "Tab"_s },
+    { VK_CLEAR, "Clear"_s },
+    { VK_RETURN, "Enter"_s },
+    { VK_SHIFT, "Shift"_s },
+    { VK_CONTROL, "Control"_s },
+    { VK_MENU, "Alt"_s },
+    { VK_PAUSE, "Pause"_s },
+    { VK_CAPITAL, "CapsLock"_s },
+    // VK_KANA == VK_HANGUL
+    { VK_JUNJA, "JunjaMode"_s },
+    { VK_FINAL, "FINAL_MODE"_s },
+    // VK_HANJA == VK_KANJI
+    { VK_ESCAPE, "Escape"_s },
+    { VK_CONVERT, "Convert"_s },
+    { VK_NONCONVERT, "NonConvert"_s },
+    { VK_ACCEPT, "Accept"_s },
+    { VK_MODECHANGE, "ModeChange"_s },
+    // VK_SPACE
+    { VK_PRIOR, "PageUp"_s },
+    { VK_NEXT, "PageDown"_s },
+    { VK_END, "End"_s },
+    { VK_HOME, "Home"_s },
+    { VK_LEFT, "ArrowLeft"_s },
+    { VK_UP, "ArrowUp"_s },
+    { VK_RIGHT, "ArrowRight"_s },
+    { VK_DOWN, "ArrowDown"_s },
+    { VK_SELECT, "Select"_s },
+    { VK_PRINT, "Print"_s },
+    { VK_EXECUTE, "Execute"_s },
+    { VK_SNAPSHOT, "PrintScreen"_s },
+    { VK_INSERT, "Insert"_s },
+    { VK_DELETE, "Delete"_s },
+    { VK_HELP, "Help"_s },
+    // VK_0..9
+    // VK_A..Z
+    { VK_LWIN, "Meta"_s },
+    // VK_COMMAND == VK_LWIN
+    { VK_RWIN, "Meta"_s },
+    { VK_APPS, "ContextMenu"_s },
+    { VK_SLEEP, "Standby"_s },
+    // VK_NUMPAD0..9
+    // VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL,
+    // VK_DIVIDE
+    { VK_F1, "F1"_s },
+    { VK_F2, "F2"_s },
+    { VK_F3, "F3"_s },
+    { VK_F4, "F4"_s },
+    { VK_F5, "F5"_s },
+    { VK_F6, "F6"_s },
+    { VK_F7, "F7"_s },
+    { VK_F8, "F8"_s },
+    { VK_F9, "F9"_s },
+    { VK_F10, "F10"_s },
+    { VK_F11, "F11"_s },
+    { VK_F12, "F12"_s },
+    { VK_F13, "F13"_s },
+    { VK_F14, "F14"_s },
+    { VK_F15, "F15"_s },
+    { VK_F16, "F16"_s },
+    { VK_F17, "F17"_s },
+    { VK_F18, "F18"_s },
+    { VK_F19, "F19"_s },
+    { VK_F20, "F20"_s },
+    { VK_F21, "F21"_s },
+    { VK_F22, "F22"_s },
+    { VK_F23, "F23"_s },
+    { VK_F24, "F24"_s },
+    { VK_NUMLOCK, "NumLock"_s },
+    { VK_SCROLL, "ScrollLock"_s },
+    { VK_LSHIFT, "Shift"_s },
+    { VK_RSHIFT, "Shift"_s },
+    { VK_LCONTROL, "Control"_s },
+    { VK_RCONTROL, "Control"_s },
+    { VK_LMENU, "Alt"_s },
+    { VK_RMENU, "Alt"_s },
+    { VK_BROWSER_BACK, "BrowserBack"_s },
+    { VK_BROWSER_FORWARD, "BrowserForward"_s },
+    { VK_BROWSER_REFRESH, "BrowserRefresh"_s },
+    { VK_BROWSER_STOP, "BrowserStop"_s },
+    { VK_BROWSER_SEARCH, "BrowserSearch"_s },
+    { VK_BROWSER_FAVORITES, "BrowserFavorites"_s },
+    { VK_BROWSER_HOME, "BrowserHome"_s },
+    { VK_VOLUME_MUTE, "AudioVolume"_s },
+    { VK_VOLUME_DOWN, "AudioVolumeDown"_s },
+    { VK_VOLUME_UP, "AudioVolumeUp"_s },
+    { VK_MEDIA_NEXT_TRACK, "MediaTrackNext"_s },
+    { VK_MEDIA_PREV_TRACK, "MediaTrackPrevious"_s },
+    { VK_MEDIA_STOP, "MediaStop"_s },
+    { VK_MEDIA_PLAY_PAUSE, "MediaPlayPause"_s },
+    // VK_OEM_1..8, 102, PLUS, COMMA, MINUS, PERIOD
+    { VK_PROCESSKEY, "Process"_s },
+    // VK_PACKET - Used to pass Unicode char, considered as printable key.
+    { VK_ATTN, "Attn"_s },
+    { VK_CRSEL, "CrSel"_s },
+    { VK_EXSEL, "ExSel"_s },
+    { VK_EREOF, "EraseEof"_s },
+    { VK_PLAY, "Play"_s },
+    { VK_ZOOM, "ZoomToggle"_s },
+    { VK_OEM_CLEAR, "Clear"_s },
+};
+
+// Disambiguates the meaning of certain non-printable keys which have different
+// meanings under different languages, but use the same VKEY code.
+static String languageSpecificOemVirtualKeyToDomKey(int virtualKey, HKL layout)
+{
+    WORD language = LOWORD(layout);
+    WORD primaryLanguage = PRIMARYLANGID(language);
+    if (primaryLanguage == LANG_KOREAN) {
+        switch (virtualKey) {
+        case VK_HANGUL:
+            return "HangulMode"_s;
+        case VK_HANJA:
+            return "HanjaMode"_s;
+        default:
+            return String();
+        }
+    } else if (primaryLanguage == LANG_JAPANESE) {
+        switch (virtualKey) {
+        // VK_KANA isn't generated by any modern layouts but is a listed value
+        // that third-party apps might synthesize, so we handle it anyway.
+        case VK_KANA:
+        case VK_ATTN:
+            return "KanaMode"_s;
+        case VK_KANJI:
+            return "KanjiMode"_s;
+        case VK_OEM_ATTN:
+            return "Alphanumeric"_s;
+        case VK_OEM_FINISH:
+            return "Katakana"_s;
+        case VK_OEM_COPY:
+            return "Hiragana"_s;
+        case VK_OEM_BACKTAB:
+            return "Romaji"_s;
+        case VK_OEM_AUTO:
+            return "Hankaku"_s;
+        case VK_OEM_ENLW:
+            return "Zenkaku"_s;
+        default:
+            return String();
+        }
+    }
+    return String();
+}
+
+static String nonPrintableVirtualKeyToDomKey(int virtualKey, HKL layout)
+{
+    // 1. Check if |virtualKey| has a |layout|-specific meaning.
+    const String key = languageSpecificOemVirtualKeyToDomKey(virtualKey, layout);
+    if (!key.isNull())
+        return key;
+
+    // 2. Most |virtualKeys| have the same meaning regardless of |layout|.
+    const NonPrintableKeyEntry* result = std::lower_bound(
+        std::begin(cNonPrintableKeyMap), std::end(cNonPrintableKeyMap), virtualKey,
+        [](const NonPrintableKeyEntry& entry, int needle) {
+            return entry.virtualKey < needle;
+        });
+    if (result != std::end(cNonPrintableKeyMap) && result->virtualKey == virtualKey)
+        return result->domKey;
+
+    return String();
+}
+
+WindowsKeyNames::WindowsKeyNames()
+{
+    updateLayout();
+}
+
+String WindowsKeyNames::domKeyFromLParam(LPARAM lParam)
+{
+    unsigned scanCode = (lParam >> 16) & 0xff;
+    bool extended = lParam & 0x01000000;
+    unsigned virtualKey = MapVirtualKey(scanCode, MAPVK_VSC_TO_VK);
+    KeyModifierSet modifiers;
+    if (GetKeyState(VK_SHIFT) < 0)
+        modifiers.add(KeyModifier::Shift);
+    if (GetKeyState(VK_CONTROL) < 0)
+        modifiers.add(KeyModifier::Control);
+    if (GetKeyState(VK_MENU ) < 0)
+        modifiers.add(KeyModifier::Alt);
+    if (GetKeyState(VK_CAPITAL) & 1)
+        modifiers.add(KeyModifier::CapsLock);
+
+    updateLayout();
+    // Windows expresses right-Alt as VK_MENU with the extended flag set.
+    // This key should generate AltGraph under layouts which use that modifier.
+    if (virtualKey == VK_MENU && extended && m_hasAltGraph)
+        return "AltGraph"_s;
+
+    String key = nonPrintableVirtualKeyToDomKey(virtualKey, m_keyboardLayout);
+    if (!key.isNull())
+        return key;
+
+    const KeyModifierSet modifiersToTry[] = {
+        // Trying to match Firefox's behavior and UIEvents DomKey guidelines.
+        // If the combination doesn't produce a printable character, the key value
+        // should be the key with no modifiers except for Shift and AltGr.
+        // See https://w3c.github.io/uievents/#keys-guidelines
+        modifiers,
+        KeyModifierSet({ KeyModifier::Shift, KeyModifier::CapsLock }) & modifiers,
+    };
+
+    for (auto tryModifiers : modifiersToTry) {
+        const auto& it = m_printableKeyCodeToKey.find(std::make_pair(virtualKey, tryModifiers));
+        if (it != m_printableKeyCodeToKey.end()) {
+            key = it->value;
+            if (!key.isNull())
+                return key;
+        }
+    }
+
+    return "Unidentified"_s;
+}
+
+String WindowsKeyNames::domKeyFromChar(UChar c)
+{
+    switch (c) {
+    case '\x1b':
+        return "Escape"_s;
+    case '\t':
+        return "Tab"_s;
+    case '\r':
+        return "Enter"_s;
+    default:
+        break;
+    }
+    return makeString(c);
+}
+
+// This table must be sorted by 'scanCode' for binary search.
+constexpr struct {
+    unsigned scanCode;
+    ASCIILiteral domCode;
+} cDomCodeMap[] = {
+    { 0x0001, "Escape"_s },
+    { 0x0002, "Digit1"_s },
+    { 0x0003, "Digit2"_s },
+    { 0x0004, "Digit3"_s },
+    { 0x0005, "Digit4"_s },
+    { 0x0006, "Digit5"_s },
+    { 0x0007, "Digit6"_s },
+    { 0x0008, "Digit7"_s },
+    { 0x0009, "Digit8"_s },
+    { 0x000a, "Digit9"_s },
+    { 0x000b, "Digit0"_s },
+    { 0x000c, "Minus"_s },
+    { 0x000d, "Equal"_s },
+    { 0x000e, "Backspace"_s },
+    { 0x000f, "Tab"_s },
+    { 0x0010, "KeyQ"_s },
+    { 0x0011, "KeyW"_s },
+    { 0x0012, "KeyE"_s },
+    { 0x0013, "KeyR"_s },
+    { 0x0014, "KeyT"_s },
+    { 0x0015, "KeyY"_s },
+    { 0x0016, "KeyU"_s },
+    { 0x0017, "KeyI"_s },
+    { 0x0018, "KeyO"_s },
+    { 0x0019, "KeyP"_s },
+    { 0x001a, "BracketLeft"_s },
+    { 0x001b, "BracketRight"_s },
+    { 0x001c, "Enter"_s },
+    { 0x001d, "ControlLeft"_s },
+    { 0x001e, "KeyA"_s },
+    { 0x001f, "KeyS"_s },
+    { 0x0020, "KeyD"_s },
+    { 0x0021, "KeyF"_s },
+    { 0x0022, "KeyG"_s },
+    { 0x0023, "KeyH"_s },
+    { 0x0024, "KeyJ"_s },
+    { 0x0025, "KeyK"_s },
+    { 0x0026, "KeyL"_s },
+    { 0x0027, "Semicolon"_s },
+    { 0x0028, "Quote"_s },
+    { 0x0029, "Backquote"_s },
+    { 0x002a, "ShiftLeft"_s },
+    { 0x002b, "Backslash"_s },
+    { 0x002c, "KeyZ"_s },
+    { 0x002d, "KeyX"_s },
+    { 0x002e, "KeyC"_s },
+    { 0x002f, "KeyV"_s },
+    { 0x0030, "KeyB"_s },
+    { 0x0031, "KeyN"_s },
+    { 0x0032, "KeyM"_s },
+    { 0x0033, "Comma"_s },
+    { 0x0034, "Period"_s },
+    { 0x0035, "Slash"_s },
+    { 0x0036, "ShiftRight"_s },
+    { 0x0037, "NumpadMultiply"_s },
+    { 0x0038, "AltLeft"_s },
+    { 0x0039, "Space"_s },
+    { 0x003a, "CapsLock"_s },
+    { 0x003b, "F1"_s },
+    { 0x003c, "F2"_s },
+    { 0x003d, "F3"_s },
+    { 0x003e, "F4"_s },
+    { 0x003f, "F5"_s },
+    { 0x0040, "F6"_s },
+    { 0x0041, "F7"_s },
+    { 0x0042, "F8"_s },
+    { 0x0043, "F9"_s },
+    { 0x0044, "F10"_s },
+    { 0x0045, "Pause"_s },
+    { 0x0046, "ScrollLock"_s },
+    { 0x0047, "Numpad7"_s },
+    { 0x0048, "Numpad8"_s },
+    { 0x0049, "Numpad9"_s },
+    { 0x004a, "NumpadSubtract"_s },
+    { 0x004b, "Numpad4"_s },
+    { 0x004c, "Numpad5"_s },
+    { 0x004d, "Numpad6"_s },
+    { 0x004e, "NumpadAdd"_s },
+    { 0x004f, "Numpad1"_s },
+    { 0x0050, "Numpad2"_s },
+    { 0x0051, "Numpad3"_s },
+    { 0x0052, "Numpad0"_s },
+    { 0x0053, "NumpadDecimal"_s },
+    { 0x0056, "IntlBackslash"_s },
+    { 0x0057, "F11"_s },
+    { 0x0058, "F12"_s },
+    { 0x0059, "NumpadEqual"_s },
+    { 0x0064, "F13"_s },
+    { 0x0065, "F14"_s },
+    { 0x0066, "F15"_s },
+    { 0x0067, "F16"_s },
+    { 0x0068, "F17"_s },
+    { 0x0069, "F18"_s },
+    { 0x006a, "F19"_s },
+    { 0x006b, "F20"_s },
+    { 0x006c, "F21"_s },
+    { 0x006d, "F22"_s },
+    { 0x006e, "F23"_s },
+    { 0x0070, "KanaMode"_s },
+    { 0x0071, "Lang2"_s },
+    { 0x0072, "Lang1"_s },
+    { 0x0073, "IntlRo"_s },
+    { 0x0076, "F24"_s },
+    { 0x0077, "Lang4"_s },
+    { 0x0078, "Lang3"_s },
+    { 0x0079, "Convert"_s },
+    { 0x007b, "NonConvert"_s },
+    { 0x007d, "IntlYen"_s },
+    { 0x007e, "NumpadComma"_s },
+    { 0x0108, "Undo"_s },
+    { 0x010a, "Paste"_s },
+    { 0x0110, "MediaTrackPrevious"_s },
+    { 0x0117, "Cut"_s },
+    { 0x0118, "Copy"_s },
+    { 0x0119, "MediaTrackNext"_s },
+    { 0x011c, "NumpadEnter"_s },
+    { 0x011d, "ControlRight"_s },
+    { 0x0120, "AudioVolumeMute"_s },
+    { 0x0121, "LaunchApp2"_s },
+    { 0x0122, "MediaPlayPause"_s },
+    { 0x0124, "MediaStop"_s },
+    { 0x012c, "Eject"_s },
+    { 0x012e, "AudioVolumeDown"_s },
+    { 0x0130, "AudioVolumeUp"_s },
+    { 0x0132, "BrowserHome"_s },
+    { 0x0135, "NumpadDivide"_s },
+    { 0x0137, "PrintScreen"_s },
+    { 0x0138, "AltRight"_s },
+    { 0x013b, "Help"_s },
+    { 0x0145, "NumLock"_s },
+    { 0x0147, "Home"_s },
+    { 0x0148, "ArrowUp"_s },
+    { 0x0149, "PageUp"_s },
+    { 0x014b, "ArrowLeft"_s },
+    { 0x014d, "ArrowRight"_s },
+    { 0x014f, "End"_s },
+    { 0x0150, "ArrowDown"_s },
+    { 0x0151, "PageDown"_s },
+    { 0x0152, "Insert"_s },
+    { 0x0153, "Delete"_s },
+    { 0x015b, "MetaLeft"_s },
+    { 0x015c, "MetaRight"_s },
+    { 0x015d, "ContextMenu"_s },
+    { 0x015e, "Power"_s },
+    { 0x015f, "Sleep"_s },
+    { 0x0163, "WakeUp"_s },
+    { 0x0165, "BrowserSearch"_s },
+    { 0x0166, "BrowserFavorites"_s },
+    { 0x0167, "BrowserRefresh"_s },
+    { 0x0168, "BrowserStop"_s },
+    { 0x0169, "BrowserForward"_s },
+    { 0x016a, "BrowserBack"_s },
+    { 0x016b, "LaunchApp1"_s },
+    { 0x016c, "LaunchMail"_s },
+    { 0x016d, "MediaSelect"_s },
+};
+
+String WindowsKeyNames::domCodeFromLParam(LPARAM lParam)
+{
+    unsigned extendedScanCode = (lParam >> 16) & 0x1ff;
+    const auto* result = std::lower_bound(
+        std::begin(cDomCodeMap), std::end(cDomCodeMap), extendedScanCode,
+        [](const auto& entry, int needle) {
+            return entry.scanCode < needle;
+        });
+    if (result != std::end(cDomCodeMap) && result->scanCode == extendedScanCode)
+        return result->domCode;
+
+    return "Unidentified"_s;
+}
+
+void WindowsKeyNames::updateLayout()
+{
+    HKL currentLayout = GetKeyboardLayout(0);
+    if (currentLayout == m_keyboardLayout)
+        return;
+
+    BYTE keyboardStateToRestore[256];
+    if (!GetKeyboardState(keyboardStateToRestore))
+        return;
+
+    m_keyboardLayout = currentLayout;
+    m_printableKeyCodeToKey.clear();
+    m_hasAltGraph = false;
+
+    // Map size for some sample keyboard layouts:
+    // US: 476, French: 602, Persian: 482, Vietnamese: 1436
+    m_printableKeyCodeToKey.reserveInitialCapacity(1500);
+
+    KeyModifierSet allCombination { KeyModifier::Shift, KeyModifier::Control, KeyModifier::Alt, KeyModifier::CapsLock };
+
+    for (int combination = 0; combination <= allCombination.toRaw(); ++combination) {
+        BYTE keyboardState[256] = { };
+
+        // Setting up keyboard state for modifiers.
+        auto modifiers = KeyModifierSet::fromRaw(combination);
+        setModifierState(keyboardState, modifiers);
+
+        for (unsigned virtualKey = 0; virtualKey <= 0xFF; ++virtualKey) {
+            wchar_t translatedChars[5];
+            int rv = ToUnicodeEx(virtualKey, 0, keyboardState, translatedChars,
+                WTF_ARRAY_LENGTH(translatedChars), 0, m_keyboardLayout);
+
+            if (rv == -1) {
+                // Dead key, injecting VK_SPACE to get character representation.
+                BYTE emptyState[256] = { };
+                rv = ToUnicodeEx(VK_SPACE, 0, emptyState, translatedChars,
+                    WTF_ARRAY_LENGTH(translatedChars), 0, m_keyboardLayout);
+                // Expecting a dead key character (not followed by a space).
+                if (rv == 1)
+                    m_printableKeyCodeToKey.set(std::make_pair(virtualKey, modifiers), "Dead"_s);
+            } else if (rv == 1) {
+                if (translatedChars[0] >= 0x20) {
+                    m_printableKeyCodeToKey.set(std::make_pair(virtualKey, modifiers), String(translatedChars, 1));
+
+                    // Detect whether the layout makes use of AltGraph.
+                    if (hasControlAndAlt(modifiers))
+                        m_hasAltGraph = true;
+                }
+            }
+        }
+    }
+    SetKeyboardState(keyboardStateToRestore);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/win/WindowsKeyNames.h b/Source/WebCore/platform/win/WindowsKeyNames.h
new file mode 100644 (file)
index 0000000..0fdfec0
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright (C) 2019 Sony Interactive Entertainment Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include <windows.h>
+#include <wtf/HashMap.h>
+#include <wtf/OptionSetHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class WindowsKeyNames {
+public:
+    WindowsKeyNames();
+
+    String domKeyFromLParam(LPARAM);
+    String domKeyFromChar(UChar);
+    String domCodeFromLParam(LPARAM);
+
+    enum class KeyModifier : uint8_t;
+    using KeyModifierSet = OptionSet<KeyModifier>;
+
+private:
+    void updateLayout();
+
+    HKL m_keyboardLayout = 0;
+    bool m_hasAltGraph = false;
+
+    using VirtualKeyModifierSetPair = std::pair<unsigned, KeyModifierSet>;
+    using VirtualKeyToKeyMap = HashMap<VirtualKeyModifierSetPair, String, DefaultHash<VirtualKeyModifierSetPair>::Hash, PairHashTraits<WTF::UnsignedWithZeroKeyHashTraits<unsigned>, HashTraits<KeyModifierSet>>>;
+    VirtualKeyToKeyMap m_printableKeyCodeToKey;
+};
+
+} // namespace WebCore
index 9d33a82..cd9c946 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-25  Fujii Hironori  <Hironori.Fujii@sony.com>
+
+        [Win] Update KeyboardEvent as per the latest specification
+        https://bugs.webkit.org/show_bug.cgi?id=202183
+
+        Reviewed by Ross Kirsling.
+
+        * Shared/WebEvent.h:
+        * Shared/WebKeyboardEvent.cpp:
+        (WebKit::WebKeyboardEvent::WebKeyboardEvent):
+        * Shared/win/WebEventFactory.cpp:
+        (WebKit::windowsKeyNames):
+        (WebKit::WebEventFactory::createWebKeyboardEvent):
+
 2019-11-25  ChangSeok Oh  <changseok@webkit.org>
 
         [GTK] Check EGL image extension by using native gl API in AcceleratedBackingStoreWayland
index c36100c..7dba08f 100644 (file)
@@ -263,7 +263,7 @@ public:
 #elif USE(LIBWPE)
     WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isKeypad, OptionSet<Modifier>, WallTime timestamp);
 #else
-    WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<Modifier>, WallTime timestamp);
+    WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<Modifier>, WallTime timestamp);
 #endif
 
     const String& text() const { return m_text; }
index a5a23cf..20d938b 100644 (file)
@@ -132,10 +132,12 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String&
 
 #else
 
-WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<Modifier> modifiers, WallTime timestamp)
+WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<Modifier> modifiers, WallTime timestamp)
     : WebEvent(type, modifiers, timestamp)
     , m_text(text)
     , m_unmodifiedText(unmodifiedText)
+    , m_key(key)
+    , m_code(code)
     , m_keyIdentifier(keyIdentifier)
     , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
     , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
index b3e6295..88d53d2 100644 (file)
@@ -31,6 +31,7 @@
 #include <WebCore/PlatformKeyboardEvent.h>
 #include <WebCore/PlatformWheelEvent.h>
 #include <WebCore/Scrollbar.h>
+#include <WebCore/WindowsKeyNames.h>
 #include <WebCore/WindowsKeyboardCodes.h>
 #include <windowsx.h>
 #include <wtf/ASCIICType.h>
@@ -446,11 +447,19 @@ WebWheelEvent WebEventFactory::createWebWheelEvent(HWND hWnd, UINT message, WPAR
     return WebWheelEvent(WebEvent::Wheel, position, globalPosition, FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, modifiers, WallTime::now());
 }
 
+static WindowsKeyNames& windowsKeyNames()
+{
+    static NeverDestroyed<WindowsKeyNames> keyNames;
+    return keyNames;
+}
+
 WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
 {
     WebEvent::Type type = keyboardEventTypeForEvent(message);
     String text = textFromEvent(wparam, type);
     String unmodifiedText = unmodifiedTextFromEvent(wparam, type);
+    String key = message == WM_CHAR ? windowsKeyNames().domKeyFromChar(wparam) : windowsKeyNames().domKeyFromLParam(lparam);
+    String code = windowsKeyNames().domCodeFromLParam(lparam);
     String keyIdentifier = keyIdentifierFromEvent(wparam, type);
     int windowsVirtualKeyCode = static_cast<int>(wparam);
     int nativeVirtualKeyCode = static_cast<int>(wparam);
@@ -460,7 +469,7 @@ WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message
     bool isSystemKey = isSystemKeyEvent(message);
     auto modifiers = modifiersForCurrentKeyState();
 
-    return WebKeyboardEvent(type, text, unmodifiedText, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, WallTime::now());
+    return WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, macCharCode, autoRepeat, isKeypad, isSystemKey, modifiers, WallTime::now());
 }
 
 #if ENABLE(TOUCH_EVENTS)