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{
2912if ((self = [super init ])) {
30- _keyCommand = keyCommand;
31- _modifierFlags = modifierFlags;
32- _block = block;
13+ _event = event;
3314 }
3415return 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 (![objectisKindOfClass: [RCTKeyCommandclass ]]) {
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: inputflags: 0 ];
54+ }
7555
76- @end
56+ - (BOOL )matchesInput : (NSString *)input flags : (NSEventModifierFlags )flags
57+ {
58+ return [self .inputisEqualToString: input] && self.flags == flags;
59+ }
7760
61+ - (BOOL )matchesKeyCode : (RCTKeyCode)keyCode
62+ {
63+ return [self matchesKeyCode: keyCodeflags: 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 [RCTKeyCommandssharedInstance ].commands ) {
84- if ([command.keyCommandisEqualToString: 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{
113101if ((self = [super init ])) {
114- _commands = [NSMutableSet new ];
102+ _observers = [NSHashTable weakObjectsHashTable ];
115103 }
116104return self;
117105}
118106
119- - (void )registerKeyCommandWithInput : (NSString *)input
120- modifierFlags : (NSEventModifierFlags )flags
121- action : (void (^)(NSEvent *))block
107+ - (void )addObserver : (NSObject <RCTKeyCommandObserver> *)observer
122108{
123109RCTAssertMainQueue ();
124-
125- RCTKeyCommand *keyCommand = [[RCTKeyCommandalloc ]initWithKeyCommand: inputmodifierFlags: flagsblock: block];
126- [_commandsremoveObject: keyCommand];
127- [_commandsaddObject: keyCommand];
110+ [_observersaddObject: observer];
128111}
129112
130- - (void )unregisterKeyCommandWithInput : (NSString *)input
131- modifierFlags : (NSEventModifierFlags )flags
113+ - (void )removeObserver : (NSObject <RCTKeyCommandObserver> *)observer
132114{
133115RCTAssertMainQueue ();
116+ [_observersremoveObject: observer];
117+ }
134118
135- for (RCTKeyCommand *command in _commands.allObjects ) {
136- if ([commandmatchesInput: inputflags: flags]) {
137- [_commandsremoveObject: command];
138- break ;
139- }
119+ - (BOOL )observeEvent : (NSEvent *)event
120+ {
121+ RCTAssertMainQueue ();
122+ RCTKeyCommand *command = [[RCTKeyCommandalloc ]initWithEvent: event];
123+ for (id <RCTKeyCommandObserver> observer in _observers) {
124+ [observerobserveKeyCommand: 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 = [[RCTKeyCommandssharedInstance ]observeEvent: event];
136+ if (!isDefaultPrevented) {
137+ [super keyDown: event];
138+ }
139+ }
147140
148- for (RCTKeyCommand *command in _commands) {
149- if ([commandmatchesInput: inputflags: flags]) {
150- return YES ;
151- }
141+ - (void )keyUp : (NSEvent *)event
142+ {
143+ BOOL isDefaultPrevented = [[RCTKeyCommandssharedInstance ]observeEvent: event];
144+ if (!isDefaultPrevented) {
145+ [super keyUp: event];
152146 }
153- return NO ;
154147}
155148
156149@end
150+