2015-03-23 20:28:42 +00:00
/ * *
* Copyright ( c ) 2015 - present , Facebook , Inc .
* All rights reserved .
*
* This source code is licensed under the BSD - style license found in the
* LICENSE file in the root directory of this source tree . An additional grant
* of patent rights can be found in the PATENTS file in the same directory .
* /
2015-02-20 04:10:52 +00:00
# import "RCTEventDispatcher.h"
# import "RCTAssert.h"
# import "RCTBridge.h"
2016-04-01 13:53:12 +00:00
# import "RCTBridge+Private.h"
2015-08-11 13:37:12 +00:00
# import "RCTUtils.h"
2016-04-01 13:53:12 +00:00
# import "RCTProfile.h"
2015-05-28 03:15:33 +00:00
2015-07-21 19:37:24 +00:00
const NSInteger RCTTextUpdateLagWarningThreshold = 3 ;
2015-08-11 13:37:12 +00:00
NSString * RCTNormalizeInputEventName ( NSString * eventName )
{
if ( [ eventName hasPrefix : @ "on" ] ) {
eventName = [ eventName stringByReplacingCharactersInRange : ( NSRange ) { 0 , 2 } withString : @ "top" ] ;
} else if ( ! [ eventName hasPrefix : @ "top" ] ) {
eventName = [ [ @ "top" stringByAppendingString : [ eventName substringToIndex : 1 ] . uppercaseString ]
stringByAppendingString : [ eventName substringFromIndex : 1 ] ] ;
}
return eventName ;
}
2015-06-02 09:58:49 +00:00
static NSNumber * RCTGetEventID ( id < RCTEvent > event )
2015-05-28 03:15:33 +00:00
{
2015-06-02 09:58:49 +00:00
return @ (
2015-08-24 10:14:33 +00:00
event . viewTag . intValue |
2016-04-01 13:53:04 +00:00
( ( ( uint64_t ) event . eventName . hash & 0 xFFFF ) < < 32 ) |
( ( ( uint64_t ) event . coalescingKey ) < < 48 )
) ;
2015-05-28 03:15:33 +00:00
}
2015-02-20 04:10:52 +00:00
@ implementation RCTEventDispatcher
{
2016-04-01 13:53:12 +00:00
// We need this lock to protect access to _eventQueue and __eventsDispatchScheduled . It ' s filled in on main thread and consumed on js thread .
2015-05-28 03:15:33 +00:00
NSLock * _eventQueueLock ;
2016-04-01 13:53:12 +00:00
NSMutableDictionary * _eventQueue ;
BOOL _eventsDispatchScheduled ;
2015-02-20 04:10:52 +00:00
}
2015-05-28 03:15:33 +00:00
@ synthesize bridge = _bridge ;
RCT_EXPORT _MODULE ( )
2015-11-25 11:09:00 +00:00
- ( void ) setBridge : ( RCTBridge * ) bridge
2015-02-20 04:10:52 +00:00
{
2015-11-25 11:09:00 +00:00
_bridge = bridge ;
_eventQueue = [ NSMutableDictionary new ] ;
_eventQueueLock = [ NSLock new ] ;
2016-04-01 13:53:12 +00:00
_eventsDispatchScheduled = NO ;
2015-09-29 12:26:01 +00:00
}
2015-02-24 17:06:57 +00:00
- ( void ) sendAppEventWithName : ( NSString * ) name body : ( id ) body
{
[ _bridge enqueueJSCall : @ "RCTNativeAppEventEmitter.emit"
2015-02-20 04:10:52 +00:00
args : body ? @ [ name , body ] : @ [ name ] ] ;
}
2015-02-24 17:06:57 +00:00
- ( void ) sendDeviceEventWithName : ( NSString * ) name body : ( id ) body
{
[ _bridge enqueueJSCall : @ "RCTDeviceEventEmitter.emit"
args : body ? @ [ name , body ] : @ [ name ] ] ;
}
2015-02-20 04:10:52 +00:00
- ( void ) sendInputEventWithName : ( NSString * ) name body : ( NSDictionary * ) body
{
2015-08-11 13:37:12 +00:00
if ( RCT_DEBUG ) {
RCTAssert ( [ body [ @ "target" ] isKindOfClass : [ NSNumber class ] ] ,
@ "Event body dictionary must include a 'target' property containing a React tag" ) ;
}
2015-03-23 20:28:42 +00:00
2015-08-11 13:37:12 +00:00
name = RCTNormalizeInputEventName ( name ) ;
2015-02-20 04:10:52 +00:00
[ _bridge enqueueJSCall : @ "RCTEventEmitter.receiveEvent"
2015-02-24 17:06:57 +00:00
args : body ? @ [ body [ @ "target" ] , name , body ] : @ [ body [ @ "target" ] , name ] ] ;
2015-02-20 04:10:52 +00:00
}
- ( void ) sendTextEventWithType : ( RCTTextEventType ) type
reactTag : ( NSNumber * ) reactTag
text : ( NSString * ) text
2015-11-02 17:13:41 +00:00
key : ( NSString * ) key
2015-07-21 19:37:24 +00:00
eventCount : ( NSInteger ) eventCount
2015-02-20 04:10:52 +00:00
{
static NSString * events [ ] = {
2015-08-11 13:37:12 +00:00
@ "focus" ,
@ "blur" ,
@ "change" ,
@ "submitEditing" ,
@ "endEditing" ,
2015-11-02 17:13:41 +00:00
@ "keyPress"
2015-02-20 04:10:52 +00:00
} ;
2015-03-23 20:28:42 +00:00
2015-11-02 17:13:41 +00:00
NSMutableDictionary * body = [ [ NSMutableDictionary alloc ] initWithDictionary : @ {
2015-07-21 19:37:24 +00:00
@ "eventCount" : @ ( eventCount ) ,
2015-02-24 17:06:57 +00:00
@ "target" : reactTag
2015-02-20 04:10:52 +00:00
} ] ;
2015-11-02 17:13:41 +00:00
if ( text ) {
body [ @ "text" ] = text ;
}
if ( key ) {
if ( key . length = = 0 ) {
key = @ "Backspace" ; // backspace
} else {
switch ( [ key characterAtIndex : 0 ] ) {
case ' \ t ' :
key = @ "Tab" ;
break ;
case ' \ n ' :
key = @ "Enter" ;
default :
break ;
}
}
body [ @ "key" ] = key ;
}
[ self sendInputEventWithName : events [ type ] body : body ] ;
2015-02-20 04:10:52 +00:00
}
2015-05-28 03:15:33 +00:00
- ( void ) sendEvent : ( id < RCTEvent > ) event
2015-02-20 04:10:52 +00:00
{
2015-05-28 03:15:33 +00:00
[ _eventQueueLock lock ] ;
2015-06-02 09:58:49 +00:00
NSNumber * eventID = RCTGetEventID ( event ) ;
2015-05-28 03:15:33 +00:00
2016-04-01 13:53:12 +00:00
id < RCTEvent > previousEvent = _eventQueue [ eventID ] ;
2015-05-28 03:15:33 +00:00
if ( previousEvent ) {
2016-04-01 13:53:12 +00:00
RCTAssert ( [ event canCoalesce ] , @ "Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@" , event , eventID , previousEvent ) ;
2015-05-28 03:15:33 +00:00
event = [ previousEvent coalesceWithEvent : event ] ;
}
_eventQueue [ eventID ] = event ;
2016-04-01 13:53:12 +00:00
if ( ! _eventsDispatchScheduled ) {
_eventsDispatchScheduled = YES ;
[ _bridge dispatchBlock : ^ {
[ self flushEventsQueue ] ;
} queue : RCTJSThread ] ;
}
2015-05-28 03:15:33 +00:00
[ _eventQueueLock unlock ] ;
}
- ( void ) dispatchEvent : ( id < RCTEvent > ) event
{
2016-02-03 13:22:14 +00:00
[ _bridge enqueueJSCall : [ [ event class ] moduleDotMethod ] args : [ event arguments ] ] ;
2015-05-28 03:15:33 +00:00
}
- ( dispatch_queue _t ) methodQueue
{
return RCTJSThread ;
}
2016-04-01 13:53:12 +00:00
// js thread only
2016-02-03 13:22:15 +00:00
- ( void ) flushEventsQueue
2015-05-28 03:15:33 +00:00
{
[ _eventQueueLock lock ] ;
2016-02-03 13:22:15 +00:00
NSDictionary * eventQueue = _eventQueue ;
2015-08-17 14:35:34 +00:00
_eventQueue = [ NSMutableDictionary new ] ;
2016-04-01 13:53:12 +00:00
_eventsDispatchScheduled = NO ;
2015-05-28 03:15:33 +00:00
[ _eventQueueLock unlock ] ;
2015-06-02 09:58:49 +00:00
for ( id < RCTEvent > event in eventQueue . allValues ) {
2015-05-28 03:15:33 +00:00
[ self dispatchEvent : event ] ;
}
}
@ end