Accept user input without pressing enter

Asked

Viewed 614 times

2

Hello, in the menu(self) method I need to accept a user input without having to press the Enter key, only pressing a number to choose an option. I’m new and I’m learning, sorry for the mess!

class CombatRules():
"""Define as regras do combate"""
def __init__(self, character, enemy):
    """Cria um objeto da luta entre o personagem e o inimigo"""
    self.character = character
    self.enemy = enemy

def initiative(self):
    """Verifica quem ataca primeiro"""
    #Verifica quem é mais rapido!
    if self.character.spd >= self.enemy.spd:
        return self.character
    elif self.enemy.spd > self.character.spd:
        return self.enemy

def menu(self):
    """Gera o menu do combate"""
    print(tabulation_lines("Menu"))
    print(tabulation_menu("1 - Atack", "2 - Defend"))
    input("")

def show_combat(self):
    """Mostra situação de combate"""
    print(tabulation_lines("Stats"))
    print(tabulation(self.character.name, self.enemy.name))
    print(tabulation(self.character.classe_name, self.enemy.classe_name, "Classe: "))
    print(tabulation_hp(self.character.live_hp, self.character.hp, self.enemy.live_hp, self.enemy.hp, "Hp: "))
    print(tabulation(self.character.atk, self.enemy.atk, "Atk: "))
    print(tabulation(self.character.defs, self.enemy.defs, "Def: "))
    print(tabulation(self.character.spd, self.enemy.spd, "Spd: "))
    self.menu()

def combat(self):
    """Inicia o combate"""
    if self.initiative() == self.character:
        initiative = 0
    elif self.initiative() == self.enemy:
        initiative = 1
    #while initiative >= 0:
    self.show_combat()

3 answers

6


This is boring to do, because "input" doesn’t even do this, and then it depends on calling, from Python, the Apis that each terminal application makes available - and they are fundamentally different between Windows and all other operating systems.

So, if you really want to play your game on the terminal, it is important to use a library for this, which already has some facilities both to read the keyboard, and to be able to position the elements of your game, without just one line below the other.

Disclaimer: the terminal may not be the best option for such a game: you will have much more freedom to read the keyboard in real time, such as the mouse, and position graphic elements, if you use a library that gives direct access to both screen elements and the keyboard and mouse, such as the pygame, or even using a graphical library such as Tkinter, GTK+ or Qt.

That said, there is a library under development called "terminedia" (I am the author), which aims, among other things, precisely enables the development of simple games in real time at the terminal. Keep in mind that the idea is more "being able to make games in the terminal" as something unusual and fun with a "vintage" air, than to "make it easy to create games for beginners, since they don’t need to leave the terminal". Not even - making a game using the terminedia is not necessarily simpler.

But said all this, it provides various features that can make a person’s life quite fun on the terminal, including keyboard reading.

I’m leaning some things to release "0.3" - when it will be able to be installed with "Pip install terminedia" - so at the moment it is necessary to do

pip install git+https://github.com/jsbueno/terminedia.git.

Also there is not yet a function waiting for a key to be pressed - the function inkey returns whether a key is currently pressed or not. (see update down below)

On the other hand, it has several features to position text exactly where you want it (and other effects to go testing). You can rewrite your "tabulation" functions using screen.print_at(...) finished, which allows you to place text in the exact position of the screen. (And, use effects such as colors, bold, flashing, etc... in the text) )

Using the finished one, a way to get the first character without waiting for enter is:

import terminedia as TM
import time

def getch():
   with TM.keyboard():
       while True:
           key = TM.inkey()
           if key:
              return key
           sleep(1/30)

And to print text positioned and colored, something like:

with TM.Screen() as sc:
    sc.context.color = "yellow"
    sc.print_at((10, 10), "Título do menu")

One of the things missing is a "step-by-step" documentation - but all the features are documented here: https://terminedia.readthedocs.io/en/latest/

And the "examples" folder of the project has some programming making use of the main functionalities:

Updating: The functionality of waiting for a key to be pressed is without a doubt something very useful. So I added the function getch to the project - all that is necessary to wait for a key to be typed now is:

import terminedia as TM

tecla = TM.getch()

Even if the key pressed is a special, up arrow type key, or F1-F12 function keys, they can be read - the special object TM.KeyCodes has the codes of these keys for comparison:

import terminedia as TM

tecla = TM.getch()
if tecla == TM.KeyCodes.UP:
   print("Você pressionou 'seta pra cima'")

(as the above instructions are for installation from master, the function is already available. If the project is already installed, pass the option -U to the pip for it to be updated:

pip install -U git+https://github.com/jsbueno/terminedia.git.

https://github.com/jsbueno/terminedia/tree/master/terminedia/examples

5

With the function input this is not possible. It is implemented in C and designed to store in buffer all content typed up to receive the enter. What you need to do is interact directly on the STDIN of the operating system and capture each character separately.

Luckily, there are already libraries that do this, so you don’t need to rework it. An example is readchar.

from readchar import readchar

letra = readchar()

For the Linux environment, the implementation of this function is:

# -*- coding: utf-8 -*-
# Initially taken from:
# http://code.activestate.com/recipes/134892/
# Thanks to Danny Yoo
import sys
import tty
import termios


def readchar():
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

Source: https://github.com/magmax/python-readchar/blob/master/readchar/readchar_linux.py

  • The problem with this, besides the opaque complication, is that it’s only for Posix terminals - it doesn’t work in windows. So, in my reply I suggested a higher level library (because the end of the day does more or less there too)

  • @jsbueno It also has the version for Windows - at least according to the repository.

  • yes, using the readchar library is one thing - it’s already a "higher-level library" - but, tweaking the code from the inside that does it only on Linux is something else.

  • (in windows, alias, this part is simpler - in theory - Python itself already provides the package "msvcrt" that has "getch" - and is what is used in the past.

  • @jsbueno Ah, yes, the intention was just to show that the implementation in readchar interacts directly with STDIN, it was not the intention to propose as a solution the function itself in isolation.

-2

You can store what was typed by the user in a variable, if the entered value is greater than 0 it already executes the next method or finishes the application.

  • And how you suggest to store in the variable what was typed by the user?

  • A brief example: numero = input("Type a number:") print(numero) if Len(numero) > 0: executeProximoMetodo()

  • 1

    But the function input waits for the user to type Enter to release the buffer in memory and it is precisely this behavior that the author of the question wishes to circumvent.

  • Indeed. I am mistaken, when invoking input, it is automatically mandatory to use enter

  • I think I found a workable solution. It’s a lib that simulates a Keypress, called pynput, just install and instantiate it. Follow the link-Documentation https://nitratine.net/blog/post/simulate-keypresses-in-python/

Browser other questions tagged

You are not signed in. Login or sign up in order to post.