Cannot Read Property 'Keycode' 'Character' Assertion Failure When Detect Modifier Key + Numeric Key

Cannot read property 'keyCode' 'character' Assertion failure when detect modifier key + numeric key

To enable AXIsProcessTrusted() in your app you need to go to your macOS system preferences, open Security and Privacy, click on Accessibility, click on the plus sign to add your app to the list off apps that can control your computer. You might need to click at the padlock and type your password to unlock your settings.

Sample Image

import Cocoa

class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("AXIsProcessTrusted:",AXIsProcessTrusted())
NSEvent.addGlobalMonitorForEvents(matching: .keyDown) {
self.keyDown(with: $0)
}
}
override func keyDown(with event: NSEvent) {
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
case [.command] where event.characters == "1", [.command, .shift] where event.characters == "1":
print("command+1 or command+shift+1")
default:
break
}
}
}

Global modifier key press detection in Swift

You can add Global Monitor For Events matching .flagsChanged to your view controller so you can check its modifierFlags intersection with deviceIndependentFlagsMask and check the resulting keys.

Declaration

class func addGlobalMonitorForEvents(matching mask: NSEventMask, handler block: @escaping (NSEvent) -> Void) -> Any?

installs an event monitor that receives copies of events posted to
other applications. Events are delivered asynchronously to your app
and you can only observe the event; you cannot modify or otherwise
prevent the event from being delivered to its original target
application. Key-related events may only be monitored if accessibility
is enabled or if your application is trusted for accessibility access
(see AXIsProcessTrusted()). Note that your handler will not be called
for events that are sent to your own application.

import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSEvent.addGlobalMonitorForEvents(matching: .flagsChanged) {
switch $0.modifierFlags.intersection(.deviceIndependentFlagsMask) {
case [.shift]:
print("shift key is pressed")
case [.control]:
print("control key is pressed")
case [.option] :
print("option key is pressed")
case [.command]:
print("Command key is pressed")
case [.control, .shift]:
print("control-shift keys are pressed")
case [.option, .shift]:
print("option-shift keys are pressed")
case [.command, .shift]:
print("command-shift keys are pressed")
case [.control, .option]:
print("control-option keys are pressed")
case [.control, .command]:
print("control-command keys are pressed")
case [.option, .command]:
print("option-command keys are pressed")
case [.shift, .control, .option]:
print("shift-control-option keys are pressed")
case [.shift, .control, .command]:
print("shift-control-command keys are pressed")
case [.control, .option, .command]:
print("control-option-command keys are pressed")
case [.shift, .command, .option]:
print("shift-command-option keys are pressed")
case [.shift, .control, .option, .command]:
print("shift-control-option-command keys are pressed")
default:
print("no modifier keys are pressed")
}
}
}
}

Prevent error funk sound in event monitor OS X

I ended up using MASShortcut as a workaround solution to this issue.

Swift - Capture keydown from NSViewController

Xcode 8.2.1 • Swift 3.0.2

import Cocoa

class ViewController: NSViewController {

@IBOutlet var textField: NSTextField!

override func viewDidLoad() {
super.viewDidLoad()
NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) {
self.flagsChanged(with: $0)
return $0
}
NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
self.keyDown(with: $0)
return $0
}
}
override func keyDown(with event: NSEvent) {
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
case [.command] where event.characters == "l",
[.command, .shift] where event.characters == "l":
print("command-l or command-shift-l")
default:
break
}
textField.stringValue = "key = " + (event.charactersIgnoringModifiers
?? "")
textField.stringValue += "\ncharacter = " + (event.characters ?? "")
}
override func flagsChanged(with event: NSEvent) {
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
case [.shift]:
print("shift key is pressed")
case [.control]:
print("control key is pressed")
case [.option] :
print("option key is pressed")
case [.command]:
print("Command key is pressed")
case [.control, .shift]:
print("control-shift keys are pressed")
case [.option, .shift]:
print("option-shift keys are pressed")
case [.command, .shift]:
print("command-shift keys are pressed")
case [.control, .option]:
print("control-option keys are pressed")
case [.control, .command]:
print("control-command keys are pressed")
case [.option, .command]:
print("option-command keys are pressed")
case [.shift, .control, .option]:
print("shift-control-option keys are pressed")
case [.shift, .control, .command]:
print("shift-control-command keys are pressed")
case [.control, .option, .command]:
print("control-option-command keys are pressed")
case [.shift, .command, .option]:
print("shift-command-option keys are pressed")
case [.shift, .control, .option, .command]:
print("shift-control-option-command keys are pressed")
default:
print("no modifier keys are pressed")
}
}
}

To get rid of the purr sound when pressing the character keys you need to subclass your view, override the method performKeyEquivalent and return true.

import Cocoa

class View: NSView {
override func performKeyEquivalent(with event: NSEvent) -> Bool {
return true
}
}

Sample Project

Why is this functionKey selected when I press F1, F2, etc?

Apple's documentation isn't what is used to be.

If the documentation doesn't help, check the header. Copied from NSEvents.h:

    NSEventModifierFlagFunction           = 1 << 23, // Set if any function key is pressed.

NSEventModifierFlagFunction was NSFunctionKeyMask, documentation:

NSFunctionKeyMask

Set if any function key is pressed. The function keys include the F keys at the top of most keyboards (F1, F2, and so on) and the navigation keys in the center of most keyboards (Help, Forward Delete, Home, End, Page Up, Page Down, and the arrow keys).

Apparently the .function flag is also set when the fn-key is pressed (on my Apple keyboard, my Logitech keyboard handles the fn-key internally).

Emulate / send Modifier Key (Cntrl, Alt, fn, Shift) in OSx

All you have to do is create an event tap and set the mask.

Sample:

@interface AppDelegate ()

@property (assign) CFMachPortRef myEventTap;
@property (assign) CFRunLoopSourceRef myRunLoopSource;

@end

@implementation AppDelegate

CGEventRef MyEventTapCallBack(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGEventSetFlags(event, kCGEventFlagMaskShift);
return event;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.myEventTap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged),
MyEventTapCallBack,
(__bridge void *)self);
if (self.myEventTap) {
self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0);
if (self.myRunLoopSource)
CFRunLoopAddSource(CFRunLoopGetMain(), self.myRunLoopSource, kCFRunLoopCommonModes);
}
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
if (self.myRunLoopSource) {
CFRunLoopSourceInvalidate(self.myRunLoopSource);
CFRelease(self.myRunLoopSource);
}
if (self.myEventTap)
CFRelease(self.myEventTap);
}

@end

How to monitor global modifier key state (in any application)?

One option is to use EventTaps. This lets you monitor all keyboard events. See:
http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate

Unfortunately event taps will stop working if an application is requesting secure input. For example Quicken.



Related Topics



Leave a reply



Submit