VBでマウスの動きを捉える方法(DirectInput編)


先のSetWindowHook()APIを使う方法では、
自アプリがアクティブの場合のみマウスの動きを捉えることができましたが、
他アプリでの動きを捉えるにはVC++等でDLLを作成する必要がありました。

今回ご紹介するDirectInputを使う方法では
やり方によっては他アプリ上でのマウス操作を捉えることができます。
またマウスの動きだけでなくキーボードの入力まで
捉えることが可能です。


フックによるマウス操作の捕捉は
OSからのメッセージをVBランタイム内のウィンドウプロシジャが受け取る前に
フックプロシジャで横取りすることで行っていました。
DirectInputでは仕組みはちょっと違います。

DirectInputの場合、マウスやキーボード、ジョイスティックなどの操作を
Windowsメッセージによらずにアプリケーションに報告します。
このため他アプリがアクティブであろうと
操作を取得することが可能な訳です。


DirectInputを使うための準備

DirectInputをVBから使うには「DirectX8 for Visual Basic Type Library」を参照設定します。
ちなみにDirectXの各バージョンは使える機能が異なる全く違うライブラリみたいなものですが
最新のものをインストールすれば前のバージョンも全てインストールされます。
(おかげでセットアップファイルのサイズがどんどんでかくなるw)


いつも通りサンプルプログラムを元に説明していきます。
こちらのサンプルプログラムを実行すると下記のウィンドウが開きます。

「Mouse」ボタンでマウス操作の捕捉を開始し、
「Keyboard」ボタンでキー操作の捕捉を開始します。
それぞれ再度押すと補足を中止します。(マウス操作は環境によっては補足をやめません^^;)
補足した操作は下のリストボックスに表示されます。(表示するだけでジェスチャのチェックまではしてません^^;)

このサンプルプログラムがアクティブでなく他のアプリがアクティブな状態でも
ちゃんとマウスとキーボードの状態変化を捉えていることが確認できると思います。


プログラムは全てForm1に書いてありますので、順に説明致します。

Option Explicit



'///////////////////////////////////////////////////////

'DirectInput

'///////////////////////////////////////////////////////





'///////////////////////////////////////////////////////

Implements DirectXEvent8

Implements文の意味はヘルプで調べて下さい。。。では不親切かもしれないので簡単に説明します。
簡単にいえば「指定されたクラスのメソッド/プロパティを必ず持つ」ということの宣言になります。
ここの場合DirectXEvent8インターフェースのメソッドをこのフォームが持つということになります。
別の言い方をすれば「このForm1というフォームはDirectXEvent8インターフェースとしての一面を持っていますよ
ということ宣言しているということです。
この結果DirectXEvent8インターフェースを引数に持つ関数にこのフォームを渡せることになります。

'///////////////////////////////////////////////////////

Private Const MAX_BUFFERSIZE As Long = 10       'マウス用バッファサイズ





'///////////////////////////////////////////////////////

Private mDX As DirectX8                         'DirectXオブジェクト

Private mDI As DxVBLibA.DirectInput8            'DirectInputオブジェクト



Private mDIDevM As DxVBLibA.DirectInputDevice8  'マウス用DirectInputDeviceオブジェクト

Private mhEventM As Long                        'マウス用イベントハンドル

Private mDIDevK As DxVBLibA.DirectInputDevice8  'キー用DirectInputDeviceオブジェクト

Private mhEventK As Long                        'キー用イベントハンドル

定数とモジュールレベルで存在する変数を定義しています。
各変数の意味や用途はその都度説明します。

'フォームロード時

Private Sub Form_Load()



    'コントロールの初期化

    chk_Mouse.Enabled = False

    chk_Keyboard.Enabled = False



    'DirectXオブジェクトの生成

    Set mDX = New DxVBLibA.DirectX8



    'DirectInputオブジェクトの生成

    Set mDI = mDX.DirectInputCreate()

    If mDI Is Nothing Then

        MsgBox "DirectInputオブジェクトが生成できません。"

        Exit Sub

    End If

    

    'マウスの準備

    'DirectInputDeviceオブジェクトの生成

    Set mDIDevM = mDI.CreateDevice("guid_SysMouse")

    If mDIDevM Is Nothing Then

        MsgBox "Mouse用DirectInputDeviceオブジェクトが生成できません。"

    Else

        '入力データ形式の設定

        mDIDevM.SetCommonDataFormat DIFORMAT_MOUSE2

        

        '強調レベルの設定

        mDIDevM.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE

        

        'イベントバッファの準備

        Dim diprop As DxVBLibA.DIPROPLONG

        With diprop

            .lHow = DIPH_DEVICE

            .lObj = 0

            .lData = 10

        End With

        mDIDevM.SetProperty "DIPROP_BUFFERSIZE", diprop

        

        'イベントの設定

        mhEventM = mDX.CreateEvent(Me)

        mDIDevM.SetEventNotification mhEventM

        

        'チェックボックスを使用可能にする

        chk_Mouse.Enabled = True

    End If

    

    'キーの準備

    Set mDIDevK = mDI.CreateDevice("GUID_SysKeyboard")

    If mDIDevK Is Nothing Then

        MsgBox "Keyboard用DirectInputDeviceオブジェクトが生成できません。"

    Else

        '入力データ形式の設定

        mDIDevK.SetCommonDataFormat DIFORMAT_KEYBOARD

        

        '強調レベルの設定

        mDIDevK.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE

        

        'イベントの設定

        mhEventK = mDX.CreateEvent(Me)

        mDIDevK.SetEventNotification mhEventK

        

        'チェックボックスを使用可能にする

        chk_Keyboard.Enabled = True

    End If



End Sub

フォームロード時にはコントロールの初期化DirectX(DirectInput)の準備
マウス捕捉の準備キーボード捕捉の準備を行っています。

 

'フォームロード時

Private Sub Form_Load()



    'コントロールの初期化

    chk_Mouse.Enabled = False

    chk_Keyboard.Enabled = False

まずマウスとキーの各情報を取得するかのスイッチであるチェックボックスを使用不可にしています。
各チェックボックスは情報取得の準備が成功したときに使用可能にしています。

'DirectXオブジェクトの生成

    Set mDX = New DxVBLibA.DirectX8



    'DirectInputオブジェクトの生成

    Set mDI = mDX.DirectInputCreate()

    If mDI Is Nothing Then

        MsgBox "DirectInputオブジェクトが生成できません。"

        Exit Sub

    End If

DirectX、DirectInputオブジェクトの生成を行っています。
DirectXの各オブジェクトは親と言えるオブジェクトから子のオブジェクトを作っていきます。

 DirectX → DirectInput → DirectInputDevice

'マウスの準備

    'DirectInputDeviceオブジェクトの生成

    Set mDIDevM = mDI.CreateDevice("guid_SysMouse")

    If mDIDevM Is Nothing Then

        MsgBox "Mouse用DirectInputDeviceオブジェクトが生成できません。"

    Else

マウスの動き取得用のDirectInputDeviceオブジェクトを生成します。
DirectInputDeviceオブジェクトはその名が示すようにデバイス毎に作成します。
デバイスとはマウスやキーボード、ジョイスティックなどです。
マウスやキーボードはシステムに一つしかない(複数あっても一つと見なされる)ので
CreateDeviceメソッドに"guid_SysMouse"又は"GUID_SysKeyboard"を指定できます。
ジョイスティックなどは複数存在しますので列挙し目的のジョイスティックのGUIDを指定します。

'入力データ形式の設定

        mDIDevM.SetCommonDataFormat DIFORMAT_MOUSE2

取得するデータ形式を設定します。以下のようなものを指定できます。

引数 取得するデータ形式
DIFORMAT_JOYSTICK 通常のジョイスティックやジョイパッド
DIFORMAT_JOYSTICK2 フォースフィードバックとかがついているジョイスティック
DIFORMAT_KEYBOARD キーボード
DIFORMAT_MOUSE 4ボタンまでのマウス
DIFORMAT_MOUSE2 8ボタンまでのマウス

なぜデータ形式を指定する必要があるかというと、
マウスとテンキーがくっついているようなデバイスも世の中にはあるので
一つのデバイス(同じGUID)で複数のデータ形式が取得できる場合があるためです(たぶん)。

'強調レベルの設定

        mDIDevM.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE

強調レベルを指定します。
第一引数はターゲットのウィンドウハンドルですので自分自身のウィンドウを指定します。
大切なのは第二引数のフラグで、主に下記の4つの組み合わせになります。

引数 取得するデータ形式
DISCL_BACKGROUND 自アプリがアクティブでなくとも状態を取得できる
DISCL_FOREGROUND 自アプリがアクティブであるときのみ状態を取得できる
DISCL_EXCLUSIVE 自アプリのみ状態を取得できる
DISCL_NONEXCLUSIVE 自アプリ以外も状態を取得できる

実際には2種類のON/OFFなので組み合わせ的には4つになります。

引数 取得するデータ形式
DISCL_FOREGROUND + DISCL_EXCLUSIVE 自アプリがアクティブ時のみ取得し、自アプリがデバイスを占有する
DISCL_FOREGROUND + DISCL_NONEXCLUSIVE 自アプリがアクティブ時のみ取得し、他アプリもデバイスを使える
DISCL_BACKGROUND + DISCL_EXCLUSIVE 自アプリがアクティブでないときも取得し、自アプリがデバイスを占有する
DISCL_BACKGROUND + DISCL_NONEXCLUSIVE 自アプリがアクティブでないときも取得し、他アプリもデバイスを使える

またDISCL_NOWINKEYというフラグがあり、Windowsキーを無効にできたりします
(ただしアクションマッピングを設定しないとダメ。
 単純に自アプリアクティブ時に禁止させるだけならDISCL_FOREGROUNDにすればよい。)

今回はどのアプリがアクティブであっても情報を取得したくかつ占有する必要はないので、
(マウスの場合DISCL_BACKGROUND+DISCL_EXCLUSIVEはできない。ジョイスティック専用)
DISCL_BACKGROUND + DISCL_NONEXCLUSIVEを指定します。

'イベントバッファの準備

        Dim diprop As DxVBLibA.DIPROPLONG

        With diprop

            .lHow = DIPH_DEVICE

            .lObj = 0

            .lData = MAX_BUFFERSIZE

        End With

        mDIDevM.SetProperty "DIPROP_BUFFERSIZE", diprop

マウスの動きはバッファモードで取得したいので情報を蓄積するバッファを準備します。
これは動作情報を全て取得したいときに使用します。
(バッファからあふれない限り全ての反応を取得できます。まぁマウスなら10もあれば十分じゃないのかな?)

設定はDIPROPLONG型の各メンバに値をセットして
SetPropertyメソッドで設定します。
SetPropertyメソッドの第一引数"DIPROP_BUFFERSIZE"がバッファサイズであること示してます。
ちなみにSetPropertyメソッドではジョイスティックのデッドゾーン(無効範囲)などの設定も行えます。
またGetPropertyメソッドで細分度(マウスホイールの感度)などを取得できます。
マウスホイールは上回転/下回転って情報だけでなく、
ゆっくりまわしたかいきおいよく回したかも取得できるんですよ。
(マウスが対応していれば。Intellimouseとかだとかなり細かくとれます)

        'イベントの設定

        mhEventM = mDX.CreateEvent(Me)

        mDIDevM.SetEventNotification mhEventM

イベントを受け取るイベントハンドラを登録します。
ここで先に説明した「Implements DirectXEvent8」が関係してきます。
DirectXEvent8インターフェースとして振舞うことが可能となったForm1(Me)を引数に
DirectXオブジェクトのCreateEventメソッドを呼び出してイベントハンドルを取得し、
DirectInputDeviceオブジェクトのSetEventNotificationメソッドに渡します。
これによりマウス用DirectInputDeviceオブジェクト(mDIDevM)で
情報(マウスの動き)を取得したときForm1のDirectXEvent8_DXCallbackが呼び出されるようになる訳です。

またCreateEventメソッドの戻り値はイベントを識別するためのハンドルになります。
マウスの動きがあったときも、キーボードの状態が変化したときも同じDirectXEvent8_DXCallbackが呼び出されるようにするので
どちらのイベントが起きたのかの判断に必要になります。
このためフォームレベルで宣言した変数に退避しておくわけです。

'チェックボックスを使用可能にする

        chk_Mouse.Enabled = True

    End If

ここまででマウスの捕捉準備が整ったのでチェックボックス(「Mouse」ボタン)を使用可能にします。

 

'キーの準備

    Set mDIDevK = mDI.CreateDevice("GUID_SysKeyboard")

    If mDIDevK Is Nothing Then

        MsgBox "Keyboard用DirectInputDeviceオブジェクトが生成できません。"

    Else

        '入力データ形式の設定

        mDIDevK.SetCommonDataFormat DIFORMAT_KEYBOARD

        

        '強調レベルの設定

        mDIDevK.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE

        

        'イベントの設定

        mhEventK = mDX.CreateEvent(Me)

        mDIDevK.SetEventNotification mhEventK

        

        'チェックボックスを使用可能にする

        chk_Keyboard.Enabled = True

    End If

キーの捕捉準備も基本的に同じです。
違うところはDirectInputオブジェクトのCreateDeviceメソッドにキーボードであることの"GUID_SysKeyboard"を指定することと
SetCommonDataFormatでの入力データ形式を「DIFORMAT_KEYBOARD」にすること
キーの入力はバッファリングモードを使わないためにその部分の処理がないことです。


次に捕捉を開始します。
「Mouse」ボタンと「Keyboard」ボタン(どっちもチェックボックス)がクリックされたときに
その状態によってアクセス権の取得と破棄を行います。

'マウス情報へのアクセスON/OFF

Private Sub chk_Mouse_Click()

    Select Case chk_Mouse.Value

        Case 0  'OFF

            If Not mDIDevM Is Nothing Then

                'アクセス権の破棄

                mDIDevM.Unacquire

            End If

            

        Case 1  'ON

            If Not mDIDevM Is Nothing Then

                'アクセス権の取得

                mDIDevM.Acquire

            End If

    End Select

End Sub





'キーボード情報へのアクセスON/OFF

Private Sub chk_Keyboard_Click()

    Select Case chk_Keyboard.Value

        Case 0  'OFF

            If Not mDIDevK Is Nothing Then

                'アクセス権の破棄

                mDIDevK.Unacquire

            End If

            

        Case 1  'ON

            If Not mDIDevK Is Nothing Then

                'アクセス権の取得

                mDIDevK.Acquire

            End If

    End Select

End Sub

マウスやキーボードの動き情報を取得するためには「アクセス権」を取得する必要があります。
アクセス権を取得するにはDirectInputDeviceオブジェクトのAcquireメソッドを呼び出します。
破棄するにはUnacquireメソッドを呼びます。


アクセス権を取得したのちマウスを動かしたりキーを押したりすると
DirectXEvent8_DXCallbackが呼び出されます。

'DirectXイベント処理

Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long)

    

    Dim x As Long

    

    Select Case eventid

        Case mhEventM       'マウスのイベント

            

            '情報を取得するバッファを準備

            Dim devdata(MAX_BUFFERSIZE - 1) As DxVBLibA.DIDEVICEOBJECTDATA

            

            '情報を取得

            Dim datacnt As Long

            On Error Resume Next

            datacnt = mDIDevM.GetDeviceData(devdata, DIGDD_DEFAULT)

            If Err Then

                '情報が取得できなかった

                datacnt = 0

                

                '再度アクセス権を要求

                mDIDevM.Acquire

            End If

            On Error GoTo 0

            

            '取得した情報の表示

            For x = 0 To datacnt - 1

                With devdata(x)

                    Select Case .lOfs

                        Case DIMOFS_X

                            AddMessage .lSequence, "X Move " + Format$(.lData)

                            

                        Case DIMOFS_Y

                            AddMessage .lSequence, "Y Move " + Format$(.lData)

                            

                        Case DIMOFS_Z

                            AddMessage .lSequence, "Z Move " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON0

                            AddMessage .lSequence, "Button0 " + Format$(.lData)

                    

                        Case DIMOFS_BUTTON1

                            AddMessage .lSequence, "Button1 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON2

                            AddMessage .lSequence, "Button2 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON3

                            AddMessage .lSequence, "Button3 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON4

                            AddMessage .lSequence, "Button4 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON5

                            AddMessage .lSequence, "Button5 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON6

                            AddMessage .lSequence, "Button6 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON7

                            AddMessage .lSequence, "Button7 " + Format$(.lData)

                            

                        Case Else

                            AddMessage .lSequence, "Unknown " + Format$(.lData)

                    End Select

                End With

            Next

            

            

        Case mhEventK       'キーボードのイベント

            

            '全てのキー状態を取得

            Dim keystate As DIKEYBOARDSTATE

            mDIDevK.GetDeviceStateKeyboard keystate

            

            'キー状態を表示

            Dim keymsg As String

            For x = 0 To 255

                If keystate.Key(x) And &H80 Then

                    keymsg = keymsg + Right$("0" + Hex$(x), 2) + " "

                End If

            Next

            If keymsg <> "" Then

                AddMessage 0, "KeyDown " + keymsg

            End If

            

    End Select

    

End Sub

まずDirectXEvent8_DXCallbackの引数eventIDの値がmhEventMなのかmhEventKなのかを判定します。
これは先に説明していますが、マウスによるイベントなのかキーボードによるイベントなのかを判断するためです。

マウスによるイベントの処理から説明していきます。

	Case mhEventM       'マウスのイベント

            

            '情報を取得するバッファを準備

            Dim devdata(MAX_BUFFERSIZE - 1) As DxVBLibA.DIDEVICEOBJECTDATA

マウスの状態に変化(マウスが動かされた、または、ボタンが押された、またはボタンが離された)があったことは
このDirectXEvent8_DXCallbackが呼び出されたことでわかりました。
ですので、次はどのような変化があったのかを取得することになります。
これには二通りの方法があります。
 (1)バッファの内容を見る
 (2)現在のマウスの状態を取得する

(2)の方が簡単と言えば簡単なのですが、本当に今現在の状態しかわかりません。
つまり、ボタンを押してすぐ離したなんて場合、「現在の状態」ではボタンがすでに離されている可能性があるので
押されたのかどうかがわからない訳です。
しかし(1)の方法ならば前回のイベント発生から今回までの間に起きた変化がすべてバッファに蓄積されているので、
それを順に調べていくことで確実に変化を検知できる訳です。
ボタンの押下では問題になりにくいですが、マウスカーソルを自前で描画するようなゲームだと
動きの変化を取得できないと反応が悪く感じられちゃうんですよね。
(なおバッファリングモードでも取得をしないでおくとバッファがあふれます。)

で、ここでは(1)の方法をとります。
(そのために準備段階でバッファリングを行うことを指定しているので^^;)
で、変化内容を取得するためのバッファ領域を確保するのが上のコードになります。
DIDEVICEOBJECTDATA型の配列を先のSetPropertyメソッドで指定したバッファサイズの分だけ確保します。

		'情報を取得

            Dim datacnt As Long

            On Error Resume Next

            datacnt = mDIDevM.GetDeviceData(devdata, DIGDD_DEFAULT)

            If Err Then

                '情報が取得できなかった

                datacnt = 0

                

                '再度アクセス権を要求

                mDIDevM.Acquire

            End If

            On Error GoTo 0

バッファ領域を確保しましたら蓄積されている変化情報を読み込みます。
読み込みはGetDeviceDataメソッドで行います。
戻り値として格納された件数が返されます。

なお取得に失敗した場合は再度アクセス権を取得するようにします。

		'取得した情報の表示

            For x = 0 To datacnt - 1

                With devdata(x)

                    Select Case .lOfs

                        Case DIMOFS_X

                            AddMessage .lSequence, "X Move " + Format$(.lData)

                            

                        Case DIMOFS_Y

                            AddMessage .lSequence, "Y Move " + Format$(.lData)

                            

                        Case DIMOFS_Z

                            AddMessage .lSequence, "Z Move " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON0

                            AddMessage .lSequence, "Button0 " + Format$(.lData)

                    

                        Case DIMOFS_BUTTON1

                            AddMessage .lSequence, "Button1 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON2

                            AddMessage .lSequence, "Button2 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON3

                            AddMessage .lSequence, "Button3 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON4

                            AddMessage .lSequence, "Button4 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON5

                            AddMessage .lSequence, "Button5 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON6

                            AddMessage .lSequence, "Button6 " + Format$(.lData)

                            

                        Case DIMOFS_BUTTON7

                            AddMessage .lSequence, "Button7 " + Format$(.lData)

                            

                        Case Else

                            AddMessage .lSequence, "Unknown " + Format$(.lData)

                    End Select

                End With

            Next

変化情報はDIDEVICEOBJECTDATA型の配列に順番に格納されますので
あとはこれを先頭から見ていくことになります。
DIDEVICEOBJECTDATA型は下記のように定義されています。

Type DIDEVICEOBJECTDATA 

	lData As Long 			'変化情報

	lOfs As Long 			'変化の種類

	lSequence As Long 		'通番

	lTimeStamp As Long 		'タイムスタンプ

	lUserData As Long 		'ユーザーデータ

End Type

まずlOfsの内容をみてどんな変化があったのかを調べます。
マウスの場合CONST_DIMOUSEOFS型の数値が入っています。

DIMOFS_BUTTON0〜DIMOFS_BUTTON7	ボタンの変化

DIMOFS_X					横の動き

DIMOFS_Y					縦の動き

DIMOFS_Z					ホイールの動き

変化の内容はlDataに格納されています。
縦横及びホイールの動きは変化量が格納されています。
ボタンは押された場合128、離された場合0となります。

ここで注意が必要なのはそれぞれが同時に変化した場合です。
つまり斜めに移動した場合、縦の変化分、横の変化分がそれぞれ一件ずつバッファに格納されます。
移動をそのまま見てしまうと、真横に移動してからすぐに上下に移動された場合(実際には無理だろうけどw)と
斜めに移動されたのが区別できなくなってしまうんですね。

そこでlSequenceの値が重要になります。
つまりこの値が同じである場合、それは同時に変化したということになります。
サンプルプログラムではそこまでみてなくて、
バッファの内容をそのままリストボックスに追加しています。
(リストボックスへの追加はAddMessage関数で行っていますが詳細は省略します。)

以上でマウスの動きを捕捉できます。

 

次にキーボードの処理です。

	Case mhEventK       'キーボードのイベント

            

            '全てのキー状態を取得

            Dim keystate As DIKEYBOARDSTATE

            mDIDevK.GetDeviceStateKeyboard keystate

            

キーボードの場合はバッファリングモードを用いていないので
いきなり現在のキーボードの内容を取得しています。(もちろんバッファリングモードでも可能です。)
GetDeviceStateKeyboardメソッドで現在の状態を取得します。
DIKEYBOARDSTATE型の変数はKeyという256個分の配列で
各キーの状態が0:押されていない128:押されているで表現されます。
どのキーが0〜255のどこなのかはCONST_DIKEYFLAGS列挙型で定義されています。

なおDirectInputではテンキーの内容はNumLockの内容にかかわらずに取得できます。
またCapsやNumLockなどはトグル状態(一回押すと128、もう一回押すと0)で取得できます。
この辺は実際に押してみて表示してみればわかるでしょう。
複数のキーが同時に押されているときはそれぞれのキーの要素が128になります。
(なお組み合わせによってはわからなかったりしますが、これは昔からのPCの仕様です。
 A,B,C,D,E,Fの同時押しは判断できません。指つりそうになるしねw)

'キー状態を表示

            Dim keymsg As String

            For x = 0 To 255

                If keystate.Key(x) And &H80 Then

                    keymsg = keymsg + Right$("0" + Hex$(x), 2) + " "

                End If

            Next

            If keymsg <> "" Then

                AddMessage 0, "KeyDown " + keymsg

            End If

サンプルプログラムでは押されているキーのコード(正確にはインデックス番号)を16進で表示しています。

以上がキーボードの状態取得になります。(バッファリングモードより楽でしょ^^)


このようにDirectInputを使うことにより多少の制限はありますが、
他アプリでのマウスやキーボードの入力をVBで簡単に取得することができるのです。

簡単にまとめますと、下記のようになります。

@DirectXオブジェクトを生成

ADirectInputオブジェクトを生成(DirectXオブジェクトのDirectInputCreateメソッド)

B取得するデバイス毎にDirectInputDeviceオブジェクトを生成(DirectInputオブジェクトのCreateDeviceメソッド)

C入力データ形式の設定(DirectInputDeviceオブジェクトのSetCommonDataFormatメソッド)

D強調レベルの設定(DirectInputDeviceオブジェクトのSetCooperativeLevelメソッド)

E必要があればバッファリングモードの設定(DirectInputDeviceオブジェクトのSetPropertyメソッド)

Fイベントの設定(DirectXオブジェクトのCreateEventメソッド、及び、DirectInputDeviceオブジェクトのSetEventNotificationメソッド)

Gアクセス権の取得(DirectInputDeviceオブジェクトのAcquireメソッド)

HDirectXEvent8_DXCallbackの引数(イベントハンドル)のチェック

Iバッファリングモード時にはバッファを確保して蓄積データの取得(DirectInputDeviceオブジェクトのGetDeviceDataメソッド)
 または直接状態の取得(DirectInputDeviceオブジェクトのGetDeviceStateKeyboardメソッドなど)

J終了時にはアクセス権の破棄とオブジェクトの開放(DirectInputDeviceオブジェクトのUnacquireメソッド)

こうやって並べてみるとかなり面倒そうに感じますが、
やってみるとそんなに難しくはないです。

DirectInputを使う方法はフックと違い、情報の取得のみが可能です。
フックの場合は情報の変更まで可能ですのでより強力いえますが、
フックプロシジャを用意しなければならないなどDirectInputより面倒ですね。

DirectInputを使えばVBだけで汎用マウスジェスチャやマウスボタンにキー割り当てなどを行うツールが作れると思います。
時間があったら作ってみようかな。
 MicrosoftのIntelliMouse 4.0に付属するIntelliPoint5.0があまりにもダメだし^^;
;)
 バージョンアップしたらすんごく使えるようになりました。^^)


上に戻る

VB.Net(VB2005)から使用する方法は、別ページになってます。
上のメニューからどうぞ。