Search code examples
pythonpython-3.xwhile-loopkeypresspywin32

How do I "execute" only one key press inside a while loop? (PyWin32)


I have a paradox here. I'm using GetKeyState in order to retrieve the state of a giving vk_code. I've developed two functions to aid me in my task:

import win32api

def get_key_state(vk_code):
    state = int(win32api.GetKeyState(vk_code))
    if state == 1 or state == -127:
        return 1 # Key is on.
    elif state == 0 or state == -128:
        return 0 # Key is off.

def press_key(vk_code):
    state = int(win32api.GetKeyState(vk_code))
    if state == -127 or state == -128:
        return 1 # Key was pressed.
    else:
        return 0 # Key was released.

The value of state starts with 0, and then while the giving key is held down, it changes to -127, and then when I release, it changes to 1, and then while the key is held down again, it changes to -128, and then finally it gets back to 0.

When I use press_key inside a main loop, like this:

if __name__ == "__main__":

    while True:
        p_key = 80
        if press_key(p_key):
            print("P key was pressed.")

I get the following output when the giving key is pressed and released:

enter image description here

How can I get the key press only once if its inside a while loop? Like this:

enter image description here

But without breaking the whole loop.

Observation: I know I'm kinda of reinventing the wheel here (Since I could use PyHook or something), but I really want to know it! I want the "event" to be triggered only once inside the main-loop (Even if the key is kept held down), and I'm failing to grasp the logic to do it.


Solution

  • Well if you want to ensure that the press will only be registered once no matter how long they hold you can have a state variable to check if this is the first time that particular keypress is registered:

    import win32api
    
    HUMAN_KEYPRESS_TIME = 0.3
    
    def press_key(vk_code):
        state = int(win32api.GetKeyState(vk_code))
        if state == -127 or state == -128:
            return 1
        else:
            return 0
    
    keyDown = False
    if __name__ == "__main__":
        firstPress = True
        while True:
            p_key = 80
            if press_key(p_key):
                if firstPress:
                    firstPress = False
                    print("P key was pressed.")
            else:
                firstPress = True
    

    This won't hold up the loop, and it allows you the press the key as rapidly as your keyboard will allow; the other method only allows you to press every 300 ms and blocks the loop for that long.