Search code examples
pythonpython-3.xinputcursor-position

Move the Cursor Back For taking Input Python


I was trying to do like the following:

a = input('Enter your name:_____________________________________________')

but here, the cursor is positioned at :

Enter your name:_____________________________________________
                                                             ^
                                                            Here

How do I position the cursor at:

Enter your name:_____________________________________________
                ^
               Here

I'm doing this on IDLE. (Command prompt is also appreciated)


Solution

  • Having looked at this further, my final solution is to create my own custom input. NB: this only works in windows command prompt. If you are looking to do this in Unix you will have to look into an alternative. I may update this answer later to support Unix. [Edit: Updated to support both Unix and Windows]

    Again, this will not work in IDLE

    This function takes a prefix for your input, the number of max_length of the input, and the blank_char to fill the length of the input with.

    First, we capture the user input and if it is a displayable character, we add it to our word. Every time we get a new character we overwrite the existing input line to keep up to date with the current state of the word.

    We also look for the b'\x08' charater (backspace) so we can remove the last character from our word, and the return charcter to see if our user has pressed Enter.

    Once enter has been pressed, return the word.

    There is also a built in limit, where the user can only input as many characters as there are underscores, as this will cause letters to linger, you can always modify this by incrementing the number of underscores or something similar.

    WINDOWS ONLY:

    import msvcrt
    
    
    def windows_get_input(prefix="", underscores=20, blank_char='_'):
    
        word = ""
    
        print(prefix + (underscores - len(word)) * blank_char, end='\r', flush=True)
        # Reprint prefix to move cursor
        print(prefix, end="", flush=True)
    
        while True:
            ch = msvcrt.getch()
            if ch in b'\x08':
                # Remove character if backspace
                word = word[:-1]
            elif ch in b'\r':
                # break if enter pressed
                break
            else:
                if len(word) == underscores:
                    continue
                try:
                    char = str(ch.decode("utf-8"))
                except:
                    continue
                word += str(char)
            # Print `\r` to return to start of line and then print prefix, word and underscores.
            print('\r' + prefix + word + (underscores - len(word)) * blank_char, end='\r', flush=True)
            # Reprint prefix and word to move cursor
            print(prefix + word, end="", flush=True)
        print()
        return word
    
    print(windows_get_input("Name: ", 20, '_'))
    
    

    Handling both Windows and Unix

    WINDOWS and UNIX:

    def unix_getch():
        import termios
        import sys, tty
        def _getch():
            fd = sys.stdin.fileno()
            old_settings = termios.tcgetattr(fd)
            try:
                tty.setraw(fd)
                ch = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
            return ch.encode("utf-8")
        return _getch()
    
    def get_input(prefix="", underscores=20, blank_char='_'):
    
        word = ""
    
        try:
            import msvcrt
            func = msvcrt.getch
        except:
            func = unix_getch
    
        print(prefix + (underscores - len(word)) * blank_char, end='\r', flush=True)
        # Reprint prefix to move cursor
        print(prefix, end="", flush=True)
    
        while True:
            ch = func()
            if ch in b'\x08\x7f':
                # Remove character if backspace
                word = word[:-1]
            elif ch in b'\r':
                # break if enter pressed
                break
            else:
                if len(word) == underscores:
                    continue
                try:
                    char = str(ch.decode("utf-8"))
                except:
                    continue
                word += str(char)
            # Print `\r` to return to start of line and then print prefix, word and underscores.
            print('\r' + prefix + word + (underscores - len(word)) * blank_char, end='\r', flush=True)
            # Reprint prefix and word to move cursor
            print(prefix + word, end="", flush=True)
        print()
        return word
    
    print(get_input("Name: ", 20, '_'))
    
    

    Handling IDLE

    With IDLE, this fails. Thanks Python for giving us this... Anayway, if you want to handle running in IDLE, simply add the following at the top of the get_input() function:

        import sys
    
        if 'idlelib.run' in sys.modules:
            return input(prefix)
    

    This will check if you are using IDLE and just prompt the user for input normally.