Last updated: November 29, 2016

This tutorial requires a basic knowledge of Python. This tutorial will be expanded into a normal post format.
python
"""
This is a tutorial for curses. Curses is a Python library that helps you handle
keyboard input and control the displayed text on the terminal. The tutorial
closely follows https://docs.python.org/3.3/howto/curses.html.

We'll jump in with the structure of a basic curses program.
"""

import curses

def main():
    # create a window object that represents the terminal window
    stdscr = curses.initscr()
    # Don't print what I type on the terminal
    curses.noecho()
    # React to every key press, not just when pressing "enter"
    curses.cbreak()
    # Enable easy key codes (will come back to this)
    stdscr.keypad(True)
    # Proceed with your program
    print("Running some program...")
    # Clean up after yourself
    teardown()

def teardown():
    # reverse everything that you changed about the terminal
    curses.nocbreak()
    stdscr.keypad(False)
    curses.echo()
    # restore the terminal to its original state
    curses.endwin()

main()

"""
Unfortunately, if something goes wrong during your part of the program, it can
exit without running the teardown function. That could leave your terminal in
a weird state because curses messed with it. Curses has an answer to this
problem that also happens to make all of the above code a lot easier to write.
"""

import curses
from curses import wrapper

def main(stdscr):
    # Clear screen
    stdscr.clear()
    # Proceed with your program
    print("Running some program")

# wrapper is a function that does all of the setup and teardown, and makes sure
# your program cleans up properly if it errors!
wrapper(main)

"""
Using the wrapper function is much cleaner, as you can see. From now on, we'll
just modify what's inside the function `main`, and assume we have the import and
the wrapper set up as above.
Now we can learn how to handle user input.

When the user presses a key, we want to be able to handle that action. The first
step in doing so is discovering which key was pressed. The function `getch` does
this for us. It returns a value that we can compare like so:
c = stdscr.getch()
c == ord('a') # Do this to check for a letter key
c == curses.KEY_UP # Do this to check for special keys
See https://docs.python.org/3.5/library/curses.html#constants for all special
key values.
"""

def main(stdscr):
    stdscr.clear()
    while True:
        # Store the key value in the variable `c`
        c = stdscr.getch()
        # Clear the terminal
        stdscr.clear()
        if c == ord('a'):
            stdscr.addstr("You pressed the 'a' key.")
        elif c == curses.KEY_UP:
            stdscr.addstr("You pressed the up arrow.")
        else:
            stdscr.addstr("This program doesn't know that key.....")

"""
What's stdscr.addstr? That's curses' way of printing. Later, we'll see that it
can also take arguments like y and x positions, which tell it where to print
the string on the terminal. For now, it just prints wherever the cursor is.
It's important to note that stdscr.clear, which is called in the block above,
not only clears the terminal, but also moves the cursor back to the top left.

You may have noticed that the program waits at stdscr.getch for the user to
press a key. We call this behavior "blocking", and would say that stdscr.getch
blocks the flow of the program. For some programs, this is useful. For others,
often in the case of games, this is not the desired behavior. Thankfully, curses
allows non-blocking key input as well.
"""

import time

def main(stdscr):
    # Make stdscr.getch non-blocking
    stdscr.nodelay(True)
    stdscr.clear()
    width = 4
    count = 0
    direction = 1
    while True:
        c = stdscr.getch()
        # Clear out anything else the user has typed in
        curses.flushinp()
        stdscr.clear()
        # If the user presses p, increase the width of the springy bar
        if c == ord('p'):
            width += 1
        # Draw a springy bar
        stdscr.addstr("#" * count)
        count += direction
        if count == width:
            direction = -1
        elif count == 0:
            direction = 1
        # Wait 1/10 of a second. Read below to learn about how to avoid
        # problems with using time.sleep with getch!
        time.sleep(0.1)

"""
Calling stdscr.nodelay(True) made stdscr.getch() non-blocking. If Python gets to
that line and the user hasn't typed anything since last time, getch will return
-1, which doesn't match any key.

What if the user managed to type more than one character since the last time
getch was called? All of those characters will start to build up, and getch will
return the value for each one in the order that they came. This can cause
delayed reactions if you're writing a game. After getch, you can call
curses.flushinp to clear out the rest of the characters that the user typed.

This is a good place to talk more about getch.

Every time the user presses a key, that key's value gets stored in a list. When
getch is called, it goes to that list and pops that value. If the user manages
to press several keys before getch is called, getch will pop the least recently
added value (the oldest key pressed). The rest of the keys remain in the list!
The process continues like this. So there's a problem if there is a delay
between calls to getch: Key values can build up. If you don't want this to
happen, curses.flushinp() clears the list of inputted values. This ensures that
the next key the user presses after curses.flushinp() is what getch will return
next time it is called.
"""

"""
To continue learning about curses, checkout the addstr method to see how you can
print strings at certain y, x coordinates. You can start here:
https://docs.python.org/3/library/curses.html#window-objects
"""