マウスのプログラム制御方法について(winAPI-C)
マウスのプログラム制御方法について(winAPI-C)
今、非クライアント領域も含むマウスを制御するプログラムをwinAPIをつかって組んでいます。今のところマウスの制御(移動、クリック)をSendInput()を使って実現していますが、クリックの動作が不安定です。そこで不安定になる原因の目星をつけているのですが、ここで質問です。
1.SendInput()を一定時間の間に多く実行過ぎるといけないのか(今のところ一秒間に60回程度)
2.解決策として考えたのですが、別スレッドでDefWindowProc()を使用してマウス制御することは可能かどうか
//別スレッド
HWND hWnd = GetDesktopWindow;
while(1) {
DefWindowProc(hWnd, WM_MOUSEMOVE, ?????, /*マウス座標*/);
}
3.2の方法が可能ならば例で書いたコードであっているのかどうか(特にデスクトップウィンドウハンドルにメッセージを送るとパソコン全体を操作してマウスを制御したことになるのか)と????にいれる引数を知りたいです。
1.SendInput()を一定時間の間に多く実行過ぎるといけないのか(今のところ一秒間に60回程度)
2.解決策として考えたのですが、別スレッドでDefWindowProc()を使用してマウス制御することは可能かどうか
//別スレッド
HWND hWnd = GetDesktopWindow;
while(1) {
DefWindowProc(hWnd, WM_MOUSEMOVE, ?????, /*マウス座標*/);
}
3.2の方法が可能ならば例で書いたコードであっているのかどうか(特にデスクトップウィンドウハンドルにメッセージを送るとパソコン全体を操作してマウスを制御したことになるのか)と????にいれる引数を知りたいです。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
1秒間に60回も連打する事自体が意味が無いと思います。
そんなに連打されたらアプリがイベント処理できないのでは?
そんなに連打されたらアプリがイベント処理できないのでは?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
メッセージをキュー-に送らずにマウスを制御することは可能なのでしょうか?
マウスの移動をなめらかにするためにSendInput()を一秒間に60回程度実行しています
マウスの移動をなめらかにするためにSendInput()を一秒間に60回程度実行しています
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
マウスが動いてもアプリはメッセージキューから受け取らざるおえませんがマウスだけ動けば良いのですか?turkey さんが書きました:メッセージをキュー-に送らずにマウスを制御することは可能なのでしょうか?
マウスの移動をなめらかにするためにSendInput()を一秒間に60回程度実行しています
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
このプログラムは他のPCを遠隔操作するプログラムですのでマウスを移動させるのとクリックがないといけないです。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
問題はですね。マウス移動とクリック動作をさせられてもアプリ側は秒間60回に追従出来ませんってのが問題です。
あと一秒に60回も遠隔通信できませんがLAN内の通信なのでしょうか?
あと一秒に60回も遠隔通信できませんがLAN内の通信なのでしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
いえ、LAN内の通信ではありません。200ms間隔にマウス座標を送り、その間は受信側がマウス座標を補完して直線上に進めています。なのでマウスの座標を移動させるのは一秒間に60回ということです。
ということは、SendInput()をつかうにしろメッセージを送るにしろ無理ということでしょうか。
リアルタイムにマウスを動かすのはこの方法しか見つからなかったんです。
(リモートデスクトップ等のソフトはもっと低レベル層で操作している?)
ということは、SendInput()をつかうにしろメッセージを送るにしろ無理ということでしょうか。
リアルタイムにマウスを動かすのはこの方法しか見つからなかったんです。
(リモートデスクトップ等のソフトはもっと低レベル層で操作している?)
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
じゃあ60回動くのはマウスの移動だけでクリックはしないのですね?
なら、SendInput()で問題ないと思いますがアプリでのコントールをどうやっているかがわからないので、そこで問題があり失敗している可能性があります。
ただ、秒間60回もリモートデスクトップ等でも動いていないと思いますけどね。
リモートデスクトップでも、まともに絵をかけないと思いますが如何でしょうか?
なら、SendInput()で問題ないと思いますがアプリでのコントールをどうやっているかがわからないので、そこで問題があり失敗している可能性があります。
ただ、秒間60回もリモートデスクトップ等でも動いていないと思いますけどね。
リモートデスクトップでも、まともに絵をかけないと思いますが如何でしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
たしかに、そうですね。秒間60回更新はあきらめることにします。
SendInput()を使うにしたがって不安があるのでお聞きしてもよろしいでしょうか。現時点でのコードを概略で書くとこんなかんじです。
このような使い方でいいでしょうか。送信側でクリックを押すと、受信側で始めの一回だけキーを押した情報をSendInput()に送るやり方のほうがただしいのか、今のでいいのかわかりません。
SendInput()を使うにしたがって不安があるのでお聞きしてもよろしいでしょうか。現時点でのコードを概略で書くとこんなかんじです。
//受信スレッド-----------------
next_point = /*(受信座標x, 受信座標y)*/; //200ms秒ごとにおくられてくる座標
isLButton = true; //左クリックを押した情報がきたら
isRButton = true; //右クリックを押した情報がきたら
isLButton = false; //左クリックを押した情報がきたら
isRButton = false; //右クリックを押した情報がきたら
//------------------------------
//マウスを移動させる関数 (別スレッドから呼び出される)------------------
void MouseMove::MoveMousePosion(void)
{
POINT now_point;
INPUT mouse_info;
char str[STR_BUFF];
GetCursorPos(&now_point); //今のマウス座標取得
if((now_point.x != next_point.x)||(now_point.y != next_point.y))
{
mouse_info.type = INPUT_MOUSE;
mouse_info.mi.dx = MI_H((int)(now_point.x + (next_point.x - now_point.x)/10.0));
mouse_info.mi.dy = MI_V((int)(now_point.y + (next_point.y - now_point.y)/10.0));
mouse_info.mi.dwFlags = MouseState();
mouse_info.mi.dwExtraInfo = GetMessageExtraInfo();
if (SendInput(1, &mouse_info, sizeof(mouse_info)) == false) {
sprintf(str, "InputErrorCode:%d", GetLastError());
miq.msgEnQueue(ERROR, str);//エラーメッセージをおくります
}
}
}
//mi.dwExtraInfo に入れるマウス状態を返す
DWORD MouseMove::MouseState(void)
{
if(isRButton == true) {
return MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTDOWN;
}
if(isLButton == true) {
return MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTDOWN;
}
return MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
}
Re: マウスのプログラム制御方法について(winAPI-C)
動作の仕様がまだあまり理解できませんが、この仕様で遠隔操作させてパケット送信すると
間違いなくフリーズするレベルかと思います。
送信スレッド側では200msごとに常にマウスイベントが発生するのでしょうか?
なぜ聞くかというと無駄な処理を回避するためです。マウスの移動やクリックイベントが発生した場合のみ
イベントを受信してみては?
パケット送信するならばできるだけ無駄を省き通信回数を減らす方法を考えます。
あとは無駄な処理をさせないこと。
受信側では19行目でマウス座標に変化がないと破棄しているので
送信側でもマウス座標に変化がないもしくはマウス移動したイベントを受信しない限り
受信スレッドには送信しなくてもいいと思います。
WM_MOUSEMOVEイベントで処理の軽減ができるかと思います。
通信対戦させるために似たようなものをこれから実装するのですが、
この辺を考慮して作るといいと思います。
全然違ったらごめんなさい。
間違いなくフリーズするレベルかと思います。
送信スレッド側では200msごとに常にマウスイベントが発生するのでしょうか?
なぜ聞くかというと無駄な処理を回避するためです。マウスの移動やクリックイベントが発生した場合のみ
イベントを受信してみては?
パケット送信するならばできるだけ無駄を省き通信回数を減らす方法を考えます。
あとは無駄な処理をさせないこと。
受信側では19行目でマウス座標に変化がないと破棄しているので
送信側でもマウス座標に変化がないもしくはマウス移動したイベントを受信しない限り
受信スレッドには送信しなくてもいいと思います。
WM_MOUSEMOVEイベントで処理の軽減ができるかと思います。
通信対戦させるために似たようなものをこれから実装するのですが、
この辺を考慮して作るといいと思います。
全然違ったらごめんなさい。
Re: マウスのプログラム制御方法について(winAPI-C)
たいしかに送信側での今の仕様だと、クリックはイベントが起きて送信はいいですが、マウス移動については常に200ms毎に座標を送ります。これは改善したほうがいいかもしれません。
返答ありがとうございました。
加えて、これまでのテストの結果マウスの不安定要素は以下のとおりです。
1.リアルタイムにクリックされない(クリックデータのみ遅れて受信されたりしているので送信側の問題?)
2.アプリケーションを閉じた後、左クリックが押せなくなる。
3.アプリケーションを閉じた後、一定時間(10秒くらい)右クリックが連打される
1はただのバグだと思いますが、2,3については目星がつかない状況です。
返答ありがとうございました。
加えて、これまでのテストの結果マウスの不安定要素は以下のとおりです。
1.リアルタイムにクリックされない(クリックデータのみ遅れて受信されたりしているので送信側の問題?)
2.アプリケーションを閉じた後、左クリックが押せなくなる。
3.アプリケーションを閉じた後、一定時間(10秒くらい)右クリックが連打される
1はただのバグだと思いますが、2,3については目星がつかない状況です。
Re: マウスのプログラム制御方法について(winAPI-C)
AのPCからBのPCへやり取りするのでしょうか?
それとも同一のPC上でのスレッド間通信でしょうか?
送信側と受信側のソースコード見ないとなんとも言えませんね。
皆目検討もつきません。
それとも同一のPC上でのスレッド間通信でしょうか?
送信側と受信側のソースコード見ないとなんとも言えませんね。
皆目検討もつきません。
Re: マウスのプログラム制御方法について(winAPI-C)
クライアント側の処理はこんな感じになるかと思います。
サーバー側はソケット開いて待っていればいいと思います。
ここでポイントになるのはWM_LBUTTONUPです。
あえてWM_LBUTTONDOWNにはしませんでした。
WM_LBUTTONDOWNで判定すると押している間にもいっぱいイベントが発生するからです。
よってクリックを押してから離された時に判定しています。
あとはコメントしてあるところにそれに対応した処理を書けばよいかと思います。
スレッドは使ってもできますが、そこはお好みで
サーバー側はソケット開いて待っていればいいと思います。
ここでポイントになるのはWM_LBUTTONUPです。
あえてWM_LBUTTONDOWNにはしませんでした。
WM_LBUTTONDOWNで判定すると押している間にもいっぱいイベントが発生するからです。
よってクリックを押してから離された時に判定しています。
あとはコメントしてあるところにそれに対応した処理を書けばよいかと思います。
スレッドは使ってもできますが、そこはお好みで
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
// ここでソケットを用意する
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
// 追加箇所
case WM_MOUSEMOVE:
// マウス座標を取得してソケットに送る。
break;
case WM_LBUTTONUP:
// マウス左クリックされたのでソケットに送る。
break;
case WM_RBUTTONUP:
// マウス右クリックされたのでソケットに送る。
break;
// ここまで追加
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
// ここでソケットをクローズ
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Re: マウスのプログラム制御方法について(winAPI-C)
すみません、書き忘れてましたが、たしかに送信側のWM_LBUTTONDOWNについては不安な点があったのでメッセージのLPARMの30bit目で判断して押した時と離した時はそれぞれ一回ずつ送っていました。
そこでコードにもあるように受信側が受信データを元にマウスのクリック状態をフラグに格納していました。
そこでコードにもあるように受信側が受信データを元にマウスのクリック状態をフラグに格納していました。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
何か問題がある時は通信なのか受信側の動作なのか確認するのがセオリーです。turkey さんが書きました:すみません、書き忘れてましたが、たしかに送信側のWM_LBUTTONDOWNについては不安な点があったのでメッセージのLPARMの30bit目で判断して押した時と離した時はそれぞれ一回ずつ送っていました。
そこでコードにもあるように受信側が受信データを元にマウスのクリック状態をフラグに格納していました。
受信する代わりにテキストでコマンドを書いて動くようにして想定通りに動作する確認してみてはどうでしょうか?
後々問題が出た時にも通信ログを残して再現テストにも使える機能に出来るはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
たしかにそうですね。一つ一つの機能を確認していきたいと思います。
またわからないことがあったら掲示板を利用させてもらいます。
返答ありがとうございました。
またわからないことがあったら掲示板を利用させてもらいます。
返答ありがとうございました。
Re: マウスのプログラム制御方法について(winAPI-C)
送信側は、マウスボタンのアップダウンのイベントも200msごとにまとめて送っているわけですよね。
マウスボタンのダウン→アップがクリックとして認識される間隔はシステムに設定があり変更もできます。
現在の仕様では、そもそも確実にクリック操作を送信できる保証がありません。
データの送受信間隔を短くしてもリアルタイムに届くとは限りませんし。
マウスボタンのダウン→アップがクリックとして認識される間隔はシステムに設定があり変更もできます。
現在の仕様では、そもそも確実にクリック操作を送信できる保証がありません。
- マウスボタンのアップダウンだけではクリックかどうか分からないので、クリックをひとつのイベントとして送受信する必要がある。
- 受信側でクリックは、システムの設定を読み取り、その間隔以内(早すぎてもいけない)でマウスボタンダウン→マウスボタンアップを行う。
データの送受信間隔を短くしてもリアルタイムに届くとは限りませんし。
Re: マウスのプログラム制御方法について(winAPI-C)
前者の場合にしてクリックを実装することができました。しかし、不可解なことがあります。ISLe さんが書きました:というふうにしなければいけないと思います。
- マウスボタンのアップダウンだけではクリックかどうか分からないので、クリックをひとつのイベントとして送受信する必要がある。
- 受信側でクリックは、システムの設定を読み取り、その間隔以内(早すぎてもいけない)でマウスボタンダウン→マウスボタンアップを行う。
まずクリックについて,下のコードは問題のないコードです。
POINT now_position;
GetCursorPos(&now_position);
INPUT mouse_info;
mouse_info.type = INPUT_MOUSE;
mouse_info.mi.dx = MI_H(now_position.x);
mouse_info.mi.dy = MI_V(now_position.y);
mouse_info.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
mouse_info.mi.dwExtraInfo = GetMessageExtraInfo();
SendInput(1, &mouse_info, sizeof(mouse_info));
mouse_info.type = INPUT_MOUSE;
mouse_info.mi.dx = 0;
mouse_info.mi.dy = 0;
mouse_info.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
mouse_info.mi.dwExtraInfo = GetMessageExtraInfo();
SendInput(1, &mouse_info, sizeof(mouse_info));
mouse_info.type = INPUT_MOUSE;
mouse_info.mi.dx = 0;
mouse_info.mi.dy = 0;
mouse_info.mi.dwFlags = MOUSEEVENTF_LEFTUP;
mouse_info.mi.dwExtraInfo = GetMessageExtraInfo();
SendInput(1, &mouse_info, sizeof(mouse_info));
POINT now_position;
GetCursorPos(&now_position);
INPUT mouse_info[3];
mouse_info[0].type = INPUT_MOUSE;
mouse_info[0].mi.dx = MI_H(now_position.x);
mouse_info[0].mi.dy = MI_V(now_position.y);
mouse_info[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
mouse_info[0].mi.dwExtraInfo = GetMessageExtraInfo();
mouse_info[1].type = INPUT_MOUSE;
mouse_info[1].mi.dx = 0;
mouse_info[1].mi.dy = 0;
mouse_info[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
mouse_info[1].mi.dwExtraInfo = GetMessageExtraInfo();
mouse_info[2].type = INPUT_MOUSE;
mouse_info[2].mi.dx = 0;
mouse_info[2].mi.dy = 0;
mouse_info[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
mouse_info[2].mi.dwExtraInfo = GetMessageExtraInfo();
SendInput(3, mouse_info, sizeof(mouse_info));
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
http://msdn.microsoft.com/ja-jp/library/cc411004.aspx
> INPUT 構造体のサイズを指定します。cbSize パラメータの値が INPUT 構造体のサイズと等しくない場合、関数は失敗します。
との事ですので、配列全体サイズを指定すると失敗すると思います。
> INPUT 構造体のサイズを指定します。cbSize パラメータの値が INPUT 構造体のサイズと等しくない場合、関数は失敗します。
との事ですので、配列全体サイズを指定すると失敗すると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
多分 ヒントはINPUT構造体です。
初期化していない。
INPUT mouse_info[3]の下にこれを追加したらどうですかね?
ZeroMemory(mouse_info, sizeof(mouse_info));
違ったらごめんなさい。
初期化していない。
INPUT mouse_info[3]の下にこれを追加したらどうですかね?
ZeroMemory(mouse_info, sizeof(mouse_info));
違ったらごめんなさい。
最後に編集したユーザー AKIЯA on 2012年10月31日(水) 21:50 [ 編集 1 回目 ]
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 13年前
- 住所: 東海地方
- 連絡を取る:
Re: マウスのプログラム制御方法について(winAPI-C)
結局何処が問題だったのでしょうか?turkey さんが書きました:無事解決しました。ありがとうございました。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
Re: マウスのプログラム制御方法について(winAPI-C)
SendInput(3, mouse_info, sizeof(INPUT));
多分 ここですかね?
softyaさんので正解だと思います。
多分 ここですかね?
softyaさんので正解だと思います。