モディファイヤキーつきでキー入力をエミュレートする
May 15th, 2010 | Published in CS
Mac アプリをつくっててだいぶハマってしまったのでその小話。
キーボード入力をエミュレートするには、 Foundation の CGEventCreateKeyboardEvent()
を使うのが基本です。ドキュメントにもそう書いてある。
Quartz Event Services Reference:
CGEventRef event1, event2, event3, event4; event1 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)56, true); event2 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, true); event3 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, false); event4 = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)56, false);
56
はシフトキーを表し、 6
は z キー。つまり、大文字の z (‘Z’) をタイプするよというサンプルコード、のはずなのですが、 Mac OS X 10.6.3 でやってみてもまるでうまくいかない。たんに z
が入力されるにとどまります。
で、ぐぐっていると スタックがオーバーフローして:
CGEventRef event1, event2; event1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);//'z' keydown event CGEventSetFlags(event1, kCGEventFlagMaskShift);//set shift key down for above event CGEventPost(kCGSessionEventTap, event1);//post eventのように、
CGEventSetFlags()
をかまして、モディファイヤキーが押されているのをイベントに修飾せよ、とある。なるほど。
それでやってみると、たしかに Z
が入力されます。I’m feeling lucky! と思うもつかのま、こんどは z
に戻らない。むむむ、これは…
そこから一週間ほどもがいていたのですが、状態をリセットすればいいんじゃなかろうかと気づいてやってみたらうまくいった。バッドノウハウすぎるだろこれ..
けっきょくうまくいったコードは以下のようなものになりました。
- (void) postKey:(uint16_t) key withModifiers:(uint16_t) modifiers down:(BOOL)down { CGEventRef event = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)key, down);
if (modifiers & MODE_SHIFT) { CGEventSetFlags(event, NSShiftKeyMask); } else if (modifiers & MODE_CONTROL) { CGEventSetFlags(event, kCGEventFlagMaskControl); } else if (modifiers & MODE_OPTION) { CGEventSetFlags(event, kCGEventFlagMaskAlternate); } else if (modifiers & MODE_COMMAND) { CGEventSetFlags(event, kCGEventFlagMaskCommand); } else CGEventSetFlags(event, 0); // <<<<<<< これ
CGEventPost(kCGSessionEventTap, event); CFRelease(event); }
CGEventSetFlags に指定するフラグは OR でとればよいので、もっとかんたんに書けるはず。しかし今夜はここで力尽きた..
教訓: 仕様、コードに一致していないドキュメントはむしろ害になり得るので気をつけよう。自戒自戒。