NSView doesn’t catch keyDown events - objective-c

I need to catch mouseDown and keyDown events in a subclass of NSViewController and as it’s not possible (please, correct me if I’m wrong) I left my GameViewController class blank and put all it’s methods to a new GameView class. In the identity inspector of GameViewController.xib I set my class to GameView while File’s Owner is set to GameViewController. After all, my mouseDown method works, but keyDown doesn’t.
I tried this:
- (BOOL) acceptsFirstResponder {
return YES;
}
but it didn’t help.
Please, show me what to do.
UPD: Actually keyDown method works, but first I need to click somewhere on the blank space of my window and only then everything works as it was planned. Once again, mouseDown events are triggered with no problems. What may I be doing wrong?

Your view accepts first responder when offered it, but nothing is attempting to make it the first responder until you click.
Set the window's initialFirstResponder some time before showing it. If you're using a NIB, it can be set there. Or you could do it programmatically.
After the window is shown, you can call [window makeFirstResponder:view] to make the view the first responder of its window.

Related

Invoke NSTextField's action to be send when clicked ouside

I have a NSTextField that have been edited. If I press enter then action is being called as expected.
I would like to have the same effect when I click anywhere outside of NSTextField. Resigning First Responder could be the key, but that happens only when some elements are clicked/selected/focused (e.g. another NSTextField or NSTableView) and doesn't happen with others (e.g. NSButton or NSSlider).
NSTextField focus can be unset using [[self window] makeFirstResponder:nil] but that would be too ugly to call this line in every object's action.
Is there a better solution?
You will want to delve into the Cocoa Event Handling Guide.
Take a good look at NSResponder.
Many objects inherit from NSResponder, including NSWindow and NSApplication.
Taking a guess at what you are trying to accomplish, committing an edit when the view is not in focus, you may want to also include observing notifications when the app will terminate, go into the background, etc...

How to force an NSWindow to be always active/focused?

I have a transparent NSWindow that follows the user's screen everywhere he goes (the NSWindowstays in front of every app, no matter what, even fullscreen apps).
In that NSWindow i have a mouseDown event that shows a popup. Let's say i'm on safari in fullscreen mode and i have my Window in front of it, i click on safari and i click again on my Window: nothing happens, the mouseDown doesn't occur. I have to click again so the mouseDown event is triggered.
How can i force my NSWindow to be always active so i don't have to click it 2x to trigger the mouseDown when i click on a background app and click in my window again?
Thank you!
I'm not sure if this is exactly what you want (it's not quite a window wide setting), but, from the documentation:
By default, a mouse-down event in a window that isn’t the key window
simply brings the window forward and makes it key; the event isn’t
sent to the NSView object over which the mouse click occurs. The
NSView can claim an initial mouse-down event, however, by overriding
acceptsFirstMouse: to return YES.
The argument of this method is the
mouse-down event that occurred in the non-key window, which the view
object can examine to determine whether it wants to receive the mouse
event and potentially become first responder. You want the default
behavior of this method in, for example, a control that affects the
selected object in a window.
However, in certain cases it’s
appropriate to override this behavior, such as for controls that
should receive mouseDown: messages even when the window is inactive.
Examples of controls that support this click-through behavior are the
title-bar buttons of a window.
Or you could try fiddling with
- (void)sendEvent:(NSEvent *)theEvent
and see if you can handle events in a custom way.
If you add a borderless NSButton instance to your window's view and set your image as the button's image (and as its alternate image, to make it more beautiful), it will work out of the box: Just connect the button's action method to your app delegate (or the object where you want to process the click action). A click on the image (i.e. the button) will then trigger the button's action method, no matter which window is active.
This worked for me, hope that will be helpful, This will keep your window always on Top of all applications
[self.window makeKeyAndOrderFront:nil];
[self.window setLevel:NSStatusWindowLevel];
I think what you really should do is use an NSPanel (a floating palette -- a special kind of NSWindow) that will do exactly what you want in a way that's consistent with the OS rather than trying to fight intended behavior.
Here's the NSPanel documentation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nspanel_Class/Reference/Reference.html
And here's some helpful and pithy information:
http://cocoadev.com/wiki/NSPanel
By default, an NSPanel will disappear when the application is inactive, but you can turn this off.
I apologize for not laying it out more fully ... pressed for time.
Edit:
Note that you can probably get your window to behave as desired simply:
"The NSView can claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES."
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html
You'll need to do this with any NSView subclass to skip the "activation click".

NSTextField in status bar doesn't want to receive focus

For some reson sometimes a NSTextField I'm using in Status Bar menu doesn't always allow me to input text. I click it and nothing happens as if it was disabled. Upon restarting program it works again. I don't do anything with it, it's just created in the interface builder.
That's because no NSWindow contains the NSTextField. The NSWindow sets the first responder when the window gets the main window. The NSStatusBar is global. It's never focused so your textfield only will be focused in the very beginning.
I'm not sure if there's a way to solve this problem in a nice way. You might try to set the first responder manually. You could also add a global event monitor
Example:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent* incoming) {
[textfield setStringValue:[incoming characters]];
}];
Note: This is a very bad way to fix this problem. I'd first try to set the NSTextField manually as a first responder if this is possible.

UITextView: Must I always resignFirstResponder?

Must I always resignFirstResponder for a UITextView? Or, will this happen automatically when its view controller disappears?
I'm asking because I'm having an issue similar to iPhone Objective-C: Keyboard won't hide with resignFirstResponder, sometimes, where the keyboard stays up even when the nav controller pushes and pops other view controllers. The keyboard works, and when I hit done, it unfocuses the UITextView (i.e., the cursor disappears), but the keyboard stays up.
I never found out why this is happening, but maybe it's due to not doing resignFirstResponder before pushing another view controller, but I thought it was optional?
At a total guess, the UITextView has a reference to the view controller (as its delegate) but does not retain it. When you go to the next screen, the controller is dealloced and then the UITextView (which has perhaps been retained by something else) tries to call back to the dealloced controller and crashes. When you call resignFirstResponder, you reverse the order this happens, and therefore no crash.
The way round this to add a textView.delegate = nil call in your view controller's dealloc method - obviously put it before you release the text view.
The contract between a UITextView and it's delegate says that the delegate will send -resignFirstResponder when the text view is done editing. This informs the framework that the view is done editing, fires the events relating to that (willEndEditing and didEndEditing), and allows other parts of the responder hierarchy to react accordingly. Failing to do so might work, but it's not following the contract (that's all a protocol is) it agreed to.
I don't think you have to because the Xcode Sample UICatalog UITextField doesn't call resignFirstResponder before the TextViewController is popped.
The reason the keyboard got stuck for me is that I was having the same view controller present two view controllers modally at the same time, one after the other. UIKit didn't like that.
Calling resignFirstResponder makes sure that the text property contains the actual text shown in the control.
Depending on the state this is not always necessary, but if your controls have resigned first responder, you know that you're working with valid data.

IPad dismiss Keyboard without knowing which Textfield opened it

Is there a way to do a general resignFirstResponder to hide the keyboard regardless of what textfield/view/etc calls it?
Reason is I have a lot of textfields on my view and don't want to have to resignFirstResponder for all textfields to hide the keyboard. Just want a general
[self resignFirstResponder].
Any ideas?
Thanks in advance
I know that this has already been marked as answered, but for those that run into this like I did you can just use the following method on the view that contains the textfields.
- (BOOL)endEditing:(BOOL)force
This method looks at the current view and its subview hierarchy for the text field that is currently the first responder. If it finds one, it asks that text field to resign as first responder. If the force parameter is set to YES, the text field is never even asked; it is forced to resign. UIView Documentation
[self.view endEditing:YES];
it will hide keyboard when we click on view.
You can dismiss the keyboard without any reference to UITextfield / UITextView with help of below code:
[[[UIApplication sharedApplication] keyWindow] endEditing:YES];
this will dismiss the keyboard globally without the reference.
hope this will help you.
The easiest way to do this is to have a method for whenever you want to dismiss the keyboard that looks like this:
-(void)dismissKeyboard {
[firstField becomeFirstResponder];
[firstField resignFirstResponder];
}
You can check these questions:
Is it possible to make the iPhone keyboard invisible / remove it without resigning first responder?
Hide Input Keyboard on iPhone Without Knowing First Responder?
In summary:
You can call becomeFirstResponder on some other thing that you choose. It could be a UIViewController or a UIView. I had a similar problem before, I needed to make my keyboard go away when I was pushing my view controller back to its caller, without knowing which textfield was the first responder. Then, on viewWillAppear of my view controller which I was returning back, I called [self becomeFirstResponder] and the keyboard of the pushed view was gone. Because this made whichever text field was it loose being the first responder
In my own app when I had more than one text field and would like to make the keyboard go away regardless which of the fields called it, I would just wrote a method and let each and every of them resignFirstResponder.
I assume that as a programmer, you should have the clear knowledge how many text fields are on your view controller and how you can access them, otherwise it'll get messed up and you app won't look good... :-P