SendInputが上手く動作しない

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
メッセージ
作成者
西野孝雄

SendInputが上手く動作しない

#1 投稿記事 by 西野孝雄 »

お久しぶりです。宜しくお願いします。
件名のままの質問ですが、まずコードを載せます。

コード: 全て選択


Const INPUT_MOUSE		= 0
Const INPUT_KEYBOARD	= 1
Const INPUT_HARDWARE	= 2

Type INPUT
	types As DWord
	ki As KEYBDINPUT
End Type

Type KEYBDINPUT
	wVk As Word
	wScan As Word
	dwFlags As DWord
	time As DWord
	dwExtraInfo As ULONG_PTR
End Type

Declare Function SendInput Lib "user32" (ByVal cInputs As DWord, ByRef pInputs As INPUT, ByVal cbSize As Long) As DWord
Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal uCode As DWord, ByVal uMapType As DWord) As DWord
Declare Function GetMessageExtraInfo Lib "user32.dll" () As Long


Sub MainWnd_CommandButton1_Click()
	Dim in As INPUT

	With in
		.types			= INPUT_KEYBOARD
		.ki.wVk			= VK_LWIN
		.ki.wScan		= MapVirtualKey(VK_LWIN, 0)
		.ki.dwFlags		= KEYEVENTF_EXTENDEDKEY
		.ki.time		= 0
		.ki.dwExtraInfo	= GetMessageExtraInfo()
	End With
	SendInput( 1, in, SizeOf(INPUT) )

	Sleep(500)

	in.ki.dwFlags = KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP
	SendInput( 1, in, SizeOf(INPUT) )
End Sub

以上の様にして、とりあえず実験でWindowsキーを押してみようとしてるんですが一向に反応が有りません。
他ののキ―も試しましたし、メモ帳やテキストボックスに文字を打つようにしてみましたが変化はありません。
dwExtraInfoの所は0で説明してるページが多いですがGetMessageExtraInfo()で説明してる所もあったので試しましたが変化はありません。
検索して見つけた、個別にSendInputせずにINPUT構造体の配列を作り、まとめてSendInputという方法でも変化はありません。

http://dev.activebasic.com/trac/ablib/changeset/418
AB関連のページ?の様なのですが、気になるところと言えば、
共有体の部分がコメントアウトされていてunion[5] As DWordになっている事です。
AB独自の設定かと思いKEYBDINPUTの内容を順番に入れると
マウスがカーソルが右上に飛んだり、スクリーンセーバーが急に立ち上がったり良く分からない動作になります。

一体どこが間違っているのでしょうか。
どなたかご存知の方は教えていただけるとありがたいです。

AB 4.13  OS Win Xp Home SP3
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市

#2 投稿記事 by konisi »

Sleepを抜いて、サイズを調整したら上手く行きましたよ。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
西野孝雄

SendInputが上手く動作しない

#3 投稿記事 by 西野孝雄 »

konisiさん、返信ありがとうございます。

書かれた通りにやるとちゃんと動作してくれました。
しかしなぜこのような事が起きるのでしょうか?
INPUT構造体が前回書いたアドレス先の様にするのが正解だとすると
サイズはDWORDが7つで28バイト。

コード: 全て選択

Type INPUT 
    types As DWord 
    union[5] As DWord
End Type
前回書いたINPUT構造体では8バイト足りないので
padding[7] As Byte で確かに数値は合いますが
これはAB独自の仕様なのでしょうか?
それとも何か別の理由があるのでしょうか?
後の為にも知っておきたいので教えて下さい。
konisi
記事: 893
登録日時: 2005年7月25日(月) 13:27
お住まい: 埼玉県東松山市

#4 投稿記事 by konisi »

MSDNのSendInputに関する記事によると、
cbSize
INPUT 構造体のサイズを指定します。cbSize パラメータの値が INPUT 構造体のサイズと等しくない場合、関数は失敗します。
と書いてあります。つまりこれはWindowsのAPIの仕様です。
同じ関数でマウスやキーボードやハードウェアを同期式に割り込み無しに順番に操作する為に、構造体のサイズを揃えたかったのでしょう。
揃える意味があんまないような気もするけど。

#大学から投稿してみる。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。

に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
西野孝雄

SendInputが上手く動作しない

#5 投稿記事 by 西野孝雄 »

konisiさん、すいません。私の書き方が解り難かったですね。

構造体のサイズが違うとダメなのは分るのですが
聞きたかったのは、ABではなぜ構造体のサイズ調整が必要なのかなという事です。

SendInputで検索しても当然、ABでの説明は皆無なのですが
他言語の説明で、構造体のサイズ調整をしている物などひとつもなかったので
これはAB特有の問題なのかなと思ったわけです。
Toshi
記事: 98
登録日時: 2005年7月19日(火) 19:47
お住まい: 山形県

#6 投稿記事 by Toshi »

C++ での宣言はこうなっています。

コード: 全て選択

typedef struct tagINPUT {
    DWORD   type;

    union
    {
        MOUSEINPUT      mi;
        KEYBDINPUT      ki;
        HARDWAREINPUT   hi;
    };
} INPUT, *PINPUT, FAR* LPINPUT;
このとき、INPUT 構造体のサイズは共用体の中で一番大きい MOUSEINPUT 構造体に合わせられ、28 バイトになります。(32 ビットの場合)
そして、SendInput API に渡すときにはそのサイズでないと受け付けてくれません。

今回の場合、最初の宣言で INPUT 構造体を「KEYBDINPUT 専用」にしていますよね。

コード: 全て選択

Type INPUT
    types As DWord
    ki As KEYBDINPUT
End Type

Type KEYBDINPUT
    wVk As Word
    wScan As Word
    dwFlags As DWord
    time As DWord
    dwExtraInfo As ULONG_PTR
End Type 
このとき KEYBDINPUT のサイズが 16 バイトになり INPUT 構造体のサイズは 20 バイトです。
しかしサイズを 28 バイトにして渡さなければなりませんので、

コード: 全て選択

padding[7] As Byte
これを足すことで合わせます。

AB は今のところ共用体が使えませんので、このような対処が必要になります。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知

Re: SendInputが上手く動作しない

#7 投稿記事 by NoWest »

> SendInputで検索しても当然、ABでの説明は皆無なのですが
> 他言語の説明で、構造体のサイズ調整をしている物などひとつもなかったので
混乱させてしまったようで、申し訳ないです。ページをコミットした者です。

既にkonisiさんとToshiさんが書き込まれているように、
今回の問題はWin32APIの仕様を踏まえて、
共用体を用いて実装されているC++用のINPUT構造体を
共用体を使用することができないActiveBasic用に実装する必要に迫られたので
仕方なくパディング調整を行っていることが原因です。

ただし、ActiveBasicはメモリ操作(ポインタ操作)が可能なので、

コード: 全て選択

Type INPUT  
         types As DWord  
         union[5] As DWord  
End Type  
をそのまま使っていただいて

コード: 全て選択

 Dim input As INPUT
Dim pki As *KEYBDINPUT
pki = input.union As *KEYBDINPUT
のようにすればKEYBDINPUT専用のINPUT構造体を作成する必要はありません。
同様にMOUSEINPUT構造体もHARDWAREINPUT構造体も読み込めます。

逆に書き込みたい場合は

コード: 全て選択

Dim ki As KEYBDINPUT
memcpy(input.union As VoidPtr,VarPtr(ki) As VoidPtr,SizeOf(KEYBDINPUT))
とすることもできます。

> これはAB特有の問題なのかなと思ったわけです。
共用体を仕様に持たない言語であればAB以外でもこの問題は発生します。
ただし、Win32API自体が共用体を必ずしも必要としている訳ではありません。
Win32APIが必要としているのはあるメモリ領域に指定のフォーマットで
且つデータの基本サイズが28byteの1つ以上の並びです。
西野孝雄

SendInputが上手く動作しない

#8 投稿記事 by 西野孝雄 »

Toshiさん、NoWestさん、
とてもわかりやすい説明ありがとうございます。

サイズが共用体の中で一番大きい構造体に合わせられるってのがポイントですね。
それで、共有体が使えないからKEYBDINPUT専用にしたのが原因ですね。

いやぁ、凄く納得しました。本当にありがとうございます。