Check modifierFlags of NSEvent if a certain modifier was pressed but no other
Asked Answered
G

4

23

I just experimented with the addLocalMonitorForEventsMatchingMask:handler: method in NSEvent and came across the following question: How do I find out if only certain modifiers were pressed?

A short example to set this question into context: I wanted to listen for the shortcut "⌘+W". Therefore I wrote the following code:

[NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent *theEvent) {
    if ([theEvent modifierFlags] & NSCommandKeyMask && [theEvent keyCode] == 13) {
        [self.window performClose:self];
    }
    return theEvent;
}];

This works well, however the shortcut will be triggered, even if more modifier keys are pressed, e.g. "⌃+⌘+W" or "⇧+⌃+⌥+⌘+W". Is there a way to circumvent this?

A simple solution would be to check for all other modifier keys and ensure they are not pressed. This seems tedious and error prone - besides it's ugly enough as it is now with the unary "&". In addition you may get into trouble if (for some reason) another modifier key is added to keyboard layouts.

As always I'm thankful for any recommendations.

Guilty answered 21/5, 2011 at 20:25 Comment(0)
N
34

I think this'll do it:

// Mask out everything but the key flags
NSUInteger flags = [theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if( flags == NSCommandKeyMask ){
    // Got it!
}

Hat tip to SpaceDog for pointing out the deprecation of the original mask name, NSDeviceIndependentModifierFlagsMask.

Notify answered 21/5, 2011 at 20:44 Comment(4)
Wow, that's neat! Now I have to use the unary "&" just once and finally understood what the NSDeviceIndependentModifierFlagsMask is for: The modifierFlags normally are set to 256 by default and other flags are added to it, this way I clean up so only the pressed keys are represented by the modifierFlags value. This way it's possible to write combinations of modifier keys like in Carbon, e.g. flags == NSCommandKeyMask + NSControlKeyMas if ⌘ and ⌃ should be pressed rather writing flags & NSCommandKeyMask && flags & NSControlKeyMask. Thanks a lot!Guilty
Pedantic mode dictates that masks should only be (bitwise) OR'd ('|'). Otherwise carry bits will come back to bite you.Balfore
[theEvent modifierFlags] & (NSControlKeyMask|NSCommandKeyMask) can be used for multiplesFrankfurter
unfortunately, thanks to Apple, NSDeviceIndependentModifierFlagsMask is deprecated. Back to the drawing board.Garcon
S
16

Swift 5 version

if event.modifierFlags.intersection(.deviceIndependentFlagsMask) == .command {
    // Got it!
}
Septuor answered 31/5, 2019 at 6:30 Comment(0)
G
7

@JoshCaswell answer has been outdated thanks to Apple, because NSDeviceIndependentModifierFlagsMask has been deprecated since 10.12.

His answer updated to the new syntax is

// Mask out everything but the key flags
NSUInteger flags = [theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if( flags == NSCommandKeyMask ){
  // Got it!
}

NSDeviceIndependentModifierFlagsMask has been replaced with NSEventModifierFlagDeviceIndependentFlagsMask because it makes a world of difference...

Garcon answered 29/9, 2017 at 5:30 Comment(0)
U
1

Maybe even better...

if event.modifierFlags.contains(.shift){
    // do it
}
Unrest answered 19/4, 2021 at 17:26 Comment(1)
This does not work, additional modifiers do also pass.Haroldson

© 2022 - 2024 — McMap. All rights reserved.