1

I have a problem on getting user input. I do not like the keyboard module because it requires root user and the pynput module blocks the entire script.

I tried this and it is pretty fast for normal request but when I have two loops, it is nearly impossible to get the user input (I need it in two loops because I print an ASCII animation to the console):

(UPDATED Example-CODE, to small reproducable one):


import tty
import termios
import select
import sys


def get_pressed_key():
    """
    Detects which arrow key is pressed on the keyboard and returns the corresponding direction.
    """
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setcbreak(sys.stdin.fileno())  # Set the terminal to cbreak mode
        ch = None
        if sys.stdin in select.select([sys.stdin], [], [], 0.001)[0]:  # Adjust delay value here
            ch = sys.stdin.read(1)
            if ch == '\x1b':  # Escape key
                ch = sys.stdin.read(2)
                if ch == '[A':
                    return "up"
                elif ch == '[B':
                    return "down"
                elif ch == '[C':
                    return "right"
                elif ch == '[D':
                    return "left"
            elif ch == '\r' or ch == '\n':  # Enter key
                return "enter"
            elif ch == ' ':  # Space key
                return "space"
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return None



def clear_input():
    termios.tcflush(sys.stdin, termios.TCIOFLUSH)

def clear_console():
    """clearing the console"""
    os.system("cls" if os.name == "nt" else "clear")

printing the animation goes something like this:


import time
import os

def start_screen():
    """Prints a beautiful ASCII-Logo for the game to the console"""


    stop = False
    while stop is False:
        if ((get_pressed_key() == "enter")or (stop is True)):
            stop = True
            break

        
        frames = ["file1", "file2", "file3"]
        for index, frame in enumerate(frames):
            for line in frames[index]:
                if ((get_pressed_key() == "enter")or (stop is True)):
                    stop = True
                    break
                print(line)
            print(f"\nHit the Enter Key, to continue", end="")
            # Check while sleeping if enter has been entered
            ind = 0
            while ind in range(40):
                time.sleep(0.01)
                if ((get_pressed_key() == "enter")or (stop is True)):
                    stop = True
                    break
                ind += 1

            if stop is True:
                break

            clear_console()
    time.sleep(0.1)
    clear_console()


start_screen()

Update Question:

Maybe is there a way using multiprocessing to get the keyboard input? How would you do it running a seperate kernel from the main scripts kernel?

Muddyblack k
  • 314
  • 3
  • 16
  • To be clear, `termios` only exists on POSIX-compliant systems (and indeed, if you're not willing to use libraries, you're going to end up locking yourself into one OS anyways). Are you targeting only POSIX systems? – Silvio Mayolo Apr 18 '23 at 22:33
  • We are not really allowed to use an external library in our project. I would use pynput but there I always either block my script or get threading overflow – Muddyblack k Apr 18 '23 at 23:15
  • If I understand the problem correctly, you should remove the `time.sleep(0.01)` in `start_screen()`, and adjust the timeout in `get_pressed_key()` instead (probably pass it as a function argument) – yut23 Apr 19 '23 at 03:12
  • If you remove the sleep, it prints the animation too fast – Muddyblack k Apr 19 '23 at 06:33
  • It would be easier to test and modify your code if you edited it into a small, self-contained [MRE] that runs as-is. – CrazyChucky Apr 19 '23 at 12:06

0 Answers0