Changeset 190407 in webkit


Ignore:
Timestamp:
Oct 1, 2015 7:28:38 AM (9 years ago)
Author:
Wenson Hsieh
Message:

Implement keyboard event sending for iOS in WebKitTestRunner
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.
Location:
trunk
Files:
2 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r190401 r190407  
     12015-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Implement keyboard event sending for iOS in WebKitTestRunner
     4        https://bugs.webkit.org/show_bug.cgi?id=149676
     5
     6        Reviewed by Simon Fraser.
     7
     8        Adds a new basic test for the oninput event listener when typing in a text field.
     9
     10        * fast/events/ios/input-value-after-oninput-expected.txt: Added.
     11        * fast/events/ios/input-value-after-oninput.html: Added.
     12
    1132015-10-01  Youenn Fablet  <youenn.fablet@crf.canon.fr>
    214
  • trunk/Tools/ChangeLog

    r190406 r190407  
     12015-10-01  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Implement keyboard event sending for iOS in WebKitTestRunner
     4        https://bugs.webkit.org/show_bug.cgi?id=149676
     5
     6        Reviewed by Simon Fraser.
     7
     8        Adds support for generating and sending key events in WebKitTestRunner. This is accomplished in a similar
     9        way as touch events, using IOHIDEvent machinery. Also adds callbacks to the UIScriptController JS API that
     10        allows us to run code when the keyboard is shown or hidden.
     11
     12        * WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl: Adds the typeCharacter JS interface.
     13        * WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
     14        (WTR::UIScriptController::setDidShowKeyboardCallback):
     15        (WTR::UIScriptController::didShowKeyboardCallback):
     16        (WTR::UIScriptController::setDidHideKeyboardCallback):
     17        (WTR::UIScriptController::didHideKeyboardCallback):
     18        (WTR::UIScriptController::typeCharacterUsingHardwareKeyboard):
     19        (WTR::UIScriptController::platformSetDidShowKeyboardCallback):
     20        (WTR::UIScriptController::platformSetDidHideKeyboardCallback):
     21        * WebKitTestRunner/UIScriptContext/UIScriptController.h:
     22        * WebKitTestRunner/cocoa/TestRunnerWKWebView.h:
     23        * WebKitTestRunner/cocoa/TestRunnerWKWebView.mm:
     24        (-[TestRunnerWKWebView initWithFrame:configuration:]): Registers the TestRunnerWKWebView to listen to
     25                the notifications that the keyboard has been raised or lowered.
     26        (-[TestRunnerWKWebView _keyboardDidShow:]):
     27        (-[TestRunnerWKWebView _keyboardDidHide:]):
     28        * WebKitTestRunner/ios/HIDEventGenerator.h:
     29        * WebKitTestRunner/ios/HIDEventGenerator.m:
     30        (-[HIDEventGenerator _sendIOHIDKeyboardEvent:usage:isKeyDown:]): Helper to send a HID keyboard event.
     31        (shouldWrapWithShiftKeyEventForCharacter): Helper used to generate key events.
     32        (hidUsageCodeForCharacter): Ditto.
     33        (-[HIDEventGenerator keyDown:completionBlock:]): Synthesizes and sends HIDKeyboardEvents, triggering
     34                a keyDown event in WebKit.
     35        * WebKitTestRunner/ios/IOKitSPI.h:
     36        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
     37
    1382015-10-01  Carlos Garcia Campos  <cgarcia@igalia.com>
    239
  • trunk/Tools/WebKitTestRunner/UIScriptContext/Bindings/UIScriptController.idl

    r190368 r190407  
    3636    void doubleTapAtPoint(long x, long y, object callback);
    3737
     38    void typeCharacterUsingHardwareKeyboard(DOMString character, object callback);
     39
     40    attribute object didShowKeyboardCallback;
     41    attribute object didHideKeyboardCallback;
     42
    3843    attribute object willBeginZoomingCallback;
    3944    attribute object didEndZoomingCallback;
  • trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp

    r190368 r190407  
    7676}
    7777
     78void UIScriptController::setDidShowKeyboardCallback(JSValueRef callback)
     79{
     80    m_didShowKeyboardCallback = m_context.registerCallback(callback);
     81    platformSetDidShowKeyboardCallback();
     82}
     83
     84JSValueRef UIScriptController::didShowKeyboardCallback() const
     85{
     86    return m_context.callbackWithID(m_didShowKeyboardCallback);
     87}
     88
     89void UIScriptController::setDidHideKeyboardCallback(JSValueRef callback)
     90{
     91    m_didHideKeyboardCallback = m_context.registerCallback(callback);
     92    platformSetDidHideKeyboardCallback();
     93}
     94
     95JSValueRef UIScriptController::didHideKeyboardCallback() const
     96{
     97    return m_context.callbackWithID(m_didHideKeyboardCallback);
     98}
     99
    78100#if !PLATFORM(IOS)
    79101void UIScriptController::zoomToScale(double, JSValueRef)
     
    86108
    87109void UIScriptController::doubleTapAtPoint(long x, long y, JSValueRef)
     110{
     111}
     112
     113void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef, JSValueRef)
    88114{
    89115}
     
    116142{
    117143}
     144
     145void UIScriptController::platformSetDidShowKeyboardCallback()
     146{
     147}
     148
     149void UIScriptController::platformSetDidHideKeyboardCallback()
     150{
     151}
    118152#endif
    119153
  • trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h

    r190368 r190407  
    4949    void doubleTapAtPoint(long x, long y, JSValueRef callback);
    5050   
     51    void typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback);
     52
    5153    void setWillBeginZoomingCallback(JSValueRef);
    5254    JSValueRef willBeginZoomingCallback() const;
     
    5456    void setDidEndZoomingCallback(JSValueRef);
    5557    JSValueRef didEndZoomingCallback() const;
     58
     59    void setDidShowKeyboardCallback(JSValueRef);
     60    JSValueRef didShowKeyboardCallback() const;
     61
     62    void setDidHideKeyboardCallback(JSValueRef);
     63    JSValueRef didHideKeyboardCallback() const;
    5664
    5765    double zoomScale() const;
     
    6876    void platformSetWillBeginZoomingCallback();
    6977    void platformSetDidEndZoomingCallback();
     78    void platformSetDidShowKeyboardCallback();
     79    void platformSetDidHideKeyboardCallback();
    7080
    7181    virtual JSClassRef wrapperClass() override;
     
    7787    unsigned m_willBeginZoomingCallback { 0 };
    7888    unsigned m_didEndZoomingCallback { 0 };
     89    unsigned m_didShowKeyboardCallback { 0 };
     90    unsigned m_didHideKeyboardCallback { 0 };
    7991};
    8092
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.h

    r190368 r190407  
    3434@property (nonatomic, copy) void (^willBeginZoomingCallback)(void);
    3535@property (nonatomic, copy) void (^didEndZoomingCallback)(void);
     36@property (nonatomic, copy) void (^didShowKeyboardCallback)(void);
     37@property (nonatomic, copy) void (^didHideKeyboardCallback)(void);
     38
     39- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration;
     40- (void)dealloc;
    3641
    3742- (void)zoomToScale:(double)scale animated:(BOOL)animated completionHandler:(void (^)(void))completionHandler;
    38 
    3943#endif
    4044
  • trunk/Tools/WebKitTestRunner/cocoa/TestRunnerWKWebView.mm

    r190368 r190407  
    4545@interface TestRunnerWKWebView ()
    4646@property (nonatomic, copy) void (^zoomToScaleCompletionHandler)(void);
     47@property (nonatomic, copy) void (^showKeyboardCompletionHandler)(void);
    4748@end
    4849
     
    5859
    5960#if PLATFORM(IOS)
     61- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
     62{
     63    if (self = [super initWithFrame:frame configuration:configuration]) {
     64        NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
     65        [center addObserver:self selector:@selector(_keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
     66        [center addObserver:self selector:@selector(_keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
     67    }
     68    return self;
     69}
     70
     71- (void)dealloc
     72{
     73    [super dealloc];
     74    [[NSNotificationCenter defaultCenter] removeObserver:self];
     75}
     76
    6077- (void)zoomToScale:(double)scale animated:(BOOL)animated completionHandler:(void (^)(void))completionHandler
    6178{
     
    6481
    6582    [self.scrollView setZoomScale:scale animated:animated];
     83}
     84
     85- (void)_keyboardDidShow:(NSNotification *)notification
     86{
     87    if (self.didShowKeyboardCallback)
     88        self.didShowKeyboardCallback();
     89}
     90
     91- (void)_keyboardDidHide:(NSNotification *)notification
     92{
     93    if (self.didHideKeyboardCallback)
     94        self.didHideKeyboardCallback();
    6695}
    6796
  • trunk/Tools/WebKitTestRunner/ios/HIDEventGenerator.h

    r190368 r190407  
    5151- (void)markerEventReceived:(IOHIDEventRef)event;
    5252
     53// Keyboard
     54- (void)keyDown:(NSString *)character completionBlock:(void (^)(void))completionBlock;
     55
    5356@end
  • trunk/Tools/WebKitTestRunner/ios/HIDEventGenerator.mm

    r190368 r190407  
    130130}
    131131
     132- (void)_sendIOHIDKeyboardEvent:(uint64_t)timestamp usage:(uint32_t)usage isKeyDown:(bool)isKeyDown
     133{
     134    RetainPtr<IOHIDEventRef> eventRef = adoptCF(IOHIDEventCreateKeyboardEvent(kCFAllocatorDefault,
     135        timestamp,
     136        kHIDPage_KeyboardOrKeypad,
     137        usage,
     138        isKeyDown,
     139        kIOHIDEventOptionNone));
     140    [self _sendHIDEvent:eventRef.get()];
     141}
     142
    132143- (IOHIDEventRef)_createIOHIDEventType:(HandEventType)eventType
    133144{
     
    429440}
    430441
     442static inline bool shouldWrapWithShiftKeyEventForCharacter(NSString *key)
     443{
     444    if (key.length != 1)
     445        return false;
     446    int keyCode = [key characterAtIndex:0];
     447    if (65 <= keyCode && keyCode <= 90)
     448        return true;
     449    switch (keyCode) {
     450    case '`':
     451    case '!':
     452    case '@':
     453    case '#':
     454    case '$':
     455    case '%':
     456    case '^':
     457    case '&':
     458    case '*':
     459    case '(':
     460    case ')':
     461    case '_':
     462    case '+':
     463    case '{':
     464    case '}':
     465    case '|':
     466    case ':':
     467    case '"':
     468    case '<':
     469    case '>':
     470    case '?':
     471    case '~':
     472        return true;
     473    }
     474    return false;
     475}
     476
     477static inline uint32_t hidUsageCodeForCharacter(NSString *key)
     478{
     479    const int uppercaseAlphabeticOffset = 'A' - kHIDUsage_KeyboardA;
     480    const int lowercaseAlphabeticOffset = 'a' - kHIDUsage_KeyboardA;
     481    const int numericNonZeroOffset = '1' - kHIDUsage_Keyboard1;
     482    if (key.length == 1) {
     483        // Handle alphanumeric characters and basic symbols.
     484        int keyCode = [key characterAtIndex:0];
     485        if (97 <= keyCode && keyCode <= 122) // Handle a-z.
     486            return keyCode - lowercaseAlphabeticOffset;
     487
     488        if (65 <= keyCode && keyCode <= 90) // Handle A-Z.
     489            return keyCode - uppercaseAlphabeticOffset;
     490
     491        if (49 <= keyCode && keyCode <= 57) // Handle 1-9.
     492            return keyCode - numericNonZeroOffset;
     493
     494        // Handle all other cases.
     495        switch (keyCode) {
     496        case '`':
     497        case '~':
     498            return kHIDUsage_KeyboardGraveAccentAndTilde;
     499        case '!':
     500            return kHIDUsage_Keyboard1;
     501        case '@':
     502            return kHIDUsage_Keyboard2;
     503        case '#':
     504            return kHIDUsage_Keyboard3;
     505        case '$':
     506            return kHIDUsage_Keyboard4;
     507        case '%':
     508            return kHIDUsage_Keyboard5;
     509        case '^':
     510            return kHIDUsage_Keyboard6;
     511        case '&':
     512            return kHIDUsage_Keyboard7;
     513        case '*':
     514            return kHIDUsage_Keyboard8;
     515        case '(':
     516            return kHIDUsage_Keyboard9;
     517        case ')':
     518        case '0':
     519            return kHIDUsage_Keyboard0;
     520        case '-':
     521        case '_':
     522            return kHIDUsage_KeyboardHyphen;
     523        case '=':
     524        case '+':
     525            return kHIDUsage_KeyboardEqualSign;
     526        case '\t':
     527            return kHIDUsage_KeyboardTab;
     528        case '[':
     529        case '{':
     530            return kHIDUsage_KeyboardOpenBracket;
     531        case ']':
     532        case '}':
     533            return kHIDUsage_KeyboardCloseBracket;
     534        case '\\':
     535        case '|':
     536            return kHIDUsage_KeyboardBackslash;
     537        case ';':
     538        case ':':
     539            return kHIDUsage_KeyboardSemicolon;
     540        case '\'':
     541        case '"':
     542            return kHIDUsage_KeyboardQuote;
     543        case '\r':
     544        case '\n':
     545            return kHIDUsage_KeyboardReturnOrEnter;
     546        case ',':
     547        case '<':
     548            return kHIDUsage_KeyboardComma;
     549        case '.':
     550        case '>':
     551            return kHIDUsage_KeyboardPeriod;
     552        case '/':
     553        case '?':
     554            return kHIDUsage_KeyboardSlash;
     555        case ' ':
     556            return kHIDUsage_KeyboardSpacebar;
     557        }
     558    }
     559    const int functionKeyOffset = kHIDUsage_KeyboardF1;
     560    for (int functionKeyIndex = 1; functionKeyIndex <= 12; ++functionKeyIndex) {
     561        if ([key isEqualToString:[NSString stringWithFormat:@"F%d", functionKeyIndex]])
     562            return functionKeyOffset + functionKeyIndex - 1;
     563    }
     564    if ([key isEqualToString:@"escape"])
     565        return kHIDUsage_KeyboardEscape;
     566    if ([key isEqualToString:@"return"] || [key isEqualToString:@"enter"])
     567        return kHIDUsage_KeyboardReturnOrEnter;
     568    if ([key isEqualToString:@"leftArrow"])
     569        return kHIDUsage_KeyboardLeftArrow;
     570    if ([key isEqualToString:@"rightArrow"])
     571        return kHIDUsage_KeyboardRightArrow;
     572    if ([key isEqualToString:@"upArrow"])
     573        return kHIDUsage_KeyboardUpArrow;
     574    if ([key isEqualToString:@"downArrow"])
     575        return kHIDUsage_KeyboardDownArrow;
     576    if ([key isEqualToString:@"delete"])
     577        return kHIDUsage_KeyboardDeleteOrBackspace;
     578    // The simulator keyboard interprets both left and right modifier keys using the left version of the usage code.
     579    if ([key isEqualToString:@"leftControl"] || [key isEqualToString:@"rightControl"])
     580        return kHIDUsage_KeyboardLeftControl;
     581    if ([key isEqualToString:@"leftShift"] || [key isEqualToString:@"rightShift"])
     582        return kHIDUsage_KeyboardLeftShift;
     583    if ([key isEqualToString:@"leftAlt"] || [key isEqualToString:@"rightAlt"])
     584        return kHIDUsage_KeyboardLeftAlt;
     585
     586    return 0;
     587}
     588
     589- (void)keyDown:(NSString *)character completionBlock:(void (^)(void))completionBlock
     590{
     591    bool shouldWrapWithShift = shouldWrapWithShiftKeyEventForCharacter(character);
     592    uint32_t usage = hidUsageCodeForCharacter(character);
     593    uint64_t absoluteMachTime = mach_absolute_time();
     594
     595    if (shouldWrapWithShift)
     596        [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:kHIDUsage_KeyboardLeftShift isKeyDown:true];
     597
     598    [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:usage isKeyDown:true];
     599    [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:usage isKeyDown:false];
     600
     601    if (shouldWrapWithShift)
     602        [self _sendIOHIDKeyboardEvent:absoluteMachTime usage:kHIDUsage_KeyboardLeftShift isKeyDown:false];
     603
     604    [self _sendMarkerHIDEventWithCompletionBlock:completionBlock];
     605}
     606
    431607@end
  • trunk/Tools/WebKitTestRunner/ios/IOKitSPI.h

    r190368 r190407  
    6161
    6262enum {
     63    kHIDPage_KeyboardOrKeypad       = 0x07
    6364    kHIDPage_VendorDefinedStart     = 0xFF00
    6465};
     
    128129#define kGSEventPathInfoInTouch (1 << 1)
    129130
     131enum {
     132    kHIDUsage_KeyboardA = 0x04,
     133    kHIDUsage_Keyboard1 = 0x1E,
     134    kHIDUsage_Keyboard2 = 0x1F,
     135    kHIDUsage_Keyboard3 = 0x20,
     136    kHIDUsage_Keyboard4 = 0x21,
     137    kHIDUsage_Keyboard5 = 0x22,
     138    kHIDUsage_Keyboard6 = 0x23,
     139    kHIDUsage_Keyboard7 = 0x24,
     140    kHIDUsage_Keyboard8 = 0x25,
     141    kHIDUsage_Keyboard9 = 0x26,
     142    kHIDUsage_Keyboard0 = 0x27,
     143    kHIDUsage_KeyboardReturnOrEnter = 0x28,
     144    kHIDUsage_KeyboardEscape = 0x29,
     145    kHIDUsage_KeyboardDeleteOrBackspace = 0x2A,
     146    kHIDUsage_KeyboardTab = 0x2B,
     147    kHIDUsage_KeyboardSpacebar = 0x2C,
     148    kHIDUsage_KeyboardHyphen = 0x2D,
     149    kHIDUsage_KeyboardEqualSign = 0x2E,
     150    kHIDUsage_KeyboardOpenBracket = 0x2F,
     151    kHIDUsage_KeyboardCloseBracket = 0x30,
     152    kHIDUsage_KeyboardBackslash = 0x31,
     153    kHIDUsage_KeyboardSemicolon = 0x33,
     154    kHIDUsage_KeyboardQuote = 0x34,
     155    kHIDUsage_KeyboardGraveAccentAndTilde = 0x35,
     156    kHIDUsage_KeyboardComma = 0x36,
     157    kHIDUsage_KeyboardPeriod = 0x37,
     158    kHIDUsage_KeyboardSlash = 0x38,
     159    kHIDUsage_KeyboardF1 = 0x3A,
     160    kHIDUsage_KeyboardHome = 0x4A,
     161    kHIDUsage_KeyboardPageUp = 0x4B,
     162    kHIDUsage_KeyboardEnd = 0x4D,
     163    kHIDUsage_KeyboardRightArrow = 0x4F,
     164    kHIDUsage_KeyboardLeftArrow = 0x50,
     165    kHIDUsage_KeyboardDownArrow = 0x51,
     166    kHIDUsage_KeyboardUpArrow = 0x52,
     167    kHIDUsage_KeyboardLeftControl = 0xE0,
     168    kHIDUsage_KeyboardLeftShift = 0xE1,
     169    kHIDUsage_KeyboardLeftAlt = 0xE2
     170};
     171
    130172WTF_EXTERN_C_END
    131173
  • trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm

    r190368 r190407  
    3131#import "HIDEventGenerator.h"
    3232#import "PlatformWebView.h"
     33#import "StringFunctions.h"
    3334#import "TestController.h"
    3435#import "TestRunnerWKWebView.h"
     
    9394}
    9495
     96void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
     97{
     98    unsigned callbackID = m_context.prepareForAsyncTask(callback);
     99
     100    // Assumes that the keyboard is already shown.
     101    [[HIDEventGenerator sharedHIDEventGenerator] keyDown:toWTFString(toWK(character)) completionBlock:^{
     102        m_context.asyncTaskComplete(callbackID);
     103    }];
     104}
     105
    95106double UIScriptController::minimumZoomScale() const
    96107{
     
    131142}
    132143
     144void UIScriptController::platformSetDidShowKeyboardCallback()
     145{
     146    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
     147    webView.didShowKeyboardCallback = ^{
     148        m_context.fireCallback(m_didShowKeyboardCallback);
     149    };
     150}
     151
     152void UIScriptController::platformSetDidHideKeyboardCallback()
     153{
     154    TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
     155    webView.didHideKeyboardCallback = ^{
     156        m_context.fireCallback(m_didHideKeyboardCallback);
     157    };
     158}
     159
    133160}
    134161
Note: See TracChangeset for help on using the changeset viewer.