#pragma twice

KAB-studio > プログラミング > #pragma twice > 184 Version 10.06 キー入力メッセージの置き換え

#pragma twice 184 Version 10.06 キー入力メッセージの置き換え

前のページへ 表紙・目次へ 次のページへ

 Version 10.06
キー入力メッセージの置き換え

「今回はキー入力メッセージについて見ていきます」
『キー入力、って前にやったね』
「そう、今回は Version 9.17 ( No.178 ) で出てきた、WM_KEYDOWN や 
WM_KEYUP 、そして WM_CHAR についての話」
『たしか、普通の文字は WM_CHAR でいいんだけど、それだとカーソルキー
とかは送られてこない、って話だったよね』
「逆に、 WM_KEYDOWN と WM_KEYUP だと大文字小文字が区別できない、とか
ね」
『そうそう、そんな感じ』
「で、あのとき〈これは MFC の機能〉って言ったでしょ」
『……ってことは、 SDK だけだと自分でやらなくちゃいけないってこ
と!?』
「そういうこと。というわけで、まずはこのコードを試してみて」

// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
    ( HWND p_hWnd
    , UINT p_uiMessage
    , WPARAM p_wParam
    , LPARAM p_lParam
    )
{
    if( p_uiMessage == WM_DESTROY )
    {
        // ×ボタンが押されました。
        PostQuitMessage( 0 );
        return 0;
    }
    else if( p_uiMessage == WM_KEYDOWN )
    {
        // キーが押されました。
        OutputDebugString( "WM_KEYDOWN\n" );
    }
    else if( p_uiMessage == WM_KEYUP )
    {
        // キーが離されました。
        OutputDebugString( "WM_KEYUP\n" );
    }
    else if( p_uiMessage == WM_CHAR )
    {
        // 文字が入力されました。
        OutputDebugString( "WM_CHAR\n" );
    }

    // 標準的な処理をします。
    return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}

「これをビルドして実行してから、キー入力してみて」
『ほい。お、こんな感じになったよ』

WM_KEYDOWN
WM_CHAR
WM_KEYUP

『キーが押されて WM_KEYDOWN が送られてきて、次に WM_CHAR が送られて
きて、最後にキーが離されて WM_KEYUP が送られてくるんだね。あ、でも、
カーソルキーとかだと』

WM_KEYDOWN
WM_KEYUP

『ってなるね。文字じゃないからだよね』
「そういうこと。つまり、キーが押されたときには必ず WM_KEYDOWN と 
WM_KEYUP が送られてきて、もしそれが文字なら」
『 WM_CHAR も送られてくる、ってことなんだ』
「そういうこと。あ、ちなみに WM_KEYDOWN と WM_KEYUP は必ずしもペアで
送られてくるわけじゃないから」
『え、そうなの?』
「キーを押しっぱなしにしてみて」
『押しっぱなし……あ、 WM_KEYDOWN と WM_CHAR がいっぱい出てきた』
「キーリピートの時には WM_KEYDOWN と WM_CHAR が送られてきて、 
WM_KEYUP は送られてこないから」
『確かにキーは上げられてないものね』
「さて。話を戻して、 WM_CHAR が送られてくる部分について」
『そうそう、そこって自分でやらなきゃいけないって言ってたよね』
「でも、今は送られてきてるよね」
『あ、ってことは、もうそういう機能は入れてあるって事?』
「そういうこと。それはこの部分」

// メッセージループ。
int MessageLoop()
{
// 略
        // メッセージを変換します。
        TranslateMessage( &stMsg );
// 略
}

『この TranslateMessage() って関数?』
「そう、これが WM_CHAR を作ってるんです」
『……作ってる?』
「とりあえずこれをコメントアウトして試してみて」
『ほい。ビルドして実行……あ! ホントだ、 WM_CHAR が送られてこな
い!!』
「 TranslateMessage() は WM_KEYDOWN を変換する API 。変換っていうの
とはちょっと違うかもしれないけどね」
『 WM_KEYDOWN は残ってるんでしょ?』
「そう、ちゃんとウィンドウプロシージャに送られてきてるからね。 
TranslateMessage() は、 WM_KEYDOWN が送られてくると、まずそのキーが
普通の文字になるかどうか調べます」
『普通のキーじゃない、カーソルキーとかだと無視するわけね』
「そう。逆に普通の文字だったら、それを文字に変換してメッセージキュー
に WM_CHAR として送ります」
『送ったら?』
「送ったら普通に関数から抜けて、次の DispatchMessage() に移って、あ
とはウィンドウプロシージャへ。あ、えーっと」
『?』
「これは実際に見てもらった方がいいかな。このコードを試してみて」

// メッセージループ。
int MessageLoop()
{
    BOOL bRes;
    MSG stMsg;

    // メッセージループです。
    while( 1 )
    {
        // メッセージをキューから取り出します。
        bRes = GetMessage( &stMsg, NULL, 0, 0 );
        if  ( 
                ( bRes == 0 )
            || 
                ( bRes == -1 )
            )
        {
            // 終了するのでループから抜けます。
            break;
        }

        if( stMsg.message == WM_KEYDOWN )
        {
            // キーが押されました。
            OutputDebugString( "WM_KEYDOWN in MessageLoop\n" );
        }
        else if( stMsg.message == WM_KEYUP )
        {
            // キーが離されました。
            OutputDebugString( "WM_KEYUP in MessageLoop\n" );
        }
        else if( stMsg.message == WM_CHAR )
        {
            // 文字が入力されました。
            OutputDebugString( "WM_CHAR in MessageLoop\n" );
        }

        // メッセージを変換します。
        TranslateMessage( &stMsg );
        // ウィンドウプロシージャに送ります。
        DispatchMessage( &stMsg );
    }

    return stMsg.wParam;
}

『さっきのに似てる……』
「ウィンドウプロシージャの中でやってたのをメッセージループの中でして
るだけだからね。ちなみにメッセージは MSG 構造体の message ってメンバ
変数に入ってるのでそれを調べてます」
『で、ビルドして実行……あ』

WM_KEYDOWN in MessageLoop
WM_KEYDOWN
WM_CHAR in MessageLoop
WM_CHAR
WM_KEYUP in MessageLoop
WM_KEYUP

「〈in MessageLoop〉って付いてるのがメッセージループの、付いてないの
がウィンドウプロシージャのだから」
『ってことは WM_KEYDOWN が WM_CHAR に変換されても、それは置いといて
そのまま WM_KEYDOWN がウィンドウプロシージャに送られて来るんだ』
「そういうこと。 TranslateMessage() は WM_CHAR をメッセージキューに
入れるだけだから。だから、メッセージキューの中身は、まず」

WM_KEYDOWN

「ってなってて、これを GetMessage() で取り出すとメッセージキューの中
は空になります。で、 WM_KEYDOWN が TranslateMessage() に渡されると」

WM_CHAR

「と、メッセージキューに WM_CHAR が入れられます」
『でもこの時はまだ WM_KEYDOWN の処理中ってことね』
「そういうこと。 WM_KEYDOWN の処理が終わって、メッセージループの次の
周で GetMessage() で WM_CHAR が取り出されます」
『ふ、複雑……この前の WM_DESTROY とかも複雑だったけど、これも……』
「確かに〈おまじない〉として何も考えずに TranslateMessage() を入れて
もいいんだけど、こういう仕組みになってるっていうことは憶えておいて」

/*
    Preview Next Story!
*/
『なんとなく、メッセージループの仕組みが分かってきたかも』
「なんとなくでいいから、イメージは持っておいてね」
『なんとなくでいいの?』
「今回のはね。次回のはちゃんと憶えておいて欲しいけど」
『ほほう』
「というわけで次回」
< Version 10.07 メッセージを待つ! >
『につづく!』
「次回は重要! ユーザーを困らせないためにもしっかり憶えて!」
『おおっ、なんか久々にそういうの出てきた!』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。