1- /* *
2- * Copyright (c) 2015-present, Facebook, Inc.
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-
81#import " RCTKeyCommands.h"
9-
10- #import < AppKit/AppKit.h>
11-
122#import " RCTDefines.h"
133#import " RCTUtils.h"
144
15- @interface RCTKeyCommand : NSObject <NSCopying >
16-
17- @property (nonatomic , strong ) NSString *keyCommand;
18- @property (nonatomic ) NSEventModifierFlags modifierFlags;
19- @property (nonatomic , copy ) void (^block)(NSEvent *);
20-
21- @end
22-
235@implementation RCTKeyCommand
6+ {
7+ BOOL _preventDefault;
8+ }
249
25- - (instancetype )initWithKeyCommand : (NSString *)keyCommand
26- modifierFlags : (NSEventModifierFlags )modifierFlags
27- block : (void (^)(NSEvent *))block
10+ - (instancetype )initWithEvent : (NSEvent *)event
2811{
2912 if ((self = [super init ])) {
30- _keyCommand = keyCommand;
31- _modifierFlags = modifierFlags;
32- _block = block;
13+ _event = event;
3314 }
3415 return self;
3516}
3617
3718RCT_NOT_IMPLEMENTED (- (instancetype )init)
3819
39- - (id )copyWithZone:(__unused NSZone *)zone
20+ - (NSString *)input
4021{
41- return self ;
22+ return _event. characters ;
4223}
4324
44- - (NSUInteger ) hash
25+ - (unsigned short ) keyCode
4526{
46- return _keyCommand. hash ^ _modifierFlags ;
27+ return _event. keyCode ;
4728}
4829
49- - (BOOL )isEqual : (RCTKeyCommand *) object
30+ - (BOOL )isDown
5031{
51- if (![object isKindOfClass: [RCTKeyCommand class ]]) {
52- return NO ;
53- }
54- return [self matchesInput: object.keyCommand
55- flags: object.modifierFlags];
32+ return _event.type == NSEventTypeKeyDown;
5633}
5734
58- - (BOOL ) matchesInput : ( NSString *) keyCommand flags : ( int )flags
35+ - (NSEventModifierFlags )flags
5936{
60- return [_keyCommand isEqual: keyCommand] && _modifierFlags == flags ;
37+ return _event. modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask ;
6138}
6239
63- - (NSString *)description
40+ - (NSWindow *)window
6441{
65- return [NSString stringWithFormat: @" <%@ :%p input=\" %@ \" flags=%zd hasBlock=%@ >" ,
66- [self class ], self , _keyCommand, _modifierFlags,
67- _block ? @" YES" : @" NO" ];
42+ return _event.window ;
6843}
6944
70- @end
71-
72- @interface RCTKeyCommands ()
45+ - (NSString *)description
46+ {
47+ return [NSString stringWithFormat: @" <%@ :%p input=\" %@ \" flags=%zd isDown=%@ >" ,
48+ [self class ], self , self .input, self .flags, self .isDown ? @" YES" : @" NO" ];
49+ }
7350
74- @property (nonatomic , strong ) NSMutableSet <RCTKeyCommand *> *commands;
51+ - (BOOL )matchesInput : (NSString *)input
52+ {
53+ return [self matchesInput: input flags: 0 ];
54+ }
7555
76- @end
56+ - (BOOL )matchesInput : (NSString *)input flags : (NSEventModifierFlags )flags
57+ {
58+ return [self .input isEqualToString: input] && self.flags == flags;
59+ }
7760
61+ - (BOOL )matchesKeyCode : (RCTKeyCode)keyCode
62+ {
63+ return [self matchesKeyCode: keyCode flags: 0 ];
64+ }
7865
79- @implementation NSWindow (RCTKeyCommands)
66+ - (BOOL )matchesKeyCode : (RCTKeyCode)keyCode flags : (NSEventModifierFlags )flags
67+ {
68+ return self.keyCode == keyCode && self.flags == flags;
69+ }
8070
81- - (void )keyDown : ( NSEvent *) theEvent
71+ - (void )preventDefault
8272{
83- for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance ].commands ) {
84- if ([command.keyCommand isEqualToString: theEvent.characters] &&
85- command.modifierFlags == (theEvent.modifierFlags & NSDeviceIndependentModifierFlagsMask )) {
86- if (command.block ) {
87- command.block (theEvent);
88- }
89- return ;
90- }
91- }
73+ _preventDefault = YES ;
74+ }
9275
93- [super keyDown: theEvent];
76+ - (BOOL )isDefaultPrevented
77+ {
78+ return _preventDefault;
9479}
9580
9681@end
9782
9883@implementation RCTKeyCommands
84+ {
85+ NSHashTable <id <RCTKeyCommandObserver>> *_observers;
86+ }
9987
10088+ (instancetype )sharedInstance
10189{
@@ -111,46 +99,52 @@ + (instancetype)sharedInstance
11199- (instancetype )init
112100{
113101 if ((self = [super init ])) {
114- _commands = [NSMutableSet new ];
102+ _observers = [NSHashTable weakObjectsHashTable ];
115103 }
116104 return self;
117105}
118106
119- - (void )registerKeyCommandWithInput : (NSString *)input
120- modifierFlags : (NSEventModifierFlags )flags
121- action : (void (^)(NSEvent *))block
107+ - (void )addObserver : (NSObject <RCTKeyCommandObserver> *)observer
122108{
123109 RCTAssertMainQueue ();
124-
125- RCTKeyCommand *keyCommand = [[RCTKeyCommand alloc ] initWithKeyCommand: input modifierFlags: flags block: block];
126- [_commands removeObject: keyCommand];
127- [_commands addObject: keyCommand];
110+ [_observers addObject: observer];
128111}
129112
130- - (void )unregisterKeyCommandWithInput : (NSString *)input
131- modifierFlags : (NSEventModifierFlags )flags
113+ - (void )removeObserver : (NSObject <RCTKeyCommandObserver> *)observer
132114{
133115 RCTAssertMainQueue ();
116+ [_observers removeObject: observer];
117+ }
134118
135- for (RCTKeyCommand *command in _commands.allObjects ) {
136- if ([command matchesInput: input flags: flags]) {
137- [_commands removeObject: command];
138- break ;
139- }
119+ - (BOOL )observeEvent : (NSEvent *)event
120+ {
121+ RCTAssertMainQueue ();
122+ RCTKeyCommand *command = [[RCTKeyCommand alloc ] initWithEvent: event];
123+ for (id <RCTKeyCommandObserver> observer in _observers) {
124+ [observer observeKeyCommand: command];
140125 }
126+ return command.isDefaultPrevented ;
141127}
142128
143- - (BOOL )isKeyCommandRegisteredForInput : (NSString *)input
144- modifierFlags : (NSEventModifierFlags )flags
129+ @end
130+
131+ @implementation NSWindow (RCTKeyCommands)
132+
133+ - (void )keyDown : (NSEvent *)event
145134{
146- RCTAssertMainQueue ();
135+ BOOL isDefaultPrevented = [[RCTKeyCommands sharedInstance ] observeEvent: event];
136+ if (!isDefaultPrevented) {
137+ [super keyDown: event];
138+ }
139+ }
147140
148- for (RCTKeyCommand *command in _commands) {
149- if ([command matchesInput: input flags: flags]) {
150- return YES ;
151- }
141+ - (void )keyUp : (NSEvent *)event
142+ {
143+ BOOL isDefaultPrevented = [[RCTKeyCommands sharedInstance ] observeEvent: event];
144+ if (!isDefaultPrevented) {
145+ [super keyUp: event];
152146 }
153- return NO ;
154147}
155148
156149@end
150+
0 commit comments