0

I'm working on a programm where I need a user input for selection while not focused on the console window. The method I want to use is with keyboard inputs on the numpad. I've found this library Python keyboard lib to achieve this. My problem here is that it takes very long time for python to register the key press and gives a feel of poor performance. I need to know whether numpad 4 or numpad 6 is pressed for navigation. In the wiki of the lib was mentioned that you shouldn't use:

while True:
if keyboard.is_pressed('space'):
    print('space was pressed!')

This will use 100% of your CPU and print the message many times.

So, this is my code:

print("Choose Attacker or Defender operator:")
print("  Attacker    Defender")
att_state = False
def_state = False
while True:
    if keyboard.read_key() == "4":
        clear()
        print("->Attacker    Defender")
        def_state = False
        att_state = True
    if keyboard.read_key() == "6":
        clear()
        print("  Attacker  ->Defender")
        att_state = False
        def_state = True
    if keyboard.read_key() == "5" and att_state:
        clear()
        printAllOp(attackers)
        break
    if keyboard.read_key() == "5" and def_state:
        clear()
        printAllOp(defenders)
        break

selection = 0
while att_state:
    if keyboard.read_key() == "4":
        if selection > 0:
            selection -= 1
            clear()
            printAllOp(attackers, selection)
    if keyboard.read_key() == "6":
        if selection < 31:
            selection += 1
            clear()
            printAllOp(attackers, selection)
    if keyboard.read_key() == "2":
        if selection < 23:
            selection += 7
            clear()
            printAllOp(attackers, selection)
    if keyboard.read_key() == "8":
        if selection > 6:
            selection -= 7
            clear()
            printAllOp(attackers, selection)
    if keyboard.read_key() == "5":
        clear()
        searchOp(attackers, selection, att_source)
        att_state = False
        break

I've also realized that the performance is different when using if and elif that's why everything is written with ifs for now.

Hyron
  • 1
  • 1

3 Answers3

1

Use read_event instead of read_key, it will block until there is an event.

edit: read_key here is launched multiple times, so every if condition will wait until a key is pressed or release. So instead of doing: if read_key == 'a' if read_key == 'b' etc... you can read only once like key = keyboard.read_key() and then compare your key: if key == "4": if key == "6": etc... if you want to get more informations on your input (key_up & key_down), you can use keyboard.read_event

Girvile
  • 11
  • 2
  • I'm not super familiar with input like this in python, but this looks like a promising answer. A code example would be helpful. I think you are suggesting to somehow replace the whole while loop by using read_event, but I'm not sure. – timeSmith May 30 '23 at 08:33
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 30 '23 at 08:35
0

You can put microseconds or millisecond sleep for each while iteration, for 10 microseconds sleep,

import time

while True:
    if keyboard.is_pressed('space'):
        print('space was pressed!')
    time.sleep(seconds/100000.0)

This should reduce your CPU usage hence, it should increase the overall performance.

Even better, use keyboard hooks like keyboard.on_press. That's the right way of doing it.

Additionally, if it is ok for you to bind to an OS (Windows or particular version of Linux distribution), you can compile your python as binary, which is very simple to do using PyInstaller.

Yogee
  • 1,412
  • 14
  • 22
  • I don't think `keyboard.on_press` will work if the focus is not on the console window where Python is running. This is why I suggested `add_hotkey()` callbacks in my answer. I also don't think adding sleep to a busyloop will increase performance of detecting keystrokes by polling..? – vaizki Dec 17 '21 at 12:19
  • It's not a CPU problem. Usage is under 1%. It's something with the code. – Hyron Dec 17 '21 at 14:43
0

You should not be using keyboard.read_key() at all, instead use keyboard.add_hotkey() to register callbacks which modify a global state.

Example:

att_state = False
def_state = False

def set_state(new_state):
    att_state = (new_state == 'att')
    def_state = not att_state
    # add code to update display

# Register callbacks for 4 and 6
keyboard.add_hotkey('4', lambda: set_state('att'))
keyboard.add_hotkey('6', lambda: set_state('def'))

# Process keystrokes until '5' is pressed
keyboard.wait(hotkey='5')

Note: I have never used this library and did not test this code (no Windows) so buyer beware :)

vaizki
  • 1,678
  • 1
  • 9
  • 12