【C#】別のアプリケーションに対してキーボード操作を行う

偶にキーボード操作が煩わしいという事は無いでしょうか?

Excel、ホームページの問い合わせフォーム、チャット…

アプリケーションが違うだけで入力することは一緒なのに毎回入力するのは面倒臭い。
コピペするにしても、コピー元を探さないといけないので非常に億劫。
判子のように、ポンポンと文字を入力できたらどんなに楽でしょうか。

今回は、アプリケーションからキーボードで文字を入力する操作する方法について触れます。

実装概要

利用者が選択しているアプリケーションのウィンドウに対して、
裏でキーボード操作を代行するのが目的です。

このアプリケーションを実装するためには次のような手順が必要です。

  1. 選択されているアプリケーションのウィンドウを取得
  2. 対象のウィンドウのハンドル(操作権限)を取得
  3. 対象のウィンドウでキー操作のシミューレーション

つまり、別のウィンドウを一時的に奪うわけです。

参考

公式ページでも解説されています。

docs.microsoft.com

公式ページでは特定のアプリケーションを開いて入力する所まで解説しています。

選択されているアプリケーションと特定のアプリケーションの選択では実装方法が異なります。
もし、特定のアプリケーションに限定する場合は公式の解説が参考になります。

実装方法

まずは、作成したクラスファイルをまとめるためのフォルダーを追加しておきます。 
ソリューションエクスプローラーから、プロジェクト直下にTextEmulateと言うフォルダーを設置します。
この記事では複数のクラスファイルを用意しますが、作成したクラスファイルはすべてこのフォルダーに入れます。

【Tips】フォルダーの追加方法
ソリューションエクスプローラーの追加したいプロジェクト配下のファイル(フォルダ)を選んで右クリックメニューを開きます。
メニューから 追加 > 新しいフォルダー を選択すればフォルダーを追加できます。

ちなみに、フォルダーを作るのは必須ではありません。
モジュールを分かりやすくするためにフォルダーにまとめていますので、環境に合わせて変えて下さい。

私は実装する時に、次の機能をそれぞれ別のクラスにしたいです。

  • 別の処理から呼び出されるクラス
  • API(Windows Api)連携用のクラス

次の項からそれぞれのクラスを実装していきます。

【Tips】クラスファイルの追加方法
ソリューションエクスプローラーの追加したいプロジェクト配下のファイル(フォルダ)を選んで右クリックメニューを開きます。
メニューから 追加 > 新しい項目の追加 を選択します。
項目のメニューからクラス(c#のマークが右上にある)を選択し、名前にクラス名を追加します。
すべて選択が終わったら、右下の追加ボタンを選択します。

API連携用のクラスを作成する

まず、MyWindowApiと言うクラスを作成します。
APIから関数を参照するために次の処理を追加します。

using System;
using System.Runtime.InteropServices;

namespace (プロジェクト名).TextEmulate
{
    /// <summary>
    /// ウィンドウ周りのAPI参照クラス
    /// </summary>
    class MyWindowApi
    {
        /// <summary>
        /// 選択しているウィンドウのハンドルを取得
        /// </summary>
        /// <returns>ウィンドウのハンドル</returns>
        [DllImport("USER32.DLL")]
        public static extern IntPtr GetForegroundWindow();
    }
}

現在選択しているウィンドウを取得をするには、GetForegroundWindowという関数を使います。

docs.microsoft.com

現在ユーザーが選択しているウィンドウ、つまりユーザーから見て最前にあるウィンドウの事をフォアグラウンドと言います。
今回は今現在操作している最中に補助をしたいので、フォアグラウンドのウィンドウを取得できるようにします。

別の処理から呼び出されるクラス

別の処理から実際に呼び出されるクラスを作ります。

今回は、次のようなキーボード操作の流れをシミュレート出来るようにします。

  1. 指定された文字を入力
  2. エンターキーを押す

新しくKeyboardEmulateというクラスを追加して、次の処理を追記します。

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace (プロジェクト名).TextEmulate
{
    /// <summary>
    /// キーボードをシミュレート
    /// </summary>
    class KeyboardEmulate
    {
        /// <summary>
        /// 現在選択されているウィンドウに対してキーを送信
        /// </summary>
        /// <param name="keys">送信するキー</param>
        public void writeKeys(string keys)
        {
            // 選択しているウィンドウを取得
            IntPtr targetWindowHandle = MyWindowApi.GetForegroundWindow();
            if(targetWindowHandle == IntPtr.Zero)
            {
                // 操作できるウィンドウがない
                return;
            }
          
            // 現在選択しているウィンドウに対してキーを送信
            SendKeys.SendWait(keys);

            // タイプ後にENTERを送信
            SendKeys.SendWait("{ENTER}");
        }

    }
}

キーの操作のシミュレートはSendKeysSendWait関数で実行できます。

docs.microsoft.com

文字だけでなく、Enterキーのような特殊なキー操作にも対応しています。

呼び出し方

他のクラスと同様に、インスタンスを作って関数を呼べば今選択しているウィンドウに対してキー操作を行います。

using (プロジェクト名).TextEmulate;

// 省略

KeyboardEmulate keyboardEmulate = new KeyboardEmulate();
keyboardEmulate.writeKeys('入力テキスト');

注意

あくまで再現できるのはキーボード操作だけですので、入力するカーソルは手動で合わせる必要があります。
また、既存のアプリケーションと機能が競合する場合もあります。


以上です。

発火部分の実装には触れませんでしたが、
例えば常駐アプリにして次の場合に発火させるという方法があります。

  • キーボードの組み合わせのショートカットとして登録
  • 直前のウィンドウ情報を保持しておいて、入力する内容を決めたら保持したウィンドウに対してキーボード操作する
  • 外部デバイスの入出力を監視して、デバイスのイベントで発火させる

ここまで書いてきましたが、実は発火側を作ったり設計したりする方が難しいです。
しかし、キーボード操作自体は比較的簡単に実装出来るのでアプリケーションで出来る事が広がります。

©︎2017-2018 WebSandBag