Input written in the terminal is copied to my code once I close it. Why?

60 Views Asked by At

I'm making a custom TUI essentially, and it works great, except that for some reason, VSCode is capturing keystrokes from the terminal and writing them in my python file. Briefly, it even captured keystrokes from my system terminal, and idk how to get it to stop. I'm guessing that I'm somehow leaving my listener open, but I'm not sure, as this is the first time that I've used the pynput module or given my VSCode system-wide permissions.

import math
from pynput import keyboard
from IPython.display import clear_output

open_field = " _ "
wall = " X "

'''
The function, "coordinate_field" creates a grid like the one below, and also prints the location and movement of characters within the grid as the code runs. In future iterations, I intend to make the walls impassable, add momentum and battle functionality.

 X  X  X  X  X  X  X  X  X  X  X  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  _  _  _  _  _  _  _  _  _  _  X 
 X  X  X  X  X  X  X  X  X  X  X  X 
'''
def coordinate_field (p1_location, p2_location, p1_direction, p2_direction):
    x_coordinate = 0
    y_coordinate = 1
    field = ""
    ''' 
    The grid is 12*12.
    156 is 12*12+12 because adding each line break takes an
    iteration as well.
    '''
    for i in range(156):
        x_coordinate += 1
        coordinate_point = [x_coordinate, y_coordinate]
        if x_coordinate > 12:
            field += "\n"
            x_coordinate -= 13
            y_coordinate += 1
        elif y_coordinate in [1,12] or x_coordinate in [1,12]:
            field += wall
        # The following elifs add the characters.
        elif coordinate_point == p1_location:
            field += p1_direction
        elif coordinate_point == p2_location:
            field += p2_direction
        else:
            field += open_field
    clear_output(wait=True)
    print(field)

p1_location = [4, 7]

'''
This following list will be joined before going in to the function. I think that it needs to be a list at this stage
because p1_direction += "<" and such didn't seem to work in this context.
'''
p1_direction = ["-","-","-"]

'''
on_press is probably the source of the issue, unless the 
keyboard.Listener is. I don't really understand either, and got 
both from ChatGPT.
'''
def on_press(key):
    try:
        if key == keyboard.Key.enter:
            return False  # Stop listener
        elif key == keyboard.Key.left:
            p1_direction.append("<")
        elif key == keyboard.Key.right:
            p1_direction.append(">")
        elif key == keyboard.Key.up:
            p1_direction.append("^")
        elif key == keyboard.Key.down:
            p1_direction.append("v")
    except AttributeError:
        pass

def movement (p1_direction):
    print ("Type three moves: ")

    with keyboard.Listener(on_press=on_press) as listener:
        listener.join()
    
    # This loop guarantees that only the last three directional
    # inputs are counted.
    while len(p1_direction) > 3:
        p1_direction.remove(p1_direction[0])
    
    # This translates the inputs into motion.
    for i in range(len(p1_direction)):
        if p1_direction[i] == "^":
            p1_location[1] -= 1
        if p1_direction[i] == "v":
            p1_location[1] += 1
        if p1_direction[i] == "<":
            p1_location[0] -= 1
        if p1_direction[i] == ">":
            p1_location[0] += 1
    
    # Finally, the list is joined, used as an argument in the 
    # coordinate_field function, and separated again.
    p1_direction = "".join(p1_direction)
    coordinate_field (p1_location, [7,5], p1_direction, "^^<")
    p1_direction = list(p1_direction)
    return p1_direction

# All this code will someday be part of a larger game, but for
# now, I run it endlessly to test it.
while True:
    p1_direction = movement(p1_direction)

With the code running, whatever random characters you type get written into my python code. All I want is for the character to move around in the field, and I have a lot more features yet to add. Maybe it's helpful to know that I got the on_press function from chatGPT.

1

There are 1 best solutions below

3
nigh_anxiety On

To prevent the keyboard inputs from being passed to the system after the script ends, you need to set the parameter suppress=True

    with keyboard.Listener(on_press=on_press) as listener:
        listener.join()

I found a hint about that in this unanswered post.
Here is the relevant documentation of the parameter in pynput:

suppress (bool) – Whether to suppress events. Setting this to True will prevent the input events from being passed to the rest of the system.

Note however, that this means keystrokes will be ignored in any other application while your script is running, including the Ctrl+C KeyboardInterupt command to end the script. You could add another way to exit the script with an on_release callback function, such as:

stop = False
def on_release(key):
    global stop
    # If user hits Esc, end the program
    if key == keyboard.Key.esc:
        stop = True
        return False

...
    #In the main loop:
    if stop:
        sys.exit()

If you only want to suppress certain events from going to the system, then you need to pass system specific callback functions to the correct named arguments. The pynput documentation FAQ about this is found here