// SPDX-License-Identifier: WTFPL // Code is written by Google AI #include #include #include // グローバル変数で周波数と前回のカウンタ値を保持 LARGE_INTEGER g_frequency; LARGE_INTEGER g_last_count; bool g_is_first_press = true; // キー入力イベントを処理するコールバック関数(低レベルキーボードフック) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT* pKeyInfo = (KBDLLHOOKSTRUCT*)lParam; double elapsed_ms = 0.0; // キーが押されたイベント(WM_KEYDOWN または WM_SYSKEYDOWN)のみを対象にする // オートリピート時も WM_KEYDOWN が連続して発生します if (nCode >= 0 && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN || wParam == WM_KEYUP || wParam == WM_SYSKEYUP)) { LARGE_INTEGER current_count; // 高解像度タイムスタンプを取得 QueryPerformanceCounter(¤t_count); // 経過時間の計算 if (!g_is_first_press) { // 前回からの差分カウンタ数をミリ秒に変換 elapsed_ms = (double)(current_count.QuadPart - g_last_count.QuadPart) * 1000.0 / g_frequency.QuadPart; } else { g_is_first_press = false; } // 前回の値を更新 g_last_count = current_count; // キー情報と経過時間の表示 (仮想キーコードを16進数で表示) printf("Key %s: VK: 0x%X | Interval: ", (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) ? "Pressed " : "Released", pKeyInfo->vkCode); if (elapsed_ms > 0.0) { printf("%.3f ms\n", elapsed_ms); } else { printf("---- ms (First)\n"); } } // 次のフックにイベントを渡す return CallNextHookEx(NULL, nCode, wParam, lParam); } int main() { HHOOK hHook; MSG msg; printf("--- キー入力間隔 測定プログラム ---\n"); printf("ウィンドウが非アクティブでも検知します。終了するには Ctrl + C を押してください。\n"); // QPCの周波数(1秒あたりのカウント数)を取得 if (!QueryPerformanceFrequency(&g_frequency)) { fprintf(stderr, "QueryPerformanceCounter がシステムでサポートされていません。\n"); return 1; } // 低レベルキーボードフックを設定(コンソールがバックグラウンドでも入力を監視可能) hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0); if (!hHook) { fprintf(stderr, "フックの登録に失敗しました。"); return 1; } // フックを動作させるためのメッセージループ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // フックを解除 UnhookWindowsHookEx(hHook); return 0; }