NSWindow, press ENTER: how to restrict keyboard to listening to focused NSControl?
I have one NSWindow
with the main OK button. This button has the property "key equivalent" in the interface builder, ENTERie key ↵.
This works well, but now I have a new NSComboBox
one that should call a method when the user selects a list item, or he teaches ENTER/ ↵.
However, when I press Enter, the main button gets notified and the window closes. How can this be prevented?
source to share
This is the normal behavior you get, but you can hack it a bit by removing and adding the key equivalent.
Add the following NSComboBox delegates:
- (void)comboBoxWillPopUp:(NSNotification *)notification;{
[self.closeButton setKeyEquivalent:@""];
}
- (void)comboBoxWillDismiss:(NSNotification *)notification;{
[self.closeButton setKeyEquivalent:@"\r"];
}
source to share
One way you can get around to prevent the notification from being entered is as follows: -
// Connect this action method to your combobbox and inside where the flag is set BOOL
to yes
- (IBAction)comBoxItm:(id)sender
{
self.isEnterCalled=YES;
}
// Now check this flag against your method where the close window is called
-(void)someMethod
{
//Check the flag value if it is yes then just ignore it
if (!self.isEnterCalled)
{
//Close window logic
}
self.isEnterCalled=NO;
}
source to share
Get into the same problem. There was a hotkey that I would like to disable by editing some of the text boxes. I found a solution for myself. There is no need to override many base methods NSTextField
.
First, I removed all "key equivalents". I used to discover the key Enterusing a class method of the + (void)addLocalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(NSEvent *(^)(NSEvent *))block
class NSEvent
. You are passing a block as a parameter where you can check some conditions. The first parameter is the event mask. For your task it will be NSKeyDownMask
, look for other masks on the NSEvent man page
The parameter block will execute every time the user presses the button. You have to check if the right button is pressed and - in general - if the current window of the first responder is not an editable control. To do this, we need a NSWindow
class so that we don't have to implement this code every time we deal with NSKeyDownMask
ed local monitors.
NSWindow+Responders
list of classes:
@interface NSWindow (Responders)
- (BOOL)isEditableFirstResponder;
@end
@implementation NSWindow (Responders)
- (BOOL)isEditableFirstResponder
{
if (!self.firstResponder)
return NO; // no first responder at all
if ([self.firstResponder isKindOfClass:[NSTextField class]]) // NSComboBox is NSTextField subclass
{
NSTextField *field=(NSTextField *)self.firstResponder;
return field.isEditable;
}
if ([self.firstResponder isKindOfClass:[NSButton class]]) // yep, buttons may be responders
return YES;
return NO; // the first responder is not NSTextField or NSButton subclass - not editable
}
@end
Don't know if there is another way to check if we are editing any textbox or combo box. So there is at least the part that you add the local monitor somewhere in your class (NSWindow, NSView, some controller, etc.).
- (void)someMethod
{
id monitor=[NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:(NSEvent *)^(NSEvent *theEvent){
if (theEvent.keyCode==/*Enter key code*/ && ![self.window.isEditableFirstResponder]) // you should check the key modifiers too
{
// your code here
}
return theEvent; // you may return the event to pass the key to the receiver
}];
}
Local monitors are a safe defense against Apple policies. It only works inside your application. For events, global key event you can use addGlobalMonitor
, but Apple can reject your app from AppStore.
And don't forget to remove your monitor when not needed.
- (void)viewControllerShutdownMethod
{
[NSEvent removeMonitor:monitor];
}
Good luck.
source to share