Implement UIScriptController::toggleCapsLock() for iOS
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Dec 2018 19:19:25 +0000 (19:19 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Dec 2018 19:19:25 +0000 (19:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191815

Reviewed by Andy Estes.

Source/WebCore/PAL:

Add HID usage enumerator for the Caps Lock key.

* pal/spi/cocoa/IOKitSPI.h:

Source/WebKit:

Add test infrastructure to clear the current modifier state. We will use this to ensure that
the caps lock state does not persist between tests.

* UIProcess/API/C/WKContext.cpp:
(WKContextClearCurrentModifierStateForTesting): Added.
* UIProcess/API/C/WKContextPrivate.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::clearCurrentModifierStateForTesting): Added.
* UIProcess/WebProcessPool.h:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::clearCurrentModifierStateForTesting): Added.
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

Tools:

Add support for toggling the caps lock state in WebKitTestRunner on iOS.

* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetStateToConsistentValues): Clear the current modifier state
before running a test. This ensures that the caps lock state does not persist between
tests should a test enable caps lock and not disable it.
* WebKitTestRunner/ios/HIDEventGenerator.mm:
(hidUsageCodeForCharacter): Map "capsLock" to the Caps Lock key usage code.
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::createUIPhysicalKeyboardEvent): Modified to take the keyboard input flags to use to
create the event. Also substituted NSString* for const String& as the data type for the first
two parameters to avoid conversions in the implementation of UIScriptController::toggleCapsLock()
below.
(WTR::UIScriptController::keyDown): Update as needed due to changes to prototype of createUIPhysicalKeyboardEvent().
(WTR::UIScriptController::toggleCapsLock): Dispatch a UIEvent to toggle caps lock.

LayoutTests:

Add iOS-specific results for some of the tests. We need to continue to skip the caps
lock tests on iOS until we have the fix for <rdar://problem/44930119>.

* fast/forms/password-scrolled-after-caps-lock-toggled.html: Replace input.focus() with
UIHelper.activateElement(input) to make it work on iOS and update logic accordingly.
Compensate for the fact that one less character than the size of the input is visible in
a password field on iOS.
* fast/repaint/placeholder-after-caps-lock-hidden.html: Replace input.focus() with
UIHelper.activateElement(input) to make it work on iOS and update logic accordingly.
* platform/ios-wk2/TestExpectations:
* platform/ios-wk2/fast/forms/password-scrolled-after-caps-lock-toggled-expected.txt: Added.
* platform/ios-wk2/fast/repaint/placeholder-after-caps-lock-hidden-expected.txt: Added.

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/forms/password-scrolled-after-caps-lock-toggled.html
LayoutTests/fast/repaint/placeholder-after-caps-lock-hidden.html
LayoutTests/platform/ios-wk2/TestExpectations
LayoutTests/platform/ios-wk2/fast/forms/password-scrolled-after-caps-lock-toggled-expected.txt [new file with mode: 0644]
LayoutTests/platform/ios-wk2/fast/repaint/placeholder-after-caps-lock-hidden-expected.txt [new file with mode: 0644]
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/cocoa/IOKitSPI.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/C/WKContext.cpp
Source/WebKit/UIProcess/API/C/WKContextPrivate.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/WebProcess/WebProcess.cpp
Source/WebKit/WebProcess/WebProcess.h
Source/WebKit/WebProcess/WebProcess.messages.in
Tools/ChangeLog
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/ios/HIDEventGenerator.mm
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

index 754ab34..f7f8580 100644 (file)
@@ -1,3 +1,23 @@
+2018-12-17  Daniel Bates  <dabates@apple.com>
+
+        Implement UIScriptController::toggleCapsLock() for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=191815
+
+        Reviewed by Andy Estes.
+
+        Add iOS-specific results for some of the tests. We need to continue to skip the caps
+        lock tests on iOS until we have the fix for <rdar://problem/44930119>.
+
+        * fast/forms/password-scrolled-after-caps-lock-toggled.html: Replace input.focus() with
+        UIHelper.activateElement(input) to make it work on iOS and update logic accordingly.
+        Compensate for the fact that one less character than the size of the input is visible in
+        a password field on iOS.
+        * fast/repaint/placeholder-after-caps-lock-hidden.html: Replace input.focus() with
+        UIHelper.activateElement(input) to make it work on iOS and update logic accordingly.
+        * platform/ios-wk2/TestExpectations:
+        * platform/ios-wk2/fast/forms/password-scrolled-after-caps-lock-toggled-expected.txt: Added.
+        * platform/ios-wk2/fast/repaint/placeholder-after-caps-lock-hidden-expected.txt: Added.
+
 2018-12-17  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r233268): Elements animated in from offscreen sometimes don't display
index 33fd6b2..0c5e10c 100644 (file)
@@ -52,9 +52,15 @@ function runTest()
 function testFocusedEmptyFieldIsNotScrolled()
 {
     debug("Case 1: Empty field:");
-    input.focus();
-    shouldBeZero("document.getElementById('input').scrollLeft");
-    runNextTest();
+    function handleFocus() {
+        shouldBeZero("document.getElementById('input').scrollLeft");
+        runNextTest();
+    }
+    input.addEventListener("focus", handleFocus, { once: true });
+    if (window.testRunner)
+        UIHelper.activateElement(input);
+    else
+        input.focus();
 }
 
 function testFieldDidNotScrollAfterTyping()
@@ -90,10 +96,10 @@ function _toggleCapsLockWithCallbackAndRunNextTest(expectCapsLockEnabled, callba
         eventToListenFor = "keyup";
     }
 
-    let oldValue = document.getElementById('input').scrollLeft;
+    let oldValue = document.getElementById("input").scrollLeft;
     function handleCapsLockChange(event) {
         console.assert(event.key === "CapsLock");
-        callback(oldValue, document.getElementById('input').scrollLeft);
+        callback(oldValue, document.getElementById("input").scrollLeft);
         runNextTest();
     }
     input.addEventListener(eventToListenFor, handleCapsLockChange, { once: true });
@@ -166,6 +172,14 @@ function done()
 input = document.getElementById("input");
 console.assert(input.hasAttribute("size"));
 numberOfCharactersToOverflowFieldWhenCapsLockShown = input.size;
+
+// FIXME: Find a way to compute the maximum number of visible characters the field can hold
+// in a way that allows for running this test by hand.
+let mayBeIOS = window.TouchEvent != undefined;
+if (mayBeIOS) {
+    // The look of the password field on iOS gives less space to the value than on Mac.
+    --numberOfCharactersToOverflowFieldWhenCapsLockShown;
+}
 console.assert(numberOfCharactersToOverflowFieldWhenCapsLockShown >= 3);
 
 description("Tests that the password field is scrolled when the caps lock indicator is toggled.");
index d16f298..2533b7a 100644 (file)
@@ -38,15 +38,17 @@ function runTest()
         return;
 
     let input = document.getElementById("input");
-    input.focus();
-
-    function handleCapsLockEnabled(event) {
-        console.assert(event.key === "CapsLock");
-        input.addEventListener("keyup", handleKeyUp, false);
-        UIHelper.keyDown("a");
+    function handleFocus() {
+        function handleCapsLockEnabled(event) {
+            console.assert(event.key === "CapsLock");
+            input.addEventListener("keyup", handleKeyUp, false);
+            UIHelper.keyDown("a");
+        }
+        input.addEventListener("keydown", handleCapsLockEnabled, { once: true });
+        UIHelper.toggleCapsLock();
     }
-    input.addEventListener("keydown", handleCapsLockEnabled, { once: true });
-    UIHelper.toggleCapsLock();
+    input.addEventListener("focus", handleFocus, { once: true });
+    UIHelper.activateElement(input);
 }
 </script>
 </head>
index 41872a2..c36183d 100644 (file)
@@ -1323,4 +1323,10 @@ http/wpt/webauthn/public-key-credential-create-failure-hid.https.html [ Skip ]
 http/wpt/webauthn/public-key-credential-create-success-hid.https.html [ Skip ]
 http/wpt/webauthn/public-key-credential-get-failure-hid-silent.https.html [ Skip ]
 http/wpt/webauthn/public-key-credential-get-failure-hid.https.html [ Skip ]
-http/wpt/webauthn/public-key-credential-get-success-hid.https.html [ Skip ]
\ No newline at end of file
+http/wpt/webauthn/public-key-credential-get-success-hid.https.html [ Skip ]
+
+# FIXME: Unskip these tests once we have the fix for <rdar://problem/44930119>.
+fast/forms/auto-fill-button/caps-lock-indicator-should-be-visible-after-hiding-auto-fill-strong-password-button.html [ Skip ]
+fast/forms/auto-fill-button/caps-lock-indicator-should-not-be-visible-when-auto-fill-strong-password-button-is-visible.html [ Skip ]
+fast/forms/password-scrolled-after-caps-lock-toggled.html [ Skip ]
+fast/repaint/placeholder-after-caps-lock-hidden.html [ Skip ]
diff --git a/LayoutTests/platform/ios-wk2/fast/forms/password-scrolled-after-caps-lock-toggled-expected.txt b/LayoutTests/platform/ios-wk2/fast/forms/password-scrolled-after-caps-lock-toggled-expected.txt
new file mode 100644 (file)
index 0000000..574ce22
--- /dev/null
@@ -0,0 +1,45 @@
+Tests that the password field is scrolled when the caps lock indicator is toggled.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Case 1: Empty field:
+PASS document.getElementById('input').scrollLeft is 0
+
+After caps lock enabled:
+PASS document.getElementById('input').scrollLeft is 0
+
+After caps lock disabled:
+PASS document.getElementById('input').scrollLeft is 0
+
+Case 2: After typing into field:
+PASS document.getElementById('input').scrollLeft is 0
+
+After caps lock enabled:
+PASS document.getElementById('input').scrollLeft is non-zero.
+
+After caps lock disabled:
+PASS document.getElementById('input').scrollLeft is 0
+
+Case 3: After selecting the first 2 characters:
+PASS document.getElementById('input').scrollLeft is 0
+
+After caps lock enabled:
+FAIL document.getElementById('input').scrollLeft should be 0. Was 3.
+
+After caps lock disabled:
+PASS document.getElementById('input').scrollLeft is 0
+
+Case 4: After selecting the last 2 characters:
+PASS document.getElementById('input').scrollLeft is 0
+
+After caps lock enabled:
+PASS document.getElementById('input').scrollLeft is non-zero.
+
+After caps lock disabled:
+PASS document.getElementById('input').scrollLeft is 0
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/ios-wk2/fast/repaint/placeholder-after-caps-lock-hidden-expected.txt b/LayoutTests/platform/ios-wk2/fast/repaint/placeholder-after-caps-lock-hidden-expected.txt
new file mode 100644 (file)
index 0000000..c729569
--- /dev/null
@@ -0,0 +1,27 @@
+Tests that the placeholder text is repainted when the caps lock indicator is hidden.
+
+
+(repaint rects
+  (rect 25 50.50 27 27)
+  (rect 30 55.50 17 17)
+  (rect 11.50 50.50 23.50 24)
+  (rect 16.50 57 13.50 14)
+  (rect 11.50 50.50 40.50 24)
+  (rect 16.50 57 30.50 14)
+  (rect 25 50.50 27 24)
+  (rect 30 57 17 14)
+  (rect 25 50.50 10 24)
+  (rect 11.50 49 40.50 27)
+  (rect 16.50 55.50 30.50 17)
+  (rect 11.50 49 40.50 24)
+  (rect 16.50 55.50 30.50 14)
+  (rect 11.50 50.50 40.50 27)
+  (rect 16.50 55.50 30.50 17)
+  (rect 11.50 52 40.50 24)
+  (rect 16.50 57 30.50 14)
+  (rect 11.50 52 23.50 24)
+  (rect 16.50 57 13.50 14)
+  (rect 11.50 52 40.50 24)
+  (rect 16.50 57 30.50 14)
+)
+
index f613ff2..8f91cad 100644 (file)
@@ -1,3 +1,14 @@
+2018-12-17  Daniel Bates  <dabates@apple.com>
+
+        Implement UIScriptController::toggleCapsLock() for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=191815
+
+        Reviewed by Andy Estes.
+
+        Add HID usage enumerator for the Caps Lock key.
+
+        * pal/spi/cocoa/IOKitSPI.h:
+
 2018-12-17  Matt Lewis  <jlewis3@apple.com>
 
         Unreviewed, rolling out r239254.
index e366014..207a5d5 100644 (file)
@@ -183,6 +183,7 @@ enum {
     kHIDUsage_KeyboardComma = 0x36,
     kHIDUsage_KeyboardPeriod = 0x37,
     kHIDUsage_KeyboardSlash = 0x38,
+    kHIDUsage_KeyboardCapsLock = 0x39,
     kHIDUsage_KeyboardF1 = 0x3A,
     kHIDUsage_KeyboardPrintScreen = 0x46,
     kHIDUsage_KeyboardInsert = 0x49,
index 4fa9ebe..8fcc3d5 100644 (file)
@@ -1,3 +1,24 @@
+2018-12-17  Daniel Bates  <dabates@apple.com>
+
+        Implement UIScriptController::toggleCapsLock() for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=191815
+
+        Reviewed by Andy Estes.
+
+        Add test infrastructure to clear the current modifier state. We will use this to ensure that
+        the caps lock state does not persist between tests.
+
+        * UIProcess/API/C/WKContext.cpp:
+        (WKContextClearCurrentModifierStateForTesting): Added.
+        * UIProcess/API/C/WKContextPrivate.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::clearCurrentModifierStateForTesting): Added.
+        * UIProcess/WebProcessPool.h:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::clearCurrentModifierStateForTesting): Added.
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+
 2018-12-17  David Kilzer  <ddkilzer@apple.com>
 
         REGRESSION (r239262): Fix broken builds prior to Mojave
index 2389ec8..2d1d89c 100644 (file)
@@ -649,3 +649,8 @@ void WKContextSetIDBPerOriginQuota(WKContextRef contextRef, uint64_t quota)
 {
     WebKit::toImpl(contextRef)->setIDBPerOriginQuota(quota);
 }
+
+void WKContextClearCurrentModifierStateForTesting(WKContextRef contextRef)
+{
+    toImpl(contextRef)->clearCurrentModifierStateForTesting();
+}
index 46d37e1..f9c7d32 100644 (file)
@@ -118,6 +118,8 @@ WK_EXPORT void WKContextClearSupportedPlugins(WKContextRef context);
 
 WK_EXPORT void WKContextSetIDBPerOriginQuota(WKContextRef context, uint64_t quota);
 
+WK_EXPORT void WKContextClearCurrentModifierStateForTesting(WKContextRef context);
+
 #ifdef __cplusplus
 }
 #endif
index c8f805e..fa43a3d 100644 (file)
@@ -2358,4 +2358,9 @@ void WebProcessPool::tryPrewarmWithDomainInformation(WebProcessProxy& process, c
     process.send(Messages::WebProcess::PrewarmWithDomainInformation(*prewarmInformation), 0);
 }
 
+void WebProcessPool::clearCurrentModifierStateForTesting()
+{
+    sendToAllProcesses(Messages::WebProcess::ClearCurrentModifierStateForTesting());
+}
+
 } // namespace WebKit
index 076794d..0634324 100644 (file)
@@ -467,6 +467,7 @@ public:
     void resetMockMediaDevices();
 
     void sendDisplayConfigurationChangedMessageForTesting();
+    void clearCurrentModifierStateForTesting();
 
 #if PLATFORM(GTK) || PLATFORM(WPE)
     void setSandboxEnabled(bool enabled) { m_sandboxEnabled = enabled; };
index 2831aaa..09cea95 100644 (file)
 #include <WebCore/Page.h>
 #include <WebCore/PageCache.h>
 #include <WebCore/PageGroup.h>
+#include <WebCore/PlatformKeyboardEvent.h>
 #include <WebCore/PlatformMediaSessionManager.h>
 #include <WebCore/ProcessWarming.h>
 #include <WebCore/ResourceLoadObserver.h>
@@ -1761,4 +1762,9 @@ void WebProcess::resetMockMediaDevices()
 }
 #endif
 
+void WebProcess::clearCurrentModifierStateForTesting()
+{
+    PlatformKeyboardEvent::setCurrentModifierState({ });
+}
+
 } // namespace WebKit
index 9172ee1..23dec03 100644 (file)
@@ -399,6 +399,8 @@ private:
 #endif
 #endif
 
+    void clearCurrentModifierStateForTesting();
+
     RefPtr<WebConnectionToUIProcess> m_webConnection;
 
     HashMap<uint64_t, RefPtr<WebPage>> m_pageMap;
index 2b19851..7b4752d 100644 (file)
@@ -153,4 +153,6 @@ messages -> WebProcess LegacyReceiver {
     RemoveMockMediaDevice(String persistentId);
     ResetMockMediaDevices();
 #endif
+
+    ClearCurrentModifierStateForTesting()
 }
index e456f27..3cf02fe 100644 (file)
@@ -1,5 +1,29 @@
 2018-12-17  Daniel Bates  <dabates@apple.com>
 
+        Implement UIScriptController::toggleCapsLock() for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=191815
+
+        Reviewed by Andy Estes.
+
+        Add support for toggling the caps lock state in WebKitTestRunner on iOS.
+
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::resetStateToConsistentValues): Clear the current modifier state
+        before running a test. This ensures that the caps lock state does not persist between
+        tests should a test enable caps lock and not disable it.
+        * WebKitTestRunner/ios/HIDEventGenerator.mm:
+        (hidUsageCodeForCharacter): Map "capsLock" to the Caps Lock key usage code.
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::createUIPhysicalKeyboardEvent): Modified to take the keyboard input flags to use to
+        create the event. Also substituted NSString* for const String& as the data type for the first
+        two parameters to avoid conversions in the implementation of UIScriptController::toggleCapsLock()
+        below.
+        (WTR::UIScriptController::keyDown): Update as needed due to changes to prototype of createUIPhysicalKeyboardEvent().
+        (WTR::UIScriptController::toggleCapsLock): Dispatch a UIEvent to toggle caps lock.
+
+2018-12-17  Daniel Bates  <dabates@apple.com>
+
         [iOS] Remove -[WebEvent initWithKeyEventType:...:characterSet:]
         https://bugs.webkit.org/show_bug.cgi?id=192633
 
index 7621470..72184d0 100644 (file)
@@ -228,7 +228,7 @@ private:
 
     UIScriptContext* m_context;
 
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
     bool m_capsLockOn { false };
 #endif
 };
index 0850558..2f98ed3 100644 (file)
@@ -872,6 +872,8 @@ bool TestController::resetStateToConsistentValues(const TestOptions& options, Re
 
     WKContextSetAllowsAnySSLCertificateForServiceWorkerTesting(platformContext(), true);
 
+    WKContextClearCurrentModifierStateForTesting(TestController::singleton().context());
+
     // FIXME: This function should also ensure that there is only one page open.
 
     // Reset the EventSender for each test.
index 50e7aeb..a94e44a 100644 (file)
@@ -925,6 +925,8 @@ static inline uint32_t hidUsageCodeForCharacter(NSString *key)
     if (auto keyCode = keyCodeForDOMFunctionKey(key))
         return *keyCode;
 
+    if ([key isEqualToString:@"capsLock"])
+        return kHIDUsage_KeyboardCapsLock;
     if ([key isEqualToString:@"pageUp"])
         return kHIDUsage_KeyboardPageUp;
     if ([key isEqualToString:@"pageDown"])
index a9d54ad..5832853 100644 (file)
@@ -400,9 +400,9 @@ static UIKeyModifierFlags parseModifierArray(JSContextRef context, JSValueRef ar
     return modifiers;
 }
 
-static UIPhysicalKeyboardEvent *createUIPhysicalKeyboardEvent(const String& hidInputString, const String& uiEventInputString, UIKeyModifierFlags modifierFlags, bool isKeyDown)
+static UIPhysicalKeyboardEvent *createUIPhysicalKeyboardEvent(NSString *hidInputString, NSString *uiEventInputString, UIKeyModifierFlags modifierFlags, UIKeyboardInputFlags inputFlags, bool isKeyDown)
 {
-    auto* keyboardEvent = [getUIPhysicalKeyboardEventClass() _eventWithInput:uiEventInputString inputFlags:(UIKeyboardInputFlags)0];
+    auto* keyboardEvent = [getUIPhysicalKeyboardEventClass() _eventWithInput:uiEventInputString inputFlags:inputFlags];
     keyboardEvent._modifierFlags = modifierFlags;
     auto hidEvent = createHIDKeyEvent(hidInputString, keyboardEvent.timestamp, isKeyDown);
     [keyboardEvent _setHIDEvent:hidEvent.get() keyboard:nullptr];
@@ -422,15 +422,16 @@ void UIScriptController::keyDown(JSStringRef character, JSValueRef modifierArray
     String inputString = toWTFString(toWK(character));
     String uiEventInputString = inputString.length() > 1 ? emptyString() : inputString;
     auto modifierFlags = parseModifierArray(m_context->jsContext(), modifierArray);
+    UIKeyboardInputFlags inputFlags = static_cast<UIKeyboardInputFlags>(0);
 
     // Note that UIKit will call -release on the passed UIPhysicalKeyboardEvent.
 
     // Key down
-    auto* keyboardEvent = createUIPhysicalKeyboardEvent(inputString, uiEventInputString, modifierFlags, true /* isKeyDown */);
+    auto* keyboardEvent = createUIPhysicalKeyboardEvent(inputString, uiEventInputString, modifierFlags, inputFlags, true /* isKeyDown */);
     [[UIApplication sharedApplication] handleKeyUIEvent:keyboardEvent];
 
     // Key up
-    keyboardEvent = createUIPhysicalKeyboardEvent(inputString, uiEventInputString, modifierFlags, false /* isKeyDown */);
+    keyboardEvent = createUIPhysicalKeyboardEvent(inputString, uiEventInputString, modifierFlags, inputFlags, false /* isKeyDown */);
     [[UIApplication sharedApplication] handleKeyUIEvent:keyboardEvent];
 }
 
@@ -932,7 +933,10 @@ void UIScriptController::setKeyboardInputModeIdentifier(JSStringRef identifier)
 
 void UIScriptController::toggleCapsLock(JSValueRef callback)
 {
-    // FIXME: Implement for iOS. See <https://bugs.webkit.org/show_bug.cgi?id=191815>.
+    m_capsLockOn = !m_capsLockOn;
+    auto *keyboardEvent = createUIPhysicalKeyboardEvent(@"capsLock", [NSString string], m_capsLockOn ? UIKeyModifierAlphaShift : 0,
+        kUIKeyboardInputModifierFlagsChanged, m_capsLockOn);
+    [[UIApplication sharedApplication] handleKeyUIEvent:keyboardEvent];
     doAsyncTask(callback);
 }