[iOS] Special keys are misidentified in DOM keyboard events
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 18:35:37 +0000 (18:35 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Oct 2018 18:35:37 +0000 (18:35 +0000)
commita6dbf3c34633eb1fde3cfe08d8159381f3959b05
tree9a464d424d064b75366bd63446351fc4201fe865
parentb72caeeb1dee4221645feb97344f92baeec24028
[iOS] Special keys are misidentified in DOM keyboard events
https://bugs.webkit.org/show_bug.cgi?id=189974

Reviewed by Wenson Hsieh.

Source/WebCore:

This patch fixes two issues:
    1. Special keyboard keys would be misidentified in dispatched DOM keyboard events.
    2. DOM keypress events may not be dispatched for some special keys.

UIKit uses special input strings to identify the Page Up, Page Down, Escape, Up Arrow, Down Arrow,
Left Arrow, and Right Arrow keys. It also uses ASCII control characters to represent some other
special keys, including Num Lock / Clear, Home, End, Forward Delete, and F1, ..., F24. We need
to explicitly handle these special keyboard keys in order to be able to identify the key that
was pressed as well as to correctly disambiguate a key down to know whether to dispatch a DOM
keypress event for the key.

Unlike UIKit, AppKit reserves Unicode Private Use Area (PUA) code points in 0xF700–0xF8FF to
represent special keyboard keys. This makes it straightforward to disambiguate such keys using
the input string of the keyboard event alone. To simplify the implementation for iOS
we normalize the input string be AppKit compatible. See the explaination for WebCore::windowsKeyCodeForCharCode()
below for more details on why this is done.

Tests: fast/events/ios/keydown-keyup-arrow-keys-in-non-editable-element.html
       fast/events/ios/keypress-keys-in-non-editable-element.html

* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
Do not use unified source build strategy when building WebEvent.mm as it makes
use of SoftLinking macros that are incompatible with this strategy.

* platform/ios/KeyEventIOS.mm:
(WebCore::windowsKeyCodeForCharCode): Recognize some special AppKit special char codes.
These special char codes are generated by WebKit. WebKit uses the same special char codes
as AppKit as a convenience instead of defining our own constants for the same purpose.
Encoding the special UIKit input strings (e.g. up arrow) as distinct char codes allows us
to use integer arithmetic and switch blocks to map characters to Windows virtual key
codes as opposed to special cased branches to perform pointer or string comparisions.
The latter would be necessary in Modern WebKit in order for key down events to be properly
disambiguated to dispatch a DOM keypress event because pointers are not perserved, though
what they point to is, when sending the WebEvent from UIProcess to the WebProcess and
vice versa.
(WebCore::isFunctionKey): Convenience function that determines whether the specified char
code corresponds to a function key on the keyboard. The term "function key" is taken from
AppKit parlance to describe a special keyboard key. These keys include F1, F2, ..., F24,
and cursor keys among other special keyboard keys.
(WebCore::PlatformKeyboardEvent::disambiguateKeyDownEvent): Write in terms of isFunctionKey().
* platform/ios/PlatformEventFactoryIOS.h:
* platform/ios/PlatformEventFactoryIOS.mm:
(WebCore::keyIdentifierForKeyEvent): Remove code to handle UIKit special input strings as
we now map such special input strings to char codes and hence can use the default code path.
(WebCore::keyForKeyEvent): Ditto.
(WebCore::codeForKeyEvent): Remove code to compute the Window virtual key code corresponding
to a UIKit special key command now that we map such special input strings to char codes and
subsequently map the char codes to the Windows virtual key code (see -[WebEvent initWithKeyEventType:...]
constructors). So, we can now use WebEvent.keyCode directly to compute the DOM UIEvents code
for the event.
(WebCore::PlatformKeyboardEventBuilder::PlatformKeyboardEventBuilder): Remove code to fix up
WebEvent.keyCode to account for UIKit special input strings now that we map such special key
commands to char codes and subsequently map the char codes to the Windows virtual key code (see -[WebEvent initWithKeyEventType:...]
constructors). So, we can now take WebEvent.keyCode verbatim to be the Window virtual key code.
(WebCore::convertSpecialKeyToCharCode): Deleted.
(WebCore::keyCodeForEvent): Deleted.
* platform/ios/WebEvent.mm:
(normalizedStringWithAppKitCompatibilityMapping): Added; converts a UIKit character string
to the corresponding AppKit-compatible one (if not already compatible). See the explaination
for WebCore::windowsKeyCodeForCharCode() above for more details on why this is done.

(-[WebEvent initWithKeyEventType:timeStamp:characters:charactersIgnoringModifiers:modifiers:isRepeating:withFlags:keyCode:isTabKey:characterSet:]):
(-[WebEvent initWithKeyEventType:timeStamp:characters:charactersIgnoringModifiers:modifiers:isRepeating:withFlags:withInputManagerHint:keyCode:isTabKey:]):
Normalize the character strings to be AppKit compatible.

Source/WebCore/PAL:

Forward declare or define more SPI.

* pal/spi/cocoa/IOKitSPI.h:
* pal/spi/ios/UIKitSPI.h:

Source/WebKit:

Take the key code of WebEvent to be the key code for the new WebKeyboardEvent verbatim
now that we normalize the character strings of the WebEvent to account for the special
UIKit input strings.

* Shared/ios/WebIOSEventFactory.mm:
(WebIOSEventFactory::createWebKeyboardEvent):

Tools:

Add support for testing keys Forward Delete and Num Lock / Clear.

* WebKitTestRunner/ios/HIDEventGenerator.mm:
(hidUsageCodeForCharacter):

LayoutTests:

Add tests to ensure that we do not regress key identification for special keys.

Update the expected results for test fast/events/ios/keydown-keyup-special-keys-in-non-editable-element.html
now that we correctly identify some more keys.

* fast/events/ios/keydown-keyup-arrow-keys-in-non-editable-element-expected.txt: Added.
* fast/events/ios/keydown-keyup-arrow-keys-in-non-editable-element.html: Added.
* fast/events/ios/keydown-keyup-special-keys-in-non-editable-element-expected.txt:
* fast/events/ios/keypress-keys-in-non-editable-element-expected.txt: Added.
* fast/events/ios/keypress-keys-in-non-editable-element.html: Added.
* resources/ui-helper.js:
(window.UIHelper.typeCharacter): Actually type the specified character in DumpRenderTree.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236678 268f45cc-cd09-0410-ab3c-d52691b4dbfc
21 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/ios/keydown-keyup-arrow-keys-in-non-editable-element-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/keydown-keyup-arrow-keys-in-non-editable-element.html [new file with mode: 0644]
LayoutTests/fast/events/ios/keydown-keyup-special-keys-in-non-editable-element-expected.txt
LayoutTests/fast/events/ios/keypress-keys-in-non-editable-element-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/keypress-keys-in-non-editable-element.html [new file with mode: 0644]
LayoutTests/resources/ui-helper.js
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cocoa/IOKitSPI.h
Source/WebCore/PAL/pal/spi/ios/UIKitSPI.h
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/ios/KeyEventIOS.mm
Source/WebCore/platform/ios/PlatformEventFactoryIOS.h
Source/WebCore/platform/ios/PlatformEventFactoryIOS.mm
Source/WebCore/platform/ios/WebEvent.mm
Source/WebKit/ChangeLog
Source/WebKit/Shared/ios/WebIOSEventFactory.mm
Tools/ChangeLog
Tools/WebKitTestRunner/ios/HIDEventGenerator.mm