title: SendInput() causes infinite loop when used with GetAsyncKeyState() (WinAPI)
body: <p>So I want to make when you hold down your left click, the mouse starts to click at regular intervals.</p>
  <p>In theory all should work right, but in practice, not so well.</p>
  <p>Anyways here is the code I am using for the detection and clicking of the mouse:</p>
  <pre><code>while (1)
  {
      if (GetAsyncKeyState(VK_LBUTTON) &amp;&amp; GetAsyncKeyState(VK_RBUTTON))
      {
          if (weapon_selector == nullptr) continue;
  
          if (weapon_selector-&gt;isSemiAutomatic)
          {
              for (Vector2I x : weapon_selector-&gt;recoilTable)
              {
                  // Detect for hardware click instead
                  if (!(GetAsyncKeyState(VK_LBUTTON) &amp; 0x8000) || !GetAsyncKeyState(VK_RBUTTON)) // This right here should detect if you are not holding either of the left or right mouse buttons, and thus abort the movement/clicks of the mouse
                  {
                      Utilities::SleepThread(200);
                      break;
                  }
  
                  Mouse::Click(); // Look in the code below how this is defined
                  Mouse::MoveRelative_Lerp(x.x, x.y, (int)weapon_selector-&gt;repeatDelay); // This is essentially doing this_thread::sleep_for() for around 150 ms every time after the click has happened, which would give plenty of time for the GetAsyncKeyState() function to &quot;update&quot; or whatever if it needed it. This function only moves the mouse, it does not click anywhere!
              }
              Utilities::SleepThread(200);
          }
          else
          {
              ...
          }
      }
  
      Utilities::SleepThread(1);
  }
  </code></pre>
  <p>Here is my implementation for the Mouse::Click() function:</p>
  <pre><code>void Mouse::Click()
  {
      INPUT input;
      input.type = INPUT_MOUSE;
      input.mi.mouseData = NULL;
      input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
      input.mi.time = 0;
      input.mi.dwExtraInfo = NULL;
  
      SendInput(1, &amp;input, sizeof(input));
  
      input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
  
      SendInput(1, &amp;input, sizeof(input));
  }
  </code></pre>
  <p>I tried pretty much everything I could think of to fix this with no success, like <a href="https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644986(v=vs.85)" rel="nofollow noreferrer">Mouse low level hook</a>, also checking the injected flag in low level mouse hook, Detecting hardware mouse clicking with <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices" rel="nofollow noreferrer">RegisterRawInputDevices()</a> (with no success either), setting virtualClick variables and all kinds of different checks, no luck.. im tired trying to do this for the past 2 days</p>
  <p>I would appreciate it a lot if someone has dealt with this before and can help me.</p>
  <h1><strong>Minimal reproducible example:</strong></h1>
  <p><strong>main.cpp</strong></p>
  <pre><code>#include &lt;Windows.h&gt;
  #include &lt;hidusage.h&gt;
  
  #include &lt;iostream&gt;
  #include &lt;cmath&gt;
  #include &lt;string&gt;
  #include &lt;thread&gt;
  #include &lt;atomic&gt;
  #include &lt;vector&gt;
  #include &lt;fstream&gt;
  
  #include &quot;Mouse.hpp&quot;
  #include &quot;Utils.hpp&quot;
  #include &quot;Vector2_int.hpp&quot;
  
  struct WeaponData
  {
      const char* szName;
      std::vector&lt;Vector2I&gt; recoilTable;
      int repeatDelay;
      int magCapacity;
      bool isSemiAutomatic;
  };
  
  #pragma region Recoil Tables
  WeaponData RecoilTables[] = {
      {&quot;Revolver&quot;, {}, 175, 8, true},
      {&quot;SAR&quot;, {}, 175, 16, true},
      {&quot;SAP (P2000)&quot;, {}, 150, 10, true},
      {&quot;Python&quot;, {}, 150, 6, true},
      {&quot;Thompson&quot;, {}, 130, 20, false},
      {&quot;Custom SMG&quot;, {}, 100, 24, false},
      {&quot;AK&quot;, {}, 133, 30, false},
      {&quot;MP5&quot;, {}, 100, 30, false},
      {&quot;LR300&quot;, {}, 120, 30, false},
      {&quot;M92&quot;, {}, 150, 15, true},
      {&quot;M249&quot;, {}, 120, 100, false},
      {&quot;M39&quot;, {}, 200, 20, true},
  };
  #pragma endregion
  
  void populate_recoil_table(WeaponData* data)
  {
      if (data-&gt;recoilTable.size() &gt; 0) return;
  
      for (int i = 0; i &lt; data-&gt;magCapacity; i++)
      {
          data-&gt;recoilTable.push_back({0, 0});
      }
  }
  
  int main()
  {
      WeaponData* weapon_selector = &amp;RecoilTables[0];
  
      populate_recoil_table(weapon_selector);
  
      // just to see the movement of the mouse
      weapon_selector-&gt;recoilTable.at(0).x = 20;
      weapon_selector-&gt;recoilTable.at(0).y = 20;
  
      while (1)
      {
          if (GetAsyncKeyState(VK_LBUTTON) &amp;&amp; GetAsyncKeyState(VK_RBUTTON))
          {
              if (weapon_selector == nullptr) continue;
  
              if (weapon_selector-&gt;isSemiAutomatic)
              {
                  for (Vector2I x : weapon_selector-&gt;recoilTable)
                  {
                      if (!(GetAsyncKeyState(VK_LBUTTON) &amp; 0x8000) || !(GetAsyncKeyState(VK_RBUTTON) &amp; 0x8000))
                      {
                          puts(&quot;stopped bcs no buttons hold&quot;);
                          Utilities::SleepThread(200);
                          break;
                      }
  
                      puts(&quot;clicking&quot;);
                      Mouse::Click();
                      Utilities::SleepThread(weapon_selector-&gt;repeatDelay);
                  }
                  Utilities::SleepThread(200);
              }
              else
              {
                  for (Vector2I x : weapon_selector-&gt;recoilTable)
                  {
                      if (!GetAsyncKeyState(VK_LBUTTON) || !GetAsyncKeyState(VK_RBUTTON)) { Utilities::SleepThread(200); break; }
  
                      Mouse::MoveRelative_Lerp(x.x, x.y, (int)weapon_selector-&gt;repeatDelay);
                  }
                  Utilities::SleepThread(200);
              }
          }
  
          Utilities::SleepThread(1);
      }
  }
  </code></pre>
  <p><strong>Mouse::Click() function</strong></p>
  <pre><code>void Mouse::Click()
  {
      INPUT input;
      input.type = INPUT_MOUSE;
      input.mi.mouseData = NULL;
      input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
      input.mi.dx = 0;
      input.mi.dy = 0;
      input.mi.time = 0;
      input.mi.dwExtraInfo = NULL;
      SendInput(1, &amp;input, sizeof(input)); // First send UP event to &quot;unclick&quot; our mouse button
  
      input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN; // Then send DOWN event to click and hold the button
      SendInput(1, &amp;input, sizeof(input));
  
      input.mi.dwFlags = MOUSEEVENTF_LEFTUP; // Then send UP again to release it to simulate a click
      SendInput(1, &amp;input, sizeof(input));
  }
  </code></pre>
  <p><strong>Utilities::SleepThread() function</strong></p>
  <pre><code>void SleepThread(uint32_t milliseconds)
      {
          std::chrono::high_resolution_clock::time_point target = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(milliseconds);
  
          while (std::chrono::high_resolution_clock::now() &lt; target)
          {
              std::this_thread::yield();
          }
      }
  </code></pre>
  <p>Things to note for the example:</p>
  <ol>
  <li>Vector2I is essentially struct with 2 ints: x and y, with some function to add,subtract,etc..</li>
  <li>weapon_selector-&gt;recoilTable is initialized, its not emtpy! Look at <strong>populate_recoil_table()</strong> function</li>
  <li>The code is compiled with C++17 (MSVC compiler/Visual Studio 2019)</li>
  </ol>
  <h1>EDIT: I fixed my issue</h1>
  <p>I had to first &quot;unpress&quot; my button then send DOWN message again, idk why i didnt think of it earlier, the only downside is that the last message before the function ends is DOWN, so the mouse is &quot;stuck&quot; for a little bit (cannot be noticed) but it updates straight away if your physical button is not pressed.</p>
  <p><strong>Fixed click function:</strong></p>
  <pre><code>void Mouse::Click()
  {
      INPUT input;
      input.type = INPUT_MOUSE;
      input.mi.mouseData = NULL;
      input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
      input.mi.dx = 0;
      input.mi.dy = 0;
      input.mi.time = 0;
      input.mi.dwExtraInfo = NULL;
      SendInput(1, &amp;input, sizeof(input));
  
      Utilities::SleepThread(10); // The application im targeting doesnt get the update if its instant mouse press, thus waiting a little
  
      input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
      SendInput(1, &amp;input, sizeof(input));
  }
  </code></pre>