How to properly test against certain values in NSEventModifierFlags via Swift?
I have found a solution, here I check for the shift
key:
override func flagsChanged(with event: NSEvent)
{
if event.modifierFlags.contains(.shift)
{
// shift pressed
}
if event.modifierFlags.contains(.shift) == false
{
// shift released
}
}
Checking keyDown event.modifierFlags yields error
Apple's documentation indicates that you simply and the modifier flags
The documentation is still referring to C and Objective-C. Swift uses OptionSetType
, which does not use bitwise operators for checking flags.
Instead, use the contains()
method to check for one or more flags:
if theEvent.modifierFlags.contains(.CommandKeyMask) {
NSLog("command key down")
}
if theEvent.modifierFlags.contains(.AlternateKeyMask) {
NSLog("option key down")
}
if theEvent.modifierFlags.contains([.CommandKeyMask, .AlternateKeyMask]) {
NSLog("command and option keys down")
}
To check for a single key, use intersect
to filter out any unwanted flags, then use ==
to check for a single flag:
let modifierkeys = theEvent.modifierFlags.intersect(.DeviceIndependentModifierFlagsMask)
if modifierkeys == .CommandKeyMask {
NSLog("Only command key down")
}
How can I detect that the Shift key has been pressed?
From the Cocoa event handling guide:
The flagsChanged: method can be useful for detecting the pressing of modifier keys without any other key being pressed simultaneously. For example, if the user presses the Option key by itself, your responder object can detect this in its implementation of flagsChanged:.
More details can be found here.
The documentation for NSResponder also states the following:
flagsChanged:
Informs the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
-- (void)flagsChanged:(NSEvent *)theEvent
Swift: masks as type properties
This is from an earlier Xcode 6 beta, the correct answer now (Xcode 7/Swift 2) is https://stackoverflow.com/a/32004398/669586
The following is possible:
if (theEvent.modifierFlags & NSEventModifierFlags.CommandKeyMask).value != 0 {
because there is a definition of &
for RawOptionSet
func &<T : RawOptionSet>(a: T, b: T) -> T
However, note that RawOptionSet
also implements LogicValue
, so the following is possible, too:
if theEvent.modifierFlags & NSEventModifierFlags.CommandKeyMask {
Although I consider the first solution to be a bit more clear for the readers
Checking bitmask in Swift
keyEquivalentModifierMask
is a Int
, whereas NSEventModifierFlags.CommandKeyMask
is an enum-like with UInt
raw value, so you have to read the rawValue
out of it and convert keyEquivalentModifierMask
to Uint
:
if UInt(button.keyEquivalentModifierMask) & NSEventModifierFlags.CommandKeyMask.rawValue > 0 {
}
Simple Callback with MASShortcut using Swift
There are a few issues here. Before fixing them you should make sure that you have MASShortcut
2.1.2 installed (you can see this in your Podfile.lock
). If you don't you should run pod update
to get the newest version.
Another potential issue with you testing this is your shortcut conflicting with OS X default shortcuts. In your current example Command+Option+Space is bound to opening a Finder window and selecting the search field. If you have this disabled that's fine, otherwise I would recommend adding Control to your test case.
So there are a few issues with your code so far. First off I would recommend changing your keyMask
declaration a bit to:
let keyMask: NSEventModifierFlags = .CommandKeyMask | .ControlKeyMask | .AlternateKeyMask
This way Swift can infer the type and you only have to have NSEventModifierFlags
once (notice that I added the .ControlKeyMask
here for my comment above).
A cool part about enums in Swift is that you can call rawValue
on them. In this case the rawValue
of NSEventModifierFlags
is a UInt
which will fix your type problem when creating your shortcut.
Now your keyCode
argument must be a UInt
as well. So you can pull this out into a temporary value:
let keyCode = UInt(kVK_Space)
In Swift, methods that look like class level initializers are actually turned in to Swift initializers. So in this case, you're trying to call a class method called shortcutWithKeyCode:modifierFlags:
when Swift has actually turned this into an initializer. So you can create your shortcut like this:
let shortcut = MASShortcut(keyCode: keyCode, modifierFlags: keyMask.rawValue)
Note the rawValue
call to convert our modifier flags into a UInt
.
Finally, the API to register this shortcut globally is actually a method on MASShortcutMonitor
. In your bridging header where you have:
#import <MASShortcut/MASShortcut.h>
You'll have to add a new import to get this API. The new one is:
#import <MASShortcut/MASShortcutMonitor.h>
Now you can register your shortcut:
MASShortcutMonitor.sharedMonitor().registerShortcut(shortcut, withAction: callback)
And your all set. Your callback function was already setup correctly!
One last thing. I would recommend removing your shortcut in applicationWillTerminate:
like this:
MASShortcutMonitor.sharedMonitor().unregisterAllShortcuts()
How to ask a remote windows machine to automatically launch an application?
If you're developing an application that should always be running on the server, you probably need to implement it as a Windows service. For C#, see the classes in the System.ServiceProcess
namespace -- you will need to inherit from ServiceBase
.
Alternatively, you can set the program to be run as a scheduled task on boot. See the Task Scheduler API to do this.
How Can I get keyboard input in a SpriteKit Game?
The easiest way I know is to implement the keyDown method in your SKScene (and not directly in the AppDelegate). You don't have to subclass anything.
- (void)keyDown:(NSEvent *)event {
[self handleKeyEvent:event keyDown:YES];
}
- (void)keyUp:(NSEvent *)event {
[self handleKeyEvent:event keyDown:NO];
}
Then use the method handleKeyEvent:(NSEvent *)event keyDown:(BOOL)downOrUp
to check which key has been pressed :
- (void)handleKeyEvent:(NSEvent *)event keyDown:(BOOL)downOrUp {
// First check the arrow keys since they are on the numeric keypad.
if ([event modifierFlags] & NSNumericPadKeyMask) { // arrow keys have this mask
NSString *theArrow = [event charactersIgnoringModifiers];
unichar keyChar = 0;
if ([theArrow length] == 1) {
keyChar = [theArrow characterAtIndex:0];
switch (keyChar) {
case NSUpArrowFunctionKey:
self.defaultPlayer.moveForward = downOrUp;
break;
case NSLeftArrowFunctionKey:
self.defaultPlayer.moveLeft = downOrUp;
break;
case NSRightArrowFunctionKey:
self.defaultPlayer.moveRight = downOrUp;
break;
case NSDownArrowFunctionKey:
self.defaultPlayer.moveBack = downOrUp;
break;
}
}
}
// Now check the rest of the keyboard
NSString *characters = [event characters];
for (int s = 0; s<[characters length]; s++) {
unichar character = [characters characterAtIndex:s];
switch (character) {
case 'w':
self.defaultPlayer.moveForward = downOrUp;
break;
case 'a':
self.defaultPlayer.moveLeft = downOrUp;
break;
case 'd':
self.defaultPlayer.moveRight = downOrUp;
break;
case 's':
self.defaultPlayer.moveBack = downOrUp;
break;
case ' ':
self.defaultPlayer.fireAction = downOrUp;
break;
}
}
}
I took this code from the Apple SpriteKit Adventure game. I found it very usefull to learn SpriteKit :)
Related Topics
How to Create Lazy Combinations
Swift Tuple Has Unexpected Print Result
Presenting a Uiviewcontroller from Skscene Shows Black Screen
Get All Documents at Once in a Completion Handler with Getdocuments in Firestore
How to Use Querystartingatvalue in My Searchcontroller to Search for Users
Unrecognized Selector Sent to Instance When No Related Entities Found in Core Data
Setting Title of Uinavigationbar Not Working
How to Reset a Subview in Swiftui
Receiving Data from Nsinputstream in Swift
Autoscrolling Infinite Effect in .Linear Type of Icarousel in Swift
Diddiscoverservices Is Not Being Called After a Ble Connection
How to Take a Substring to the First Index of a Character
Nsmanagedobject Subclasses Duplicate Declaration
Getting a String Value from Nsorderedset Using Swiftui Foreach
Failable Initializers with Codable
Expanding Uitextview Inside a Stack View with Scrolling Enabled