スクリーン上のマウス位置の取得

[戻る]
コスモ 2004/10/06(水) 11:44:49
環境は、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);
}

SunPac 2004/10/06(水) 12:04:33
GetCursorPos()で画面上のカーソル位置を取得できます。
ScreenToClient()でウィンドウ上の座標に変換します。

コスモ 2004/10/06(水) 12:52:45
SunPacさん、どうもありがとうございます。

GetCursorPos()ははじめて目にしました。
さっそく調べて試してみたいと思います。

瀬戸っぷ [E-Mail] 2004/10/06(水) 22:47:01
> GetCursorPos()ははじめて目にしました。
> さっそく調べて試してみたいと思います。

ちなみに、WM_NCHITTESTメッセージで試すと…
自ウィンドウ以外ではやはり取れないと思います。
マウスカーソルが自ウィンドウ上に無い時にはWM_NCHITTESTが飛んでこないでしょうから…

SunPac 2004/10/07(木) 10:30:06
>ちなみに、WM_NCHITTESTメッセージで試すと…
>自ウィンドウ以外ではやはり取れないと思います。
>マウスカーソルが自ウィンドウ上に無い時にはWM_NCHITTESTが飛んでこないでしょうか
>ら…

そうですね。
ウィンドウ外のカーソル位置を取得するならSetCapture()するのでしょうね。

コスモ 2004/10/21(木) 12:01:29
SetCapture()をつかって試してみたのですが

プログラム事態うまく動きませんでした。

最初に書き込んだプログラムの

ClientToScreen(hWnd, &pt);

部分を

SetCapture(hWnd);にしたのですが。
えらーは起こらなかったのですが、ウィンドウを開いてもカーソルが砂時計になり、制御
不能になってしまいました。

マウスカーソルが画面のどこに行ってもマウス位置を取得することは不可能なのでしょう
か?

SunPac 2004/10/21(木) 12:09:00
SetCapture()はマウスメッセージを対象ウィンドウに独占させる物です。
これによりカーソルがウィンドウの外にでてもマウスメッセージが飛んでくるわけです。
もちろんこのままだと他のウィンドウにマウスメッセージが飛ばなくなるので
ある時点でReleaseCapture()しないといけません。
具体的にはWM_LBUTTONDOWNでSetCapture()してWM_LBUTTONUPでReleaseCapture()すると
いいと思います。
SetCapture()している間はマウスカーソルがどこにあろうとWM_MOUSEMOVEが飛んできます
ので、そこで座標を得ればいいわけです。

SunPac 2004/10/21(木) 12:12:30
あ、上の具体的の部分はドラッグ処理の場合でした・・・
単にマウスの位置を知りたいだけなら例えばタイマーでGetCursorPos()して
ScreenToClient()するといった手もあります。
繰り返しますがSetCapture()はマウスメッセージを対象ウィンドウに独占させる物です。
これをしないとウィンドウの外にカーソルがあるとメッセージは来ません。
そしてSetCapture()をしたら必ずReleaseCapture()しましょう。

コスモ 2004/10/21(木) 16:58:55
ありがとうございます。

けっこう複雑ですね。
ぼくに出来るかどうか不安ですが、がんばってみます。

PATIO 2004/10/21(木) 17:18:57
蛇足ですが、
SetCaptureという関数を紹介された場合は、
その関数の中身を調べて、どんな関数なのかを理解してから
使うようにしたほうが良いです。
今回の場合でいけば、そこからReleaseCaptureという関数に
たどり着けるはずですから。
紹介された関数をそのまま使ってうまく行ったとしても
コスモさん自身の知識になりませんし、
応用が全く利かないと思います。

結果が早くほしいのはわかるんですが、一つ一つ根気強く片付けていかないと
先々で行き詰ってしまうと思いますので、がんばってください。

だっち 2004/10/21(木) 23:47:33
まず、いつカーソルの位置を知りたいのでしょうか?
一番上のコードを見ると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の意味を理解しないで使用するのは危険です。
初心者だからこそ、調べるクセをつけましょう。

コスモ 2004/10/22(金) 15:25:00
MSDNで調べてみたのですが、理解が足りないみたいです。
SetCapture(HWND hWnd)
と書いてあったので、これだけでよいのかと思ってしまいました。

マウス位置を取得したいのは、マウスをクリックしてではなく、常に取得したいと考えて
います。マウスが画面上のどこにあってもです。

   result = DefWindowProc(hWnd, uMsg, wParam, lParam);
   return result == HTCLIENT ? HTCAPTION : result;
この部分は、マウスがウィンドウ上のどこにあってもタイトルバーの上にあると判断させ
るためのコードです。(これは必要ではありません。)

MSDNの調べ方が足りなくて申し訳ありませんでした。
御迷惑をおかけしました。

シャノン 2004/10/22(金) 15:46:03
常に取得したいというのは、自アプリがアクティブな間だけですか?
それとも、アクティブでない間も取得したいのですか?
それによって、また変わってきます。

自アプリがアクティブな間だけでよいのであれば、SetCapture がよいでしょう。
この場合、アクティブでなくなるときに ReleaseCapture するのを忘れてはいけませ
ん。

アクティブでない間も取得したいのなら、SetCapture は使えません。
この場合、タイマーで定期的に GetCursorPos するか、あるいはマウスフックが必要に
なるでしょう。

dairygoods 2004/10/22(金) 16:03:31
ちなみに、マウスのボタンを押していない状態でSetCapture() した場合、
自アプリウィンドウの外のイベントは取得できないので、
やはりタイマーかフックを使うしかないと思います。

コスモ 2004/10/23(土) 14:50:12
自アプリがアクティブでないときも取得をしたいと思っています。

また、自アプリ以外での操作も可能にしたいので
アドバイスを参考にさせていただくとタイマーかマウスブックというものを使うべきであ
ると思いました。

タイマーとマウスブックについて調べてみたいと思います。
親切に教えていただきまして、本当にありがとうございます。

瀬戸っぷ [E-Mail] 2004/10/23(土) 16:30:34
> タイマーとマウスブックについて調べてみたいと思います。
> 親切に教えていただきまして、本当にありがとうございます。

「マウスフック」です。
適切なキーワードでないと検索に掛からないと思いますよ。

コスモ 2004/10/29(金) 10:51:25
SetTimerをMSDNで検索したのですが、情報がありませんでした。
タイマーやフックについて検索しても
プログラムに使用できそうな有力な情報にはたどりつけませんでした。

どこか説明のあるところをご存知の方はいらっしゃいますでしょうか?

PATIO 2004/10/29(金) 11:25:58
フックに関する基本的な内容が知りたいなら
以下のページの下のほうにDLL・フックと言うのがあるので読んでみては?
これを読んでもどうして良いかわからないとなると他に紹介できる当てはないです。

http://www.kab-studio.biz/Programing/Codian/index.html

あと、MSDNでSetTimerで検索かけて出てこないと言うことはないはずです。
CWnd::SetTimerが引っかかってこないはずは無いので。
MSDNってローカルを言ってますか?オンラインを言ってますか?
ローカルならアクティブサブセットの設定が全てになっていないのでは?

PATIO 2004/10/29(金) 12:53:57
えーと、SetTimerに関しては見つかったけど、どう利用していいかわからなかったと
言う事なんでしょうか?

SetTimerを使ってタイマーをかけておけば、定期的にWM_TIMERがくるので
そのタイミングでマウスの位置を拾ってみてはどうかと言う話だと思うんですけれど。
タイマーの間隔次第でそれなりには拾えると思います。
まあ、Windowsのタイマーは他の処理に比べると優先度が低いのでOSが忙しくなると
はしょられたりするみたいですけれど。
どの程度の精度でマウスのカーソルの位置が知りたいのかにもよるでしょうねぇ。

リアルタイムにって事になると多分システムフックを使わないと駄目ではないかと思いま
す。それなりにアプリに通知する仕組みまで考える必要はありますけれどね。
詳しくは前の書き込みのホームページを参照と言う事で。

コスモ 2004/11/25(木) 14:24:40
PATIOさん、詳しい回答どうもありがとうございます。
ちょっと体調を崩してしまって・・・。
返信が遅くなってしまって本当に申し訳ありませんでした。

CWnd::SetTimerはあったのですが、ぼくはSDKで作成してますので、
これは使えないのかととらえてしまいました。

MSDNはオンラインをつかってます。

フックに関しても勉強してみます。

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

PATIO 2004/11/25(木) 15:10:16
プラットホームの方にもSetTimerはありますよ。
オンラインMSDNでも出てくるはずなんですが、どうも日本語の方はSDKの方の和訳をして
いない
みたいですね。CWnd::SetTimerの下の方にリンク用の文字はあるんですが、
リンクされていないみたいです。
MSDN Japanではなくて、本家のMSDNに行けば、ちゃんとありましたよ。
日本のMSDNは全てにおいて本国の後追いなのでこういうケースが多いです。
日本のMSDNになければ、本国の方のMSDNを探した方がいいです。
英語の表記になりますけれど、辞書片手に読めないほど難しい英語ではないと
思いますし、別に翻訳しているわけではないので正確な日本語に訳せなくても
意味さえ解れば良い訳なのでチャレンジしてみた方がいいです。

因みにVC++6をインストールされているのであれば、
HELPを見た方が早いです。
こちらは日本語訳した物があると思います。
最新のプラットホームSDKのAPIを調べるのでなければ、
HELPで調べた方が良いかもしれません。

コスモ 2004/11/25(木) 16:16:17
何度も何度もありがとうございます。

初心者は何をやるにしても難しいですね。

PATIOさんの熱心なご指導を無駄にしないようにがんばります。

コスモ 2004/12/01(水) 17:04:06
[[解決]]
時間はかかりましたが、TIMERをつかって画面上のマウスの位置を取得することができま
した。

初心者のぼくにお力をかしてくださった皆様、本当にどうもありがとうございました。

古いスレッドには追加発言できません。