How can I change the cursor position of the user input in input() function in Python?

Viewed 933

While using the input() function I want to take or receive a string from the user to a variable. So is it possible to input inside square brackets instead of plain text? For example;

a = input("-->")

this shows the output like this:

-->

but instead can I have the output like this:

--> [ _ ]

and take the input inside the square bracket. (_ represents the cursor.)

3 Answers

Manipulating the cursor position when you call input() requires a hack with ANSI escape sequences. (See @chepner's answer.) To do what you want more correctly, you need to use a library that can manipulate the terminal, such as curses.

You can, sort of. If your terminal supports ANSI escape sequences, you can save the current cursor position by outputting \033[s and move the cursor back to the last saved position with \033[u. Then your call to input will look like

a = input("--> [\033[s ]\033[u")

However, this is purely visual: nothing stops you from typing "beyond" the square bracket. The main limitation is that input itself knows nothing about the terminal; it just reads from standard input, which is line-buffered. input returns nothing until a complete line is entered; until then, it just waits for the terminal to send something. A library like curses provides much more exact handling; for instance, it can stop responding to key presses if you try to type beyond the ] in your prompt.

The following code snippet, using curses, will handle standard visible ascii characters, deleting characters, and newline (for submit).

from curses import wrapper

def prompt(stdscr, prompt_template="--> [ {} ]"):
    user_inp = ""
    display_str = prompt_template.format(user_inp)

    stdscr.addstr(0, 0, display_str)
    while True:
        inp_ch = stdscr.getch()

        # standard ASCII characters
        if 32 <= inp_ch <= 126:
            user_inp += chr(inp_ch)
        elif inp_ch in (8, 127, 263): # BS, DEL, Key_Backspace
            user_inp = user_inp[:-1]
        elif inp_ch == 10: # is newline, enter pressed
            break
        else: # all other characters are ignored
            continue

        display_str = prompt_template.format(user_inp)
        stdscr.erase()
        stdscr.addstr(0, 0, display_str)
        stdscr.refresh()

    return user_inp

print(wrapper(prompt))
Related