Xamarin.MacでGlobal Event Monitorを使いキー入力を監視する
概要
Xamarin.Macで開発している社内アプリで確実に動くファンクションキーを実現したい。
何も考えずに単純にキー入力を監視する実装にしたところ、一部で「キーを押しても動かない」という苦情が発生した。 原因は、ウインドウはひとつしか開いておらず、一見するとウインドウにフォーカスが当たっているように見えるが、実はデスクトップにフォーカスが当たっているという状況であった。 対策として、アプリ起動時に強制的にフルスクリーンにしてやろうかとも思ったがWindows 8並にスマートではないので、そのような状況でも動くファンクションキーの実装方法を模索している。
実装
アプリを開発する
NSEventにNSEvent.AddGlobalMonitorForEventsMatchingMaskを叩いて監視対象のイベントの種類と発生時に呼ばれるイベントハンドラを設定するだけである。 非常に簡単。
当初はNSEventMask.KeyDownで実装してみたが、これは文字キーの入力でしかイベントが発生せず、ShiftキーやCtrlキーなどを単品で押した場合には何も起こらない。 実装中のアプリではCtrlキー単品をショートカットキーとしており上記ではダメであった。 そこでNSEventMask.FlagsChangedに変えて実装してみたところCtrlキー単品でも上手くいった。
public override void DidFinishLaunching(NSNotification notification)
{
NSEvent.AddGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDown, (theEvent) => {
Console.WriteLine("keydown: " + theEvent.Characters);
});
NSEvent.AddGlobalMonitorForEventsMatchingMask(NSEventMask.FlagsChanged, (theEvent) => {
var flags = theEvent.ModifierFlags & NSEventModifierMask.DeviceIndependentModifierFlagsMask;
if (flags == 0)
{
Console.WriteLine("release");
}
else
{
Console.WriteLine("modifier: " + flags);
}
});
}
アプリを許可する
Global Event MonitorはOSのあらゆるイベントを監視できるため、一歩間違えばスパイウェアやキーロガーなどの非常に危ういアプリも簡単に作り放題となる。 そのためMac OS Xではシステム環境設定から明示的に許可したアプリでしかGlobal Event Monitorは機能しないようになっている。
- 左上のリンゴマークをクリック
- システム環境設定を開く
- セキュリティとプライバシーを開く
- プライバシーのタブを開く
- アクセシビリティを選ぶ
- 左下の鍵マークをクリックして認証する
- 中央のプラスマークをクリックして許可するアプリを追加する
なお、このアクセシビリティの許可がされていない状態でGlobal Event Monitorを使用しているアプリを実行してもエラーも何も発生しない。 この挙動は確実に半年くらいしてどんな実装だったかを忘れたころにトラブルになり、エラーも出ないのでデバッグも捗らず原因不明のバグに悩まされデスマーチ突入は決定的である。 これを回避するためアプリ起動時にアクセシビリティの許可がされているかを確認し警告を出す方法を模索しているが、まだ解決方法は見つかっていない。
関連項目
- Xamarin.Mac/アクセシビリティの許可の有無を取得する
- Xamarin.Mac/システム環境設定を開く
- MonoMac/フルスクリーン表示に対応する
- Xamarin.Mac/キーボードの入力をシミュレートする
- キーコード/Mac OS X