[iOS] Software keyboard is shown too frequently on some websites
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Apr 2019 17:30:00 +0000 (17:30 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Apr 2019 17:30:00 +0000 (17:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195856
<rdar://problem/49191395>

Reviewed by Darin Adler.

Source/WebCore/PAL:

Declare new GraphicsServices SPI.

* pal/spi/ios/GraphicsServicesSPI.h:

Source/WebKit:

On some websites, hidden editable elements are very frequently focused upon user interaction. Currently, this
causes the software keyboard to pop in and out unexpectedly; luckily, these same sites also apply
inputmode="none" to the hidden editable element, which ought to ensure that the software keyboard doesn't appear
when the element is focused.

However, since we disabled support for inputmode="none" in r240497, the software keyboard is no longer
suppressed, and becomes a big nuissance. r240497 removed support for this feature because, when using a hardware
keyboard, pressing the globe key no longer showed UI for switching languages. However, support for inputmode
none makes a much larger impact when a software keyboard is used (since the entire software keyboard animates in
and out), whereas a hardware keyboard only displays an input accessory view. For this reason, we can mitigate
this bug without reintroducing <rdar://problem/47406553> by re-enabling inputmode="none", but only when a
hardware keyboard is not attached.

* UIProcess/API/Cocoa/WKWebView.mm:
(hardwareKeyboardAvailabilityChangedCallback):
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView shouldShowAutomaticKeyboardUI]):

Don't show the keyboard if inputmode is none and a hardware keyboard is not attached.

(-[WKContentView _hardwareKeyboardAvailabilityChanged]):

Reload input views if the inputmode is none to ensure that if a hardware keyboard is attached while editing an
element with inputmode="none", we'll show the input accessory view once again.

Tools:

Add support for attaching or detaching the hardware keyboard on iOS in layout tests.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::setHardwareKeyboardAttached):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::setHardwareKeyboardAttached):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/Configurations/WebKitTestRunnerApp.xcconfig:

Additionally link against GraphicsServices in WebKitTestRunner.

* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::TestController::platformResetStateToConsistentValues):
(WTR::UIScriptController::setHardwareKeyboardAttached):

WebKitLibraries:

Add a symbol for GSEventSetHardwareKeyboardAttached.

* WebKitPrivateFrameworkStubs/iOS/12/GraphicsServices.framework/GraphicsServices.tbd:

LayoutTests:

Fix a failing layout test, which (among other reasons) is currently failing because support for inputmode="none"
is disabled.

* fast/forms/ios/inputmode-none-expected.txt:
* fast/forms/ios/inputmode-none.html:
* resources/ui-helper.js:

Add a UIHelper method for attaching or detaching the hardware keyboard.

(window.UIHelper.setHardwareKeyboardAttached):
(window.UIHelper):

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

20 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/forms/ios/inputmode-none-expected.txt
LayoutTests/fast/forms/ios/inputmode-none.html
LayoutTests/resources/ui-helper.js
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/ios/GraphicsServicesSPI.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/Configurations/WebKitTestRunnerApp.xcconfig
Tools/WebKitTestRunner/ios/TestControllerIOS.mm
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm
WebKitLibraries/ChangeLog
WebKitLibraries/WebKitPrivateFrameworkStubs/iOS/12/GraphicsServices.framework/GraphicsServices.tbd

index 741df96..e675084 100644 (file)
@@ -1,3 +1,23 @@
+2019-04-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Software keyboard is shown too frequently on some websites
+        https://bugs.webkit.org/show_bug.cgi?id=195856
+        <rdar://problem/49191395>
+
+        Reviewed by Darin Adler.
+
+        Fix a failing layout test, which (among other reasons) is currently failing because support for inputmode="none"
+        is disabled.
+
+        * fast/forms/ios/inputmode-none-expected.txt:
+        * fast/forms/ios/inputmode-none.html:
+        * resources/ui-helper.js:
+
+        Add a UIHelper method for attaching or detaching the hardware keyboard.
+
+        (window.UIHelper.setHardwareKeyboardAttached):
+        (window.UIHelper):
+
 2019-04-12  Ryan Haddad  <ryanhaddad@apple.com>
 
         [macOS WK1] ASSERTION FAILED: formData in WebCore::ResourceRequest::doUpdateResourceHTTPBody()
index b1c4c83..92b8e3f 100644 (file)
@@ -1,27 +1,27 @@
+
+
 This test verifies that the system keyboard is not visible when tapping on an input field with inputmode=none.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-
 ACTIVATE input with inputmode=text
-PASS textKeyboardHeight = systemKeyboardRect.height; systemKeyboardRect.height > 0 is true
-PASS inputWithSystemKeyboard.value is "Text"
+PASS systemKeyboardRect.height > 0 is true
+PASS inputWithSystemKeyboard.value is 'Text'
 
 ACTIVATE input with inputmode=none
-PASS systemKeyboardRect.height is textKeyboardHeight
+PASS Successfully dismissed keyboard
 
 TEST enter text in input with inputmode=none
-PASS inputWithoutSystemKeyboard.value is "None"
+PASS inputWithoutSystemKeyboard.value is 'None'
 
 TEST selection in input with inputmode=none
 PASS selectionRects.length is 1
-PASS selectionRects[0].left is 159
-PASS selectionRects[0].top is 261
-PASS selectionRects[0].width is 28
+PASS selectionRects[0].left is 16
+PASS selectionRects[0].top is 38
+PASS selectionRects[0].width is 27
 PASS selectionRects[0].height is 15
-
 PASS successfullyParsed is true
 
 TEST COMPLETE
+
index f2f6a35..92d8396 100644 (file)
@@ -1,48 +1,53 @@
-<!DOCTYPE html>
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
 <html>
 <head>
-<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
 <script src="../../../resources/js-test.js"></script>
 <script src="../../../resources/ui-helper.js"></script>
 </head>
 <body onload="runTest()">
-<input id="input-keyboard" inputmode="text">
-<input id="input-nokeyboard" inputmode="none">
+<div><input id="input-keyboard" inputmode="text"></div>
+<div><input id="input-nokeyboard" inputmode="none"></div>
+<pre id="description"></pre>
+<pre id="console"></pre>
 <script>
 jsTestIsAsync = true;
 
 async function runTest() {
+    await UIHelper.setHardwareKeyboardAttached(false);
     inputWithSystemKeyboard = document.getElementById("input-keyboard");
     inputWithoutSystemKeyboard = document.getElementById("input-nokeyboard");
 
-    description('This test verifies that the system keyboard is not visible when tapping on an input field with inputmode=none.');
+    description("This test verifies that the system keyboard is not visible when tapping on an input field with inputmode=none.");
 
-    debug('\nACTIVATE input with inputmode=text');
-    await UIHelper.activateFormControl(inputWithSystemKeyboard);
+    debug("\nACTIVATE input with inputmode=text");
+    await UIHelper.activateElementAndWaitForInputSession(inputWithSystemKeyboard);
     systemKeyboardRect = await UIHelper.inputViewBounds();
-    shouldBe('textKeyboardHeight = systemKeyboardRect.height; systemKeyboardRect.height > 0', 'true');
+    shouldBe("systemKeyboardRect.height > 0", "true");
     await UIHelper.enterText("Text");
-    shouldBe('inputWithSystemKeyboard.value', '"Text"');
+    shouldBe("inputWithSystemKeyboard.value", "'Text'");
 
-    debug('\nACTIVATE input with inputmode=none');
-    await UIHelper.activateFormControl(inputWithoutSystemKeyboard);
-    systemKeyboardRect = await UIHelper.inputViewBounds();
-    shouldBe('systemKeyboardRect.height', 'textKeyboardHeight');
+    debug("\nACTIVATE input with inputmode=none");
+    await UIHelper.activateElement(inputWithoutSystemKeyboard);
+    await UIHelper.waitForKeyboardToHide();
+    testPassed("Successfully dismissed keyboard");
 
-    debug('\nTEST enter text in input with inputmode=none');
+    debug("\nTEST enter text in input with inputmode=none");
     await UIHelper.enterText("None");
-    shouldBe('inputWithoutSystemKeyboard.value', '"None"');
-
-    debug('\nTEST selection in input with inputmode=none');
-    inputWithoutSystemKeyboard.setSelectionRange(0, inputWithSystemKeyboard.value.length);
-    selectionRects = await UIHelper.getUISelectionRects();
-    shouldBe('selectionRects.length', '1');
-    shouldBe('selectionRects[0].left', '159');
-    shouldBe('selectionRects[0].top', '261');
-    shouldBe('selectionRects[0].width', '28');
-    shouldBe('selectionRects[0].height', '15');
-
-    debug('');
+    shouldBe("inputWithoutSystemKeyboard.value", "'None'");
+
+    debug("\nTEST selection in input with inputmode=none");
+    inputWithoutSystemKeyboard.select();
+
+    selectionRects = [];
+    while (!selectionRects.length)
+        selectionRects = await UIHelper.getUISelectionViewRects();
+
+    shouldBe("selectionRects.length", "1");
+    shouldBe("selectionRects[0].left", "16");
+    shouldBe("selectionRects[0].top", "38");
+    shouldBe("selectionRects[0].width", "27");
+    shouldBe("selectionRects[0].height", "15");
     finishJSTest();
 }
 </script>
index 94f0faa..2c9e290 100644 (file)
@@ -833,4 +833,9 @@ window.UIHelper = class UIHelper {
             testRunner.runUIScript("JSON.stringify(uiController.menuRect)", result => resolve(JSON.parse(result)));
         });
     }
+
+    static setHardwareKeyboardAttached(attached)
+    {
+        return new Promise(resolve => testRunner.runUIScript(`uiController.setHardwareKeyboardAttached(${attached ? "true" : "false"})`, resolve));
+    }
 }
index bcdfdf8..17d426e 100644 (file)
@@ -1,3 +1,15 @@
+2019-04-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Software keyboard is shown too frequently on some websites
+        https://bugs.webkit.org/show_bug.cgi?id=195856
+        <rdar://problem/49191395>
+
+        Reviewed by Darin Adler.
+
+        Declare new GraphicsServices SPI.
+
+        * pal/spi/ios/GraphicsServicesSPI.h:
+
 2019-04-10  Antoine Quint  <graouts@apple.com>
 
         Enable Pointer Events on watchOS
index 1b5bd97..e899e21 100644 (file)
@@ -46,6 +46,7 @@ void GSFontPurgeFontCache(void);
 typedef struct __GSKeyboard* GSKeyboardRef;
 uint32_t GSKeyboardGetModifierState(GSKeyboardRef);
 Boolean GSEventIsHardwareKeyboardAttached();
+void GSEventSetHardwareKeyboardAttached(Boolean attached, uint8_t country);
 
 extern const char *kGSEventHardwareKeyboardAvailabilityChangedNotification;
 
index 5a5cd79..18eb8de 100644 (file)
@@ -1,3 +1,37 @@
+2019-04-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Software keyboard is shown too frequently on some websites
+        https://bugs.webkit.org/show_bug.cgi?id=195856
+        <rdar://problem/49191395>
+
+        Reviewed by Darin Adler.
+
+        On some websites, hidden editable elements are very frequently focused upon user interaction. Currently, this
+        causes the software keyboard to pop in and out unexpectedly; luckily, these same sites also apply
+        inputmode="none" to the hidden editable element, which ought to ensure that the software keyboard doesn't appear
+        when the element is focused.
+
+        However, since we disabled support for inputmode="none" in r240497, the software keyboard is no longer
+        suppressed, and becomes a big nuissance. r240497 removed support for this feature because, when using a hardware
+        keyboard, pressing the globe key no longer showed UI for switching languages. However, support for inputmode
+        none makes a much larger impact when a software keyboard is used (since the entire software keyboard animates in
+        and out), whereas a hardware keyboard only displays an input accessory view. For this reason, we can mitigate
+        this bug without reintroducing <rdar://problem/47406553> by re-enabling inputmode="none", but only when a
+        hardware keyboard is not attached.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (hardwareKeyboardAvailabilityChangedCallback):
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView shouldShowAutomaticKeyboardUI]):
+
+        Don't show the keyboard if inputmode is none and a hardware keyboard is not attached.
+
+        (-[WKContentView _hardwareKeyboardAvailabilityChanged]):
+
+        Reload input views if the inputmode is none to ensure that if a hardware keyboard is attached while editing an
+        element with inputmode="none", we'll show the input accessory view once again.
+
 2019-04-12  Antoine Quint  <graouts@apple.com>
 
         Opt some websites into the simulated mouse events dispatch quirk when in modern compatibility mode
index 2591dbe..481cab1 100644 (file)
@@ -3335,6 +3335,7 @@ static void hardwareKeyboardAvailabilityChangedCallback(CFNotificationCenterRef,
 {
     ASSERT(observer);
     WKWebView *webView = (__bridge WKWebView *)observer;
+    [webView->_contentView _hardwareKeyboardAvailabilityChanged];
     webView._page->hardwareKeyboardAvailabilityChanged(GSEventIsHardwareKeyboardAttached());
 }
 
index 7fdd146..eb5bd43 100644 (file)
@@ -415,6 +415,7 @@ FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(DECLARE_WKCONTENTVIEW_ACTION_FOR_WEB_VIEW)
 - (void)_elementDidBlur;
 - (void)_didUpdateInputMode:(WebCore::InputMode)mode;
 - (void)_didReceiveEditorStateUpdateAfterFocus;
+- (void)_hardwareKeyboardAvailabilityChanged;
 - (void)_selectionChanged;
 - (void)_updateChangedSelection;
 - (BOOL)_interpretKeyEvent:(::WebEvent *)theEvent isCharEvent:(BOOL)isCharEvent;
index 84e731f..f0aa5b7 100644 (file)
 #import <pal/spi/cg/CoreGraphicsSPI.h>
 #import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
 #import <pal/spi/ios/DataDetectorsUISPI.h>
+#import <pal/spi/ios/GraphicsServicesSPI.h>
 #import <wtf/Optional.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/SetForScope.h>
 #import "NativeWebMouseEvent.h"
 #import <UIKit/UIHoverGestureRecognizer.h>
 #import <UIKit/_UILookupGestureRecognizer.h>
-#import <pal/spi/ios/GraphicsServicesSPI.h>
 #endif
 
 #if ENABLE(INPUT_TYPE_COLOR)
@@ -1595,7 +1595,12 @@ static NSValue *nsSizeForTapHighlightBorderRadius(WebCore::IntSize borderRadius,
 
 - (BOOL)shouldShowAutomaticKeyboardUI
 {
-    // FIXME: Make this function knowledgeable about the HTML attribute inputmode.
+    // FIXME: We should support inputmode="none" when the hardware keyboard is attached.
+    // We currently refrain from doing so because that would prevent UIKit from showing
+    // the language picker when pressing the globe key to change the input language.
+    if (_focusedElementInformation.inputMode == WebCore::InputMode::None && !GSEventIsHardwareKeyboardAttached())
+        return NO;
+
     switch (_focusedElementInformation.elementType) {
     case WebKit::InputType::None:
     case WebKit::InputType::Drawing:
@@ -5133,6 +5138,12 @@ static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebK
         _didAccessoryTabInitiateFocus = NO;
 }
 
+- (void)_hardwareKeyboardAvailabilityChanged
+{
+    if (hasFocusedElement(_focusedElementInformation) && _focusedElementInformation.inputMode == WebCore::InputMode::None)
+        [self reloadInputViews];
+}
+
 - (void)_didUpdateInputMode:(WebCore::InputMode)mode
 {
     if (!self.inputDelegate || _focusedElementInformation.elementType == WebKit::InputType::None)
index a7493a5..42fef77 100644 (file)
@@ -1,3 +1,27 @@
+2019-04-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Software keyboard is shown too frequently on some websites
+        https://bugs.webkit.org/show_bug.cgi?id=195856
+        <rdar://problem/49191395>
+
+        Reviewed by Darin Adler.
+
+        Add support for attaching or detaching the hardware keyboard on iOS in layout tests.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::setHardwareKeyboardAttached):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::setHardwareKeyboardAttached):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/Configurations/WebKitTestRunnerApp.xcconfig:
+
+        Additionally link against GraphicsServices in WebKitTestRunner.
+
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::TestController::platformResetStateToConsistentValues):
+        (WTR::UIScriptController::setHardwareKeyboardAttached):
+
 2019-04-12  Ludovico de Nittis  <ludovico.denittis@collabora.com>
 
         [GTK][WPE] Fix pacman install-dependencies packages
index 2ee91b0..e1cbd6c 100644 (file)
@@ -535,6 +535,10 @@ NSUndoManager *UIScriptController::platformUndoManager() const
     return nil;
 }
 
+void UIScriptController::setHardwareKeyboardAttached(bool)
+{
+}
+
 }
 
 #endif // PLATFORM(IOS_FAMILY)
index 23fe326..17a544c 100644 (file)
@@ -311,6 +311,8 @@ interface UIScriptController {
     void makeWindowContentViewFirstResponder();
     readonly attribute boolean isWindowContentViewFirstResponder;
 
+    void setHardwareKeyboardAttached(boolean attached);
+
     object attachmentInfo(DOMString attachmentIdentifier);
 
     // Editing
index 6faab08..adc7260 100644 (file)
@@ -638,6 +638,10 @@ void UIScriptController::setKeyboardInputModeIdentifier(JSStringRef)
 {
 }
 
+void UIScriptController::setHardwareKeyboardAttached(bool)
+{
+}
+
 #endif
 
 #if !PLATFORM(COCOA)
index f24cc7e..560a3d2 100644 (file)
@@ -240,6 +240,8 @@ public:
 
     JSObjectRef attachmentInfo(JSStringRef attachmentIdentifier);
 
+    void setHardwareKeyboardAttached(bool);
+
 private:
     UIScriptController(UIScriptContext&);
     
index cba936d..607a8bd 100644 (file)
@@ -30,7 +30,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.webkit.$(PRODUCT_NAME:rfc1034identifier);
 
 GCC_ENABLE_OBJC_EXCEPTIONS = YES;
 
-OTHER_LDFLAGS = $(inherited) -lWebKitTestRunner -lWebCoreTestSupport -framework JavaScriptCore -framework CoreGraphics -framework QuartzCore -framework ImageIO -framework IOKit -framework UIKit -framework WebKit -framework Foundation;
+OTHER_LDFLAGS = $(inherited) -lWebKitTestRunner -lWebCoreTestSupport -framework JavaScriptCore -framework CoreGraphics -framework QuartzCore -framework ImageIO -framework IOKit -framework UIKit -framework WebKit -framework Foundation -framework GraphicsServices;
 
 SKIP_INSTALL[sdk=macosx*] = YES;
 
index e0fa9a5..3eee005 100644 (file)
@@ -43,6 +43,7 @@
 #import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <objc/runtime.h>
+#import <pal/spi/ios/GraphicsServicesSPI.h>
 #import <wtf/MainThread.h>
 
 static BOOL overrideIsInHardwareKeyboardMode()
@@ -141,6 +142,7 @@ void TestController::platformResetStateToConsistentValues(const TestOptions& opt
 
     [[UIApplication sharedApplication] _cancelAllTouches];
     [[UIDevice currentDevice] setOrientation:UIDeviceOrientationPortrait animated:NO];
+    GSEventSetHardwareKeyboardAttached(true, 0);
 
     m_inputModeSwizzlers.clear();
     m_overriddenKeyboardInputMode = nil;
index d249678..748c3a1 100644 (file)
@@ -42,6 +42,7 @@
 #import <WebCore/FloatRect.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/WebKit.h>
+#import <pal/spi/ios/GraphicsServicesSPI.h>
 #import <wtf/SoftLinking.h>
 #import <wtf/Vector.h>
 
@@ -1140,6 +1141,11 @@ JSObjectRef UIScriptController::calendarType() const
     return JSValueToObject(jsContext, [JSValue valueWithObject:calendarTypeString inContext:[JSContext contextWithJSGlobalContextRef:jsContext]].JSValueRef, nullptr);
 }
 
+void UIScriptController::setHardwareKeyboardAttached(bool attached)
+{
+    GSEventSetHardwareKeyboardAttached(attached, 0);
+}
+
 }
 
 #endif // PLATFORM(IOS_FAMILY)
index 589e6a2..b011b47 100644 (file)
@@ -1,3 +1,15 @@
+2019-04-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Software keyboard is shown too frequently on some websites
+        https://bugs.webkit.org/show_bug.cgi?id=195856
+        <rdar://problem/49191395>
+
+        Reviewed by Darin Adler.
+
+        Add a symbol for GSEventSetHardwareKeyboardAttached.
+
+        * WebKitPrivateFrameworkStubs/iOS/12/GraphicsServices.framework/GraphicsServices.tbd:
+
 2019-01-01  Jeff Miller  <jeffm@apple.com>
 
         Update user-visible copyright strings to include 2019
index d354324..9c147f2 100644 (file)
@@ -16,6 +16,7 @@ exports:
     symbols:
       - _GSCurrentEventTimestamp
       - _GSEventIsHardwareKeyboardAttached
+      - _GSEventSetHardwareKeyboardAttached
       - _GSFontInitialize
       - _GSFontPurgeFontCache
       - _GSInitialize