RCTTVRemoteHandler.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #import "RCTTVRemoteHandler.h"
  8. #import <UIKit/UIGestureRecognizerSubclass.h>
  9. #import "RCTAssert.h"
  10. #import "RCTBridge.h"
  11. #import "RCTEventDispatcher.h"
  12. #import "RCTLog.h"
  13. #import "RCTRootView.h"
  14. #import "RCTTVNavigationEventEmitter.h"
  15. #import "RCTUIManager.h"
  16. #import "RCTUtils.h"
  17. #import "RCTView.h"
  18. #import "UIView+React.h"
  19. #if __has_include("RCTDevMenu.h")
  20. #import "RCTDevMenu.h"
  21. #endif
  22. NSString *const RCTTVRemoteEventMenu = @"menu";
  23. NSString *const RCTTVRemoteEventPlayPause = @"playPause";
  24. NSString *const RCTTVRemoteEventSelect = @"select";
  25. NSString *const RCTTVRemoteEventLongPlayPause = @"longPlayPause";
  26. NSString *const RCTTVRemoteEventLongSelect = @"longSelect";
  27. NSString *const RCTTVRemoteEventLeft = @"left";
  28. NSString *const RCTTVRemoteEventRight = @"right";
  29. NSString *const RCTTVRemoteEventUp = @"up";
  30. NSString *const RCTTVRemoteEventDown = @"down";
  31. NSString *const RCTTVRemoteEventSwipeLeft = @"swipeLeft";
  32. NSString *const RCTTVRemoteEventSwipeRight = @"swipeRight";
  33. NSString *const RCTTVRemoteEventSwipeUp = @"swipeUp";
  34. NSString *const RCTTVRemoteEventSwipeDown = @"swipeDown";
  35. @implementation RCTTVRemoteHandler {
  36. NSMutableDictionary<NSString *, UIGestureRecognizer *> *_tvRemoteGestureRecognizers;
  37. }
  38. - (instancetype)init
  39. {
  40. if ((self = [super init])) {
  41. _tvRemoteGestureRecognizers = [NSMutableDictionary dictionary];
  42. // Recognizers for Apple TV remote buttons
  43. // Play/Pause
  44. [self addTapGestureRecognizerWithSelector:@selector(playPausePressed:)
  45. pressType:UIPressTypePlayPause
  46. name:RCTTVRemoteEventPlayPause];
  47. // Menu
  48. [self addTapGestureRecognizerWithSelector:@selector(menuPressed:)
  49. pressType:UIPressTypeMenu
  50. name:RCTTVRemoteEventMenu];
  51. // Select
  52. [self addTapGestureRecognizerWithSelector:@selector(selectPressed:)
  53. pressType:UIPressTypeSelect
  54. name:RCTTVRemoteEventSelect];
  55. // Up
  56. [self addTapGestureRecognizerWithSelector:@selector(tappedUp:)
  57. pressType:UIPressTypeUpArrow
  58. name:RCTTVRemoteEventUp];
  59. // Down
  60. [self addTapGestureRecognizerWithSelector:@selector(tappedDown:)
  61. pressType:UIPressTypeDownArrow
  62. name:RCTTVRemoteEventDown];
  63. // Left
  64. [self addTapGestureRecognizerWithSelector:@selector(tappedLeft:)
  65. pressType:UIPressTypeLeftArrow
  66. name:RCTTVRemoteEventLeft];
  67. // Right
  68. [self addTapGestureRecognizerWithSelector:@selector(tappedRight:)
  69. pressType:UIPressTypeRightArrow
  70. name:RCTTVRemoteEventRight];
  71. // Recognizers for long button presses
  72. // We don't intercept long menu press -- that's used by the system to go to the home screen
  73. [self addLongPressGestureRecognizerWithSelector:@selector(longPlayPausePressed:)
  74. pressType:UIPressTypePlayPause
  75. name:RCTTVRemoteEventLongPlayPause];
  76. [self addLongPressGestureRecognizerWithSelector:@selector(longSelectPressed:)
  77. pressType:UIPressTypeSelect
  78. name:RCTTVRemoteEventLongSelect];
  79. // Recognizers for Apple TV remote trackpad swipes
  80. // Up
  81. [self addSwipeGestureRecognizerWithSelector:@selector(swipedUp:)
  82. direction:UISwipeGestureRecognizerDirectionUp
  83. name:RCTTVRemoteEventSwipeUp];
  84. // Down
  85. [self addSwipeGestureRecognizerWithSelector:@selector(swipedDown:)
  86. direction:UISwipeGestureRecognizerDirectionDown
  87. name:RCTTVRemoteEventSwipeDown];
  88. // Left
  89. [self addSwipeGestureRecognizerWithSelector:@selector(swipedLeft:)
  90. direction:UISwipeGestureRecognizerDirectionLeft
  91. name:RCTTVRemoteEventSwipeLeft];
  92. // Right
  93. [self addSwipeGestureRecognizerWithSelector:@selector(swipedRight:)
  94. direction:UISwipeGestureRecognizerDirectionRight
  95. name:RCTTVRemoteEventSwipeRight];
  96. }
  97. return self;
  98. }
  99. - (void)playPausePressed:(UIGestureRecognizer *)r
  100. {
  101. [self sendAppleTVEvent:RCTTVRemoteEventPlayPause toView:r.view];
  102. }
  103. - (void)menuPressed:(UIGestureRecognizer *)r
  104. {
  105. [self sendAppleTVEvent:RCTTVRemoteEventMenu toView:r.view];
  106. }
  107. - (void)selectPressed:(UIGestureRecognizer *)r
  108. {
  109. [self sendAppleTVEvent:RCTTVRemoteEventSelect toView:r.view];
  110. }
  111. - (void)longPlayPausePressed:(UIGestureRecognizer *)r
  112. {
  113. [self sendAppleTVEvent:RCTTVRemoteEventLongPlayPause toView:r.view];
  114. #if __has_include("RCTDevMenu.h") && RCT_DEV
  115. // If shake to show is enabled on device, use long play/pause event to show dev menu
  116. [[NSNotificationCenter defaultCenter] postNotificationName:RCTShowDevMenuNotification object:nil];
  117. #endif
  118. }
  119. - (void)longSelectPressed:(UIGestureRecognizer *)r
  120. {
  121. [self sendAppleTVEvent:RCTTVRemoteEventLongSelect toView:r.view];
  122. }
  123. - (void)swipedUp:(UIGestureRecognizer *)r
  124. {
  125. [self sendAppleTVEvent:RCTTVRemoteEventSwipeUp toView:r.view];
  126. }
  127. - (void)swipedDown:(UIGestureRecognizer *)r
  128. {
  129. [self sendAppleTVEvent:RCTTVRemoteEventSwipeDown toView:r.view];
  130. }
  131. - (void)swipedLeft:(UIGestureRecognizer *)r
  132. {
  133. [self sendAppleTVEvent:RCTTVRemoteEventSwipeLeft toView:r.view];
  134. }
  135. - (void)swipedRight:(UIGestureRecognizer *)r
  136. {
  137. [self sendAppleTVEvent:RCTTVRemoteEventSwipeRight toView:r.view];
  138. }
  139. - (void)tappedUp:(UIGestureRecognizer *)r
  140. {
  141. [self sendAppleTVEvent:RCTTVRemoteEventUp toView:r.view];
  142. }
  143. - (void)tappedDown:(UIGestureRecognizer *)r
  144. {
  145. [self sendAppleTVEvent:RCTTVRemoteEventDown toView:r.view];
  146. }
  147. - (void)tappedLeft:(UIGestureRecognizer *)r
  148. {
  149. [self sendAppleTVEvent:RCTTVRemoteEventLeft toView:r.view];
  150. }
  151. - (void)tappedRight:(UIGestureRecognizer *)r
  152. {
  153. [self sendAppleTVEvent:RCTTVRemoteEventRight toView:r.view];
  154. }
  155. #pragma mark -
  156. - (void)addLongPressGestureRecognizerWithSelector:(nonnull SEL)selector
  157. pressType:(UIPressType)pressType
  158. name:(NSString *)name
  159. {
  160. UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:selector];
  161. recognizer.allowedPressTypes = @[ @(pressType) ];
  162. _tvRemoteGestureRecognizers[name] = recognizer;
  163. }
  164. - (void)addTapGestureRecognizerWithSelector:(nonnull SEL)selector pressType:(UIPressType)pressType name:(NSString *)name
  165. {
  166. UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:selector];
  167. recognizer.allowedPressTypes = @[ @(pressType) ];
  168. _tvRemoteGestureRecognizers[name] = recognizer;
  169. }
  170. - (void)addSwipeGestureRecognizerWithSelector:(nonnull SEL)selector
  171. direction:(UISwipeGestureRecognizerDirection)direction
  172. name:(NSString *)name
  173. {
  174. UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:selector];
  175. recognizer.direction = direction;
  176. _tvRemoteGestureRecognizers[name] = recognizer;
  177. }
  178. - (void)sendAppleTVEvent:(NSString *)eventType toView:(__unused UIView *)v
  179. {
  180. [[NSNotificationCenter defaultCenter] postNotificationName:RCTTVNavigationEventNotification
  181. object:@{@"eventType" : eventType}];
  182. }
  183. @end