如何在Windows实现低CPU占用的按键检测?命令行监听左Shift+左点击
Great question! The problem with your current code is that the tight while loop is constantly polling key states without any pause, which eats up 100% of a single CPU core. Let's fix this with two practical, low-CPU approaches:
1. Quick & Simple Fix: Add Sleep to Reduce Polling Frequency
This is the easiest way to slash CPU usage drastically. By adding a short sleep in your loop, you give the CPU time to handle other tasks instead of spinning nonstop.
Here's the modified code:
#include <iostream> #include <windows.h> int main() { std::cout << "Press left shift and left click to start\n"; // Check key states with a short sleep between polls while (GetKeyState(VK_LSHIFT) >= 0 || GetKeyState(VK_LBUTTON) >= 0) { // Sleep for 10ms - adjust this value based on responsiveness needs Sleep(10); } std::cout << "Starting\n"; return 0; }
- A
Sleep(10)means the loop runs only ~100 times per second—more than fast enough to detect a key press—while dropping CPU usage to near 0%. - You can tweak the sleep duration (e.g., 5ms for slightly faster response, 20ms for even lower CPU use) based on your needs.
2. Optimal Event-Driven Solution: Low-Level Mouse Hook
For the most efficient approach (zero polling, CPU usage effectively 0 when idle), use Windows' low-level mouse hook (WH_MOUSE_LL). This hook lets your program receive mouse events system-wide (even without focus) and only triggers when a mouse action occurs.
Here's a complete implementation:
#include <iostream> #include <windows.h> // Flag to signal when the key combination is detected bool g_startTriggered = false; // Low-level mouse hook procedure LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode >= 0) { // Check if this is a left mouse button down event if (wParam == WM_LBUTTONDOWN) { // Check if left shift is pressed at the same time if (GetKeyState(VK_LSHIFT) < 0) { g_startTriggered = true; // Return 1 to prevent the event from propagating to other apps (optional) return 1; } } } // Pass the event to the next hook in the chain return CallNextHookEx(nullptr, nCode, wParam, lParam); } int main() { std::cout << "Press left shift and left click to start\n"; // Set up the low-level mouse hook HHOOK mouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, GetModuleHandle(nullptr), 0); if (!mouseHook) { std::cerr << "Failed to set mouse hook! Error: " << GetLastError() << std::endl; return 1; } // Message loop to keep the hook active (blocks until g_startTriggered is true) MSG msg; while (!g_startTriggered && GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Clean up the hook UnhookWindowsHookEx(mouseHook); std::cout << "Starting\n"; return 0; }
Key Notes:
WH_MOUSE_LLis a special low-level hook that doesn't require a separate DLL (unlike other global hooks), making it easy to implement in your console app.- The hook callback only runs when a mouse event happens, so your program uses almost no CPU while waiting.
GetMessageblocks the main thread until a message arrives (either the mouse event or system messages), so the thread is in a sleep state when idle.- We set
g_startTriggeredto true once the combination is detected, which exits the message loop and lets your program proceed.
Which Approach to Choose?
- Use the sleep-based fix if you want minimal code changes and don't mind very low, occasional CPU usage.
- Use the mouse hook solution for long-running programs or when you need the lowest possible CPU footprint.
内容的提问来源于stack exchange,提问作者George Tian

