[iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content...
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 21:16:19 +0000 (21:16 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Feb 2019 21:16:19 +0000 (21:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192824
<rdar://problem/47100332>

Reviewed by Wenson Hsieh.

Source/WebCore:

When building with USE(UIKIT_KEYBOARD_ADDITIONS) enabled, normalize input strings for some more key codes
now that hardware key events to non-editable elements use the same code path as for editable elements.

* platform/ios/KeyEventIOS.mm:
(WebCore::windowsKeyCodeForCharCode): Demarcate mappings that are only needed when building with
!USE(UIKIT_KEYBOARD_ADDITIONS) in the hope that one day we can remove this code.
(WebCore::isFunctionKey): Ditto.
* platform/ios/WebEvent.mm:
(normalizedStringWithAppKitCompatibilityMapping): Normalize some more input strings when building with
USE(UIKIT_KEYBOARD_ADDITIONS) enabled.

Source/WebCore/PAL:

Expose more enumerators.

* pal/spi/cocoa/IOKitSPI.h:

Source/WebKit:

Use the same code path for key events to editable elements and non-editable elements.

Currently we have different code paths for hardware key events depending on whether the active element
is editable or non-editable. Historically to support dispatching DOM keyboard events for hardware key
presses this differentiation was a necessary workaround for UIKit's event processing precedence of
interpreting key events for system text editing commands and app commands before dispatching unhandled
key events to WebKit. This workaround intercepted raw key UIEvents and manually reconstructed a
WebEvent from it. However there is not enough information in an UIEvent to reconstruct a WebEvent that
is identical to the WebEvent that UIKit would have dispatched. In particular, keyup UIEvents always have
empty modified and unmodified input strings. The UIKit keyboard machinery maintains additional state
that is necessary to manufacture the correct WebEvent corresponding to a UIEvent.

As a side benefit of this change, with the exception of modifier flag changes, both hardware and software
key events use the same code path.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView shouldShowAutomaticKeyboardUI]): Extracted code from _requiresKeyboardWhenFirstResponder
(-[WKContentView _disableAutomaticKeyboardUI]): Implement UIKit SPI to prevent showing the keyboard UI
when there is no focused element now that we are no longer intercepting key UIEvents. Formerly the
keyboard UI was disabled as a side effect of not becoming first responder when there was no focused
element (by returning NO in -_requiresKeyboardWhenFirstResponder).
(-[WKContentView _requiresKeyboardWhenFirstResponder]): Always return YES when building with USE(UIKIT_KEYBOARD_ADDITIONS)
so that we always accept key events. Instead of selectively replying to create a keyboard as a means of
hiding the automatic keyboard UI we now implement _disableAutomaticKeyboardUI to selectively hide the
automatic keyboard UI.
(-[WKContentView applyAutocorrection:toString:withCompletionHandler:]): If we are not in an editable
element then we cannot perform the replacement. This logic was necessary now that we always require a
keyboard.
(-[WKContentView requestAutocorrectionContextWithCompletionHandler:]): If we are not in an editable
element then return an autocorrection object that indicates that we could not compute this data. This
logic was necessary now that we always require a keyboard.
(-[WKContentView textInputTraits]): Do not update traits when the keyboard is going to be dismissed
now that we require a keyboard when first responder even if the focused element is non-editable.
(-[WKContentView _didHandleKeyEvent:eventWasHandled:]): Skip logic for re-sending UIEvents to UIKit
as UIKit now processes the event first. This logic was necessary in order to finally allow UIKit
its chance to interpret the UIEvent, we intercepted, for app key commands.
(-[WKContentView _elementDidBlur]): Call [self _endEditing] so that we dismiss any open form controls
(e.g. a <select> popover menu). Currently this happens either by -_requiresKeyboardWhenFirstResponder
responding NO when switching to another field or pressing Tab or Shift + Tab key command, which we will
no longer use when building with USE(UIKIT_KEYBOARD_ADDITIONS) once I land <https://bugs.webkit.org/show_bug.cgi?id=193048>.
* UIProcess/ios/forms/WKFormSelectPopover.mm:
(-[WKSelectPopover initWithView:hasGroups:]): Do not assign ourself as the keyboard delegate. Otherwise,
type ahead and tab cycling will not work. Currently type ahead and tab cycling work by using the non-
editable code path via -_handleKeyUIEvent. Now that we no longer differentiate between key events for
editable and non-editable elements we need to ensure that the WKContentView is the keyboard delegate
when the popover is presented.

Tools:

Fix a bug where the wrong usage code was used for F13 thru F24.

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

LayoutTests:

Update tests and expected results. As it turns out fixing the bug in WebKitTestRunner/ios/HIDEventGenerator.mm
so that we now dispatch key events for F17 thru F24 exposed a bug in UIKit. See <rdar://problem/47128940>.
This same bug is also responsible for a lack of key events when the Insert key is pressed.

Added sub-test for Tab key to keypress-keys-in-non-editable-element.html. Changed expected result in test
keypress-keys-in-non-editable-element.html for the forward delete key to expect failure. We expect that pressing
the forward delete key will not dispatch a keypress to match the behavior on Mac. This will be addressed by a
UIKit fix.

* fast/events/ios/keydown-keyup-special-keys-in-non-editable-element-expected.txt:
* fast/events/ios/keydown-keyup-special-keys-in-non-editable-element.html:
* fast/events/ios/keypress-keys-in-non-editable-element-expected.txt:
* fast/events/ios/keypress-keys-in-non-editable-element.html:

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/ios/keydown-keyup-special-keys-in-non-editable-element-expected.txt
LayoutTests/fast/events/ios/keydown-keyup-special-keys-in-non-editable-element.html
LayoutTests/fast/events/ios/keypress-keys-in-non-editable-element-expected.txt
LayoutTests/fast/events/ios/keypress-keys-in-non-editable-element.html
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cocoa/IOKitSPI.h
Source/WebCore/platform/ios/KeyEventIOS.mm
Source/WebCore/platform/ios/WebEvent.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/UIProcess/ios/forms/WKFormSelectPopover.mm
Tools/ChangeLog
Tools/WebKitTestRunner/ios/HIDEventGenerator.mm

index 6f97079..80945a5 100644 (file)
@@ -1,3 +1,25 @@
+2019-02-18  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content-editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192824
+        <rdar://problem/47100332>
+
+        Reviewed by Wenson Hsieh.
+
+        Update tests and expected results. As it turns out fixing the bug in WebKitTestRunner/ios/HIDEventGenerator.mm
+        so that we now dispatch key events for F17 thru F24 exposed a bug in UIKit. See <rdar://problem/47128940>.
+        This same bug is also responsible for a lack of key events when the Insert key is pressed.
+
+        Added sub-test for Tab key to keypress-keys-in-non-editable-element.html. Changed expected result in test
+        keypress-keys-in-non-editable-element.html for the forward delete key to expect failure. We expect that pressing
+        the forward delete key will not dispatch a keypress to match the behavior on Mac. This will be addressed by a
+        UIKit fix.
+
+        * fast/events/ios/keydown-keyup-special-keys-in-non-editable-element-expected.txt:
+        * fast/events/ios/keydown-keyup-special-keys-in-non-editable-element.html:
+        * fast/events/ios/keypress-keys-in-non-editable-element-expected.txt:
+        * fast/events/ios/keypress-keys-in-non-editable-element.html:
+
 2019-02-18  Eric Carlson  <eric.carlson@apple.com>
 
         Add MSE logging configuration
index 0d0c847..84fc32e 100644 (file)
@@ -1,5 +1,7 @@
-This tests that DOM keydown and keyup events are dispatched to a non-editable <body> on iOS when pressing special keys on a hardware keyboard. To run this test manually, verify that two messages are emitted when you press the following keys: ↑, ↓, ←, →, Delete, End, Enter, Escape, Home, Insert, left Alt, left ⌘ Command, left Ctrl, left ⇧ Shift, Page Down, Page Up, Return, right Alt, right ⌘ Command, right Ctrl, right ⇧ Shift, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24.
+This tests that DOM keydown and keyup events are dispatched to a non-editable <body> on iOS when pressing special keys on a hardware keyboard. To run this test manually, verify that two messages are emitted when you press the following keys: Tab, ↑, ↓, ←, →, Delete, End, Enter, Escape, Home, left Alt, left ⌘ Command, left Ctrl, left ⇧ Shift, Page Down, Page Up, Return, right Alt, right ⌘ Command, right Ctrl, right ⇧ Shift, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16.
 
+type: keydown, key: Tab, code: Tab, keyIdentifier: U+0009, keyCode: 9, charCode: 0, keyCode: 9, which: 9
+type: keyup, key: Dead, code: Tab, keyIdentifier: Unidentified, keyCode: 9, charCode: 0, keyCode: 9, which: 9
 type: keydown, key: ArrowUp, code: ArrowUp, keyIdentifier: Up, keyCode: 38, charCode: 0, keyCode: 38, which: 38
 type: keyup, key: ArrowUp, code: ArrowUp, keyIdentifier: Up, keyCode: 38, charCode: 0, keyCode: 38, which: 38
 type: keydown, key: ArrowDown, code: ArrowDown, keyIdentifier: Down, keyCode: 40, charCode: 0, keyCode: 40, which: 40
index cfbb050..a824482 100644 (file)
@@ -12,11 +12,12 @@ if (window.testRunner) {
 </script>
 </head>
 <body onkeydown="handleKeyDown(event)" onkeyup="handleKeyUp(event)">
-<p>This tests that DOM keydown and keyup events are dispatched to a non-editable &lt;body&gt; on iOS when pressing special keys on a hardware keyboard. To run this test manually, verify that two messages are emitted when you press the following keys: <kbd>↑</kbd>, <kbd>↓</kbd>, <kbd>←</kbd>, <kbd>→</kbd>, <kbd>Delete</kbd>, <kbd>End</kbd>, <kbd>Enter</kbd>, <kbd>Escape</kbd>, <kbd>Home</kbd>, <kbd>Insert</kbd>, left <kbd>Alt</kbd>, left <kbd>⌘ Command</kbd>, left <kbd>Ctrl</kbd>, left <kbd>⇧ Shift</kbd>, <kbd>Page Down</kbd>, <kbd>Page Up</kbd>, <kbd>Return</kbd>, right <kbd>Alt</kbd>, right <kbd>⌘ Command</kbd>, right <kbd>Ctrl</kbd>, right <kbd>⇧ Shift</kbd>, <kbd>F1</kbd>, <kbd>F2</kbd>, <kbd>F3</kbd>, <kbd>F4</kbd>, <kbd>F5</kbd>, <kbd>F6</kbd>, <kbd>F7</kbd>, <kbd>F8</kbd>, <kbd>F9</kbd>, <kbd>F10</kbd>, <kbd>F11</kbd>, <kbd>F12</kbd>, <kbd>F13</kbd>, <kbd>F14</kbd>, <kbd>F15</kbd>, <kbd>F16</kbd>, <kbd>F17</kbd>, <kbd>F18</kbd>, <kbd>F19</kbd>, <kbd>F20</kbd>, <kbd>F21</kbd>, <kbd>F22</kbd>, <kbd>F23</kbd>, <kbd>F24</kbd>.
+<p>This tests that DOM keydown and keyup events are dispatched to a non-editable &lt;body&gt; on iOS when pressing special keys on a hardware keyboard. To run this test manually, verify that two messages are emitted when you press the following keys: <kbd>Tab</kbd>, <kbd>↑</kbd>, <kbd>↓</kbd>, <kbd>←</kbd>, <kbd>→</kbd>, <kbd>Delete</kbd>, <kbd>End</kbd>, <kbd>Enter</kbd>, <kbd>Escape</kbd>, <kbd>Home</kbd><!-- FIXME: Add <kbd>Insert</kbd> once <rdar://problem/47128940> is fixed. -->, left <kbd>Alt</kbd>, left <kbd>⌘ Command</kbd>, left <kbd>Ctrl</kbd>, left <kbd>⇧ Shift</kbd>, <kbd>Page Down</kbd>, <kbd>Page Up</kbd>, <kbd>Return</kbd>, right <kbd>Alt</kbd>, right <kbd>⌘ Command</kbd>, right <kbd>Ctrl</kbd>, right <kbd>⇧ Shift</kbd>, <kbd>F1</kbd>, <kbd>F2</kbd>, <kbd>F3</kbd>, <kbd>F4</kbd>, <kbd>F5</kbd>, <kbd>F6</kbd>, <kbd>F7</kbd>, <kbd>F8</kbd>, <kbd>F9</kbd>, <kbd>F10</kbd>, <kbd>F11</kbd>, <kbd>F12</kbd>, <kbd>F13</kbd>, <kbd>F14</kbd>, <kbd>F15</kbd>, <kbd>F16</kbd><!-- FIXME: Add <kbd>F17</kbd>, <kbd>F18</kbd>, <kbd>F19</kbd>, <kbd>F20</kbd>, <kbd>F21</kbd>, <kbd>F22</kbd>, <kbd>F23</kbd>, <kbd>F24</kbd> once <rdar://problem/47128940> is fixed.-->.
 </p>
 <pre id="console"></pre>
 <script>
 var remainingKeysToPress = [
+    "\t",
     "upArrow",
     "downArrow",
     "leftArrow",
@@ -26,7 +27,7 @@ var remainingKeysToPress = [
     "enter",
     "escape",
     "home",
-    "insert",
+    // FIXME: Add "insert" once <rdar://problem/47128940> is fixed.
     "leftAlt",
     "leftCommand",
     "leftControl",
@@ -40,7 +41,8 @@ var remainingKeysToPress = [
     "rightShift",
 ];
 
-for (let i = 1; i <= 24; ++i)
+// FIXME: Check function keys up to F24 once <rdar://problem/47128940> is fixed.
+for (let i = 1; i <= 16; ++i)
     remainingKeysToPress.push("F" + i);
 
 async function nextKeyPress()
index d064128..1a503a8 100644 (file)
@@ -54,7 +54,7 @@ PASS delete did dispatch a keypress event.
 PASS enter did dispatch a keypress event.
 PASS escape did dispatch a keypress event.
 PASS return did dispatch a keypress event.
-PASS forwardDelete did dispatch a keypress event.
+FAIL forwardDelete should not have dispatched a keypress event. It did dispatch one.
 PASS upArrow did not dispatch a keypress event.
 PASS downArrow did not dispatch a keypress event.
 PASS leftArrow did not dispatch a keypress event.
@@ -89,14 +89,6 @@ PASS F13 did not dispatch a keypress event.
 PASS F14 did not dispatch a keypress event.
 PASS F15 did not dispatch a keypress event.
 PASS F16 did not dispatch a keypress event.
-PASS F17 did not dispatch a keypress event.
-PASS F18 did not dispatch a keypress event.
-PASS F19 did not dispatch a keypress event.
-PASS F20 did not dispatch a keypress event.
-PASS F21 did not dispatch a keypress event.
-PASS F22 did not dispatch a keypress event.
-PASS F23 did not dispatch a keypress event.
-PASS F24 did not dispatch a keypress event.
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 5fd14dd..d4dd00a 100644 (file)
@@ -41,11 +41,8 @@ tests.push(new TestKeyPressDispatchedFor("enter"));
 tests.push(new TestKeyPressDispatchedFor("escape"));
 tests.push(new TestKeyPressDispatchedFor("return"));
 
-// The forward delete key is mapped to the delete key on iOS and dispatches a keypress event.
-// On Mac it is treated as its own key and does not dispatch a keypress event.
-tests.push(new TestKeyPressDispatchedFor("forwardDelete"));
-
 // Special keys: KeyPress should not be dispatched.
+tests.push(new TestKeyPressNotDispatchedFor("forwardDelete"));
 tests.push(new TestKeyPressNotDispatchedFor("upArrow"));
 tests.push(new TestKeyPressNotDispatchedFor("downArrow"));
 tests.push(new TestKeyPressNotDispatchedFor("leftArrow"));
@@ -53,7 +50,7 @@ tests.push(new TestKeyPressNotDispatchedFor("rightArrow"));
 tests.push(new TestKeyPressNotDispatchedFor("clear"));
 tests.push(new TestKeyPressNotDispatchedFor("end"));
 tests.push(new TestKeyPressNotDispatchedFor("home"));
-tests.push(new TestKeyPressNotDispatchedFor("insert"));
+// FIXME: Test that keypress is not dispatched for "insert" once <rdar://problem/47128940> is fixed.
 tests.push(new TestKeyPressNotDispatchedFor("leftAlt"));
 tests.push(new TestKeyPressNotDispatchedFor("leftCommand"));
 tests.push(new TestKeyPressNotDispatchedFor("leftControl"));
@@ -64,7 +61,8 @@ tests.push(new TestKeyPressNotDispatchedFor("rightAlt"));
 tests.push(new TestKeyPressNotDispatchedFor("rightCommand"));
 tests.push(new TestKeyPressNotDispatchedFor("rightControl"));
 tests.push(new TestKeyPressNotDispatchedFor("rightShift"));
-for (let i = 1; i <= 24; ++i)
+// FIXME: Check function keys up to F24 once <rdar://problem/47128940> is fixed.
+for (let i = 1; i <= 16; ++i)
     tests.push(new TestKeyPressNotDispatchedFor("F" + i));
 
 function nextKeyPress()
index 7e86ea9..287e18b 100644 (file)
@@ -1,3 +1,22 @@
+2019-02-18  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content-editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192824
+        <rdar://problem/47100332>
+
+        Reviewed by Wenson Hsieh.
+
+        When building with USE(UIKIT_KEYBOARD_ADDITIONS) enabled, normalize input strings for some more key codes
+        now that hardware key events to non-editable elements use the same code path as for editable elements. 
+
+        * platform/ios/KeyEventIOS.mm:
+        (WebCore::windowsKeyCodeForCharCode): Demarcate mappings that are only needed when building with
+        !USE(UIKIT_KEYBOARD_ADDITIONS) in the hope that one day we can remove this code.
+        (WebCore::isFunctionKey): Ditto.
+        * platform/ios/WebEvent.mm:
+        (normalizedStringWithAppKitCompatibilityMapping): Normalize some more input strings when building with
+        USE(UIKIT_KEYBOARD_ADDITIONS) enabled.
+
 2019-02-18  Eric Carlson  <eric.carlson@apple.com>
 
         Add MSE logging configuration
index 94d25c2..6b3bae8 100644 (file)
@@ -1,3 +1,15 @@
+2019-02-18  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content-editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192824
+        <rdar://problem/47100332>
+
+        Reviewed by Wenson Hsieh.
+
+        Expose more enumerators.
+
+        * pal/spi/cocoa/IOKitSPI.h:
+
 2019-02-17  David Kilzer  <ddkilzer@apple.com>
 
         Unreviewed, rolling out r241620.
index 207a5d5..6a2f1d2 100644 (file)
@@ -185,6 +185,7 @@ enum {
     kHIDUsage_KeyboardSlash = 0x38,
     kHIDUsage_KeyboardCapsLock = 0x39,
     kHIDUsage_KeyboardF1 = 0x3A,
+    kHIDUsage_KeyboardF12 = 0x45,
     kHIDUsage_KeyboardPrintScreen = 0x46,
     kHIDUsage_KeyboardInsert = 0x49,
     kHIDUsage_KeyboardHome = 0x4A,
@@ -198,6 +199,7 @@ enum {
     kHIDUsage_KeyboardUpArrow = 0x52,
     kHIDUsage_KeypadNumLock = 0x53,
     kHIDUsage_KeyboardF13 = 0x68,
+    kHIDUsage_KeyboardF24 = 0x73,
     kHIDUsage_KeyboardMenu = 0x76,
     kHIDUsage_KeyboardLeftControl = 0xE0,
     kHIDUsage_KeyboardLeftShift = 0xE1,
index 12e9f2a..9bf3a89 100644 (file)
@@ -197,13 +197,15 @@ int windowsKeyCodeForKeyCode(uint16_t keyCode)
     return 0; // Unknown key
 }
 
+// This function is only used to map software keyboard events because they lack a key code.
+// When !USE(UIKIT_KEYBOARD_ADDITIONS), this function is also used to map hardware keyboard
+// keyup events because they lack a key code.
 int windowsKeyCodeForCharCode(unichar charCode)
 {
     switch (charCode) {
     case 8: case 0x7F: return VK_BACK;
     case 9: return VK_TAB;
     case 0xD: case 3: return VK_RETURN;
-    case 0x1B: return VK_ESCAPE; // WebKit generated code for Escape.
     case ' ': return VK_SPACE;
 
     case '0': case ')': return VK_0;
@@ -243,6 +245,9 @@ int windowsKeyCodeForCharCode(unichar charCode)
     case 'y': case 'Y': return VK_Y;
     case 'z': case 'Z': return VK_Z;
 
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
+    case 0x1B: return VK_ESCAPE; // WebKit generated code for Escape.
+
     // WebKit uses Unicode PUA codes in the OpenStep reserve range for some special keys.
     case NSUpArrowFunctionKey: return VK_UP;
     case NSDownArrowFunctionKey: return VK_DOWN;
@@ -250,6 +255,7 @@ int windowsKeyCodeForCharCode(unichar charCode)
     case NSRightArrowFunctionKey: return VK_RIGHT;
     case NSPageUpFunctionKey: return VK_PRIOR;
     case NSPageDownFunctionKey: return VK_NEXT;
+#endif
 
     // This is for U.S. keyboard mapping, and doesn't necessarily make sense for different keyboard layouts.
     // For example, '"' on Windows Russian layout is VK_2, not VK_OEM_7.
@@ -271,11 +277,13 @@ int windowsKeyCodeForCharCode(unichar charCode)
 static bool isFunctionKey(UChar charCode)
 {
     switch (charCode) {
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
     case 1: // Home
     case 4: // End
     case 5: // FIXME: For some reason WebKitTestRunner generates this code for F14 (why?).
     case 0x7F: // Forward Delete
     case 0x10: // Function key (e.g. F1, F2, ...)
+#endif
 
     // WebKit uses Unicode PUA codes in the OpenStep reserve range for some special keys.
     case NSUpArrowFunctionKey:
@@ -285,8 +293,18 @@ static bool isFunctionKey(UChar charCode)
     case NSPageUpFunctionKey:
     case NSPageDownFunctionKey:
     case NSClearLineFunctionKey: // Num Lock / Clear
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    case NSDeleteFunctionKey: // Forward delete
+    case NSEndFunctionKey:
+    case NSInsertFunctionKey:
+    case NSHomeFunctionKey:
+#endif
         return true;
     }
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    if (charCode >= NSF1FunctionKey && charCode <= NSF24FunctionKey)
+        return true;
+#endif
     return false;
 }
 
index 5443117..266b611 100644 (file)
@@ -149,7 +149,23 @@ static NSString *normalizedStringWithAppKitCompatibilityMapping(NSString *charac
         return @"\x1B";
     case kHIDUsage_KeypadNumLock: // Num Lock / Clear
         return makeNSStringWithCharacter(NSClearLineFunctionKey);
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    case kHIDUsage_KeyboardDeleteForward:
+        return makeNSStringWithCharacter(NSDeleteFunctionKey);
+    case kHIDUsage_KeyboardEnd:
+        return makeNSStringWithCharacter(NSEndFunctionKey);
+    case kHIDUsage_KeyboardInsert:
+        return makeNSStringWithCharacter(NSInsertFunctionKey);
+    case kHIDUsage_KeyboardHome:
+        return makeNSStringWithCharacter(NSHomeFunctionKey);
+#endif
     }
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    if (keyCode >= kHIDUsage_KeyboardF1 && keyCode <= kHIDUsage_KeyboardF12)
+        return makeNSStringWithCharacter(NSF1FunctionKey + (keyCode - kHIDUsage_KeyboardF1));
+    if (keyCode >= kHIDUsage_KeyboardF13 && keyCode <= kHIDUsage_KeyboardF24)
+        return makeNSStringWithCharacter(NSF13FunctionKey + (keyCode - kHIDUsage_KeyboardF13));
+#endif
     return characters;
 }
 
index d3d7554..3f26d5f 100644 (file)
@@ -1,3 +1,59 @@
+2019-02-18  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content-editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192824
+        <rdar://problem/47100332>
+
+        Reviewed by Wenson Hsieh.
+
+        Use the same code path for key events to editable elements and non-editable elements.
+
+        Currently we have different code paths for hardware key events depending on whether the active element
+        is editable or non-editable. Historically to support dispatching DOM keyboard events for hardware key
+        presses this differentiation was a necessary workaround for UIKit's event processing precedence of
+        interpreting key events for system text editing commands and app commands before dispatching unhandled
+        key events to WebKit. This workaround intercepted raw key UIEvents and manually reconstructed a
+        WebEvent from it. However there is not enough information in an UIEvent to reconstruct a WebEvent that
+        is identical to the WebEvent that UIKit would have dispatched. In particular, keyup UIEvents always have
+        empty modified and unmodified input strings. The UIKit keyboard machinery maintains additional state
+        that is necessary to manufacture the correct WebEvent corresponding to a UIEvent.
+
+        As a side benefit of this change, with the exception of modifier flag changes, both hardware and software
+        key events use the same code path.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView shouldShowAutomaticKeyboardUI]): Extracted code from _requiresKeyboardWhenFirstResponder
+        (-[WKContentView _disableAutomaticKeyboardUI]): Implement UIKit SPI to prevent showing the keyboard UI
+        when there is no focused element now that we are no longer intercepting key UIEvents. Formerly the
+        keyboard UI was disabled as a side effect of not becoming first responder when there was no focused
+        element (by returning NO in -_requiresKeyboardWhenFirstResponder).
+        (-[WKContentView _requiresKeyboardWhenFirstResponder]): Always return YES when building with USE(UIKIT_KEYBOARD_ADDITIONS)
+        so that we always accept key events. Instead of selectively replying to create a keyboard as a means of
+        hiding the automatic keyboard UI we now implement _disableAutomaticKeyboardUI to selectively hide the
+        automatic keyboard UI.
+        (-[WKContentView applyAutocorrection:toString:withCompletionHandler:]): If we are not in an editable
+        element then we cannot perform the replacement. This logic was necessary now that we always require a
+        keyboard.
+        (-[WKContentView requestAutocorrectionContextWithCompletionHandler:]): If we are not in an editable
+        element then return an autocorrection object that indicates that we could not compute this data. This
+        logic was necessary now that we always require a keyboard.
+        (-[WKContentView textInputTraits]): Do not update traits when the keyboard is going to be dismissed
+        now that we require a keyboard when first responder even if the focused element is non-editable.
+        (-[WKContentView _didHandleKeyEvent:eventWasHandled:]): Skip logic for re-sending UIEvents to UIKit
+        as UIKit now processes the event first. This logic was necessary in order to finally allow UIKit
+        its chance to interpret the UIEvent, we intercepted, for app key commands.
+        (-[WKContentView _elementDidBlur]): Call [self _endEditing] so that we dismiss any open form controls
+        (e.g. a <select> popover menu). Currently this happens either by -_requiresKeyboardWhenFirstResponder
+        responding NO when switching to another field or pressing Tab or Shift + Tab key command, which we will
+        no longer use when building with USE(UIKIT_KEYBOARD_ADDITIONS) once I land <https://bugs.webkit.org/show_bug.cgi?id=193048>.
+        * UIProcess/ios/forms/WKFormSelectPopover.mm:
+        (-[WKSelectPopover initWithView:hasGroups:]): Do not assign ourself as the keyboard delegate. Otherwise,
+        type ahead and tab cycling will not work. Currently type ahead and tab cycling work by using the non-
+        editable code path via -_handleKeyUIEvent. Now that we no longer differentiate between key events for
+        editable and non-editable elements we need to ensure that the WKContentView is the keyboard delegate
+        when the popover is presented.
+
 2019-02-18  Jiewen Tan  <jiewen_tan@apple.com>
 
         Tell Networking Process to not optimize load
index dd4cc3c..ee41cef 100644 (file)
@@ -261,7 +261,9 @@ struct WKAutoCorrectionData {
     WebKit::InteractionInformationAtPosition _positionInformation;
     WebKit::FocusedElementInformation _focusedElementInformation;
     RetainPtr<NSObject<WKFormPeripheral>> _inputPeripheral;
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
     RetainPtr<UIEvent> _uiEventBeingResent;
+#endif
     BlockPtr<void(::WebEvent *, BOOL)> _keyWebEventHandler;
 
     CGPoint _lastInteractionLocation;
index e758740..d7c14ce 100644 (file)
@@ -59,7 +59,6 @@
 #import "WKTextInputListViewController.h"
 #import "WKTimePickerViewController.h"
 #import "WKUIDelegatePrivate.h"
-#import "WKWebEvent.h"
 #import "WKWebViewConfiguration.h"
 #import "WKWebViewConfigurationPrivate.h"
 #import "WKWebViewInternal.h"
 #import "WKFormColorControl.h"
 #endif
 
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
+#import "WKWebEvent.h"
+#endif
+
 #if USE(APPLE_INTERNAL_SDK) && __has_include(<WebKitAdditions/WKPlatformFileUploadPanel.mm>)
 #import <WebKitAdditions/WKPlatformFileUploadPanel.mm>
 #endif
@@ -1497,9 +1500,9 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
     [_textSelectionAssistant didEndScrollingOverflow];
 }
 
-- (BOOL)_requiresKeyboardWhenFirstResponder
+- (BOOL)shouldShowAutomaticKeyboardUI
 {
-    // FIXME: We should add the logic to handle keyboard visibility during focus redirects.
+    // FIXME: Make this function knowledgeable about the HTML attribute inputmode.
     switch (_focusedElementInformation.elementType) {
     case WebKit::InputType::None:
     case WebKit::InputType::Drawing:
@@ -1519,6 +1522,25 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
     return NO;
 }
 
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+- (BOOL)_disableAutomaticKeyboardUI
+{
+    // Always enable automatic keyboard UI if we are not the first responder to avoid
+    // interfering with other focused views (e.g. Find-in-page).
+    return [self isFirstResponder] && ![self shouldShowAutomaticKeyboardUI];
+}
+#endif
+
+- (BOOL)_requiresKeyboardWhenFirstResponder
+{
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    return YES;
+#else
+    // FIXME: We should add the logic to handle keyboard visibility during focus redirects.
+    return [self shouldShowAutomaticKeyboardUI];
+#endif
+}
+
 - (BOOL)_requiresKeyboardResetOnReload
 {
     return YES;
@@ -3457,6 +3479,14 @@ static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoi
 // The completion handler should pass the rect of the correction text after replacing the input text, or nil if the replacement could not be performed.
 - (void)applyAutocorrection:(NSString *)correction toString:(NSString *)input withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForCorrection))completionHandler
 {
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    if ([self _disableAutomaticKeyboardUI]) {
+        if (completionHandler)
+            completionHandler(nil);
+        return;
+    }
+#endif
+
     // FIXME: Remove the synchronous call when <rdar://problem/16207002> is fixed.
     const bool useSyncRequest = true;
 
@@ -3477,6 +3507,13 @@ static void selectionChangedWithTouch(WKContentView *view, const WebCore::IntPoi
     if (!completionHandler)
         return;
 
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    if ([self _disableAutomaticKeyboardUI]) {
+        completionHandler([WKAutocorrectionContext autocorrectionContextWithContext:(WebKit::WebAutocorrectionContext { })]);
+        return;
+    }
+#endif
+
     // FIXME: Remove the synchronous call when <rdar://problem/16207002> is fixed.
     const bool useSyncRequest = true;
 
@@ -3983,6 +4020,12 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
     if (!_traits)
         _traits = adoptNS([[UITextInputTraits alloc] init]);
 
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    // Do not change traits when dismissing the keyboard.
+    if (_isBlurringFocusedNode)
+        return _traits.get();
+#endif
+
     [_traits setSecureTextEntry:_focusedElementInformation.elementType == WebKit::InputType::Password || [_formInputSession forceSecureTextEntry]];
     [_traits setShortcutConversionType:_focusedElementInformation.elementType == WebKit::InputType::Password ? UITextShortcutConversionTypeNo : UITextShortcutConversionTypeDefault];
 
@@ -4140,6 +4183,7 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
     return YES;
 }
 
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
 - (void)_handleKeyUIEvent:(::UIEvent *)event
 {
     bool isHardwareKeyboardEvent = !!event._hidEvent;
@@ -4164,6 +4208,7 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
     
     [self handleKeyWebEvent:webEvent.get()];
 }
+#endif
 
 - (void)handleKeyWebEvent:(::WebEvent *)theEvent
 {
@@ -4193,6 +4238,7 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
         return;
     }
 
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
     // If we aren't interacting with editable content, we still need to call [super _handleKeyUIEvent:]
     // so that keyboard repeat will work correctly. If we are interacting with editable content,
     // we already did so in _handleKeyUIEvent.
@@ -4211,6 +4257,7 @@ static NSString *contentTypeFromFieldName(WebCore::AutofillFieldName fieldName)
     _uiEventBeingResent = [(WKWebEvent *)event uiEvent];
     [super _handleKeyUIEvent:_uiEventBeingResent.get()];
     _uiEventBeingResent = nil;
+#endif
 }
 
 - (BOOL)_interpretKeyEvent:(::WebEvent *)event isCharEvent:(BOOL)isCharEvent
@@ -4827,6 +4874,10 @@ static const double minimumFocusedElementAreaForSuppressingSelectionAssistant =
     [_drawingCoordinator uninstallInkPicker];
 #endif
 
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+    [self _endEditing];
+#endif
+
     [_formInputSession invalidate];
     _formInputSession = nil;
 
index f5b6671..e2d2bbd 100644 (file)
@@ -78,7 +78,11 @@ ALLOW_DEPRECATED_DECLARATIONS_END
 
 @class WKSelectPopover;
 
+#if USE(UIKIT_KEYBOARD_ADDITIONS)
+@interface WKSelectTableViewController : UITableViewController
+#else
 @interface WKSelectTableViewController : UITableViewController <UIKeyInput>
+#endif
 {
     NSUInteger _singleSelectionIndex;
     NSUInteger _singleSelectionSection;
@@ -359,6 +363,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     }
 }
 
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
 #pragma mark UIKeyInput delegate methods
 
 - (BOOL)hasText
@@ -374,6 +379,8 @@ ALLOW_DEPRECATED_DECLARATIONS_END
 {
 }
 
+#endif
+
 @end
 
 @implementation WKSelectPopover {
@@ -410,8 +417,10 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     ALLOW_DEPRECATED_DECLARATIONS_END
 
     [navController release];
-    
+
+#if !USE(UIKIT_KEYBOARD_ADDITIONS)
     [[UIKeyboardImpl sharedInstance] setDelegate:_tableViewController.get()];
+#endif
     
     return self;
 }
index d4f3ce3..b133c30 100644 (file)
@@ -1,3 +1,16 @@
+2019-02-18  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Keyups for non-modifier keys identified as "Dead" when not focused in a content-editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192824
+        <rdar://problem/47100332>
+
+        Reviewed by Wenson Hsieh.
+
+        Fix a bug where the wrong usage code was used for F13 thru F24.
+
+        * WebKitTestRunner/ios/HIDEventGenerator.mm:
+        (keyCodeForDOMFunctionKey):
+
 2019-02-18  Tadeu Zagallo  <tzagallo@apple.com>
 
         Bytecode cache should a have a boot-specific validation
index 94d38a4..caf76b7 100644 (file)
@@ -834,7 +834,7 @@ static Optional<uint32_t> keyCodeForDOMFunctionKey(NSString *key)
     }
     for (int i = 13; i <= 24; ++i) {
         if ([key isEqualToString:[NSString stringWithFormat:@"F%d", i]])
-            return kHIDUsage_KeyboardF13 + i - 1;
+            return kHIDUsage_KeyboardF13 + i - 13;
     }
     return WTF::nullopt;
 }