くわこのpermission denied.

WEBエンジニアの僕がぶつかった技術的な問題や発見

【swift】バックグラウンドでもKeyDownやMouseMoveのイベントを拾う方法

f:id:mask0702:20150921223621p:plain

自分が作っているアプリケーションで、バックグラウンド(最前面でない状態)でもキーボードが押された、あるいはマウスが動いたかを判定したいことがあったが、参考にできる文献が少なかったのでメモがてらに共有。

僕がやりたかったこと

teratail.com

簡単に言うと上のteratailの記事と同じで、最前面の状態でなくてもkeyDownやMouseMoveのイベントを検知したかったのですが、記事にもある通り

バックグラウンドでキーボードのイベントを受け取る事は基本的に難しいです。簡単にできてしまえば、パスワードを盗み取るキーロガー(キーボード入力を記録するソフト)が簡単に作成できてしまいます。そのため、最前面の時のみ受け取れるようになっているウィンドウ管理システムが多いように思います。

ということで実現は難しいように思えた。ただ、BetterTouchToolのようにどうにかすればキーの動作をbindできるのだろうと思っていた。

qiitaを漁る日々

とはいえどうしようも無かったので、qiitaのCocoaタグの記事一覧からそれっぽい内容のものをシラミつぶしに読んでいった。
Cocoaに関する最近ストックされた投稿 - Qiita

すると 「addGlobalMonitorForEventsMatchingMask:handler:を使えばできる。」という記述を以下の記事で発見した。qiita.com

ということでaddGlobalMonitorForEventsMatchingMask:handler:の使い方を探し、無事ことなきを得た。

NSEvent Class Reference
nextEventMatchingMask:untilDate:inMode:dequeue: - Cocoa API解説(iOS/OS X)
stackoverflow.com

実装

上のstackoverflowからまるまる持ってきたものだが

NSEvent.addGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask, handler: {(evt: NSEvent!) -> Void in
    NSLog("Global Keydown: " + evt.characters! + " (" + String(evt.keyCode) + ")");
});

という形にすれば良い。
ちなみにaddGlobalMonitorForEventsMatchingMask:handler:を使うには、そのアプリケーションが「システム環境設定 > セキュリティとプライバシー > アクセシビリティ > プライバシー」に登録されている必要がある。
f:id:mask0702:20150922224446p:plain

また、デバック中のアプリに対して有効にするにはXcodeがこれに登録すれば良い。


詳解 Swift

詳解 Swift