個人的なことで申し訳ありませんが、鳩でもわかるC#管理人はタイピングが遅いです。そこで決められた文字列を登録しておいてペースト処理をおこなえばあたかも人が1文字ずつ打ち込んでいるかのように見せるためのアプリをつくったのですが、結果的には失敗でした。

これがそのアプリです。

作ったのでこのブログでネタにします。どんなコードを書いたのかをみてみましょう。

グローバルキーフックをするクラスの定義

まず自分自身ではないアプリ(テキストエディタやVisualStudo)などにペーストをすることを考えているのでグローバルキーフックをします。

最初にそのためのクラスを定義します。このクラスはC#でグローバルキーフックをする方法とほとんど同じです。違う点はキーが押されたときに本来の動作をさせるかさせないかをコントロールできるようにさせていることです。

ペーストを実行するためにはCtrlキーを押しながらVキーをおします。このときに普通にペーストの処理をさせずに指定された文字列を1文字ずつペーストしていきます。Shiftキーを押しながらInsertキーを押してもペーストできますが、今回は無視させてください。

変更しているのはOnKeyDownEventメソッドの定義です。自分で定義したKeyDownEventイベントが発生したときにイベントハンドラにKeyEventArgオブジェクトと引数として渡しますが、処理が終わったらIsCancelプロパティを調べてその値を返しています。

これによってCallNextHookEx関数を呼び出したり呼び出さなかったりと制御できるので、キーフックして自分がやりたい処理を行なわせたあと、本来の動作をさせたりさせないことが可能になるのです。

Form1クラス

次にForm1クラスを考えます。最初の動画で最初にでてきたフォームにRichTextBoxを貼り付けただけの簡単な作りです。

コンストラクタ内でキー操作時のイベントハンドラを追加します。

イベントハンドラの定義

キーが押されたときと離されたときのイベントハンドラを定義します。

ペーストの処理はCtrlキーを押しているときにVキーが押されたときなので、現在Ctrlキーが推されている状態かどうかを保存しておくフラグ(isCtrlKeyDown)を用意します。そのキーがCtrlキーかどうかはe.KeyCodeを調べればわかります。162か163の場合です。

KeysConverterを使えばe.KeyCodeを文字列に変換できます。isCtrlKeyDownがtrueでkc.ConvertToString(e.KeyCode) が “V”のときがペースト処理がおこわれるその時ということになります。このときは後述する自作メソッドのPasteCharacterByCharacterを呼び出します。

一文字ずつペーストをする

一文字ずつペーストをする処理を示します。

isAllowフラグを用意していますが、文字列を文字に分解してクリップボードにコピー、そのあとSendKeys.SendWait(“^v”)を実行してCtrl+Vを押したのと同じ効果を得ようとしていますが、するとそのときにまたPasteCharacterByCharacterメソッドが実行されてしまいます。

すると無限ループと同じような現象がおきてフリーズしてしまいます。またタスクマネージャをつかって強制終了させたときキーが離されたときにおこなわれるはずの処理がおこなわれていないのでキーが押しっぱなしのままロックされた状態になります。

フリーズしたうえにキー操作したときにおかしな動作をする。最初はなにがおきたのかわからず慌ててしまいましたが、上記がその原因でした。キーフックするときは注意が必要です。マウスフックも同時にしてバグると完全に死にます。

一文字ずつクリップボードにコピーしてペーストをする処理を繰り返していますが、改行文字だけをひとつだけコピーするとペーストしてもなにもおきません(改行文字だけでも複数であるならペーストできる)。そこでforeach内で’\n’を取得してしまったときは文字列に追加してほかの文字を取得したときいっしょにペースト処理を実行しています。

効果音の再生

入力時にキーを叩いたときの音がでるように効果音を鳴らします。ソリューションエクスプローラの[参照に追加]からC:\Windows\system32\wmp.dllを追加します。するとWMPLib.WindowsMediaPlayerをつかって効果音の再生ができるようになります。

ただWMPLib.WindowsMediaPlayerがひとつだけだと、同じ音を短い間隔で再生する場合、音がなりはじめる前につぎの音を鳴らす処理がはじまってしまうため、最後の音しか再生されないという問題がおきます。そこでWMPLib.WindowsMediaPlayerオブジェクトを複数生成して処理を分散させます。5つくらいあれば対応できることがわかりました。

グローバルキーフックの解除

アプリケーションを終了するときにキーフックを解除します。この処理を忘れてしまうとどうなるのでしょうか? 特に問題は確認できませんでした(見えないところでトラブルが起きているかも)が、一応やっておきます。

これで実際に使い物になるかどうか試してみましたが、テキストエディタやたいていのワープロソフトであれば使えます。ところが肝心のVisualStudoではつかえません。VisualStudoでは自動的に入力された文字列を整形する機能(int i=0; をint i = 0;に変換するなど)があり、これが邪魔しているのかうまく文字列が出力できませんでした。

ということでジョークプログラム以上のものではなく、実際には使い物になりません。