自作テキストエディタのメニューバーはツールバーで自作したので、色々とテストしています。メニューバーは 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++でも同じようにキーリピートの判断するとは思ってもみませんでしたね。参考になればと思います。
コメント