Title: [295319] branches/safari-613-branch
Revision
295319
Author
alanc...@apple.com
Date
2022-06-06 19:30:20 -0700 (Mon, 06 Jun 2022)

Log Message

Cherry-pick 97487f0eee71. rdar://problem/90755619

    [iOS 15] Unable to type in Google Docs with a hardware keyboard without refocusing editor
    https://bugs.webkit.org/show_bug.cgi?id=241308
    rdar://90755619

    Reviewed by Tim Horton.

    After the changes in r277265, we no longer call into `-reloadInputViews` when starting an input
    session after programmatically focusing an editable container with `inputmode="none"`, with a
    hardware keyboard attached. This is because `-_shouldShowKeyboardForElement:` returns `NO` (due to
    inputmode none), so we bail early at this check:

    ```
    if (!shouldShowInputView || information.elementType == WebKit::InputType::None) {
        _page->setIsShowingInputViewForFocusedElement(false);
        return;
    }
    ```

    As a result, UIKit never resets UIKeyboardImpl's input delegate, which should now be the
    `WKContentView`, and thus never consults whether we require key events (`-requiresKeyEvents`), which
    in turn means that `-handleKeyWebEvent:withCompletionHandler:` is never invoked on the content view,
    so we never dispatch key events to the page.

    In the normal, non-editable key event case, we lazily call `-reloadInputViews` in
    `-_handleKeyUIEvent:` (which is called just before keyboard WebEvents start getting dispatched by
    UIKit). However, since we're still focusing an editable element in this case, we don't end up going
    down this codepath.

    When the hardware keyboard is not connected, avoiding the call to `-reloadInputViews` is expected,
    since we aren't showing a keyboard anyways due to the fact that the element was programmatically
    focused (so the user has no way of typing or dispatching key events, in the first place).

    And finally, when the `inputmode` is not none, `_isFocusingElementWithKeyboard` is set to `YES`, so
    we begin the input session and call `-reloadInputViews` as normal.

    It's only in this `inputmode=none` case with both the hardware keyboard attached and the editable
    container being programmatically focused, where we end up in a state where the user can type with a
    hardware keyboard, but we haven't informed UIKit that we should receive key events.

    We can fix this by consulting a separate `-_shouldShowKeyboardForElementIgnoringInputMode:` instead
    which allows us to follow the normal routine for focusing an editable element with `inputmode="none"`
    which includes zooming to reveal the focused element if it's on-screen and not hidden, as well as
    calling the related delegate methods; the only difference is that we avoid showing the UCB or
    software keyboard, by returning `YES` from `-_disableAutomaticKeyboardUI` in this case.

    * LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none-expected.txt: Added.
    * LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none.html: Added.

    Add a new layout test to simulate typing in Google Docs with a hardware keyboard (i.e., focus a
    hidden contenteditable container with `inputmode="none"`), and verify that we dispatch key events to
    the focused editable element.

    * Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
    (-[WKContentView _elementTypeRequiresAccessoryView:]):
    (-[WKContentView _shouldShowKeyboardForElement:]):
    (-[WKContentView _shouldShowKeyboardForElementIgnoringInputMode:]):

    Split this helper method into two versions (one of which ignores `inputmode=none`). See above for
    more details.

    (-[WKContentView _elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:]):

    Canonical link: https://commits.webkit.org/251335@main
    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@295289 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Added Paths

Diff

Added: branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none-expected.txt (0 => 295319)


--- branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none-expected.txt	                        (rev 0)
+++ branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none-expected.txt	2022-06-07 02:30:20 UTC (rev 295319)
@@ -0,0 +1,13 @@
+This test verifies that key events are dispatched when performing a keypress in a programmatically focused hidden editable container with inputmode='none'. To manually run the test, load the page with a hardware keyboard attached and press the 'a' key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Observed keydown with key: "a"
+PASS Observed keypress with key: "a"
+PASS Observed keyup with key: "a"
+PASS observedKeyUp became true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none.html (0 => 295319)


--- branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none.html	                        (rev 0)
+++ branches/safari-613-branch/LayoutTests/fast/forms/ios/keydown-in-hidden-contenteditable-with-inputmode-none.html	2022-06-07 02:30:20 UTC (rev 295319)
@@ -0,0 +1,44 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+<script src=""
+<script src=""
+<style>
+div[contenteditable] {
+    opacity: 0;
+    position: absolute;
+    left: -1000px;
+}
+</style>
+</head>
+<body>
+<div contenteditable inputmode="none"></div>
+<script>
+jsTestIsAsync = true;
+observedKeyUp = 0;
+
+addEventListener("load", async () => {
+    description("This test verifies that key events are dispatched when performing a keypress in a programmatically focused hidden editable container with inputmode='none'. To manually run the test, load the page with a hardware keyboard attached and press the 'a' key.");
+
+    const logKeyEvent = (event) => testPassed(`Observed ${event.type} with key: "${event.key}"`);
+    const editor = document.querySelector("div[contenteditable]");
+    editor.addEventListener("keydown", logKeyEvent);
+    editor.addEventListener("keypress", logKeyEvent);
+    editor.addEventListener("keyup", (event) => {
+        logKeyEvent(event);
+        observedKeyUp = true;
+    });
+
+    await UIHelper.setHardwareKeyboardAttached(true);
+
+    editor.focus();
+    await UIHelper.keyDown("a");
+    await shouldBecomeEqual("observedKeyUp", "true");
+
+    editor.remove();
+    finishJSTest();
+});
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: branches/safari-613-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (295318 => 295319)


--- branches/safari-613-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-06-07 02:30:17 UTC (rev 295318)
+++ branches/safari-613-branch/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2022-06-07 02:30:20 UTC (rev 295319)
@@ -3406,7 +3406,7 @@
 #endif
 }
 
-- (bool)_elementTypeRequiresAccessoryView:(WebKit::InputType)type
+- (BOOL)_elementTypeRequiresAccessoryView:(WebKit::InputType)type
 {
     switch (type) {
     case WebKit::InputType::None:
@@ -3418,7 +3418,7 @@
     case WebKit::InputType::DateTimeLocal:
     case WebKit::InputType::Month:
     case WebKit::InputType::Time:
-        return false;
+        return NO;
     case WebKit::InputType::Select: {
 #if ENABLE(IOS_FORM_CONTROL_REFRESH)
         if (self._shouldUseContextMenusForFormControls)
@@ -6375,15 +6375,17 @@
     }
 }
 
-- (bool)_shouldShowKeyboardForElement:(const WebKit::FocusedElementInformation&)information
+- (BOOL)_shouldShowKeyboardForElement:(const WebKit::FocusedElementInformation&)information
 {
     if (information.inputMode == WebCore::InputMode::None)
-        return false;
+        return NO;
 
-    if (mayContainSelectableText(information.elementType))
-        return true;
+    return [self _shouldShowKeyboardForElementIgnoringInputMode:information];
+}
 
-    return [self _elementTypeRequiresAccessoryView:information.elementType];
+- (BOOL)_shouldShowKeyboardForElementIgnoringInputMode:(const WebKit::FocusedElementInformation&)information
+{
+    return mayContainSelectableText(information.elementType) || [self _elementTypeRequiresAccessoryView:information.elementType];
 }
 
 static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebKit::InputType type, WKContentView *view)
@@ -6462,7 +6464,7 @@
                 if (_isChangingFocus)
                     return YES;
 
-                if (_isFocusingElementWithKeyboard && [UIKeyboard isInHardwareKeyboardMode])
+                if ([self _shouldShowKeyboardForElementIgnoringInputMode:information] && UIKeyboard.isInHardwareKeyboardMode)
                     return YES;
 #endif
             }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to