Skip to content

Commit eda44ed

Browse files
committed
Fixed Cmd-R shortcut on iOS 9
1 parent 457fca4 commit eda44ed

File tree

1 file changed

+92
-25
lines changed

1 file changed

+92
-25
lines changed

React/Base/RCTKeyCommands.m

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@
1111

1212
#import <UIKit/UIKit.h>
1313

14+
#import "RCTDefines.h"
1415
#import "RCTUtils.h"
1516

17+
#if RCT_DEV
18+
19+
static BOOL RCTIsIOS8OrEarlier()
20+
{
21+
return [UIDevice currentDevice].systemVersion.floatValue < 9;
22+
}
23+
1624
@interface RCTKeyCommand : NSObject <NSCopying>
1725

1826
@property (nonatomic, strong) UIKeyCommand *keyCommand;
@@ -27,7 +35,7 @@ - (instancetype)initWithKeyCommand:(UIKeyCommand *)keyCommand
2735
{
2836
if ((self = [super init])) {
2937
_keyCommand = keyCommand;
30-
_block = block ?: ^(__unused UIKeyCommand *cmd) {};
38+
_block = block;
3139
}
3240
return self;
3341
}
@@ -58,29 +66,58 @@ - (BOOL)matchesInput:(NSString *)input flags:(UIKeyModifierFlags)flags
5866
return [_keyCommand.input isEqual:input] && _keyCommand.modifierFlags == flags;
5967
}
6068

69+
- (NSString *)description
70+
{
71+
return [NSString stringWithFormat:@"<%@:%p input=\"%@\" flags=%zd hasBlock=%@>",
72+
[self class], self, _keyCommand.input, _keyCommand.modifierFlags,
73+
_block ? @"YES" : @"NO"];
74+
}
75+
6176
@end
6277

6378
@interface RCTKeyCommands ()
6479

6580
@property (nonatomic, strong) NSMutableSet *commands;
6681

67-
- (BOOL)RCT_handleKeyCommand:(UIKeyCommand *)key;
68-
6982
@end
7083

71-
@implementation UIApplication (RCTKeyCommands)
84+
@implementation UIResponder (RCTKeyCommands)
7285

7386
- (NSArray *)RCT_keyCommands
7487
{
7588
NSSet *commands = [RCTKeyCommands sharedInstance].commands;
76-
return [[self RCT_keyCommands] arrayByAddingObjectsFromArray:
77-
[[commands valueForKeyPath:@"keyCommand"] allObjects]];
89+
return [[commands valueForKeyPath:@"keyCommand"] allObjects];
90+
}
91+
92+
- (void)RCT_handleKeyCommand:(UIKeyCommand *)key
93+
{
94+
// NOTE: throttle the key handler because on iOS 9 the handleKeyCommand:
95+
// method gets called repeatedly if the command key is held down.
96+
97+
static NSTimeInterval lastCommand = 0;
98+
if (RCTIsIOS8OrEarlier() || CACurrentMediaTime() - lastCommand > 0.5) {
99+
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
100+
if ([command.keyCommand.input isEqualToString:key.input] &&
101+
command.keyCommand.modifierFlags == key.modifierFlags) {
102+
if (command.block) {
103+
command.block(key);
104+
lastCommand = CACurrentMediaTime();
105+
}
106+
}
107+
}
108+
}
78109
}
79110

111+
@end
112+
113+
@implementation UIApplication (RCTKeyCommands)
114+
115+
// Required for iOS 8.x
80116
- (BOOL)RCT_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event
81117
{
82118
if (action == @selector(RCT_handleKeyCommand:)) {
83-
return [[RCTKeyCommands sharedInstance] RCT_handleKeyCommand:sender];
119+
[self RCT_handleKeyCommand:sender];
120+
return YES;
84121
}
85122
return [self RCT_sendAction:action to:target from:sender forEvent:event];
86123
}
@@ -91,9 +128,23 @@ @implementation RCTKeyCommands
91128

92129
+ (void)initialize
93130
{
94-
//swizzle UIApplication
95-
RCTSwapInstanceMethods([UIApplication class], @selector(keyCommands), @selector(RCT_keyCommands));
96-
RCTSwapInstanceMethods([UIApplication class], @selector(sendAction:to:from:forEvent:), @selector(RCT_sendAction:to:from:forEvent:));
131+
if (RCTIsIOS8OrEarlier()) {
132+
133+
//swizzle UIApplication
134+
RCTSwapInstanceMethods([UIApplication class],
135+
@selector(keyCommands),
136+
@selector(RCT_keyCommands));
137+
138+
RCTSwapInstanceMethods([UIApplication class],
139+
@selector(sendAction:to:from:forEvent:),
140+
@selector(RCT_sendAction:to:from:forEvent:));
141+
} else {
142+
143+
//swizzle UIResponder
144+
RCTSwapInstanceMethods([UIResponder class],
145+
@selector(keyCommands),
146+
@selector(RCT_keyCommands));
147+
}
97148
}
98149

99150
+ (instancetype)sharedInstance
@@ -121,11 +172,11 @@ - (void)registerKeyCommandWithInput:(NSString *)input
121172
{
122173
RCTAssertMainThread();
123174

124-
if (input.length && flags) {
175+
if (input.length && flags && RCTIsIOS8OrEarlier()) {
125176

126177
// Workaround around the first cmd not working: http://openradar.appspot.com/19613391
127178
// You can register just the cmd key and do nothing. This ensures that
128-
// command-key modified commands will work first time.
179+
// command-key modified commands will work first time. Fixed in iOS 9.
129180

130181
[self registerKeyCommandWithInput:@""
131182
modifierFlags:flags
@@ -136,19 +187,9 @@ - (void)registerKeyCommandWithInput:(NSString *)input
136187
modifierFlags:flags
137188
action:@selector(RCT_handleKeyCommand:)];
138189

139-
[_commands addObject:[[RCTKeyCommand alloc] initWithKeyCommand:command block:block]];
140-
}
141-
142-
- (BOOL)RCT_handleKeyCommand:(UIKeyCommand *)key
143-
{
144-
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
145-
if ([command.keyCommand.input isEqualToString:key.input] &&
146-
command.keyCommand.modifierFlags == key.modifierFlags) {
147-
command.block(key);
148-
return YES;
149-
}
150-
}
151-
return NO;
190+
RCTKeyCommand *keyCommand = [[RCTKeyCommand alloc] initWithKeyCommand:command block:block];
191+
[_commands removeObject:keyCommand];
192+
[_commands addObject:keyCommand];
152193
}
153194

154195
- (void)unregisterKeyCommandWithInput:(NSString *)input
@@ -178,3 +219,29 @@ - (BOOL)isKeyCommandRegisteredForInput:(NSString *)input
178219
}
179220

180221
@end
222+
223+
#else
224+
225+
@implementation RCTKeyCommands
226+
227+
+ (instancetype)sharedInstance
228+
{
229+
return nil;
230+
}
231+
232+
- (void)registerKeyCommandWithInput:(NSString *)input
233+
modifierFlags:(UIKeyModifierFlags)flags
234+
action:(void (^)(UIKeyCommand *))block {}
235+
236+
- (void)unregisterKeyCommandWithInput:(NSString *)input
237+
modifierFlags:(UIKeyModifierFlags)flags {}
238+
239+
- (BOOL)isKeyCommandRegisteredForInput:(NSString *)input
240+
modifierFlags:(UIKeyModifierFlags)flags
241+
{
242+
return NO;
243+
}
244+
245+
@end
246+
247+
#endif

0 commit comments

Comments
 (0)