Implement keyboard event sending for iOS in WebKitTestRunner
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Oct 2015 14:28:38 +0000 (14:28 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 1 Oct 2015 14:28:38 +0000 (14:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149676

Reviewed by Simon Fraser.

Tools:

Adds support for generating and sending key events in WebKitTestRunner. This is accomplished in a similar
way as touch events, using IOHIDEvent machinery. Also adds callbacks to the UIScriptController JS API that
allows us to run code when the keyboard is shown or hidden.

* WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl: Adds the typeCharacter JS interface.
* WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::setDidShowKeyboardCallback):
(WTR::UIScriptController::didShowKeyboardCallback):
(WTR::UIScriptController::setDidHideKeyboardCallback):
(WTR::UIScriptController::didHideKeyboardCallback):
(WTR::UIScriptController::typeCharacterUsingHardwareKeyboard):
(WTR::UIScriptController::platformSetDidShowKeyboardCallback):
(WTR::UIScriptController::platformSetDidHideKeyboardCallback):
* WebKitTestRunner/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
* WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
(-[TestRunnerWKWebView initWithFrame:configuration:]): Registers the TestRunnerWKWebView to listen to
        the notifications that the keyboard has been raised or lowered.
(-[TestRunnerWKWebView _keyboardDidShow:]):
(-[TestRunnerWKWebView _keyboardDidHide:]):
* WebKitTestRunner/ios/HIDEventGenerator.h:
* WebKitTestRunner/ios/HIDEventGenerator.m:
(-[HIDEventGenerator _sendIOHIDKeyboardEvent:usage:isKeyDown:]): Helper to send a HID keyboard event.
(shouldWrapWithShiftKeyEventForCharacter): Helper used to generate key events.
(hidUsageCodeForCharacter): Ditto.
(-[HIDEventGenerator keyDown:completionBlock:]): Synthesizes and sends HIDKeyboardEvents, triggering
        a keyDown event in WebKit.
* WebKitTestRunner/ios/IOKitSPI.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:

LayoutTests:

Adds a new basic test for the oninput event listener when typing in a text field.

* fast/events/ios/input-value-after-oninput-expected.txt: Added.
* fast/events/ios/input-value-after-oninput.html: Added.

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/ios/input-value-after-oninput-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/ios/input-value-after-oninput.html [new file with mode: 0644]
Tools/ChangeLog
Tools/WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl
Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp
Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.h
Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm
Tools/WebKitTestRunner/ios/HIDEventGenerator.h
Tools/WebKitTestRunner/ios/HIDEventGenerator.mm
Tools/WebKitTestRunner/ios/IOKitSPI.h
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

index 989a083525baffe948fef62a526e1f071f88bf3a..c7ade4462096bb0ae39e14ef5452994b18b7afbd 100644 (file)
@@ -1,3 +1,15 @@
+2015-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Implement keyboard event sending for iOS in WebKitTestRunner
+        https://bugs.webkit.org/show_bug.cgi?id=149676
+
+        Reviewed by Simon Fraser.
+
+        Adds a new basic test for the oninput event listener when typing in a text field.
+
+        * fast/events/ios/input-value-after-oninput-expected.txt: Added.
+        * fast/events/ios/input-value-after-oninput.html: Added.
+
 2015-10-01  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         [Streams API] Add support for private WebCore JS builtins functions
diff --git a/LayoutTests/fast/events/ios/input-value-after-oninput-expected.txt b/LayoutTests/fast/events/ios/input-value-after-oninput-expected.txt
new file mode 100644 (file)
index 0000000..4dbbf4b
--- /dev/null
@@ -0,0 +1,2 @@
+
+Successfully handled oninput, value is now "a"
diff --git a/LayoutTests/fast/events/ios/input-value-after-oninput.html b/LayoutTests/fast/events/ios/input-value-after-oninput.html
new file mode 100644 (file)
index 0000000..e877993
--- /dev/null
@@ -0,0 +1,46 @@
+<html>
+
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <script id="ui-script" type="text/plain">
+        (function() {
+            uiController.singleTapAtPoint(50, 25, function() {
+                uiController.didShowKeyboardCallback = function() {
+                    uiController.typeCharacterUsingHardwareKeyboard("a", function() { });
+                }
+            });
+        })();
+    </script>
+
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function getUIScript()
+        {
+            return document.getElementById("ui-script").text;
+        }
+
+        function handleValueChanged(value) {
+            document.getElementById("console").textContent = "Successfully handled oninput, value is now \"" + value + "\"";
+            testRunner.notifyDone();
+        }
+
+        function runTest()
+        {
+            if (!window.testRunner || !testRunner.runUIScript)
+                return;
+
+            testRunner.runUIScript(getUIScript(), function(result) { });
+        }
+    </script>
+</head>
+
+<body style="margin: 0;" onload="runTest()">
+    <input style="width: 100px; height: 50px;" id="test-input" oninput="handleValueChanged(this.value)">
+<div id="console">Failed to handle oninput<div>
+</body>
+
+</html>
index fde6576e6ae60ab96a275786891eeb057f55913f..9d3323002c71b2459016e7097375f67f6578eb5d 100644 (file)
@@ -1,3 +1,40 @@
+2015-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Implement keyboard event sending for iOS in WebKitTestRunner
+        https://bugs.webkit.org/show_bug.cgi?id=149676
+
+        Reviewed by Simon Fraser.
+
+        Adds support for generating and sending key events in WebKitTestRunner. This is accomplished in a similar
+        way as touch events, using IOHIDEvent machinery. Also adds callbacks to the UIScriptController JS API that
+        allows us to run code when the keyboard is shown or hidden.
+
+        * WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl: Adds the typeCharacter JS interface.
+        * WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::setDidShowKeyboardCallback):
+        (WTR::UIScriptController::didShowKeyboardCallback):
+        (WTR::UIScriptController::setDidHideKeyboardCallback):
+        (WTR::UIScriptController::didHideKeyboardCallback):
+        (WTR::UIScriptController::typeCharacterUsingHardwareKeyboard):
+        (WTR::UIScriptController::platformSetDidShowKeyboardCallback):
+        (WTR::UIScriptController::platformSetDidHideKeyboardCallback):
+        * WebKitTestRunner/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
+        * WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
+        (-[TestRunnerWKWebView initWithFrame:configuration:]): Registers the TestRunnerWKWebView to listen to
+                the notifications that the keyboard has been raised or lowered.
+        (-[TestRunnerWKWebView _keyboardDidShow:]):
+        (-[TestRunnerWKWebView _keyboardDidHide:]):
+        * WebKitTestRunner/ios/HIDEventGenerator.h:
+        * WebKitTestRunner/ios/HIDEventGenerator.m:
+        (-[HIDEventGenerator _sendIOHIDKeyboardEvent:usage:isKeyDown:]): Helper to send a HID keyboard event.
+        (shouldWrapWithShiftKeyEventForCharacter): Helper used to generate key events.
+        (hidUsageCodeForCharacter): Ditto.
+        (-[HIDEventGenerator keyDown:completionBlock:]): Synthesizes and sends HIDKeyboardEvents, triggering
+                a keyDown event in WebKit.
+        * WebKitTestRunner/ios/IOKitSPI.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+
 2015-10-01  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed, rolling out r190399.
index d0809231018c19a59632e960315e4e1c8d6ffef6..f1309f62e9251d567b59146f4fd1f6967350defe 100644 (file)
@@ -35,6 +35,11 @@ interface UIScriptController {
     void singleTapAtPoint(long x, long y, object callback);
     void doubleTapAtPoint(long x, long y, object callback);
 
+    void typeCharacterUsingHardwareKeyboard(DOMString character, object callback);
+
+    attribute object didShowKeyboardCallback;
+    attribute object didHideKeyboardCallback;
+
     attribute object willBeginZoomingCallback;
     attribute object didEndZoomingCallback;
 
index c61c26e9eb17a171606ba14794cde7229a6d1ea9..9ccd9f3222174ee7953041ea57777e7b86ea9ed0 100644 (file)
@@ -75,6 +75,28 @@ JSValueRef UIScriptController::didEndZoomingCallback() const
     return m_context.callbackWithID(m_didEndZoomingCallback);
 }
 
+void UIScriptController::setDidShowKeyboardCallback(JSValueRef callback)
+{
+    m_didShowKeyboardCallback = m_context.registerCallback(callback);
+    platformSetDidShowKeyboardCallback();
+}
+
+JSValueRef UIScriptController::didShowKeyboardCallback() const
+{
+    return m_context.callbackWithID(m_didShowKeyboardCallback);
+}
+
+void UIScriptController::setDidHideKeyboardCallback(JSValueRef callback)
+{
+    m_didHideKeyboardCallback = m_context.registerCallback(callback);
+    platformSetDidHideKeyboardCallback();
+}
+
+JSValueRef UIScriptController::didHideKeyboardCallback() const
+{
+    return m_context.callbackWithID(m_didHideKeyboardCallback);
+}
+
 #if !PLATFORM(IOS)
 void UIScriptController::zoomToScale(double, JSValueRef)
 {
@@ -88,6 +110,10 @@ void UIScriptController::doubleTapAtPoint(long x, long y, JSValueRef)
 {
 }
 
+void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef, JSValueRef)
+{
+}
+
 double UIScriptController::zoomScale() const
 {
     return 1;
@@ -115,6 +141,14 @@ void UIScriptController::platformSetWillBeginZoomingCallback()
 void UIScriptController::platformSetDidEndZoomingCallback()
 {
 }
+
+void UIScriptController::platformSetDidShowKeyboardCallback()
+{
+}
+
+void UIScriptController::platformSetDidHideKeyboardCallback()
+{
+}
 #endif
 
 void UIScriptController::uiScriptComplete(JSStringRef result)
index 303edeb6b72e6355555c04993e50028b36c37391..64e700121fe8509483f617461bfd090ce8b05ec4 100644 (file)
@@ -48,12 +48,20 @@ public:
     void singleTapAtPoint(long x, long y, JSValueRef callback);
     void doubleTapAtPoint(long x, long y, JSValueRef callback);
     
+    void typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback);
+
     void setWillBeginZoomingCallback(JSValueRef);
     JSValueRef willBeginZoomingCallback() const;
 
     void setDidEndZoomingCallback(JSValueRef);
     JSValueRef didEndZoomingCallback() const;
 
+    void setDidShowKeyboardCallback(JSValueRef);
+    JSValueRef didShowKeyboardCallback() const;
+
+    void setDidHideKeyboardCallback(JSValueRef);
+    JSValueRef didHideKeyboardCallback() const;
+
     double zoomScale() const;
     double minimumZoomScale() const;
     double maximumZoomScale() const;
@@ -67,6 +75,8 @@ private:
     
     void platformSetWillBeginZoomingCallback();
     void platformSetDidEndZoomingCallback();
+    void platformSetDidShowKeyboardCallback();
+    void platformSetDidHideKeyboardCallback();
 
     virtual JSClassRef wrapperClass() override;
 
@@ -76,6 +86,8 @@ private:
 
     unsigned m_willBeginZoomingCallback { 0 };
     unsigned m_didEndZoomingCallback { 0 };
+    unsigned m_didShowKeyboardCallback { 0 };
+    unsigned m_didHideKeyboardCallback { 0 };
 };
 
 }
index 3f18590a223a23e9e6ff1f8b08402e7a8b785fe3..f31b1459366b74c7e66312f14dc26d0e7534fbf0 100644 (file)
 
 @property (nonatomic, copy) void (^willBeginZoomingCallback)(void);
 @property (nonatomic, copy) void (^didEndZoomingCallback)(void);
+@property (nonatomic, copy) void (^didShowKeyboardCallback)(void);
+@property (nonatomic, copy) void (^didHideKeyboardCallback)(void);
 
-- (void)zoomToScale:(double)scale animated:(BOOL)animated completionHandler:(void (^)(void))completionHandler;
+- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration;
+- (void)dealloc;
 
+- (void)zoomToScale:(double)scale animated:(BOOL)animated completionHandler:(void (^)(void))completionHandler;
 #endif
 
 @end
index cc530b0d2994c1dd6b9d679073489842f0defcfb..cb255ae0f7586dc9090fdb10c0def58af712ba14 100644 (file)
@@ -44,6 +44,7 @@
 
 @interface TestRunnerWKWebView ()
 @property (nonatomic, copy) void (^zoomToScaleCompletionHandler)(void);
+@property (nonatomic, copy) void (^showKeyboardCompletionHandler)(void);
 @end
 
 @implementation TestRunnerWKWebView
 #endif
 
 #if PLATFORM(IOS)
+- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
+{
+    if (self = [super initWithFrame:frame configuration:configuration]) {
+        NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+        [center addObserver:self selector:@selector(_keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
+        [center addObserver:self selector:@selector(_keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [super dealloc];
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
 - (void)zoomToScale:(double)scale animated:(BOOL)animated completionHandler:(void (^)(void))completionHandler
 {
     ASSERT(!self.zoomToScaleCompletionHandler);
     [self.scrollView setZoomScale:scale animated:animated];
 }
 
+- (void)_keyboardDidShow:(NSNotification *)notification
+{
+    if (self.didShowKeyboardCallback)
+        self.didShowKeyboardCallback();
+}
+
+- (void)_keyboardDidHide:(NSNotification *)notification
+{
+    if (self.didHideKeyboardCallback)
+        self.didHideKeyboardCallback();
+}
+
 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view
 {
     [super scrollViewWillBeginZooming:scrollView withView:view];
index 212b21651d2bf6c704d868c77fc823aa67f34d19..af9be6a57ca2552add876924dd81d70b2934c3ca 100644 (file)
@@ -50,4 +50,7 @@
 
 - (void)markerEventReceived:(IOHIDEventRef)event;
 
+// Keyboard
+- (void)keyDown:(NSString *)character completionBlock:(void (^)(void))completionBlock;
+
 @end
index 2dde6a8401f671820a3a9f07e7af584a28964c8a..620f078a5362e64fc2020c92b8ce75cae2746e75 100644 (file)
@@ -129,6 +129,17 @@ static void delayBetweenMove(int eventIndex, double elapsed)
     return self;
 }
 
+- (void)_sendIOHIDKeyboardEvent:(uint64_t)timestamp usage:(uint32_t)usage isKeyDown:(bool)isKeyDown
+{
+    RetainPtr<IOHIDEventRef> eventRef = adoptCF(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault,
+        timestamp,
+        kHIDPage_KeyboardOrKeypad,
+        usage,
+        isKeyDown,
+        kIOHIDEventOptionNone));
+    [self _sendHIDEvent:eventRef.get()];
+}
+
 - (IOHIDEventRef)_createIOHIDEventType:(HandEventType)eventType
 {
     BOOL isTouching = (eventType == HandEventTouched || eventType == HandEventMoved || eventType == HandEventChordChanged);
@@ -428,4 +439,169 @@ static void delayBetweenMove(int eventIndex, double elapsed)
     }
 }
 
+static inline bool shouldWrapWithShiftKeyEventForCharacter(NSString *key)
+{
+    if (key.length != 1)
+        return false;
+    int keyCode = [key characterAtIndex:0];
+    if (65 <= keyCode && keyCode <= 90)
+        return true;
+    switch (keyCode) {
+    case '`':
+    case '!':
+    case '@':
+    case '#':
+    case '$':
+    case '%':
+    case '^':
+    case '&':
+    case '*':
+    case '(':
+    case ')':
+    case '_':
+    case '+':
+    case '{':
+    case '}':
+    case '|':
+    case ':':
+    case '"':
+    case '<':
+    case '>':
+    case '?':
+    case '~':
+        return true;
+    }
+    return false;
+}
+
+static inline uint32_t hidUsageCodeForCharacter(NSString *key)
+{
+    const int uppercaseAlphabeticOffset = 'A' - kHIDUsage_KeyboardA;
+    const int lowercaseAlphabeticOffset = 'a' - kHIDUsage_KeyboardA;
+    const int numericNonZeroOffset = '1' - kHIDUsage_Keyboard1;
+    if (key.length == 1) {
+        // Handle alphanumeric characters and basic symbols.
+        int keyCode = [key characterAtIndex:0];
+        if (97 <= keyCode && keyCode <= 122) // Handle a-z.
+            return keyCode - lowercaseAlphabeticOffset;
+
+        if (65 <= keyCode && keyCode <= 90) // Handle A-Z.
+            return keyCode - uppercaseAlphabeticOffset;
+
+        if (49 <= keyCode && keyCode <= 57) // Handle 1-9.
+            return keyCode - numericNonZeroOffset;
+
+        // Handle all other cases.
+        switch (keyCode) {
+        case '`':
+        case '~':
+            return kHIDUsage_KeyboardGraveAccentAndTilde;
+        case '!':
+            return kHIDUsage_Keyboard1;
+        case '@':
+            return kHIDUsage_Keyboard2;
+        case '#':
+            return kHIDUsage_Keyboard3;
+        case '$':
+            return kHIDUsage_Keyboard4;
+        case '%':
+            return kHIDUsage_Keyboard5;
+        case '^':
+            return kHIDUsage_Keyboard6;
+        case '&':
+            return kHIDUsage_Keyboard7;
+        case '*':
+            return kHIDUsage_Keyboard8;
+        case '(':
+            return kHIDUsage_Keyboard9;
+        case ')':
+        case '0':
+            return kHIDUsage_Keyboard0;
+        case '-':
+        case '_':
+            return kHIDUsage_KeyboardHyphen;
+        case '=':
+        case '+':
+            return kHIDUsage_KeyboardEqualSign;
+        case '\t':
+            return kHIDUsage_KeyboardTab;
+        case '[':
+        case '{':
+            return kHIDUsage_KeyboardOpenBracket;
+        case ']':
+        case '}':
+            return kHIDUsage_KeyboardCloseBracket;
+        case '\\':
+        case '|':
+            return kHIDUsage_KeyboardBackslash;
+        case ';':
+        case ':':
+            return kHIDUsage_KeyboardSemicolon;
+        case '\'':
+        case '"':
+            return kHIDUsage_KeyboardQuote;
+        case '\r':
+        case '\n':
+            return kHIDUsage_KeyboardReturnOrEnter;
+        case ',':
+        case '<':
+            return kHIDUsage_KeyboardComma;
+        case '.':
+        case '>':
+            return kHIDUsage_KeyboardPeriod;
+        case '/':
+        case '?':
+            return kHIDUsage_KeyboardSlash;
+        case ' ':
+            return kHIDUsage_KeyboardSpacebar;
+        }
+    }
+    const int functionKeyOffset = kHIDUsage_KeyboardF1;
+    for (int functionKeyIndex = 1; functionKeyIndex <= 12; ++functionKeyIndex) {
+        if ([key isEqualToString:[NSString stringWithFormat:@"F%d", functionKeyIndex]])
+            return functionKeyOffset + functionKeyIndex - 1;
+    }
+    if ([key isEqualToString:@"escape"])
+        return kHIDUsage_KeyboardEscape;
+    if ([key isEqualToString:@"return"] || [key isEqualToString:@"enter"])
+        return kHIDUsage_KeyboardReturnOrEnter;
+    if ([key isEqualToString:@"leftArrow"])
+        return kHIDUsage_KeyboardLeftArrow;
+    if ([key isEqualToString:@"rightArrow"])
+        return kHIDUsage_KeyboardRightArrow;
+    if ([key isEqualToString:@"upArrow"])
+        return kHIDUsage_KeyboardUpArrow;
+    if ([key isEqualToString:@"downArrow"])
+        return kHIDUsage_KeyboardDownArrow;
+    if ([key isEqualToString:@"delete"])
+        return kHIDUsage_KeyboardDeleteOrBackspace;
+    // The simulator keyboard interprets both left and right modifier keys using the left version of the usage code.
+    if ([key isEqualToString:@"leftControl"] || [key isEqualToString:@"rightControl"])
+        return kHIDUsage_KeyboardLeftControl;
+    if ([key isEqualToString:@"leftShift"] || [key isEqualToString:@"rightShift"])
+        return kHIDUsage_KeyboardLeftShift;
+    if ([key isEqualToString:@"leftAlt"] || [key isEqualToString:@"rightAlt"])
+        return kHIDUsage_KeyboardLeftAlt;
+
+    return 0;
+}
+
+- (void)keyDown:(NSString *)character completionBlock:(void (^)(void))completionBlock
+{
+    bool shouldWrapWithShift = shouldWrapWithShiftKeyEventForCharacter(character);
+    uint32_t usage = hidUsageCodeForCharacter(character);
+    uint64_t absoluteMachTime = mach_absolute_time();
+
+    if (shouldWrapWithShift)
+        [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:kHIDUsage_KeyboardLeftShift isKeyDown:true];
+
+    [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:usage isKeyDown:true];
+    [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:usage isKeyDown:false];
+
+    if (shouldWrapWithShift)
+        [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:kHIDUsage_KeyboardLeftShift isKeyDown:false];
+
+    [self _sendMarkerHIDEventWithCompletionBlock:completionBlock];
+}
+
 @end
index 1e902cc1852ce90c0d47dd739ac4a2821fd4118e..9bde1c663acd76502b56a53b7249e2ab1463386f 100644 (file)
@@ -60,6 +60,7 @@ typedef struct __IOHIDEvent * IOHIDEventRef;
 #define IOHIDEventFieldBase(type) (type << 16)
 
 enum {
+    kHIDPage_KeyboardOrKeypad       = 0x07
     kHIDPage_VendorDefinedStart     = 0xFF00
 };
 
@@ -127,6 +128,47 @@ IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef);
 #define kGSEventPathInfoInRange (1 << 0)
 #define kGSEventPathInfoInTouch (1 << 1)
 
+enum {
+    kHIDUsage_KeyboardA = 0x04,
+    kHIDUsage_Keyboard1 = 0x1E,
+    kHIDUsage_Keyboard2 = 0x1F,
+    kHIDUsage_Keyboard3 = 0x20,
+    kHIDUsage_Keyboard4 = 0x21,
+    kHIDUsage_Keyboard5 = 0x22,
+    kHIDUsage_Keyboard6 = 0x23,
+    kHIDUsage_Keyboard7 = 0x24,
+    kHIDUsage_Keyboard8 = 0x25,
+    kHIDUsage_Keyboard9 = 0x26,
+    kHIDUsage_Keyboard0 = 0x27,
+    kHIDUsage_KeyboardReturnOrEnter = 0x28,
+    kHIDUsage_KeyboardEscape = 0x29,
+    kHIDUsage_KeyboardDeleteOrBackspace = 0x2A,
+    kHIDUsage_KeyboardTab = 0x2B,
+    kHIDUsage_KeyboardSpacebar = 0x2C,
+    kHIDUsage_KeyboardHyphen = 0x2D,
+    kHIDUsage_KeyboardEqualSign = 0x2E,
+    kHIDUsage_KeyboardOpenBracket = 0x2F,
+    kHIDUsage_KeyboardCloseBracket = 0x30,
+    kHIDUsage_KeyboardBackslash = 0x31,
+    kHIDUsage_KeyboardSemicolon = 0x33,
+    kHIDUsage_KeyboardQuote = 0x34,
+    kHIDUsage_KeyboardGraveAccentAndTilde = 0x35,
+    kHIDUsage_KeyboardComma = 0x36,
+    kHIDUsage_KeyboardPeriod = 0x37,
+    kHIDUsage_KeyboardSlash = 0x38,
+    kHIDUsage_KeyboardF1 = 0x3A,
+    kHIDUsage_KeyboardHome = 0x4A,
+    kHIDUsage_KeyboardPageUp = 0x4B,
+    kHIDUsage_KeyboardEnd = 0x4D,
+    kHIDUsage_KeyboardRightArrow = 0x4F,
+    kHIDUsage_KeyboardLeftArrow = 0x50,
+    kHIDUsage_KeyboardDownArrow = 0x51,
+    kHIDUsage_KeyboardUpArrow = 0x52,
+    kHIDUsage_KeyboardLeftControl = 0xE0,
+    kHIDUsage_KeyboardLeftShift = 0xE1,
+    kHIDUsage_KeyboardLeftAlt = 0xE2
+};
+
 WTF_EXTERN_C_END
 
 #endif // USE(APPLE_INTERNAL_SDK)
index 8a864862b778ea3e555fddf328ee365c06f3cca8..eb1bf123fc188682dd28a0fdae9f4ab760fa0dd4 100644 (file)
@@ -30,6 +30,7 @@
 
 #import "HIDEventGenerator.h"
 #import "PlatformWebView.h"
+#import "StringFunctions.h"
 #import "TestController.h"
 #import "TestRunnerWKWebView.h"
 #import "UIScriptContext.h"
@@ -92,6 +93,16 @@ void UIScriptController::doubleTapAtPoint(long x, long y, JSValueRef callback)
     }];
 }
 
+void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
+{
+    unsigned callbackID = m_context.prepareForAsyncTask(callback);
+
+    // Assumes that the keyboard is already shown.
+    [[HIDEventGenerator sharedHIDEventGenerator] keyDown:toWTFString(toWK(character)) completionBlock:^{
+        m_context.asyncTaskComplete(callbackID);
+    }];
+}
+
 double UIScriptController::minimumZoomScale() const
 {
     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
@@ -130,6 +141,22 @@ void UIScriptController::platformSetDidEndZoomingCallback()
     };
 }
 
+void UIScriptController::platformSetDidShowKeyboardCallback()
+{
+    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
+    webView.didShowKeyboardCallback = ^{
+        m_context.fireCallback(m_didShowKeyboardCallback);
+    };
+}
+
+void UIScriptController::platformSetDidHideKeyboardCallback()
+{
+    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
+    webView.didHideKeyboardCallback = ^{
+        m_context.fireCallback(m_didHideKeyboardCallback);
+    };
+}
+
 }
 
 #endif // PLATFORM(IOS)