• ベストアンサー

VC++ のマウス入力

visual c++のAPIでアクションゲームをつくっていてアクションはWM_TIMERに50ミリ秒に設定しておいています。マウスも使いたいのでWM_LBUTTONDOWNで左クリックが押されたフラグを立てるようにしたのですが効かない時があります。 WM_TIMERの処理の最後にフラグをfalseにするようにしています。 WM_LBUTTONDOWNの代わりにWM_TIMERでGetKeyStateでフラグをたてるとちゃんと動きます。 どうすればマウスがちゃんと効くようにできますか? よろしくお願いします。 

質問者が選んだベストアンサー

  • ベストアンサー
  • 1839cc
  • ベストアンサー率54% (12/22)
回答No.4

WM_TIMERで、フラグを見てからフラグを落とすまでの間に どのような処理をしているのか、が気になります。 フラグを参照するのと同時に落とすようにしていますか? 例えばWINSOCKなどに代表される一部のAPIは、 処理中にブロッキングを起こさないように、 仮想的に並列処理を行えるように設計されています。 そのようなAPIを利用している場合、イベントハンドラが 終了する前に次のイベントを受け取る事が出来てしまいます。 つまりWM_TIMERのハンドラが、次のような挙動になる可能性があります。  1.WM_TIMERを受けてハンドラが起動する。  2.フラグは立っていないのでクリックの処理は行わない。  3.その他の処理をする。  4.マウスイベント受信でフラグを立てる。  5.3の処理が終了する。  6.フラグを落とす。 この場合、明らかにフラグを見落としているということが分かると思います。 また、「フラグ」と言うからには2値しか保持していないと 想像できるのですが、WM_LBUTTONが50ms中に複数回発生する場合は フォローしなくても問題がないか確認してください。 1の方が書いていらっしゃるように、イベントの到着には タイムラグがあります。ということは、複数のクリックが短時間に まとまって通知される可能性もあるということです。 50msだからと油断していると、複数回のクリックの情報を 失ってしまうなんて可能性があります。 そのような場合は、フラグの代わりに、(あまり綺麗な設計とは 思えませんが)カウンターを用いるといいかもしれません。

aliceakari
質問者

お礼

ありがとうございました。

すると、全ての回答が全文表示されます。

その他の回答 (3)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★『WM_TIMER』メッセージ処理を関数にしてみては? ・私は普段、WM_TIMER メッセージを使わずにコールバック関数を利用しています。  つまり、『SetTimer』関数の第4引数に TIMERPROC 型の関数を指定するのです。 ・下にサンプルを載せておきます。 サンプル: SetTimer( hWnd, TID_TIMER, 50, MyTimerProc ); VOID CALLBACK MyTimerProc( HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime ) {  /*  ここに WM_TIMER メッセージの処理部分を記述します。  */  UNREFERENCED_PARAMETER( hDlg ); // ウインドウのハンドル  UNREFERENCED_PARAMETER( uMsg ); // WM_TIMERがセットされる  UNREFERENCED_PARAMETER( idEvent ); // タイマーの識別子(TID_TIMER)  UNREFERENCED_PARAMETER( dwTime ); // 起動経過時間(GetTickCountと同じ値) } 最後に: ・『WM_TIMER』メッセージは他のメッセージと異なり、2つ以上メッセージ・キューに  入りません。また処理するときもメッセージ・キューに何も入っていないときにこの  『WM_TIMER』メッセージが発生していれば、プロシージャで処理されます。 ・つまり、『WM_TIMER』メッセージはメッセージ・キューではなく別のビット情報に  発生後にセットされます。よって、他のメッセージを処理した後に『WM_TIMER』が  処理される事になります。 ・そこで、コールバック関数を使うとこのようなタイミングのずれが生じないで即・実行  されます。今後、タイマー処理を行うときはコールバック関数を利用した方が良いか、  どうかを考えましょう。→コールバック関数の方が多少、時間が正確になります。 ・なお、タイマー間隔が 50 msというのは『WM_TIMER』メッセージの分解能力の限界値に  近いですね。 ・以上。おわり。→コールバック関数でどうなるか結果報告をお願いします。

aliceakari
質問者

お礼

ありがとうございます。 難しそうですね。 頑張ってやってみます。

すると、全ての回答が全文表示されます。
  • php504
  • ベストアンサー率42% (926/2160)
回答No.2

DirectInputはどうでしょう。 WM_TIMERの処理の中でGetDeviceState()を使ってDIMOUSESTATE 構造体 に値を読み込めばできそうな気がします。

aliceakari
質問者

お礼

ありがとうございます。 定義されていない識別子って出てきました。 DirectXを使わないとできませんか?  すみませんが学校の課題なので使うのを止めときます。

すると、全ての回答が全文表示されます。
  • koedame
  • ベストアンサー率33% (10/30)
回答No.1

回答というか理由を書きます。 実は俺もよくわからないので、・・・すみません。 理由は WM_LBUTTONDOWN というメッセージがメッセージキューと いわれる入れ物に他のメッセージと順番に格納されていて 順番に処理されていくわけですが、 例えば他の命令 WM_TIMER や WM_KEYDOWN など もメッセージキューに入れられてから処理されるので 実際は若干の時間の誤差がありまして、 タイミングよく処理されないときがあるのです。 つまり、クリックしてから0.2秒後処理される なんてことも・・・ その0.2秒の間に WM_TIMER が入って 当たり判定のアイコンの位置が移動していてもうそこには アイコンがいないよ・・・ なんてこともあるわけです。 ホントやだね~。

aliceakari
質問者

お礼

ありがとうございました。

すると、全ての回答が全文表示されます。

関連するQ&A