0

I am trying to create a code which will detect if the mouse button has been pressed. So far i have a code which will detect if the button has been pressed once. But it isn't letting me check if the button was continuously pressed. For e.g left mouse button pressed, this will start a timer, after 0.5 seconds it will check again and if it is still down output something.

I want to set it up like this

while (true)
{

    if (GetAsyncKeyState(VK_LBUTTON) & (0x8000 != 0))
    {

        cout << ("left button pressed") << endl;
        Sleep(500);
        if (GetAsyncKeyState(VK_LBUTTON) & (0x8000 != 0))
        {

            cout << ("Left button held down") << endl;
        }

    }
}

However, it does not work, it only outputs the second statement if i double click in quick succession.

Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.

The msdn website says that. Does this mean i should check if it is UP after the time to get the result i want.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
vulcanicrook
  • 53
  • 1
  • 1
  • 5
  • 4
    0x8000 is always unequal to 0, place the parentheses correctly. The simplest way to test this is with `if (GetAsyncKeyState(VK_LBUTTON) < 0)`. Now you know why GetAsyncKeyState() has the very unusual SHORT return type. – Hans Passant Jan 31 '17 at 11:12

2 Answers2

2

GetAsyncKeyState just tells you the state right now, it should not be used to monitor possible changes over time!

If you want to track the mouse no matter which application is receiving the input then you should use SetWindowsHookEx to install a low-level mouse hook.

If you only care about mouse events in your own window then it would be better to track WM_LBUTTON* mouse messages as suggested in the other answer.

In response to WM_LBUTTONDOWN you set a global flag to true and start the timer. In response to WM_LBUTTONUP you set it to false and stop the timer. If the timer fires and the flag is true then perform your desired task.

Anders
  • 97,548
  • 12
  • 110
  • 164
-2

If you're trying to implement this in WINAPI GUI application, here is your answer - write the first timestamp on WM_LBUTTONDOWN, write the second on WM_LBUTTONUP, and calculate the elapsed time you need. What is actually better - it will only catch messages that will come into YOUR application window, and won't catch other apps' key presses as you could do with GetAsyncKeyState.

UPDATE: Anyway, getting user-generated data(like clicks, key presses, etc) to work is way better using the standard windows message handling(as it is event-based, more natural to the programmer) instead of checking the state of an object once per a period of time - you can possibly miss the required event altogether. It looks like you're trying to solve the XY problem.

UPDATE2: Here is a nice tutorial of how to do it properly.

Community
  • 1
  • 1
Leontyev Georgiy
  • 1,295
  • 11
  • 24
  • Handling `WM_LBUTTONDOWN` and `WM_LBUTTONUP` doesn't allow you to respond at the time of the timeout. You'd have to implement a [timer](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632592.aspx) to find out, when a button has been pressed for a predefined interval. Besides, the question is asking for physical key state. Suggesting to use per-thread virtualized input doesn't address this requirement. – IInspectable Jan 31 '17 at 13:42
  • You'd have to ask the voter, but I suppose the reason is similar to that outlined in my comment. – IInspectable Jan 31 '17 at 13:50
  • @IInspectable Of course, timer is required here. QueryPerformanceFrequency/QueryPerformanceCounter functions, for example can do that. On the other hand, clicking a button 2 times with a small time between would crack the solution presented by the OP. Also, Sleep(), IMHO, is bad to use in pretty much any situation: it hangs the processing thread, making it unable to receive any other events. I won't even bring up its reliability... I'd like to add as well that button being pressed and released are two different events, and they should be processed as two different events. – Leontyev Georgiy Jan 31 '17 at 13:58
  • @IInspectable That guarantees that you won't face the problem of button being pressed a number of times within the required duration - KEY_UP always follows the KEY_DOWN. Also, I find it pretty hard to be sure that OP needs *physical key state*. You're trying to help with an *attempted solution*, not the *problem* itself. It would be way more helpful if OP would describe what he is *really* trying to do. – Leontyev Georgiy Jan 31 '17 at 14:03
  • I'm not saying that you are wrong, but you are answering a different question. Anyway, I cannot speak for whoever voted on your proposed answer, and I explained why I didn't upvote it. – IInspectable Jan 31 '17 at 14:12
  • @IInspectable Finding out that KEY_UP didn't come yet? Declare a flag that is *false* before first KEY_DOWN, and *true* after it. If it is *true* when another KEY_DOWN arrives, button was released within timer duration - result is "wasn't held down". Declare another flag which points at KEY_UP coming, initially false, turn it *true* when it comes. Run a timer for the desired time, if KEY_UP flag is *false* and the condition described above wasn't achieved, result is "button is held down", if KEY_UP flag is *true*, result is "wasn't held down". – Leontyev Georgiy Jan 31 '17 at 14:16
  • Look, I get it. Implementing a timeout is not rocket science. I'm not saying that it is difficult. I'm saying, that your proposed answer doesn't address the question. If you need substantial information, why a user down-voted your answer, you'll have to wait for that user to respond. Well, it's two users now. That just doubled your chances for a response. – IInspectable Jan 31 '17 at 14:24