mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
cb719a16cc
Summary: With the upgrade to React Native 0.63, we started running into nullability warnings that were breaking our build. This PR fixes those nullability warnings as well as a few other warnings in React-Core. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Fixed] - Fix xcodebuild warnings in React-Core Pull Request resolved: https://github.com/facebook/react-native/pull/29622 Test Plan: - Nullability annotations should only affect compilation, but even though RNTester compiles, I'm not fully convinced that this won't break projects downstream. It would be good to get another opinion on this. - The change in `RCTAllocateRootViewTag` is the only real logic change in this PR. We throw an exception if the root view tag is not in the correct format, so this change seems safe after some basic manual testing in RNTester. Reviewed By: shergin Differential Revision: D23386678 Pulled By: appden fbshipit-source-id: a74875195a4614c3248e8f968aa98602e3ee2de0
268 lines
7.0 KiB
Objective-C
268 lines
7.0 KiB
Objective-C
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "RCTKeyCommands.h"
|
|
|
|
#import <UIKit/UIKit.h>
|
|
|
|
#import <objc/message.h>
|
|
#import <objc/runtime.h>
|
|
#import "RCTDefines.h"
|
|
#import "RCTUtils.h"
|
|
|
|
#if RCT_DEV
|
|
|
|
@interface UIEvent (UIPhysicalKeyboardEvent)
|
|
|
|
@property (nonatomic) NSString *_modifiedInput;
|
|
@property (nonatomic) NSString *_unmodifiedInput;
|
|
@property (nonatomic) UIKeyModifierFlags _modifierFlags;
|
|
@property (nonatomic) BOOL _isKeyDown;
|
|
@property (nonatomic) long _keyCode;
|
|
|
|
@end
|
|
|
|
@interface RCTKeyCommand : NSObject <NSCopying>
|
|
|
|
@property (nonatomic, copy, readonly) NSString *key;
|
|
@property (nonatomic, readonly) UIKeyModifierFlags flags;
|
|
@property (nonatomic, copy) void (^block)(UIKeyCommand *);
|
|
|
|
@end
|
|
|
|
@implementation RCTKeyCommand
|
|
|
|
- (instancetype)init:(NSString *)key flags:(UIKeyModifierFlags)flags block:(void (^)(UIKeyCommand *))block
|
|
{
|
|
if ((self = [super init])) {
|
|
_key = key;
|
|
_flags = flags;
|
|
_block = block;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
|
|
|
- (id)copyWithZone:(__unused NSZone *)zone
|
|
{
|
|
return self;
|
|
}
|
|
|
|
- (NSUInteger)hash
|
|
{
|
|
return _key.hash ^ _flags;
|
|
}
|
|
|
|
- (BOOL)isEqual:(RCTKeyCommand *)object
|
|
{
|
|
if (![object isKindOfClass:[RCTKeyCommand class]]) {
|
|
return NO;
|
|
}
|
|
return [self matchesInput:object.key flags:object.flags];
|
|
}
|
|
|
|
- (BOOL)matchesInput:(NSString *)input flags:(UIKeyModifierFlags)flags
|
|
{
|
|
// We consider the key command a match if the modifier flags match
|
|
// exactly or is there are no modifier flags. This means that for
|
|
// `cmd + r`, we will match both `cmd + r` and `r` but not `opt + r`.
|
|
return [_key isEqual:input] && (_flags == flags || flags == 0);
|
|
}
|
|
|
|
- (NSString *)description
|
|
{
|
|
return [NSString stringWithFormat:@"<%@:%p input=\"%@\" flags=%lld hasBlock=%@>",
|
|
[self class],
|
|
self,
|
|
_key,
|
|
(long long)_flags,
|
|
_block ? @"YES" : @"NO"];
|
|
}
|
|
|
|
@end
|
|
|
|
@interface RCTKeyCommands ()
|
|
|
|
@property (nonatomic, strong) NSMutableSet<RCTKeyCommand *> *commands;
|
|
|
|
@end
|
|
|
|
@implementation RCTKeyCommands
|
|
|
|
+ (void)initialize
|
|
{
|
|
SEL originalKeyEventSelector = NSSelectorFromString(@"handleKeyUIEvent:");
|
|
SEL swizzledKeyEventSelector = NSSelectorFromString(
|
|
[NSString stringWithFormat:@"_rct_swizzle_%x_%@", arc4random(), NSStringFromSelector(originalKeyEventSelector)]);
|
|
|
|
void (^handleKeyUIEventSwizzleBlock)(UIApplication *, UIEvent *) = ^(UIApplication *slf, UIEvent *event) {
|
|
[[[self class] sharedInstance] handleKeyUIEventSwizzle:event];
|
|
|
|
((void (*)(id, SEL, id))objc_msgSend)(slf, swizzledKeyEventSelector, event);
|
|
};
|
|
|
|
RCTSwapInstanceMethodWithBlock(
|
|
[UIApplication class], originalKeyEventSelector, handleKeyUIEventSwizzleBlock, swizzledKeyEventSelector);
|
|
}
|
|
|
|
- (void)handleKeyUIEventSwizzle:(UIEvent *)event
|
|
{
|
|
NSString *modifiedInput = nil;
|
|
UIKeyModifierFlags modifierFlags = 0;
|
|
BOOL isKeyDown = NO;
|
|
|
|
if ([event respondsToSelector:@selector(_modifiedInput)]) {
|
|
modifiedInput = [event _modifiedInput];
|
|
}
|
|
|
|
if ([event respondsToSelector:@selector(_modifierFlags)]) {
|
|
modifierFlags = [event _modifierFlags];
|
|
}
|
|
|
|
if ([event respondsToSelector:@selector(_isKeyDown)]) {
|
|
isKeyDown = [event _isKeyDown];
|
|
}
|
|
|
|
BOOL interactionEnabled = !UIApplication.sharedApplication.isIgnoringInteractionEvents;
|
|
BOOL hasFirstResponder = NO;
|
|
if (isKeyDown && modifiedInput.length > 0 && interactionEnabled) {
|
|
UIResponder *firstResponder = nil;
|
|
for (UIWindow *window in [self allWindows]) {
|
|
firstResponder = [window valueForKey:@"firstResponder"];
|
|
if (firstResponder) {
|
|
hasFirstResponder = YES;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Ignore key commands (except escape) when there's an active responder
|
|
if (!firstResponder) {
|
|
[self RCT_handleKeyCommand:modifiedInput flags:modifierFlags];
|
|
}
|
|
}
|
|
};
|
|
|
|
- (NSArray<UIWindow *> *)allWindows
|
|
{
|
|
BOOL includeInternalWindows = YES;
|
|
BOOL onlyVisibleWindows = NO;
|
|
|
|
// Obfuscating selector allWindowsIncludingInternalWindows:onlyVisibleWindows:
|
|
NSArray<NSString *> *allWindowsComponents =
|
|
@[ @"al", @"lWindo", @"wsIncl", @"udingInt", @"ernalWin", @"dows:o", @"nlyVisi", @"bleWin", @"dows:" ];
|
|
SEL allWindowsSelector = NSSelectorFromString([allWindowsComponents componentsJoinedByString:@""]);
|
|
|
|
NSMethodSignature *methodSignature = [[UIWindow class] methodSignatureForSelector:allWindowsSelector];
|
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
|
|
|
invocation.target = [UIWindow class];
|
|
invocation.selector = allWindowsSelector;
|
|
[invocation setArgument:&includeInternalWindows atIndex:2];
|
|
[invocation setArgument:&onlyVisibleWindows atIndex:3];
|
|
[invocation invoke];
|
|
|
|
__unsafe_unretained NSArray<UIWindow *> *windows = nil;
|
|
[invocation getReturnValue:&windows];
|
|
return windows;
|
|
}
|
|
|
|
- (void)RCT_handleKeyCommand:(NSString *)input flags:(UIKeyModifierFlags)modifierFlags
|
|
{
|
|
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
|
|
if ([command matchesInput:input flags:modifierFlags]) {
|
|
if (command.block) {
|
|
command.block(nil);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ (instancetype)sharedInstance
|
|
{
|
|
static RCTKeyCommands *sharedInstance;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
sharedInstance = [self new];
|
|
});
|
|
|
|
return sharedInstance;
|
|
}
|
|
|
|
- (instancetype)init
|
|
{
|
|
if ((self = [super init])) {
|
|
_commands = [NSMutableSet new];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)registerKeyCommandWithInput:(NSString *)input
|
|
modifierFlags:(UIKeyModifierFlags)flags
|
|
action:(void (^)(UIKeyCommand *))block
|
|
{
|
|
RCTAssertMainQueue();
|
|
|
|
RCTKeyCommand *keyCommand = [[RCTKeyCommand alloc] init:input flags:flags block:block];
|
|
[_commands removeObject:keyCommand];
|
|
[_commands addObject:keyCommand];
|
|
}
|
|
|
|
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
|
|
{
|
|
RCTAssertMainQueue();
|
|
|
|
for (RCTKeyCommand *command in _commands.allObjects) {
|
|
if ([command matchesInput:input flags:flags]) {
|
|
[_commands removeObject:command];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
|
|
{
|
|
RCTAssertMainQueue();
|
|
|
|
for (RCTKeyCommand *command in _commands) {
|
|
if ([command matchesInput:input flags:flags]) {
|
|
return YES;
|
|
}
|
|
}
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
#else
|
|
|
|
@implementation RCTKeyCommands
|
|
|
|
+ (instancetype)sharedInstance
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
- (void)registerKeyCommandWithInput:(NSString *)input
|
|
modifierFlags:(UIKeyModifierFlags)flags
|
|
action:(void (^)(UIKeyCommand *))block
|
|
{
|
|
}
|
|
|
|
- (void)unregisterKeyCommandWithInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
|
|
{
|
|
}
|
|
|
|
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input modifierFlags:(UIKeyModifierFlags)flags
|
|
{
|
|
return NO;
|
|
}
|
|
|
|
@end
|
|
|
|
#endif
|