Is it possible to get the keyboard state in Objective-C without referring to NSEvent?
In general I can't use NSResponder methods like -[NSResponder flagsChanged:] but I need to know if the Command key is currently pressed.
I'm still wondering why you can't use NSEvent, but I'm going to answer the question anyways. Perhaps you're building a "command-line tool" and are only linked against Foundation? You're going to have to include at least one more framework. If you want to link against AppKit, you can (as I mentioned in the comments) use +[NSEvent modifierFlags]; this is a class method on NSEvent, so you can use it anywhere, without needing to have access to an individual event, to get the current state of the modifier keys as a bitmask. The docs explain the meaning of the bitmask.
if( NSCommandKeyMask & [NSEvent modifierFlags] ){
NSLog(#"Oh, yeah!");
}
You can also get this info using Quartz Event Services. In this case you have to include the ApplicationServices framework*. The CGEventSource functions will give you the same bitmask you get from NSEvent:
CGEventFlags theFlags;
theFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState);
if( kCGEventFlagMaskCommand & theFlags ){
NSLog(#"Uh huh!");
}
*This is already included if you are, in fact, writing a Cocoa app -- it's part of Quartz.
Use this code when targeting macOS 10.12 or newer:
if (NSEventModifierFlagCommand & NSEvent.modifierFlags) {
// Do whatever is needed
}
Related
I've noticed the following error popping up in the console when running my app on iOS 9 when using a storyboard. I'm using xCode7. Is this something I need to be concerned about?
-[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:] ** unhandled action -> <FBSSceneSnapshotAction: 0x176bfb20> {
handler = remote;
info = <BSSettings: 0x176a5d90> {
(1) = 5;
};
}
There is nothing wrong with your code. This is a logging message internal to Apple, and you should file a radar about it.
There are two hints that show that this is probably Apple's code:
The underscore leading the method name _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion is a convention indicating that the method is private/internal to the class that it's declared in. (See this comment.)
It's reasonable to guess that the two letter prefix in FBSSceneSnapshotAction is shorthand for FrontBoard, which according to Rene Ritchie in "iOS 9 wish-list: Guest Mode" is part of the whole family of software related to launching apps:
With iOS 8, Apple refactored its system manager, SpringBoard, into several smaller, more focused components. In addition to BackBoard, which was already spun off to handle background tasks, they added Frontboard for foreground tasks. They also added PreBoard to handle the Lock screen under secure, encrypted conditions. [...]
I have no idea what the BS prefix in BSSettings is for, but
BS is shorthand for BackBoard Settings, and an analysis of this log message would indicate that it's not anything you did, and you should file a radar with steps to reproduce the logging message.
If you want to try and grab a stack trace, you can implement the category linked to here. Some would argue that overriding private API is a bad idea, but in this case a temporary injection to grab a stack trace can't be too harmful.
EDIT:
But, we still want to know what this action is. So I put a breakpoint on -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion] and started printing out register values and found a class called FBSceneImpl which had a whole bunch of information about my application:
We are able to find out which private method is called next (stored in the program counter, instruction pointer, register 15.)
I tried finding the un-handled FBSceneSnapshotAction referenced in the log, but no dice. Then, I subclassed UIApplication, and overrode _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion. Now I was able to get at the action directly, but still, we don't know what it is.
Then, I looked at the FBSceneSnapshotAction again. Turns out it has a superclass called BSAction.
Then I wrote a tool similar to RuntimeBrowser and looked up all of the subclasses of BSAction. It turns out that there's quite a list of them:
The two method names we have (one from the log and one from the program counter on the devices) indicate that these actions are used under the hood for passing actions around the system.
Some actions are probably sent up to the app delegate's callbacks, while others are handled internally.
What's happening here is that there is an action that wasn't handled correctly and the system is noting it. We weren't supposed to see it, apparently.
AFAIK, the info above is related to iOS during snapshot the screen (i suppose for double click home multitask related behaviour).I deeply investigated my application and seems that it does not get any side behaviours. You can safely ignore it, for now.
You can use the following gist simple category to test yourself against the calls to the above function:
I have figured it out, it will happen when you have IBAction method declared in .h or .m file but you have not bind it to any control.
.m example:
- (IBAction)click:(id)sender{
}
but not assigned this method to any control in storyboard.
haven't find out why it happens in my app, but at least you can catch the exception, if you want to keep this from popping up in your log pane. It's not a solution, but it might give you more insight why it is happing by inspecting any of the arguments that are passed in the catch.
swift 2 version:
import UIKit
extension UIApplication {
func _handleNonLaunchSpecificActions(arg1: AnyObject, forScene arg2: AnyObject, withTransitionContext arg3: AnyObject, completion completionHandler: () -> Void) {
//whatever you want to do in this catch
print("handleNonLaunchSpecificActions catched")
}
}
Question
In some applications, such as mail clients or Twitter clients, I find myself typing away at something, everything looks good and right when I press the send/Tweet button the text view automatically corrects the last word to an incorrect spelling. Obviously at that point I waited just the wrong amount of time after finishing typing before sending it so the spell checking was still going on.
I guess the first question here really should be what do you think about removing that functionality? Because on the other hand I'm sure that exact same thing happens to people but it actually fixes the spelling of the last word as opposed to messing it up. Otherwise if you think this is a valid idea is there a way to disable automatic spelling correction when a NSTextView loses focus?
What I've looked at:
This question on how to deal with spelling stuff in NSTextViews
This question on turning off spell checking all together.
The NSTextInput Protocol
The NSIgnoreMisspelledWords Protocol
The NSChangeSpelling Protocol
NSSpellChecker specifically it's Auto Spelling Correction methods (I really thought this would get me somewhere) I finished wondering why a NSSpellCheckerDelegate doesn't exist
This question about NSSpellChecker's misleading (read the comments) NSNotifications
NSTextCheckingTypes (at the bottom) specifically NSTextCheckingTypeCorrection
This question about doing spell checking in general
NSTextView specifically the 'Working With the Spelling Checker' and 'Text Checking and Substitutions' methods
This question just about turning the functionality on and off
The Spell Checking Programming Topics which really only talks about non-automatic spell checking
NSTextViewDelegate specifically the 'Working With the Spelling Checker' methods
What I actually tried (in Xcode in an empty project)
Implementing the NSTextDelegate textShouldBeginEditing: and textShouldEndEditing: and inside of calling [self.textView setAutomaticSpellingCorrectionEnabled:true]; and [self.textView setAutomaticSpellingCorrectionEnabled:false]; respectively (at first I also called NSTextView's setAutomaticTextReplacementEnabled: but that's just for user settings like (c) to the copyright symbol)
In the same textShouldBeginEditing: and textShouldEndEditing: (from above) setting the NSTextView's enabledTextCheckingTypes to NSTextCheckingAllTypes and NSTextCheckingAllTypes - NSTextCheckingTypeCorrection respectively.
Subclassing NSTextView and implementing becomeFirstResponder and resignFirstResponder and in them changing the same properties as above.
Calling NSSpellChecker methods from either resignFirstResponder or textShouldEndEditing: (this works with [[NSSpellChecker sharedSpellChecker] dismissCorrectionIndicatorForView:self];) to hide the popup but it still corrects the spelling)
Example
I've noticed this functionality in Tweetbot you can test it using foriegn vs foreign. If you type it in and Tweet it while the bubble is still up it will Tweet the incorrect spelling.
The solution is to subclass NSTextView and override the handleTextCheckingResults: method.
- (void)handleTextCheckingResults:(NSArray<NSTextCheckingResult *> *)results forRange:(NSRange)range types:(NSTextCheckingTypes)checkingTypes options:(NSDictionary<NSTextCheckingOptionKey,id> *)options orthography:(NSOrthography *)orthography wordCount:(NSInteger)wordCount {
for (NSTextCheckingResult *result in results) {
if (result.resultType == NSTextCheckingTypeSpelling) {
// you can either suppress all corrections by using `return` here
// or you can compare the original string to the replacement like this:
NSString *originalString = [self.string substringWithRange:result.range];
NSString *replacement = result.replacementString;
// or you can do something more complex (like suppressing correction only under
// certain conditions
return; // we don't do the correction
}
}
// default behaviors, including auto-correct
[super handleTextCheckingResults:results forRange:range types:checkingTypes options:options orthography:orthography wordCount:wordCount];
}
This works for all of the NSTextCheckingTypes.
I've needed to make a global hot key input box in my Cocoa App.
I know about Shortcut Recorder, but it is a very old solution. It has parts implemented using Carbon, which has been deprecated, and I can't publish my app to the Mac App Store if I use it.
Is there any ready-to-use modern solution? Can anybody give me the way to make this by myself (I don't know where to start from)?
There is a modern framework named MASShortcut for implementing Global Shortcuts in OS X 10.7+.
Not all of Carbon is deprecated. You can't make a pure-Carbon application anymore, but some APIs live on and some of them are still the easiest way to do certain things.
One of these is the Carbon Events hotkey API. You certainly can sift through all the events using NSEvent's event-monitor methods, but it's unnecessary work. The Carbon Events hotkey API is still supported and much simpler—you just tell it what key you want to match and what function to call when the key is pressed. And there are Cocoa wrappers such as DDHotKey that make it even simpler.
RegisterEventHotKey, the relevant Carbon Events function (see also UnregisterEventHotKey in the same doc)
DDHotKey
MASShortcut, yet another wrapper (suggested by TongG):
MASShortcut (with ARC)
MASShortcut (without ARC)
KeyboardShortcuts, written in Swift and includes a SwiftUI hotkey recorder view [added to this answer in edit by the project's author].
In Mac OS X 10.6 and higher, you can use the methods +addGlobalMonitorForEventsMatchingMask:handler: and +addLocalMonitorForEventsMatchingMask:handler: defined from the NSEvent class. Monitoring Events reports the following information:
Local and global event monitors are mutually exclusive. For example, the global monitor does not observe the event stream of the application in which it is installed. The local event monitor only observes the event stream of its application. To monitor events from all applications, including the "current" application, you must install both event monitors.
The code shown in that page is for a local event monitor, but the code for a global event monitor is similar; what changes is the invoked NSEvent's method.
_eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:
(NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyDownMask)
handler:^(NSEvent *incomingEvent) {
NSEvent *result = incomingEvent;
NSWindow *targetWindowForEvent = [incomingEvent window];
if (targetWindowForEvent != _window) {
[self _closeAndSendAction:NO];
} else if ([incomingEvent type] == NSKeyDown) {
if ([incomingEvent keyCode] == 53) {
// Escape
[self _closeAndSendAction:NO];
result = nil; // Don't process the event
} else if ([incomingEvent keyCode] == 36) {
// Enter
[self _closeAndSendAction:YES];
result = nil;
}
}
return result;
}];
Once the monitor is not anymore necessary, you remove it using the following code:
[NSEvent removeMonitor:_eventMonitor];
In .NET I just do something like DataForm.Source = Object and then magic happens. Platform routes data changes from ui fileds to object properties, does validation and so on. Can I do something similar with Cocoa Touch and CoreData objects?
The closest thing in Cocoa is 'Key-Value Observing'. In the desktop Cocoa framework you can use bindings to hook user interface elements up to underlying objects so that changes in the objects or UI elements are reflected in the other.
Whilst Cocoa on iOS doesn't have this sort of UI bindings, you can still use 'Key-Value Observing' to synchronise changes in the data model with UI elements as described here:
http://developer.apple.com/library/iOS/#documentation/General/Conceptual/Devpedia-CocoaApp/KVO.html
I wrote a little open-source library that provides some simple data-binding functionality. It's basically just a wrapper around key-value observing (KVO).
http://github.com/kristopherjohnson/KJSimpleBinding
There are a few other similar libraries on GitHub:
http://github.com/dewind/KeyPathBindings
http://github.com/jonsterling/Observe
http://github.com/mruegenberg/objc-simple-bindings
http://github.com/zeasy/EasyBinding
Probably should also mention Github's Reactive Cocoa, a framework for composing and transforming sequences of values, an objective-C version of .NET's Reactive Extensions (Rx).
Binding mechanics can be done really simple (from the sample):
// RACObserve(self, username) creates a new RACSignal that sends a new value
// whenever the username changes. -subscribeNext: will execute the block
// whenever the signal sends a value.
[RACObserve(self, username) subscribeNext:^(NSString *newName) {
NSLog(#"%#", newName);
}];
Don't forget NSFetchedResultsController.
Not a full blown data bound controller, but makes table views a lot easier to use with Core Data.
If you're using Swift, check out Bond framework: https://github.com/ReactiveKit/Bond
Binding is as simple as:
textField.reactive.text.bind(to: label.reactive.text)
It plays well with functional:
textField.reactive.text
.map { "Hi " + $0 }
.bind(to: label.reactive.text)
And provides simple observations:
textField.reactive.text
.observeNext { text in
print(text)
}
STV (http://sensiblecocoa.com) is a framework that can do that within tableviews
I use CoreDataTableViewController from the Stanford University for my TableViewControllers. It hides a lot of details that you would normally implement in your TableViewController.
Googling for CoreDataTableViewController.h and .m will help you on the road. There are versions from several courses available, the latest does ARC, the old ones don't.
For syncing labels and edit fields with an NSManagedObject, I am still looking for a good solution.
Yes, there is a data binding framework that integrates well into Interface Builder and requires only minimal code overhead (if at all).
Take a look at https://github.com/mutech/aka-ios-beacon
EDIT:
You can for example bind a table view to a fetched results controller simply by setting the data source binding property of the table view in interface builder to:
[ yourResultsController ] { defaultCellMapping: "YourCellId" }
And the only thing you have to do is to define a property yourResultsController in your view controller.
The wiki provides a rather complete documentation and a lot of example use cases.
I'm trying to build an application that uses QTKit, with some compress options. I saw this example in the apple developer page QTCompressionOptionsWindow that uses a Window for that purpose.
in MyController.m line 65 there is a comment:
// ******** Compression Options Window *****
// create our window with the media type and set ourselves as the delegate
// you could also instantiate the window directly in the nib and hook up the delegate
// simply call showWindow or setMediaType if you want to change the list of compression options shown
mCompressionOptionsWindow = [[QTCompressionOptionsWindow alloc] initWithMediaType:[[[mCaptureMovieFileOutput connections] lastObject] mediaType]];
if (nil == mCompressionOptionsWindow) {
NSLog(#"Compression Options Window did not load!\n");
return;
}
[mCompressionOptionsWindow setDelegate:self];
Can someone explain me what it's the author trying to explain
"you could instantiate the window
directly in the nib"
?. He does have a nib with the QTCompressionOptionsWindow
Thanks for your replies
The purpose of the MyController-class in this sample is to simply illustrate how to use the QTCompressionOptionsWindow-class -- especially, how to set up the delegate-relationship.
In the MyController sample, the author chose to set this relationship up in the code snippet you posted.
The comment simply states that, if you don't want to do that programmatically, you could instead use IB for this purpose: simply create an instance (== instantiate) of the QTCompressionOptionsWindow-class in the NIB where you put your own controller and connect its "delegate" outlet to your controller.
If that sounds all jibberish to you, have a look at the sections "Controller Objects" and "Creating and Managing Outlet and Action Connections" of the "Interface Builder User Guide". Although I find them a little sparsely illustrated (given the target audience), they are quite good.
A technical note was written back in 2008 that discusses how to manage QTCompressionOptions in QTKit Capture and talks about the QTCompressionOptionsWindow sample in depth.
Technical Note 2219
"Managing QTCompressionOptions - An overview of the QTCompressionOptionsWindow sample"
http://developer.apple.com/library/mac/#technotes/tn2008/tn2219.html