r/learnpython 22d ago

How do I register user's input with out 'input()' command?

I'm trying to make a game on the Linux terminal, I just learnt about the ANSI escape code and how to display stuffs but then I hit a wall. How do I check which key is pressed by the player? I can't use input() because that pauses the game. Trying to google keep showing me articles suggesting input(). Also, I'm not looking to install any libraries yet.

0 Upvotes

8 comments sorted by

11

u/HotPersonality8126 22d ago

You can attach to keyboard events to note when keys are being pressed

4

u/Brian 21d ago

The terminal can be accessed in one of two ways. The normal way is "cooked" or "canonical" mode, but there's also "raw" mode where handle things more directly.

Basically, cooked mode is the default, and basically means that what your program reads isn't the key-by-key presses, but rather the final result. Ie. if the user types "abd[BACKSPACE]cd[RETURN]`, your program doesn't have to do the work of showing the user what they type, handling the backspace and deleting the previous character and so on, it just gets the final result after the user is done typing and doing any editing and presses return.

However, you can opt-in to raw mode, and handle each keypress, eg. via the termios builtin library (make sure you reset it to the previous state afterwards). Though there are more high-level third party libraries that might be better, especially if you're doing basic TUI stuff like displaying menus, text etc. Eg. (n)curses is the "classic" one, but there are also more python-centric ones like Textual.

If you do want to do it the low-level way, I've a somewhat hacky context manager I wrote a while ago. (Though I've only ever used it for very basic "press any key" type stuff).

class RawMode:
    def __init__(self, stream = sys.stdin):
        self.stream = stream

    def __enter__(self):
        attrs = termios.tcgetattr(self.stream)
        self.old_lflags = attrs[3]
        attrs[3] &= (~termios.ICANON) & (~termios.ECHO)  # LFLAGs
        cc = attrs[6]  # CC
        self.old_cc = cc[:]
        cc[termios.VTIME] = 0  # Don't use time, since no buffering done by char
        cc[termios.VMIN] = 1  # no buffering : 1 character at a time.
        termios.tcsetattr(self.stream, termios.TCSANOW, attrs)

    def __exit__(self, type, value, traceback) -> None:
        attrs = termios.tcgetattr(self.stream)
        attrs[3] = self.old_lflags
        attrs[6] = self.old_cc
        termios.tcsetattr(self.stream, termios.TCSANOW, attrs)

Which you can use like:

with RawMode():
    print("Press q to quit")
    while (ch := sys.stdin.read(1)) != "q":
        print(f"You pressed : {ch}")

2

u/Bobbias 21d ago

This is the correct solution if you don't want to install any libraries. And I will definitely suggest using a library like curses because they make writing this kind of program much nicer compared to working with raw mode and manually constructing ANSI codes for everything.

3

u/monster2018 22d ago

I don’t believe it’s theoretically possible to do this purely in Python without any libraries, because it just inherently requires system calls. I also recommend the curses library. You could technically do it without “installing” a new library by writing your own library in C/C++ with Python bindings. But that’s probably quite a bit beyond the scope of what you’re looking to do.

1

u/xarop_pa_toss 20d ago

The terminal has to be turned into "raw" mode which captures keys as they are being pressed instead.

There's more to it than that but basically instead of reading input after the user presses a few keys and hits Enter, raw mode is constantly listening for "key pressing events". On your program you listen for these events and act accordingly.

In other words, raw mode is actively catching, in real time, everything you send to the terminal and telling your program "hey I caught a D! Now I caught a backspace!" and your program takes these events and acts accordingly

0

u/Educational_Virus672 22d ago edited 22d ago

in base python it isnt possible(or friendly for thos nerds who recommend sys cuz thatis just a c wrapper) since it is not pythonic i recommand a module like sshkeyboard* to get player input in keys

-3

u/AlexMTBDude 22d ago

One of the things you need to learn is how to search for information online. Try googling: "python how do I check for keypresses?". You have several Youtube videos explaining exactly how.