ついでに

思い出したので書いてみる。最近「おすすめのテキストエディタ何?」っていう話題になることが多い。自分はxyzzyを愛用してるんだけど、他人にお勧めできないしなあ・・・。viはバリバリ使う職場のくせに何でemacs使いがいないんだろう。謎だ。

とりあえずTeraPadをお勧めしてます。使ったことないけど。

ルーティング

coLinuxを導入中。coLinux -> windowsの仮想アダプタへのping(ping 192.168.0.1)は通るのに、インターネットにつないでいるアダプタにpingが通らない。

明らかにルーティングまわりだよなあ、と思いつつルーティングテーブルを見たりwindowsのroutingサービスが起動しているか見たりパーソナルファイヤーウォールを切ってみたりしたけどいっこうに解決しない。

うーん、なんだろうとおもったら、WindowsXP(2000も?)でルーティングを有効にするには、

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\IPEnableRouter

の値を1にする必要があるらしい。linuxでいう/proc/sys/net/ipv4/ip_forward、AIXでいう # no -o ipforwarding みたいなものか。レジストリとか聞くととたんにやる気が萎えてくるのはなんででしょうかね?

WM_KEYDOWN/WM_KEYUP

Syntax

WM_KEYDOWN

    WPARAM wParam
    LPARAM lParam;

Parameters

wParam
Specifies the virtual-key code of the nonsystem key.
lParam
Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table.

0-15
  Specifies the repeat count for the current message. The value is the
  number of times the keystroke is autorepeated as a result of the user
  holding down the key. If the keystroke is held long enough, multiple
  messages are sent. However, the repeat count is not cumulative.
16-23
  Specifies the scan code. The value depends on the OEM.
24
  Specifies whether the key is an extended key, such as the right-hand ALT
  and CTRL keys that appear on an enhanced 101- or 102-key keyboard. T
  he value is 1 if it is an extended key; otherwise, it is 0.
25-28
  Reserved; do not use.
29
  Specifies the context code. The value is always 0 for a WM_KEYDOWN message.
30
  Specifies the previous key state. The value is 1 if the key is down before 
  the message is sent, or it is zero if the key is up.
31
  Specifies the transition state. The value is always zero for a WM_KEYDOWN 
  message.

Return Value
An application should return zero if it processes this message.

Syntax

WM_KEYUP

    WPARAM wParam
    LPARAM lParam;

Parameters

wParam
Specifies the virtual-key code of the nonsystem key.
lParam
Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table.

0-15
  Specifies the repeat count for the current message. The value is the 
  number of times the keystroke is autorepeated as a result of the user 
  holding down the key. The repeat count is always one for a WM_KEYUP message.
16-23
Specifies the scan code. The value depends on the OEM.
24
  Specifies whether the key is an extended key, such as the right-hand AL
  and CTRL keys that appear on an enhanced 101- or 102-key keyboard. 
  The value is 1 if it is an extended key; otherwise, it is 0.
25-28
  Reserved; do not use.
29
  Specifies the context code. The value is always 0 for a WM_KEYUP message.
30
  Specifies the previous key state. The value is always 1 for a WM_KEYUP message.
31
  Specifies the transition state. The value is always 1 for a WM_KEYUP message.
Return Value

An application should return zero if it processes this message.

コントロールキーを送信

いわゆるモディファイヤキーを押すのは、アルファベットキーを押すのに比べるとちょっと面倒。たとえば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:正確にはスレッドのようですが