コントロールキーを送信

いわゆるモディファイヤキーを押すのは、アルファベットキーを押すのに比べるとちょっと面倒。たとえばCtrl+aを送る場合、今までの知識から想像すると

     PostMessage(hWnd, WM_KEYDOWN, VK_CONTROL, 0);
     PostMessage(hWnd, WM_CHAR, 'a', 0);
     PostMessage(hWnd, WM_KEYUP, VK_CONTROL, 0);

これでいけそうなんだけど、うまくいかない。ただ"a"が出力されるだけでした。ただキーを押しただけだとうまくいかないらしい。ということは、グローバルなキーボードの状態を「Ctrl押下」に変更しないといけない。とすると、現在のキー入力を、アクティブになってるプロセスから、目的のアプリのプロセス*1にアタッチしないといけない。・・・ということで、下のようにすれば動くみたいです。

#include 

int main(void){
     HWND hWnd;
     BYTE kstats[256], ctrlstat;
     DWORD stid, dtid;

     hWnd = FindWindow("Notepad", NULL);
     hWnd = FindWindowEx(hWnd, NULL, "Edit", NULL);

     // キー入力をアタッチ
     stid = GetCurrentThreadId();
     dtid = GetWindowThreadProcessId(hWnd, NULL);
     AttachThreadInput(stid, dtid, TRUE);
     
     // 現在のCtrlの状態を保存
     GetKeyboardState(kstats);
     ctrlstat = kstats[VK_CONTROL];

     // Ctrlを押した状態にする(「押してるかどうか」のフラグが0x80らしい)
     kstats[VK_CONTROL] |= 0x80;
     SetKeyboardState(kstats);

     // 'a'を送信
     PostMessage(hWnd, WM_KEYDOWN, (WPARAM)VkKeyScan('a'), 0);

     // Ctrlの状態を戻す
     kstats[VK_CONTROL] = ctrlstat;
     SetKeyboardState(kstats);

     // キー入力をデタッチ
     AttachThreadInput(stid, dtid, FALSE);
     return 0;
}

モディファイヤキーを送信するだけで、こんなに手間が増えるとは!恐るべし。

*1:正確にはスレッドのようですが