WebEvent是iOS专有的类,负责封装和携带从UIKit得到的系统事件信息,并由WebKit层的WAKResponder子类传递到WebCore的EventHandler。
UIKit层的逻辑可参考《iOS私有API(三) UIWebView下的手势识别器gestureRecognizer》,WebKit层的相关类可参考《WebCore::Widget浅探》。
开源码中WebEvent的声明为:
typedef enum { WebEventMouseDown, WebEventMouseUp, WebEventMouseMoved, WebEventScrollWheel, WebEventKeyDown, WebEventKeyUp, WebEventTouchBegin, WebEventTouchChange, WebEventTouchEnd, WebEventTouchCancel } WebEventType; typedef enum { WebEventTouchPhaseBegan, WebEventTouchPhaseMoved, WebEventTouchPhaseStationary, WebEventTouchPhaseEnded, WebEventTouchPhaseCancelled } WebEventTouchPhaseType; // These enum values are copied directly from GSEvent for compatibility. typedef enum { WebEventFlagMaskAlphaShift = 0x00010000, WebEventFlagMaskShift = 0x00020000, WebEventFlagMaskControl = 0x00040000, WebEventFlagMaskAlternate = 0x00080000, WebEventFlagMaskCommand = 0x00100000, } WebEventFlagValues; typedef unsigned WebEventFlags; // These enum values are copied directly from GSEvent for compatibility. typedef enum { WebEventCharacterSetASCII = 0, WebEventCharacterSetSymbol = 1, WebEventCharacterSetDingbats = 2, WebEventCharacterSetUnicode = 253, WebEventCharacterSetFunctionKeys = 254, } WebEventCharacterSet; @interface WebEvent : NSObject { @private WebEventType _type; CFTimeInterval _timestamp; CGPoint _locationInWindow; NSString *_characters; NSString *_charactersIgnoringModifiers; WebEventFlags _modifierFlags; BOOL _keyRepeating; BOOL _popupVariant; uint16_t _keyCode; BOOL _tabKey; WebEventCharacterSet _characterSet; float _deltaX; float _deltaY; unsigned _touchCount; NSArray *_touchLocations; NSArray *_touchIdentifiers; NSArray *_touchPhases; BOOL _isGesture; float _gestureScale; float _gestureRotation; } - (WebEvent *)initWithMouseEventType:(WebEventType)type timeStamp:(CFTimeInterval)timeStamp location:(CGPoint)point; - (WebEvent *)initWithScrollWheelEventWithTimeStamp:(CFTimeInterval)timeStamp location:(CGPoint)point deltaX:(float)deltaX deltaY:(float)deltaY; - (WebEvent *)initWithTouchEventType:(WebEventType)type timeStamp:(CFTimeInterval)timeStamp location:(CGPoint)point modifiers:(WebEventFlags)modifiers touchCount:(unsigned)touchCount touchLocations:(NSArray *)touchLocations touchIdentifiers:(NSArray *)touchIdentifiers touchPhases:(NSArray *)touchPhases isGesture:(BOOL)isGesture gestureScale:(float)gestureScale gestureRotation:(float)gestureRotation; - (WebEvent *)initWithKeyEventType:(WebEventType)type timeStamp:(CFTimeInterval)timeStamp characters:(NSString *)characters charactersIgnoringModifiers:(NSString *)charactersIgnoringModifiers modifiers:(WebEventFlags)modifiers isRepeating:(BOOL)repeating isPopupVariant:(BOOL)popupVariant keyCode:(uint16_t)keyCode isTabKey:(BOOL)tabKey characterSet:(WebEventCharacterSet)characterSet; @property(nonatomic,readonly) WebEventType type; @property(nonatomic,readonly) CFTimeInterval timestamp; // Mouse @property(nonatomic,readonly) CGPoint locationInWindow; // Keyboard @property(nonatomic,readonly,retain) NSString *characters; @property(nonatomic,readonly,retain) NSString *charactersIgnoringModifiers; @property(nonatomic,readonly) WebEventFlags modifierFlags; @property(nonatomic,readonly,getter=isKeyRepeating) BOOL keyRepeating; @property(nonatomic,readonly,getter=isPopupVariant) BOOL popupVariant; @property(nonatomic,readonly) uint16_t keyCode; @property(nonatomic,readonly,getter=isTabKey) BOOL tabKey; @property(nonatomic,readonly) WebEventCharacterSet characterSet; // Scroll Wheel @property(nonatomic,readonly) float deltaX; @property(nonatomic,readonly) float deltaY; // Touch @property(nonatomic,readonly) unsigned touchCount; @property(nonatomic,readonly,retain) NSArray *touchLocations; @property(nonatomic,readonly,retain) NSArray *touchIdentifiers; @property(nonatomic,readonly,retain) NSArray *touchPhases; // Gesture @property(nonatomic,readonly) BOOL isGesture; @property(nonatomic,readonly) float gestureScale; @property(nonatomic,readonly) float gestureRotation; @end
WebEvent封装了4种事件:鼠标(手指)、键盘、滚轮、触摸,主要通过属性WebEventType type来区分。
鼠标事件主要由单击手势来触发,会产生mouseup,mousemove和mousedown事件。其中单击就是同一RunLoop内连贯的mousedown和mouseup,而mousemove是模拟事件,可触发mouseover消息。
键盘事件发生在编辑框内,按下iOS虚拟键盘的按键就会触发。
滚轮由双指平移手势触发,在输入框内有效。
触摸特指JavaScript监听的touchstart、gesturestart等消息,由UIWebTouchEventsGestureRecognizer来计算。
这些事件触发后,都会在主线程创建WebEvent,然后用GCD技术转到WebThread执行。
开源码的EventHandler.h中有如下几行:
#if PLATFORM(MAC) && defined(__OBJC__) void mouseDown(WebEvent *); void mouseUp(WebEvent *); void mouseMoved(WebEvent *); bool keyEvent(WebEvent *); bool wheelEvent(WebEvent *); void touchEvent(WebEvent *); static WebEvent *currentEvent(); #endif
使用xdb也能找到,可是在EventHandler的实现中却找不到,所以Apple是没有完全公开iOS源码的。
另有一个PlatformEventFactoryIOS.h的文件有如下声明:
class PlatformEventFactory { public: static PlatformMouseEvent createPlatformMouseEvent(WebEvent *); static PlatformWheelEvent createPlatformWheelEvent(WebEvent *); static PlatformKeyboardEvent createPlatformKeyboardEvent(WebEvent *); static PlatformTouchEvent createPlatformTouchEvent(WebEvent *); };
这些函数的作用就是把Objective-C类封装的WebEvent转换成WebCore里C++的PlatformEvent。可以猜测,接受WebEvent型参数的EventHandler函数也就只是简单做这个工作,转换后再直接调用通用的函数就ok了。如:
bool handleMousePressEvent(const PlatformMouseEvent&); bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0, bool onlyUpdateScrollbars = false); bool handleMouseReleaseEvent(const PlatformMouseEvent&); bool handleWheelEvent(const PlatformWheelEvent&); void defaultWheelEventHandler(Node*, WheelEvent*); #if ENABLE(GESTURE_EVENTS) bool handleGestureEvent(const PlatformGestureEvent&); bool handleGestureTap(const PlatformGestureEvent&, Node* preTargetedNode = 0); bool handleGestureScrollUpdate(const PlatformGestureEvent&); #endif
一个堆栈示例:
Thread 4 WebThread, Queue : (null) #0 0x03385790 in WebCore::EventHandler::mouseMoved(WebCore::PlatformMouseEvent const&) () #1 0x0338ae0f in WebCore::EventHandler::mouseMoved(WebEvent*) () #2 0x02efd822 in -[WebHTMLView(WebPrivate) mouseMoved:] () #3 0x03f6c6ac in -[WAKView _selfHandleEvent:] () #4 0x03f6c603 in -[WAKView handleEvent:] () #5 0x03f6f94d in -[WAKWindow sendEventSynchronously:] () #6 0x03f6f75b in __23-[WAKWindow sendEvent:]_block_invoke () #7 0x03f83fe2 in _WebThreadRun () #8 0x03f83ee0 in WebThreadRun () #9 0x03f6f71c in -[WAKWindow sendEvent:] () #10 0x03f6fa0c in __46-[WAKWindow sendMouseMoveEvent:contentChange:]_block_invoke () #11 0x03f83fe2 in _WebThreadRun () #12 0x03f83ee0 in WebThreadRun () #13 0x03f6f9d2 in -[WAKWindow sendMouseMoveEvent:contentChange:] () #14 0x0023609d in __64-[UIWebDocumentView(Interaction) _sendMouseMoveAndAttemptClick:]_block_invoke () #15 0x03f844ea in HandleRunSource () #16 0x0226e33f in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ () #17 0x0226dd95 in __CFRunLoopDoSources0 () #18 0x0228b124 in __CFRunLoopRun () #19 0x0228a59f in CFRunLoopRunSpecific () #20 0x0228a3eb in CFRunLoopRunInMode () #21 0x03f83c30 in RunWebThread(void*) () #22 0x05a5c65c in _pthread_body () #23 0x05a5c4e6 in _pthread_start ()
其它的Event都差不多,不再赘述了。