|
| 1 | +// Xavier Bergeron 2020 - https://github.com/xaviergmail/discordnotificationdebug |
| 2 | +// This program helps detect devices that cause false input events on Windows, breaking idle detection scripts that rely on GetLastInputInfo |
| 3 | +// I initially ran into this issue with the Discord Windows application. I assumed it used Electron's powerMonitor API (https://www.electronjs.org/docs/api/power-monitor) |
| 4 | +// After much digging around, I finally isolated the root of the issue to the underlying implementation in Chromium: |
| 5 | +// https://chromium.googlesource.com/chromium/src/+/refs/tags/89.0.4343.1/ui/base/idle/idle_win.cc |
| 6 | +// |
| 7 | +// In my case, the culprit was the JC-W01UWH Wii gamepad USB adapter commonly used by Guitar Hero / Clone Hero players. |
| 8 | + |
| 9 | + |
| 10 | +#include <iostream> |
| 11 | +#include <windows.h> |
| 12 | + |
| 13 | +// Taken directly from Chromium's implementation |
| 14 | +DWORD CalculateIdleTimeInternal() { |
| 15 | + LASTINPUTINFO last_input_info = { 0 }; |
| 16 | + last_input_info.cbSize = sizeof(LASTINPUTINFO); |
| 17 | + DWORD current_idle_time = 0; |
| 18 | + if (::GetLastInputInfo(&last_input_info)) { |
| 19 | + DWORD now = ::GetTickCount(); |
| 20 | + if (now < last_input_info.dwTime) { |
| 21 | + // GetTickCount() wraps around every 49.7 days -- assume it wrapped just |
| 22 | + // once. |
| 23 | + const DWORD kMaxDWORD = static_cast<DWORD>(-1); |
| 24 | + DWORD time_before_wrap = kMaxDWORD - last_input_info.dwTime; |
| 25 | + DWORD time_after_wrap = now; |
| 26 | + // The sum is always smaller than kMaxDWORD. |
| 27 | + current_idle_time = time_before_wrap + time_after_wrap; |
| 28 | + } |
| 29 | + else { |
| 30 | + current_idle_time = now - last_input_info.dwTime; |
| 31 | + } |
| 32 | + // Convert from ms to seconds. |
| 33 | + current_idle_time /= 1000; |
| 34 | + } |
| 35 | + return current_idle_time; |
| 36 | +} |
| 37 | + |
| 38 | +void pause() { |
| 39 | + std::cout << "Press Enter continue..." << std::flush; |
| 40 | + getchar(); |
| 41 | + std::cout << "\n\n\n" << std::flush; |
| 42 | +} |
| 43 | + |
| 44 | +int main() |
| 45 | +{ |
| 46 | + std::cout |
| 47 | + << "DiscordNotificationDebug v1 written by Xavier Bergeron\n" |
| 48 | + << "https://github.com/xaviergmail/DiscordNotificationDebug/\n\n\n" |
| 49 | + << "If you are here, you are likely experiencing issues with discord\n" |
| 50 | + << "notifications not being sent to your mobile device regardless of\n" |
| 51 | + << "the \"Push Notification Inactive Timeout\" setting. Chances are\n" |
| 52 | + << "that you either have a program, driver or peripheral firing\n" |
| 53 | + << "phantom input events that get picked up by Windows as real user\n" |
| 54 | + << "input. This program will help you isolate the cause of the problem.\n\n"; |
| 55 | + pause(); |
| 56 | + |
| 57 | + std::cout |
| 58 | + << "You should only be getting the \"System was idle for X seconds\" message\n" |
| 59 | + << "when using your keyboard or moving your mouse. If it happens without you\n" |
| 60 | + << "touching anything, there is something problematic causing phantom inputs.\n\n" |
| 61 | + << "Pay close attention to the console output. You want the counter to continuously\n" |
| 62 | + << "count upwards and it should ONLY reset if you touch your mouse or keyboard.\n" |
| 63 | + << "If it never counts up or resets at random times without you touching anything,\n" |
| 64 | + << "you may be victim of phantom inputs. If that's the case, start by unplugging\n" |
| 65 | + << "peripherals such as mice and keyboards followed by all other USB devices.\n" |
| 66 | + << "If that doesn't work, start closing all programs from the system tray\n" |
| 67 | + << "then move on to killing processes from task manager and stopping services.\n" |
| 68 | + << "If all else fails, update your drivers and/or try isolating them.\n\n"; |
| 69 | + pause(); |
| 70 | + |
| 71 | + int i = 0; |
| 72 | + const char* loading = "|/-\\"; |
| 73 | + while (true) { |
| 74 | + DWORD delta = CalculateIdleTimeInternal(); |
| 75 | + char witness = loading[i++ % 4]; |
| 76 | + if (delta <= 1) { |
| 77 | + printf("%c System is not idle!\n", witness); |
| 78 | + } |
| 79 | + else { |
| 80 | + printf("%c System has been idle for %d seconds.\n", witness, delta); |
| 81 | + } |
| 82 | + Sleep(1000); |
| 83 | + } |
| 84 | +} |
0 commit comments