環境は、WindowsXP, VC++6.0, SDK です。
作成したウィンドウ上の座標を取得することはできたのですが、
マウスがウィンドウから出てしまうと、値が取得できなくなってしまいます。
ClientToScreen()関数とScreenToClient()関数を試してみたのですが、
何の変化も見られませんでした。
スクリーン上の座標を取得する方法をご存知の方はいらっしゃいますか?
まだ初心者なので、間違っているかもしれませんが
プログラムの一部を記述します。
LRESULT CALLBACK WindowProc (
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam
) {
HDC hdc;
POINT pt;
LRESULT result;
TCHAR str[255];
switch(uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCHITTEST:
ClientToScreen(hWnd, &pt);
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
wsprintf(str, TEXT(X = %d,Y = %d), pt.x, pt.y);
hdc = GetDC(hWnd);
TextOut(hdc, 0, 0, str, lstrlen(str));
ReleaseDC(hWnd, hdc);
result = DefWindowProc(hWnd, uMsg, wParam, lParam);
return result == HTCLIENT ? HTCAPTION : result;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
GetCursorPos()で画面上のカーソル位置を取得できます。
ScreenToClient()でウィンドウ上の座標に変換します。
SunPacさん、どうもありがとうございます。
GetCursorPos()ははじめて目にしました。
さっそく調べて試してみたいと思います。
> GetCursorPos()ははじめて目にしました。
> さっそく調べて試してみたいと思います。
ちなみに、WM_NCHITTESTメッセージで試すと…
自ウィンドウ以外ではやはり取れないと思います。
マウスカーソルが自ウィンドウ上に無い時にはWM_NCHITTESTが飛んでこないでしょうから…
>ちなみに、WM_NCHITTESTメッセージで試すと…
>自ウィンドウ以外ではやはり取れないと思います。
>マウスカーソルが自ウィンドウ上に無い時にはWM_NCHITTESTが飛んでこないでしょうか
>ら…
そうですね。
ウィンドウ外のカーソル位置を取得するならSetCapture()するのでしょうね。
SetCapture()をつかって試してみたのですが
プログラム事態うまく動きませんでした。
最初に書き込んだプログラムの
ClientToScreen(hWnd, &pt);
部分を
SetCapture(hWnd);にしたのですが。
えらーは起こらなかったのですが、ウィンドウを開いてもカーソルが砂時計になり、制御
不能になってしまいました。
マウスカーソルが画面のどこに行ってもマウス位置を取得することは不可能なのでしょう
か?
SetCapture()はマウスメッセージを対象ウィンドウに独占させる物です。
これによりカーソルがウィンドウの外にでてもマウスメッセージが飛んでくるわけです。
もちろんこのままだと他のウィンドウにマウスメッセージが飛ばなくなるので
ある時点でReleaseCapture()しないといけません。
具体的にはWM_LBUTTONDOWNでSetCapture()してWM_LBUTTONUPでReleaseCapture()すると
いいと思います。
SetCapture()している間はマウスカーソルがどこにあろうとWM_MOUSEMOVEが飛んできます
ので、そこで座標を得ればいいわけです。
あ、上の具体的の部分はドラッグ処理の場合でした・・・
単にマウスの位置を知りたいだけなら例えばタイマーでGetCursorPos()して
ScreenToClient()するといった手もあります。
繰り返しますがSetCapture()はマウスメッセージを対象ウィンドウに独占させる物です。
これをしないとウィンドウの外にカーソルがあるとメッセージは来ません。
そしてSetCapture()をしたら必ずReleaseCapture()しましょう。
ありがとうございます。
けっこう複雑ですね。
ぼくに出来るかどうか不安ですが、がんばってみます。
蛇足ですが、
SetCaptureという関数を紹介された場合は、
その関数の中身を調べて、どんな関数なのかを理解してから
使うようにしたほうが良いです。
今回の場合でいけば、そこからReleaseCaptureという関数に
たどり着けるはずですから。
紹介された関数をそのまま使ってうまく行ったとしても
コスモさん自身の知識になりませんし、
応用が全く利かないと思います。
結果が早くほしいのはわかるんですが、一つ一つ根気強く片付けていかないと
先々で行き詰ってしまうと思いますので、がんばってください。
まず、いつカーソルの位置を知りたいのでしょうか?
一番上のコードを見るとWM_NCHITTEST内で行っているようですが・・・
これって現在のカーソルが指定ウィンドウのどこにあるかを調べる物でしょう。
つまり、何らかの必要性で現在カーソルがそのウィンドウのどこにあるかを調べたい時
に、その対象ウィンドウに
SendMessage(hWnd, WM_HCHITTEST, 0, MAKELPARAM(x, y));
というメッセージを送って、その戻り値によって現在の位置をチェックする物なのです。
(xとyはスクリーン上のカーソルの位置です。)
もちろん、これ以外にも使用法はあるかもしれませんが・・・
ですのでこの中で何かを処理するはどうかと思います。
しかも
result = DefWindowProc(hWnd, uMsg, wParam, lParam);
return result == HTCLIENT ? HTCAPTION : result;
という部分は全く意味不明です。
おそらくマウスが動く度にその位置をチェックしたいのでしょう。
だとすると、WM_MOUSEMOVEというメッセージがカーソルを動かす度に飛んできます。
ただしこれはクライアント領域内のみで、SetCapture()すれば位置に関係なく飛んできま
す。この辺はSunPacさんのおっしゃる通りです。
タイマーの件は、おそらくWM_TIMERが飛んできたらその時のカーソルの位置をどこかに
確保しておき、必要に応じて参照すればいい、って事でしょう。
WM_TIMERの間隔を短くすれば実際の位置との誤差も小さいでしょう。
タイマーはSetTimer()で起動できます。
あと、PATIOさんのおっしゃる通り、初めてみるAPIはMSDNで調べるようにしましょう。
関連のあるAPIにリンクが張ってあるので上のような失敗は防げるはずです。
なによりそのAPIの意味を理解しないで使用するのは危険です。
初心者だからこそ、調べるクセをつけましょう。
MSDNで調べてみたのですが、理解が足りないみたいです。
SetCapture(HWND hWnd)
と書いてあったので、これだけでよいのかと思ってしまいました。
マウス位置を取得したいのは、マウスをクリックしてではなく、常に取得したいと考えて
います。マウスが画面上のどこにあってもです。
result = DefWindowProc(hWnd, uMsg, wParam, lParam);
return result == HTCLIENT ? HTCAPTION : result;
この部分は、マウスがウィンドウ上のどこにあってもタイトルバーの上にあると判断させ
るためのコードです。(これは必要ではありません。)
MSDNの調べ方が足りなくて申し訳ありませんでした。
御迷惑をおかけしました。
常に取得したいというのは、自アプリがアクティブな間だけですか?
それとも、アクティブでない間も取得したいのですか?
それによって、また変わってきます。
自アプリがアクティブな間だけでよいのであれば、SetCapture がよいでしょう。
この場合、アクティブでなくなるときに ReleaseCapture するのを忘れてはいけませ
ん。
アクティブでない間も取得したいのなら、SetCapture は使えません。
この場合、タイマーで定期的に GetCursorPos するか、あるいはマウスフックが必要に
なるでしょう。
ちなみに、マウスのボタンを押していない状態でSetCapture() した場合、
自アプリウィンドウの外のイベントは取得できないので、
やはりタイマーかフックを使うしかないと思います。
自アプリがアクティブでないときも取得をしたいと思っています。
また、自アプリ以外での操作も可能にしたいので
アドバイスを参考にさせていただくとタイマーかマウスブックというものを使うべきであ
ると思いました。
タイマーとマウスブックについて調べてみたいと思います。
親切に教えていただきまして、本当にありがとうございます。