【C++/Win32】キーリピートを判断する方法

C++
この記事は約4分で読めます。

自作テキストエディタのメニューバーはツールバーで自作したので、色々とテストしています。メニューバーは ALT キーが押されると、トップメニューのショートカットキー(アクセラレーターキー)に下線が付いてキーボードで操作可能になるんですが、なにげに ALT キーを押しっぱなしにしたら、この下線が点滅したのでキーリピートを検知して直すことにしました。

発生している事象

↓これですね。ALTキーを押すとトップメニューのショートカットキーに下線が点滅します。ALTが押されたときに内部的にALTフラグONで描画、次に押されたらOFFにして描画みたいな動作にしているんで、こんな感じに点滅しちゃうんですよね。今回はこれを修正します。

ちなみに、この下線は ALT を押したタイミングで描画されるのが一般的な動作のようです。なので、WM_KEYUP までに入力したキーが前回と同じ ALT だったら処理しないってやれば解決できそうですが、WM_KEYDOWN メッセージの lParam で判断できるようです。

キーリピートを判断する方法

lParam の 30 ビット目が前のキー状態のようです。値は、メッセージが送信される前にキーがダウンしている場合は 1、キーがアップしている場合はゼロです。WM_KEYDOWN でも WM_SYSKEYDOWN でも判断方法は同じです。

WM_KEYDOWNで判断する場合

ENTERキーの連続入力を判断するサンプルです。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        // WM_KEYDOWN の場合
        case WM_KEYDOWN:
            // 入力キーの判断
            switch (wParam) {
                // ENTERの場合
                case VK_RETURN:
                    // キーリピートの場合
                    if ((lParam & 0x40000000) != 0) {
                        OutputDebugString(L"キーリピート中\r\n");
                    } else {
                        OutputDebugString(L"1回目\r\n");
                    }
                    break;
            }
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

WM_SYSKEYDOWNで判断する場合

ALTキーの連続入力を判断するサンプルです。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        // WM_SYSKEYDOWN の場合
        case WM_SYSKEYDOWN:
            // 入力キーの判断
            switch (wParam) {
                // ALTの場合
                case VK_MENU:
                    // キーリピートの場合
                    if ((lParam & 0x40000000) != 0) {
                        OutputDebugString(L"キーリピート中\r\n");
                    } else {
                        OutputDebugString(L"1回目\r\n");
                    }
                    break;
            }
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

おわりに

C#でも同じように判断可能です。C#の場合はこちらの記事を参照してください。C++でも同じようにキーリピートの判断するとは思ってもみませんでしたね。参考になればと思います。

コメント

タイトルとURLをコピーしました