APIのメッセージループの流れとTranslateMessage

このQ&Aのポイント
  • APIのメッセージループでは、GetMessage関数を利用してメッセージを受信し、TranslateMessage関数でメッセージを変換し、DispatchMessage関数でメッセージを送信します。
  • しかし、実際にはWM_KEYDOWNメッセージが先に送信されることがあります。これは、TranslateMessage関数がメッセージを変換する際に、WM_KEYDOWNメッセージをWM_CHARメッセージに変換するためです。
  • したがって、WM_KEYDOWNメッセージが先に送信されることがあるのは、TranslateMessage関数の処理によるものであり、思い違いではありません。
回答を見る
  • ベストアンサー

APIのメッセージループの流れとTranslateMessage

while(GetMessage(&msg, NULL, 0, 0) > 0){ TranslateMessage(&msg); DispatchMessage(&msg); } もしも「a」が押されたときは、 GetMessageで受け取って TranslateMessageでWM_CHARに変換され DispatchMessageでWM_CHARとしてのメッセージが送られる という流れになるはずです。 けど、実際には一度プロシージャにWM_KEYDOWNが送られます。 TranslateMessageが先にメッセージを変換してるので、WM_KEYDOWNが送られることはありえないと思うのですが、なぜでしょうか。 何か重大な思い違いをしているのでしょうか・・?

  • ggaogg
  • お礼率86% (209/243)

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

  • ベストアンサー
  • kmb01
  • ベストアンサー率45% (63/138)
回答No.1

>TranslateMessageでWM_CHARに変換され TranslateMessageは変換ではなく、新たにWM_CHAR, WM_SYSCHARを作り出してポストします。元のメッセージはそのままです。 そのため、続くDispatchMessageはWM_KEYDOWNで実行されます。 その次のGetMessageでは、キーボードメッセージよりもポストされたメッセージの方が優先順位が高いため、WM_CHARが取り出されることになります。

ggaogg
質問者

お礼

なるほど、変換したものをポストするだけだったんですか。 MSDNより >仮想キーメッセージを文字メッセージへ変換します。文字メッセージは、呼び出し側スレッドのメッセージキューにポストされ..... 「変換します」って部分ではまってしまったようです。 ありがとうございました。

関連するQ&A

  • メッセージループについて

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { } } else { } これはpeekMessageがメッセージを取り出してメッセージがあったら if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) を実行して、GetMessage()で待機してもし、メッセージがWM_QUITならGetMessageにWM_QUITのメッセージを渡してメッセージが消えてPeekMessageはメッセージキューがないため、0を返し永遠にelseを繰り返すという認識でよろしいのですか? あと、while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { } if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { } if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))がWM_QUITのメッセージで そしてメッセージが消えてGetMessageで待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • メッセージループについて

    確認したいのですが、AとBのプロセスがあるとしたら、 AとB while(GetMessage(&msg,NULL,0,0,PM_REMODE)) { TranslateMessage(&msg); DispatchMessage(&msg); } でAを実行中のときはBのプロセスはGetMessageによって処理を行わず待機、Bに移った場合、AはGetMessageによって待機というのでいいのでしょうか?

  • メッセージループ

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { return (int)msg.wParam; } } } else { } このソースで実行して消したら終了しませんでした。 なぜ終了できなかったのでしょうか?

  • PeekMessageについて

    確認したいのですが、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } このPeekMessageというものですがキューに溜めているということでいいのでしょうか。 後、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } の if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } はキューから出してGetMessageは待機してるということでいいのでしょか? if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } これはキューの中は出さないで、GetMessageでPeekMessageからのキューを出しているということでいいのでしょか?

  • Windowsプログラムでのメッセージループ

    Microsoft Visual C++6.0でWin32ApplicationでWindowsプログラムを作る勉強を始めました。 『Visual C++ 1 はじめてのWindowsプログラミング』(山本信雄 著) という本で勉強しています。 WinMain函數の中に次のような「メッセージループ」というものがあるんですね。 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 本の説明では 「メッセージループとは、GetMessageでメッセージの有無を常に確認しつづけるループです。Windowsプログラムは、何もしていないように見えるときでも常にメッセージループをじっこうしているのです。」 ということです。 また 「もしもメッセージがなければ、GetMessageは他のアプリケーションに処理を讓ります。これによってWindowsのマルチタスクがじつげんされています。」 ともありました。 私が思ったのは、 他のアプリケーションに処理を讓ってしまったら、上の説明にあるような「常にメッセージループをじっこうしている」ことにはならないんではないか、 ということです。 逆に、メッセージがあり續けたら、他のアプリケーションに処理を讓らないのでしょうか。 WindowsのマルチタスクはGetMessageが行っているのではなくて、WindowsというOSが行っているのではないでしょうか。 GetMessageが他のアプリケーションに処理を讓っている間の状態というのは、GetMessage函數がじっこうされている状態なのでしょうか。それとも、その間プログラムは停止しているのでしょうか。停止しているのだとしたら、再開するのはGetMessageの次のTranslateMessageからでしょうか。 編集部に質問を送ったのですが、返事はありません。 初級者ゆえ何か勘違いしているのかもしれません。 よろしくお願いいたします。

  • Win32 メッセージループ

    ウィンドウズプログラミングを勉強はじめたばかりなのですが、2つ質問があります。教えてもらえると助かります。 まず、GetMessage関数の第2引数です。 これはメッセージを取得するウィンドウハンドルを指定とありました。NULLを使えばそのスレッドのすべてのメッセージを取得することになると思いますが、NULL以外で実際にウィンドウハンドルを指定するプログラムは一体どういうときなのか知りたいです。 試しにCreateWindow関数でウィンドウを2つ作りをメッセージを取得したいウィンドウハンドルを指定したところ指定しなかった方はメッセージを取得しませんでした、もちろん想定どおりです。しかし、メッセージの取得するウィンドウでサイズなど変更できない場合がありました(取得しないウィンドウをクリックした直後など)これはメッセージキューのメッセージ処理によるものだと(自分の考えなのであってるか不明)思います。結局NULL以外使い道ないんじゃないかとと思ってしまいました。 もう一つの質問です。 ウィンドウプロシージャはコールバック関数であるのでしょうか?システムから呼ばなくてはいけない理由が知りたいです。 これも自分の勝手なよそうですが、DispatchMessage関数が送るメッセージをシステムがどのウィンドウプロシージャを呼び出すのかMSG構造体のウィンドウハンドルを見てさらにWNDCLASSEX構造体などから判断して決めるのをシステムが行うのでコールバック関数なのかな? DispatchMessage関数が直接ウィンドウプロシージャ呼び出さない理由が知りたい。

  • Sleep(1)が1msでもどってこない。

    Sleep(1)が1msでもどってこない。 ゲームのループ処理を作っていまして、 空いている時間をシステムに返すためにSleep(1)を呼んで いるのですが、 while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { //ゲーム的な処理 //時間があまればSleep() } } といった定番なことをしているのですが、 30FPSで固定されません。 調べてみるとSleep(1)が2msくらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

  • C++ GUIのメッセージループ。

    初心者です。 よろしくお願いします。 とても重く時間の掛かる処理を色んなサイトを参考にスレッドにしてみたんですけど、書き方が悪いのか、再描写がワンテンポ遅れたり、アプリケーションを複数起動したりするとフリーズしてしまったりします。 原因はメッセージループにあるような気がしてるんですが、この書き方はおかしいですか?? どのサイトから引用したのかわからなくなってしまいました。 気付いたことなどあったら何でもいいので教えて貰えたら嬉しいです!よろしくお願いします!! thread01に重い処理が書かれてます。 int thread_call() {   unsigned int dwThreadId[1];   HANDLE hThread[0] = (HANDLE)_beginthreadex(     NULL,     0,     ( unsigned int (__stdcall*)(void*) )thread01,     NULL,     0,     &dwThreadId[0] );   MSG msg;   DWORD dwRet = WAIT_TIMEOUT;   while ( 1 ) {     dwRet = ::MsgWaitForMultipleObjects( sL, hThread, FALSE, INFINITE, QS_ALLEVENTS );     if ( dwRet == WAIT_OBJECT_0 + sL ) {       if ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {         ::TranslateMessage( &msg );         ::DispatchMessage( &msg );       }     } else if ( dwRet >= WAIT_OBJECT_0 && dwRet < WAIT_OBJECT_0 + sL )       break;   }   CloseHandle( hThread[0] );   hThread[0] = NULL; }

  • ウィンドウ内でマウスが乗ると更新が止まります・・

    ウィンドウプロシージャ周りを触っているのですが、  ・ウィンドウにマウスが乗っていつつ、マウスが動いている時  ・キーボードーを押した瞬間 にメインループに処理が回らず 全体の処理が止まってしまいます。 上の問題を解決するには、どうすれば良いでしょうか? ※以下コード ---------------------------------------------- while(TRUE) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // 処理メッセージが無いとき WINDOWPLACEMENT wndpl; GetWindowPlacement(hWnd, &wndpl); if((wndpl.showCmd != SW_HIDE) && (wndpl.showCmd != SW_MINIMIZE) && (wndpl.showCmd != SW_SHOWMINIMIZED) && (wndpl.showCmd != SW_SHOWMINNOACTIVE)) { ... ゲームのような、常時更新が必要なループ処理 ... } } Sleep(1); // 最小化等でフリーズしないため } ---------------------------------------------- //以下メッセージ処理側の一部 case WM_KEYDOWN: if (wParam == VK_ESCAPE) { PostQuitMessage(0); } break; case WM_MOUSEMOVE: return DefWindowProc(hWnd, msg, wParam, lParam); default: return DefWindowProc(hWnd, msg, wParam, lParam); ---------------------------------------------- また、ゲームなどのリアルタイム更新に向いた ウィンドウプロシージャの作り方などの説明サイト等ご存知でしたら そちらも教えて頂けると幸いです。

  • LinuxでDoEvents()同等機能

    Linux初心者です。 2.6-18-at9 Debianで及ばずながらマルチスレッドのプログラムを書いています。 VBにはOSにコントロールを戻すDoEventsという機能があります。 Windows/VC++ではこれと同等機能の関数を使っています: DWORD DoEvents(VOID) { MSG msg; while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ if ( msg.message == WM_QUIT ){ return( msg.message ); } TranslateMessage( &msg ); DispatchMessage( &msg ); } return( 0 ); } どなたかの示唆によるもので内容はよく理解していませんが、Windows下ではこれで長年つかえてきました。 Linux-gccで同等の関数は定義できるのでしょうか?。

専門家に質問してみよう