macOS keyboard event intercepted three ways

Under normal circumstances,You do not need to know the contents。

In rare cases,Your app might need to get the user presses the button information,such asThe ones released Develop a Input Method。Only then can you provide candidates to the user。

How to create an input method under macOS,I'm hereSwift uses InputMethodKit to write an input methodThis article has detailed instructions,Pass it over here,How do we have focused on addressing key user,Especially the handling of a modified key。

Pocketed input method has always been a sort of a small bug,That is, some input box,Press the shift key is not performed correctly in English。He says a professional,That input method in the input box can not get some of this shift is the key event。

note,Input is normal,Everything else is normal。For it is the input method,Press the shift key has never been。

by default,We inherited IMKInputController ,By which open override func handle(_ event: NSEvent!, client sender: Any!) -> Bool Processed key information,The system will automatically call this function to send us data,Bool returned by this event to determine whether to continue to pass,The treatment is generally no problem,But for qualifier,The bug appears above。

of course,For this reason I think we can think up,What we get key information level is too high,Before passing through the layers of our hands,This time the event has been changed too many times,God knows where it is intercepted,So we find a way to get this event from the bottom of the place more。

Event pass three levels

In macOS ,Event pass through three levels:

  • Cocoa / AppKit - which is the highest level,We also used the default level NSEvent
  • Quartz will transmit to the event from the respective app IOKit,That is CGEvent
  • IOKit — The bottom,Directly from the hardware。

Illustration from


The most common we,Inside it encapsulates the key code、Modifiers logo, etc. - the biggest feature is the shift either right or left (not the other sub-Ha)。

In General,We use it is enough,Analyzing key combinations such as,Determine what the user enters。But for the above bug,Especially in some of the game,You can not switch input in English,So,We need to seek lower-level solutions。


NSEvent Come from CGEvent Package,Some of the latter bottom,At this level you can get the distinction between left and right shift coding,of course,Thus NSEvent.ModifierFlags The enumeration type can be used not directly,Since no distinction between left and right coded here。This time you need to judge yourself according to the key code of the key combinations。

but,For our input method for,Taking into account the structural problems,We do not at this level to get all the key information,As long as you can get key combination,Thus,The default data unchanged,As long as the key combination change judgment on the line,So get another earnings is that we can distinguish between each of the modified button,We can distinguish between left and right - if you really needed。

First of all,It is to add a monitor in the system,This write in your AppDelegate in,Once the program is started to ensure the implementation of:

Here we set only listen flagsChanged 的 event

Then the closure function for callback:

It is worth noting here is due to call a C function,So the closure can not capture context (here I wrote a function,Because the more content),The same time,The same reason,This function must be a global function in Swift,That is written in all the braces to the outside。

Here we must pay attention to highlight a row,We use Notification Center to deliver a message to the input method,As the examples of the life cycle of the class of uncertain input method (generally speaking, there is actually an instance of an input box,Every input box gets the focus will regenerate one instance but the old instance will not be released immediately),Example We can not call directly input to achieve the transmission parameters。

in IMKInputController Category,There are input or the end of the monitoring input method to enter a callback,We use this callback to implement and monitor the reception release,Avoid multiple instances simultaneously monitor input methods lead to competing with multi-threaded resource:

Thus,Every registered listeners into the input mode,Leave the input mode of the cancellation of listeners。As for which instance to listen,This is guaranteed by the system,In addition to our modifiers,Other buttons are also still sent by the system to ensure When did which instance,Everything is perfect。


At last,Callback notification process listening on the up:

Here's a GitHub repository,Inside monitor with Objective-C is achieved keyboard,for your reference:/keylogger


This framework may be some driver development and serial development developers will be familiar,This is the lowest level of the framework apple,You can not touch the core access and interact directly with hardware peripherals macOS,To us,This layer is too deep,Call this layer the content is not very comfortable with Swift。

In short,If you want to know more,Here's a GitHub repository,/Swift-KeyloggerThis project uses Swift 4 Construct,Use the lowest level of direct IOKit communicate with HID devices,for your reference。



How to hang up / remap an arbitrary keyboard event on OSX?

Original article written by Gerber drop-off:R0uter's Blog » macOS keyboard event intercepted three ways

Reproduced Please keep the source and description link:

About the Author


The non-declaration,I have written articles are original,Reproduced, please indicate the link on this page and my name。


Leave a Reply

Your email address will not be published. Required fields are marked *