Ericson Willians
Ericson Willians

Reputation: 7845

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.

Upvotes: 2

Views: 1461

Answers (2)

csunday95
csunday95

Reputation: 1319

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.

Upvotes: 1

Ericson Willians
Ericson Willians

Reputation: 7845

Turns out that the solution was pretty obvious. I've solved the problem perfectly using time.sleep().

import win32api
import time

HUMAN_KEYPRESS_TIME = 0.3

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.

if __name__ == "__main__":

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

I came to the conclusion that it was not possible to "execute only once" while keeping the key held down, and then I realized that the answer was time. If I want the block of code to be executed only once with a single key press, I'd just need to sleep the whole application for the interval of time between each physical key press.

Upvotes: 0

Related Questions