Written in Japanese(UTF-8)
2006. 3. 7
INASOFT
/トップ/ユーティリティとゲーム/キーボードシミュレータ/作ってみよう

キーボードシミュレータ / keybd_event APIについて / C++ / C# / VB.NET / J# / C++.NET

Icon キーボードシミュレータを作ってみよう!!


キーボードシミュレータの簡単なコマンドライン版を作ってみようという、プログラミング解説講座です。
第3回では、C#言語による.NET Frameworkなアプリケーションとして作ってみます。

第3回

第2回へ←   →第4回へ


■まずはソースコード

今回は、C#言語による.NET Framework用のプログラムの作成を行います。

.NET Frameworkとは、Microsoftが開発したランタイムみたいなもので、JavaでいうところのVM(Virtual Machine)みたいなものとお考え下さい。

JavaVMとの一番の違いは、言語が限定されないことといえるかと思います。JavaVMはJavaだけが対象言語ですが、.NET Frameworkの場合は、C++、C#、Visual Basic、J#など、多彩な言語が利用できます。(そういえば、富士通がCOBOL.NETを作ったというウワサを聞きましたけど、あれってどうなったんだろう…?)

なお、.NET Frameworkが普及しているOSはWindowsくらいなもので、他のOSの普及状況は、全くないんだか、ほとんど無いんだか、区別の付かないような状態ですね。

さて、このプログラムをC#言語で記述する場合、特別なテクニックが1つだけ必要になります。これは、keybk_event() に限っては、Windows APIの力を借りなければならないというところです。なので、せっかく.NET Framework用に書いたとしても、他OSへの異色は絶望的なわけで………。まぁ、他に作りやすくなっている部分もありますから、プログラマにとって一概に損というわけでもないだろうと思います。とりあえず、練習目的ですから、こういうのもアリかな、と。

何はともあれ、ソースコードはこんな感じになります。

  ●ソースコードと実行プログラムのダウンロードはこちらから (5KB)



//
// 引数で指定された文字列に従い、キーボード入力をシミュレートします。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace keysimcs
{
    // Win32APIを呼び出すためのクラス
    public class win32api
    {
        [DllImport("user32.dll")]
        public static extern uint keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
    }

    class keysimcs
    {
        public static int Main(string[] args)
        {
            // 入力対象のプログラムをアクティブにするまでの待ち時間(ミリ秒単位)
            int iSleepTime = 5000;
            // キーの取りこぼしを防ぐための、各入力間の待機時間(ミリ秒単位)
            int iWaitTime = 10;
            // ※1ミリ秒=0.001秒のこと

            if (args.Length == 0) {
                // 引数が指定されていない場合、使用方法を表示
                Console.WriteLine("キーボード入力をシミュレートしたい文字列を引数に指定してください。");
                Console.WriteLine("");
                Console.WriteLine("keysimcs <文字列> [<待機時間> [<文字間ウェイト>]]");
                Console.WriteLine("");
                Console.WriteLine("文字列に指定可能な文字は、英大文字・数字・スペース・タブです。");
                Console.WriteLine("(英小文字は無視されますのでご注意下さい)");
                Console.WriteLine("スペース・タブを指定する場合は、文字列全体をダブルコーテーションで囲います。");
                Console.WriteLine("待機時間は、入力開始までの待ち時間をミリ秒単位で指定します(1以上)。");
                Console.WriteLine("文字間ウェイトは、入力文字間のウェイト時間をミリ秒単位で指定します(1以上)。");
                return 1;
            }

            // 待機時間取得
            if (args.Length > 1) {
                try {
                    iSleepTime = Convert.ToInt32(args[1]);
                }
                catch (FormatException) {
                    Console.WriteLine("待機時間の指定が不正です。ミリ秒単位で1以上の数を指定してください。");
                    return 1;
                }
            }

            // 文字間ウェイト取得
            if (args.Length > 2) {
                try {
                    iWaitTime = Convert.ToInt32(args[2]);
                }
                catch(FormatException) {
                    Console.WriteLine("文字間ウェイトの指定が不正です。ミリ秒単位で1以上の数を指定してください。");
                    return 1;
                }
            }

            // 入力対象のプログラムをアクティブにするまでの待ち
            Console.WriteLine("入力対象のプログラムをアクティブにしてください。");

            Console.WriteLine(iSleepTime.ToString() + "ミリ秒間待機します...");
            Thread.Sleep(iSleepTime);
            Console.WriteLine("\n入力中...");

            // コマンドラインの文字列を取得する
            string p = args[0];

            // 取得された文字列を1文字ずつ検査し、
            // シミュレート可能文字列であればkeybd_event() APIに
            // 渡す。
            foreach (char pi in p) {
                // 入力対象の文字列かどうかを調べる
                if ( checkKey(pi) ) {
                    // キーの押し下げをシミュレートする。
                    win32api.keybd_event((byte)pi, 0, 0, (UIntPtr)0);
                    // キーの解放をシミュレートする。
                    win32api.keybd_event((byte)pi, 0, 2/*KEYEVENTF_KEYUP*/, (UIntPtr)0);

                    // dwWaitTimeミリ秒間待機する
                    // (キーの取りこぼしを防ぐため)
                    Thread.Sleep(iWaitTime);
                }
            }

            Console.WriteLine("キーボードシミュレートが終了しました。");

            return 0;
        }

        // ********************************************************************
        // * checkKey                                                         *
        // *   キーボードシミュレート対象文字列かどうかを調べる。             *
        // *   引数cが対象ならばtrueを返し、そうでなければfalseを返す。       *
        // ********************************************************************
        public static bool checkKey(char c)
        {
            if ( '0' <= c && c <= '9' ) { // 数字ならOK
                return true;
            }
            else if ( 'A' <= c && c <= 'Z' ) { // 英大文字ならOK
                return true;
            }
            else if ( c == ' ' ) { // スペースならOK
                return true;
            }
            else if ( c == '\t' ) { // タブならOK
                return true;
            }

            // それら以外の場合はNG
            return false;
        }
    }
}


■実行画面

実行画面は次のようになります。

  1. 引数を付けなかった場合

    
    C:\MyProject\keysimcs\release>keysimcs
    キーボード入力をシミュレートしたい文字列を引数に指定してください。
    
    keysimcs <文字列> [<待機時間> [<文字間ウェイト>]]
    
    文字列に指定可能な文字は、英大文字・数字・スペース・タブです。
    (英小文字は無視されますのでご注意下さい)
    スペース・タブを指定する場合は、文字列全体をダブルコーテーションで囲います。
    待機時間は、入力開始までの待ち時間をミリ秒単位で指定します(1以上)。
    文字間ウェイトは、入力文字間のウェイト時間をミリ秒単位で指定します(1以上)。
    
    C:\MyProject\keysimcs\release>
    

  2. 引数を付けた場合

    
    C:\MyProject\keysimcs\release>keysimcs ABCDEFG12345
    入力対象のプログラムをアクティブにしてください。
    5000ミリ秒間待機します...
    入力中...
    キーボードシミュレートが終了しました。
    
    C:\MyProject\keysimcs\release>
    

「入力対象のプログラムをアクティブにしてください」という表示が出たところで、貼り付け先のウィンドウをアクティブにしてやる必要があります。引数は、英大文字・数字・スペース・タブを指定してください。英小文字は無視されます。

入力対象のプログラムとして、例えばメモ帳にしたい場合は、メモ帳をアクティブにしておくことで、次のような画面になります(CAPSロックがやカナロック等がかっていない場合)。

まぁ、第2回のC++と同じ動きをしているというわけです。



■解説

今回の一番特殊な点は、C#からは直接Windows APIを呼ぶことはできないので、Windows APIを呼ぶための特別な宣言をしているということかと思います。具体的には次の部分です。



    // Win32APIを呼び出すためのクラス
    public class win32api
    {
        [DllImport("user32.dll")]
        public static extern uint keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
    }

呼び出したいAPI keybd_event() は、user32.dllの中にありますので、 [DllImport("user32.dll")] が付いています。後は、C#が持っている型(.NET Frameworkが持っている型?) の名前を使って、APIを表現してやります。



    // キーの押し下げをシミュレートする。
    win32api.keybd_event((byte)pi, 0, 0, (UIntPtr)0);
    // キーの解放をシミュレートする。
    win32api.keybd_event((byte)pi, 0, 2, (UIntPtr)0);

    // 上記の「2」は 「KEYEVENTF_KEYUP」を意味しています。

こうしておくことで、上記のように、Windows API keybd_event()を実行できるようになるというわけです。

■次回は?

次回は、Visual Studio .NETを用いて、キーボードシミュレータ(.NET Framework版)のコマンドライン版を作ってみます。

第2回へ←   →第4回へ


キーボードシミュレータ / keybd_event APIについて / C++ / C# / VB.NET / J# / C++.NET
/トップ/ユーティリティとゲーム/キーボードシミュレータ/作ってみよう