MacOSXでは,Quartzに含まれる低レベルAPIで,マウスやキーボードのイベントをシステム側にPostすることができる.
調べるとPanther当たりまでは,色々とバグがあったようだが,大分使えるようになってきているらしい.
ここでは,マウスイベント,キーボードイベントのPostについて,調べたことをまとめてみる.

マウスイベント

マウスのクリックイベントをPostする

CGPostMouseEvent
Synthesizes a low-level mouse-button event on the local machine.

CGEventErr CGPostMouseEvent (
CGPoint mouseCursorPosition,
boolean_t updateMouseCursorPosition,
CGButtonCount buttonCount,
boolean_t mouseButtonDown,
);

一つめの引数はマウスの目的位置,二つめの引数はマウスをそこにちゃんと動かすかのフラグ,三つ目の引数はマウスボタンの番号,四つ目の引数はマウスをクリックするかのフラグである.
buttonCountは,1が左,2が右,3が真ん中ボタンになるらしい.
例えば,一番左上隅をクリックするようにマウスを制御する場合は,以下のようにコーディングする.

CGPoint point;
point.x=0;
point.y=0;
CGPostMouseEvent(point, TRUE, 1, TRUE);   //mouse down
CGPostMouseEvent(point, TRUE, 1, FALSE);  //mouse up

ちゃんと,マウスアップのイベントをPostしないと,クリックしたことにならないことがあるので要注意.
また,デスクトップの表示領域は以下のAPIで取得できる.

int width = CGDisplayPixelsWide(kCGDirectMainDisplay);
int height = CGDisplayPixelsHigh(kCGDirectMainDisplay);

マウスの表示を制御する

マウスのポインタの表示/非表示を設定するには,以下のAPIを利用する.

CGDisplayErr CGDisplayHideCursor(CGDirectDisplayID display);  // カーソルを隠す
CGDisplayErr CGDisplayShowCursor(CGDirectDisplayID display);  // カーソルを表示する

マウスのポインタの表示位置を設定するには,以下のAPIを利用する.ただし,このAPIの場合,マウスが移動したことによるイベントは発生しない.マウスのイベントをちゃんと発生させたい場合は,上記のCGPostMouseEventを利用する.

CGDisplayErr CGDisplayMoveCursorToPoint(CGDirectDisplayID display, CGPoint point);

CGDirectDisplayID displayには,ディスプレイの識別子を入力するのだが,複数のディスプレイを利用したりしていない場合は,kCGDirectMainDisplayを引数にすれば,大丈夫.
詳しくは,Appleのこの辺の資料を参考にされたい.
Technical Note TN2007

キーボードイベント

キーボードイベントをシステムにPostする

キーボードイベントは,以下のAPIでPostできる.

CGEventErr CGPostKeyboardEvent (
CGCharCode keyChar,
CGKeyCode virtualKey,
boolean_t keyDown
);

三つ目の引数は,キーの押しと,上げるのフラグである.
しかし,一つめと二つめの引数が何を意味するかが,よくわからない.そこで,ヘッダファイルCGRemoteOperation.hと,ネットの情報を調べてみた.
それらをまとめると,

  • 普通のキー CGPostKeyboardEvent((CGCharCode)'v', (CGKeyCode)9, true);
  • コントロールキー CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)59, true);
  • シフトキー CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)56, true);
  • オプションキー CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)58, true);
  • コマンドキー CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true);
  • となるらしい.
    なぜ,こんなバラバラになっているのかが,よくわからないのだが,Appleのドキュメントにないので致し方ない.直感すると,CGKeyCodeで,複数の修飾キーを設定できると思うのだが・・・.
    これらを利用して,コマンドキー+'C',いわゆるコピーショートカットを実現する場合は,以下のようなコードになる.

    CGPostKeyboardEvent((CGCharCode)NULL, (CGKeyCode)55, true);
    CGPostKeyboardEvent((CGCharCode)'c', (CGKeyCode)9, true);
    CGPostKeyboardEvent((CGCharCode)'c', (CGKeyCode)9, false);
    CGPostKeyboardEvent((CGCharCode)NULL, (CGKeyCode)55, false);
    

    コマンドキーを押す,Cキーを押す,Cキーを放す,コマンドキーを放すの順番で入力したことになる.