keyhac改造

姫踊子草からkeyhacに乗り換えました - tomoemonの日記で書いたようにkeyhacでWeatherTypingは打てるようになりましたが、依然TOD(Typing of the Dead 2004)では正しく動きませんでした。正確に言えば、「った:tta」のような同じキーの連続打鍵をkeyhacがエミュレートしたときに、1打鍵分しかゲームに反映されないという問題です。

タイプウェルのようにWindowsメッセージをベースにしたソフトであれば順番にキー入力メッセージを処理するので取りこぼしはないのですが、DirectInputで定期的にポーリングしている場合は取りこぼしがありえると思い、1入力ごとに若干のウェイトを入れれば良いと考えました。

幸いkeyhacはソースコードが公開されているので、覗いたところSendInputを使って複数の文字を一度に入力していました。SendInputの挙動を詳しくは把握していませんが、1文字ごとにウェイトを入れるように変更してみました。

keyhac_keymap.py(v1.24との差分)

580a581
>         self.input_wait = 0 # 1入力ごとの待ち時間(endInputで使用)
1031c1032,1037
<         pyauto.Input.send(self.input_seq)
---
>         if self.input_wait <= 0:
>           pyauto.Input.send(self.input_seq)
>         else:
>           for e in self.input_seq:
>             pyauto.Input.send([e])
>             time.sleep(float(self.input_wait)/1000)

メインスレッド*1に勝手にsleepを入れちゃってるのでお行儀悪いと思いますが、これで期待通り動いたのでとりあえず良しとします。使うときはconfig.pyの中で以下のようにミリ秒単位で指定します。

def configure(keymap):
  keymap.input_wait = 40

意外なことに(!)TODでは40ms以下では取りこぼしが発生してしまったので40を指定しています。30fpsぐらいでポーリングしてるんでしょうかね。それにしては35を指定しても取りこぼしが起きていました。WeatherTypingではウェイト0でも取りこぼしてないので、何が違うのか気になります。


まあ、何かしらの方法で公式でもサポートしてくれるとありがたいですね。
ちなみにsrcから動かすときにkeyhacに同梱してあるctermのモジュールが古いと言われたので、同作者の内骨格というソフトに同梱しているctermを引っ張ってきて動かしました。

*1:入力エミュレート専用のスレッドであれば問題ないと思いますがそうではなさそう