Determine whether all controls can get focus (i.e. become first responder) - cocoa

I need to detect whether any NSControl, such as an NSButton, can get the focus by using the Tab key.
It can, if the user has enabled the option in the System Preferences under Keyboard / Shortcuts / Keyboard / "Change the way Tab moves focus".
More specifically, I like to make a NSButton the first responder but only if the "all controls can get focus" mode is enabled. Maybe I could ask the control if it accepts the firstReponder status?
I tried calling acceptsFirstResponder on a button, but that returns YES even if it can't become firstReponder by using the Tab key, so that's not the right way.

canBecomeKeyView is the property/method you're looking for.
From Cocoa Event Handling Guide, Keyboard Interface Control
The acceptsFirstResponder method controls whether a responder accepts first responder status when its window asks it to (that is, when makeFirstResponder: is called with the responder as the parameter). The canBecomeKeyView method controls whether the Application Kit allows tabbing to a view. It calls acceptsFirstResponder, but it also checks for other information before determining the value to return, such as whether the view is hidden and whether full keyboard access is on.

Related

FirstResponder as delegate for NSToolBar

I have a Mac app that consists of a window with a variable number of panes in it, each containing a tableview. The window has a toolbar with buttons, and I want the VC for the currently selected pane to handle validating the toolbar items, as well as being target for their actions.
If I could set first responder as delegate for the toolbar, this would be handled automatically, so my question is if that is possible! I have obviously googled around for this and some articles seem to hint that it is possible, but IB doesn't seem to let me do it.
An NSWindowController subclass would be better suited for this, that is the toolbar's delegate (it's natural role anyway) and can talk with the currently selected pane, using a custom protocol to decide on business logic.
Same goes for the UI/Menu action handlers; the window controller is perfect for this and your design will fit within it well.
It's not really got anything to do with the first responder as you are interested in the currently selected pane, not the first responder.

What responder catches undo action?

I have a view that handles undo and redo. For a specific state I change first responder from the view to the view's window. Now in that state I expect the validateMenuItem: method in the window's delegate to check the undo menu item.
This works when I close the window. But when the window is visible some other responder deals with the undo action.
My guess is that it's the window controller? But as this is a non-document based app I haven't implemented one manually. Will I have to create a custom window controller? And if so, what's the simplest way to do that?
Found the answer here: http://www.cocoabuilder.com/archive/cocoa/307917-validatemenuitem-not-called-for-undo-menu-item.html
Configuring the Undo menu item with action 'undo:' tells the
frameworks that this is the undo menu item, so it becomes one
element of a standard undo UI mechanism implemented in NSWindow. Under
these circumstances, the menu item (and especially its validation)
isn't yours to mess with.
If you want to take implement the entire mechanism yourself, then you
should use a custom action such as 'myUndo:' for the Undo menu item.
That means, as far as the frameworks know, you app doesn't have
(standard) undo, and the action/validation should work in the normal
way.

NSTextFinder action on NSTextView

I'm trying to capture all the NSTextFinderClient calls on my custom NSTextView subclass.
The show action is called on my -(void)performTextFinderAction:(id)sender override, but for find next, find previous, etc. it's not called.
Any ideas?
Thanks!
Edit:
If you create a new project and drag an NSTextView from interface builder, command-g and command-shift-g (find next and find previous) don't work when the find bar is first responder.
Why is this?
I need a custom subclass of NSTextView to respond to the find bar for every event.
I searched in the Apple's TextEdit source code because with TextEdit, the standard search bar within the Text View works fine for command-G (and other shortcuts) even the search field is the first responder.
I found the solution.
Go to your nib for the main menu, and select the "Find" (and related) menu items. They should be bound to the default action called "performFindPanelAction:." Now unbind them and bind to "performTextFinderAction:" of the First Responder instead.
You may not find that action in the First Responder's action list. So you need to add it by yourself in the First Responder's attributes inspector pane.
This was meant by the document below saying
Before OS X v10.7, the default action for these menu items was performFindPanelAction:. Whenever possible which you should update your implementation to use this new action.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/#//apple_ref/occ/instm/NSResponder/performTextFinderAction:
The find bar communicates privately with the client's NSTextFinder instead of calling NSResponder's -performTextFinderAction:. This is necessary to allow find to work when something besides the client has key focus.
What are you trying to accomplish?

How do I stop my NSbutton from being selected when the app starts by default?

I created a button, and a have a little problem: When the my app launches, the button is selected. How do I disable this selection?
Example:
Caveat: This answer is incomplete: It just hides the focus ring (without preventing the selection). There's little benefit in this solution.
Set your button's focus ring type to none:
[myButton setFocusRingType:NSFocusRingTypeNone];
You can also set this option in the XIB.
First, you should know that, by default, buttons can't get focus. A user would have to have selected System Preferences > Keyboard > Shortcuts > Full Keyboard Access: All Controls. If they've done that, they may want a button to initially have focus.
Anyway, the proper way to do this is to call [theWindow makeFirstResponder:nil] sometime after showing it the first time. When to do this depends on exactly how the window gets shown. If you show it explicitly in code, then you can make the call just after that. If it's shown because its Visible at Launch flag is set in its NIB, then you'd do it after the NIB is loaded. Etc.
Something should always be first responder in a window, if anything can be. Normally, only a few controls like text fields can become first responder, but when a user has Full Keyboard Access enabled, it's normal for a button to be selected by default.
If you don't want this particular button to start selected, set the window's initialFirstResponder to another control.
I'd advise against using -[NSWindow makeFirstResponder:nil]. The window will start with nothing selected, but the button will become selected as soon as the user hits tab. This is unusual for Mac apps because there's no way to get the window back into the "nothing selected" state as a user.

How to make a keyboard shortcut to close dialog with Xcode/Interface Builder?

This seems awfully basic but here goes. If you are keyboard-oriented you get used to using Command-W to close windows all the time in OS X. I'd like to add that capability to the dialogs I am creating in Interface Builder for my program. I can see how to add a keyboard equivalent to a button action but what if I don't have a button?
Should I add an invisible button and put the shortcut on that? Seems clunky. Surely there is just some method I can override but what I've tried so far isn't working.
When you press Command + W, it's the exact same as choosing File -> Close from the menu bar. What Close does is send a performClose: message to the first responder. That, in turn, will check if the receiver or if the receiver's delegate implements windowShouldClose:, and the window will close if it returns YES (otherwise, it will call the close method).
So really, it depends on what type of dialog you've got here. If it's non-modal (essentially, if you can access the menu bar while it's running) and is an instance or subclass of NSWindow, then all you need to do is override the windowShouldClose: method in your dialog's delegate (or your dialog class, if you subclassed NSWindow or something) and make it return YES.
However, if the dialog is a modal dialog (you can't access the menu bar, switch windows, etc. while the dialog is running), then you can't do it this way. You could add an invisible button, but in all honesty, a modal dialog should not be closed by hitting Command-W, for that most certainly violates some Apple interface guideline out there. (Especially since, as Ande noted, it's standard practice to have Esc close/cancel a dialog.)
Adding an invisible button works just fine.
Is the dialog an NSWindow? Because by default the File->Close menu option is set to the performClose: action of the first responder, and already wired to command-w
If the dialog isn't a window simply make your dialog first responder and implement the performClose: action.
why don't you try this:
-(void)keyDown:(NSEvent *)theEvent{
//If the key is X or x it just closes the window
if ([theEvent.characters.uppercaseString isEqualToString:#"X"]) {
[self.window performClose:self];
}
}
or if you want to show a window you can instanciate and show it there instead of the performClose
Jasper was right about the code part. For interface builder(storyboard), there is a quick fix:
In your storyboard, hit "CMD+Shift+L" to bring up the components lib, select File Menu Item.
Add the file menu item to the Application Scene's Main Menu Node. (Remove unwanted file menus)
Now you have a keyboard shortcut to close a window.

Resources