Search code examples
pythonterminalcurses

Python: calling 'curses' twice stuffs up my terminal


I'm using curses for a puzzle in a terminal game (Mac OSX, Python 2.6.5). The puzzle involves spinning some dials to open a lock. My code, somewhat simplified (excuse the ugliness):

import curses

dial = ["| -1  |","|-1/3 |","|  0  |","| 1/2 |","| 2/3 |","|  1  |"]

clear = "       "
pointer = "   ^   "
subdials = [clear,clear]

d = {'d0':{},'d1':{}}
d['d0'] = {'val':2,'disp':dial[2]}
d['d1'] = {'val':2,'disp':dial[2]}

def spin(scr):
    try:
        curses.curs_set(0)
    except:
        pass

    solved = 0
    p = 0
    subdials[p] = pointer
    dials = [d['d0']['disp'],d['d1']['disp']]

    maxy,maxx = scr.getmaxyx()

    newscr = scr.subwin(10,51,maxy-15,0)
    newscr.box(ord('|'),ord('-'))
    newscr.addstr(4,8,''.join(dials))
    newscr.addstr(6,8,''.join(subdials))
    newscr.refresh()

    while solved == 0:
        r = scr.getch()
        subdials[p] = clear
        currd = 'd'+str(p)

        if r == ord('q') or r == ord('Q'):
            break
        elif r == curses.KEY_LEFT:
            if p > 0 and p < 2:
                p -= 1
            else: pass
        elif r == curses.KEY_RIGHT:
            if p >= 0 and p < 1:
                p += 1
            else: pass
        elif r == curses.KEY_UP:
            if d[currd]['val'] >= 0 and d[currd]['val'] < 5:
                d[currd]['val'] += 1
                d[currd]['disp'] = dial[d[currd]['val']]
            else: pass
        elif r == curses.KEY_DOWN:
            if d[currd]['val'] > 0 and d[currd]['val'] <= 5:
                d[currd]['val'] -= 1
                d[currd]['disp'] = dial[d[currd]['val']]
            else: pass
        else: pass

        subdials[p] = pointer
        dials = [d['d0']['disp'],d['d1']['disp']]

        newscr.addstr(4,8,''.join(dials))
        newscr.addstr(6,8,''.join(subdials))
        newscr.refresh()

        if d['d0']['val'] == 5 and d['d1']['val'] == 3:
            solved = 1

    if solved == 0:
        scr.addstr(maxy-1,0,"You can't figure out the lock.")
    else:
        scr.addstr(maxy-1,0,"The lock is open!")
    scr.getch()
    scr.clear()
    return solved

def box():
    solved = curses.wrapper(spin)
    return solved

There are two ways to exit the 'box' function: by pressing 'q' to quit, or by solving the puzzle. The first time you exit from curses (in either way), no problem. But if I call 'box' again, a problem quickly arises.

First, within the curses window, any key input which my function has been instructed to pass is echoed to the screen. Second, and worse, when you exit the puzzle a second time – either by quitting or winning – noecho and cbreak aren't turned off, so my terminal is stuffed and has to be reset.

(NB: If I keep calling 'box', key input is no longer echoed in the curses window itself, but my terminal doesn't go back to normal.)

I cannot for the life of me figure out what's causing this behaviour. Help!


Solution

  • I updated Python to 2.7.3, and the problem has vanished. Huzzah!