1

I'm very new to programming as a whole. Had some basic experience with C++ and HTML, like simple calculators and other really basic stuff(I started learning on my own a few months ago) and because of this I'm not even sure if I am posting this question correctly. Maybe it goes without saying but I am new to stackoverflow as well(My first post!), so I may do some things wrong here and I kindly ask for your comprehension. Any constructive criticism is more than welcome!

So here's my problem: I am trying to make a simple chatting program in Python 3, but here's the catch: I want to use python's asychronous capabilities to allow the user to terminate the program at any given time the esc key is pressed. I've looked into a few libraries already, such as pynput, asyncio, tornado and getch(). But no matter how I change my code I just can't seem to reach my goal here.

I made an async function called runalways() that's supposed to run during the entire duration of the program, parallel to the other functions. But it doesn't and I couldn't figure out why...

I'm sorry if I couldn't explain my issue properly. Some terms and concepts are still rather blurry to me, but hopefully it won't be so for long. I'll leave the code I have so far which does a good job implementing the chat function, but that's about it. The async bit is basically inexistent at this moment.

It would be really appreciated if someone could explain what I'm missing:

import time, asyncio
from msvcrt import getch


# Creates a chat-like effect
def typing(text):
    for i in text:
        print(i, end=" ")
        time.sleep(0.1)
    time.sleep(1.0)


# Terminates the program
def termination():
    print("Program terminated")
    time.sleep(0.5)
    SystemExit


# Defines async function to read pressed keys and terminate if Esc is pressed
# (Not working)
async def runalways():
    while True:
        print(ord(getch()))
        key = ord(getch())
        if key == 27:  # Esc
            termination()


# Initialize chatting
def startChat():
    typing("\nHello!\n")
    typing("How are you?\n\n")
    typing("Answer:\t")
    x = input()
    typing("\nAnyways, that isn't relevant right now.\n")
    time.sleep(0.5)
    typing("Can we get started?\n\n")
    typing("Answer(Y/N):\t")
    x = input()


# validates input
    while (x != "Y") & (x != "N"):
        typing("\nHey, don't go fooling around now. Keep it real! Try again.\n\n")
        typing("Answer(Y/N):\t")
        x = input()
    if (x == "Y") | (x == "y"):
        typing("\nThere you go! Now, let's go through the basics...\n\n")
        termination()

    elif (x == "N") | (x == "n"):
        typing("\nSorry to hear that... See you next time, then!")
        termination()


# Defines starter point for the program
def main():
    runalways()
    startChat()


main()

I will try my best to clarify any questions that may help the understanding of my issue. Thanks in advance!

Hami
  • 704
  • 2
  • 9
  • 27
Nyte0wl
  • 11
  • 4
  • 1
    Hey! Welcome to stackoverflow! You have provided a very nice first question, well done! I made a small edit, to format the code according to [pep8](https://www.python.org/dev/peps/pep-0008/) and to clarify this is specific to windows. The `msvcrt` module is not available on Linux, so I can't help you directly. One thing, you import `asyncio` but never use it, did you forget to remove it from your code snippet? – Hami Mar 07 '20 at 00:21
  • Hi there! And thank you for the corrections! I actually have used the asyncio once in the code, right were the `runalways()` function is defined. The idea was to keep this function running as a parallel process so that if any time the user stroke the keyboard the function would check if the key stroke was Esc and if so, terminate the program. But I barely know what I'm doing here to be honest, this is something completely new to me and perhaps even a little too much, but I decided to go through anyway and see if I could do it xD – Nyte0wl Mar 07 '20 at 00:59
  • Ah yes, my apologies! I think @Prune will get you through this :) I would just leave you with this, very related [question](https://stackoverflow.com/questions/24072790/detect-key-press-in-python). – Hami Mar 07 '20 at 01:07

1 Answers1

0

You have two functions competing to grab the input. runalways wants to grab them with getch, while your main chat loop is trying with input. The two processes conflict; only one can consume each character. Whenever one thread grabs input, the other gets to claim the buffer for the next input.

Instead, you need to set up a single input channel that terminates immediately on ESC; otherwise, it echoes to the terminal and passes the character to the main loop (or buffers it until EOL appears).

Prune
  • 76,765
  • 14
  • 60
  • 81
  • Thanks for the reply! I think I see what you mean... But to be more specific, could you please confirm if the lines with `x = input()` are the ones conflicting with the getch() method? Should I try to reformulate so that all inputs go through the getch() method? – Nyte0wl Mar 07 '20 at 00:37
  • Yes, the typical way would be to run everything through `getch`, that being the lowest level of input processing you need. – Prune Mar 07 '20 at 01:01