/* numlock_debug.c */ #include #include #include /* Global hook handle so we can unhook on exit */ static HHOOK g_hHook = NULL; /* Print timestamp like "[12:34:56] " for log readability */ static void PrintTimeStamp(void) { time_t t = time(NULL); struct tm *tm_info = localtime(&t); if (tm_info) { printf("[%02d:%02d:%02d] ", // HH:MM:SS timestamp tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec); } else { printf("[??:??:??] "); } } /* * Low-level keyboard hook callback. * We only care about VK_NUMLOCK key-up events to capture the * state *after* the toggle has occurred. */ static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { /* If this is not an action event or not a key-up, pass along immediately */ if (nCode != HC_ACTION || wParam != WM_KEYUP) { return CallNextHookEx(g_hHook, nCode, wParam, lParam); } KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam; /* Ignore all keys except NumLock */ if (p->vkCode != VK_NUMLOCK) { return CallNextHookEx(g_hHook, nCode, wParam, lParam); } /* Single-line detailed log: * nCode: hook result code * wParam: message (e.g., WM_KEYUP) * vk, sc, fl: virtual key, scan code, flags * raw: raw GetKeyState result (16-bit) * ON/OFF: computed toggle state */ PrintTimeStamp(); SHORT rawState = GetKeyState(VK_NUMLOCK); int toggled = rawState & 0x0001; /* bit0: 1 if toggle state is ON */ /* * Mask with 0xFFFF to avoid sign-extension when printing * GetKeyState returns a signed SHORT but printf promotes * arguments to 32-bit int, so a negative value (0x8001) becomes * 0xFFFF8001 without masking. */ printf("nCode=%d wParam=0x%04X vk=0x%02X sc=0x%02X fl=0x%02X raw=0x%04hX => %s\n", nCode, (unsigned)wParam, (unsigned)p->vkCode, (unsigned)p->scanCode, (unsigned)p->flags, rawState & 0xFFFF, /* show only lower 16 bits */ toggled ? "ON" : "OFF"); /* Continue the hook chain */ return CallNextHookEx(g_hHook, nCode, wParam, lParam); } int main(void) { MSG msg; /* Install the low-level keyboard hook in our process. * WH_KEYBOARD_LL captures all keyboard events globally. */ g_hHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); if (!g_hHook) { fprintf(stderr, "ERROR: SetWindowsHookEx failed (%lu)\n", (unsigned long)GetLastError()); return 1; } PrintTimeStamp(); printf("NumLock debug monitor started. Press NumLock to log state. Ctrl+C to exit.\n"); /* Standard message loop to keep the hook alive */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } /* Uninstall hook and exit cleanly */ UnhookWindowsHookEx(g_hHook); return 0; }