#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のトップページをご覧ください。