Andrew M. Kuchling | e8f44d6 | 2005-08-30 01:25:05 +0000 | [diff] [blame] | 1 | \documentclass{howto} |
| 2 | |
| 3 | \title{Curses Programming with Python} |
| 4 | |
| 5 | \release{2.01} |
| 6 | |
| 7 | \author{A.M. Kuchling, Eric S. Raymond} |
| 8 | \authoraddress{\email{amk@amk.ca}, \email{esr@thyrsus.com}} |
| 9 | |
| 10 | \begin{document} |
| 11 | \maketitle |
| 12 | |
| 13 | \begin{abstract} |
| 14 | \noindent |
| 15 | This document describes how to write text-mode programs with Python 2.x, |
| 16 | using the \module{curses} extension module to control the display. |
| 17 | |
| 18 | This document is available from the Python HOWTO page at |
| 19 | \url{http://www.python.org/doc/howto}. |
| 20 | \end{abstract} |
| 21 | |
| 22 | \tableofcontents |
| 23 | |
| 24 | \section{What is curses?} |
| 25 | |
| 26 | The curses library supplies a terminal-independent screen-painting and |
| 27 | keyboard-handling facility for text-based terminals; such terminals |
| 28 | include VT100s, the Linux console, and the simulated terminal provided |
| 29 | by X11 programs such as xterm and rxvt. Display terminals support |
| 30 | various control codes to perform common operations such as moving the |
| 31 | cursor, scrolling the screen, and erasing areas. Different terminals |
| 32 | use widely differing codes, and often have their own minor quirks. |
| 33 | |
| 34 | In a world of X displays, one might ask ``why bother''? It's true |
| 35 | that character-cell display terminals are an obsolete technology, but |
| 36 | there are niches in which being able to do fancy things with them are |
| 37 | still valuable. One is on small-footprint or embedded Unixes that |
| 38 | don't carry an X server. Another is for tools like OS installers |
| 39 | and kernel configurators that may have to run before X is available. |
| 40 | |
| 41 | The curses library hides all the details of different terminals, and |
| 42 | provides the programmer with an abstraction of a display, containing |
| 43 | multiple non-overlapping windows. The contents of a window can be |
| 44 | changed in various ways--adding text, erasing it, changing its |
| 45 | appearance--and the curses library will automagically figure out what |
| 46 | control codes need to be sent to the terminal to produce the right |
| 47 | output. |
| 48 | |
| 49 | The curses library was originally written for BSD Unix; the later System V |
| 50 | versions of Unix from AT\&T added many enhancements and new functions. |
| 51 | BSD curses is no longer maintained, having been replaced by ncurses, |
| 52 | which is an open-source implementation of the AT\&T interface. If you're |
| 53 | using an open-source Unix such as Linux or FreeBSD, your system almost |
| 54 | certainly uses ncurses. Since most current commercial Unix versions |
| 55 | are based on System V code, all the functions described here will |
| 56 | probably be available. The older versions of curses carried by some |
| 57 | proprietary Unixes may not support everything, though. |
| 58 | |
| 59 | No one has made a Windows port of the curses module. On a Windows |
| 60 | platform, try the Console module written by Fredrik Lundh. The |
| 61 | Console module provides cursor-addressable text output, plus full |
| 62 | support for mouse and keyboard input, and is available from |
| 63 | \url{http://effbot.org/efflib/console}. |
| 64 | |
| 65 | \subsection{The Python curses module} |
| 66 | |
| 67 | Thy Python module is a fairly simple wrapper over the C functions |
| 68 | provided by curses; if you're already familiar with curses programming |
| 69 | in C, it's really easy to transfer that knowledge to Python. The |
| 70 | biggest difference is that the Python interface makes things simpler, |
| 71 | by merging different C functions such as \function{addstr}, |
| 72 | \function{mvaddstr}, \function{mvwaddstr}, into a single |
| 73 | \method{addstr()} method. You'll see this covered in more detail |
| 74 | later. |
| 75 | |
| 76 | This HOWTO is simply an introduction to writing text-mode programs |
| 77 | with curses and Python. It doesn't attempt to be a complete guide to |
Walter Dörwald | 9d9af8a | 2006-01-21 10:50:39 +0000 | [diff] [blame] | 78 | the curses API; for that, see the Python library guide's section on |
Andrew M. Kuchling | e8f44d6 | 2005-08-30 01:25:05 +0000 | [diff] [blame] | 79 | ncurses, and the C manual pages for ncurses. It will, however, give |
| 80 | you the basic ideas. |
| 81 | |
| 82 | \section{Starting and ending a curses application} |
| 83 | |
| 84 | Before doing anything, curses must be initialized. This is done by |
| 85 | calling the \function{initscr()} function, which will determine the |
| 86 | terminal type, send any required setup codes to the terminal, and |
| 87 | create various internal data structures. If successful, |
| 88 | \function{initscr()} returns a window object representing the entire |
| 89 | screen; this is usually called \code{stdscr}, after the name of the |
| 90 | corresponding C |
| 91 | variable. |
| 92 | |
| 93 | \begin{verbatim} |
| 94 | import curses |
| 95 | stdscr = curses.initscr() |
| 96 | \end{verbatim} |
| 97 | |
| 98 | Usually curses applications turn off automatic echoing of keys to the |
| 99 | screen, in order to be able to read keys and only display them under |
| 100 | certain circumstances. This requires calling the \function{noecho()} |
| 101 | function. |
| 102 | |
| 103 | \begin{verbatim} |
| 104 | curses.noecho() |
| 105 | \end{verbatim} |
| 106 | |
| 107 | Applications will also commonly need to react to keys instantly, |
| 108 | without requiring the Enter key to be pressed; this is called cbreak |
| 109 | mode, as opposed to the usual buffered input mode. |
| 110 | |
| 111 | \begin{verbatim} |
| 112 | curses.cbreak() |
| 113 | \end{verbatim} |
| 114 | |
| 115 | Terminals usually return special keys, such as the cursor keys or |
| 116 | navigation keys such as Page Up and Home, as a multibyte escape |
| 117 | sequence. While you could write your application to expect such |
| 118 | sequences and process them accordingly, curses can do it for you, |
| 119 | returning a special value such as \constant{curses.KEY_LEFT}. To get |
| 120 | curses to do the job, you'll have to enable keypad mode. |
| 121 | |
| 122 | \begin{verbatim} |
| 123 | stdscr.keypad(1) |
| 124 | \end{verbatim} |
| 125 | |
| 126 | Terminating a curses application is much easier than starting one. |
| 127 | You'll need to call |
| 128 | |
| 129 | \begin{verbatim} |
| 130 | curses.nocbreak(); stdscr.keypad(0); curses.echo() |
| 131 | \end{verbatim} |
| 132 | |
| 133 | to reverse the curses-friendly terminal settings. Then call the |
| 134 | \function{endwin()} function to restore the terminal to its original |
| 135 | operating mode. |
| 136 | |
| 137 | \begin{verbatim} |
| 138 | curses.endwin() |
| 139 | \end{verbatim} |
| 140 | |
| 141 | A common problem when debugging a curses application is to get your |
| 142 | terminal messed up when the application dies without restoring the |
| 143 | terminal to its previous state. In Python this commonly happens when |
| 144 | your code is buggy and raises an uncaught exception. Keys are no |
| 145 | longer be echoed to the screen when you type them, for example, which |
| 146 | makes using the shell difficult. |
| 147 | |
| 148 | In Python you can avoid these complications and make debugging much |
| 149 | easier by importing the module \module{curses.wrapper}. It supplies a |
| 150 | function \function{wrapper} that takes a hook argument. It does the |
| 151 | initializations described above, and also initializes colors if color |
| 152 | support is present. It then runs your hook, and then finally |
| 153 | deinitializes appropriately. The hook is called inside a try-catch |
| 154 | clause which catches exceptions, performs curses deinitialization, and |
| 155 | then passes the exception upwards. Thus, your terminal won't be left |
| 156 | in a funny state on exception. |
| 157 | |
| 158 | \section{Windows and Pads} |
| 159 | |
| 160 | Windows are the basic abstraction in curses. A window object |
| 161 | represents a rectangular area of the screen, and supports various |
| 162 | methods to display text, erase it, allow the user to input strings, |
| 163 | and so forth. |
| 164 | |
| 165 | The \code{stdscr} object returned by the \function{initscr()} function |
| 166 | is a window object that covers the entire screen. Many programs may |
| 167 | need only this single window, but you might wish to divide the screen |
| 168 | into smaller windows, in order to redraw or clear them separately. |
| 169 | The \function{newwin()} function creates a new window of a given size, |
| 170 | returning the new window object. |
| 171 | |
| 172 | \begin{verbatim} |
| 173 | begin_x = 20 ; begin_y = 7 |
| 174 | height = 5 ; width = 40 |
| 175 | win = curses.newwin(height, width, begin_y, begin_x) |
| 176 | \end{verbatim} |
| 177 | |
| 178 | A word about the coordinate system used in curses: coordinates are |
| 179 | always passed in the order \emph{y,x}, and the top-left corner of a |
| 180 | window is coordinate (0,0). This breaks a common convention for |
| 181 | handling coordinates, where the \emph{x} coordinate usually comes |
| 182 | first. This is an unfortunate difference from most other computer |
| 183 | applications, but it's been part of curses since it was first written, |
| 184 | and it's too late to change things now. |
| 185 | |
| 186 | When you call a method to display or erase text, the effect doesn't |
| 187 | immediately show up on the display. This is because curses was |
| 188 | originally written with slow 300-baud terminal connections in mind; |
| 189 | with these terminals, minimizing the time required to redraw the |
| 190 | screen is very important. This lets curses accumulate changes to the |
| 191 | screen, and display them in the most efficient manner. For example, |
| 192 | if your program displays some characters in a window, and then clears |
| 193 | the window, there's no need to send the original characters because |
| 194 | they'd never be visible. |
| 195 | |
| 196 | Accordingly, curses requires that you explicitly tell it to redraw |
| 197 | windows, using the \function{refresh()} method of window objects. In |
| 198 | practice, this doesn't really complicate programming with curses much. |
| 199 | Most programs go into a flurry of activity, and then pause waiting for |
| 200 | a keypress or some other action on the part of the user. All you have |
| 201 | to do is to be sure that the screen has been redrawn before pausing to |
| 202 | wait for user input, by simply calling \code{stdscr.refresh()} or the |
| 203 | \function{refresh()} method of some other relevant window. |
| 204 | |
| 205 | A pad is a special case of a window; it can be larger than the actual |
| 206 | display screen, and only a portion of it displayed at a time. |
| 207 | Creating a pad simply requires the pad's height and width, while |
| 208 | refreshing a pad requires giving the coordinates of the on-screen |
| 209 | area where a subsection of the pad will be displayed. |
| 210 | |
| 211 | \begin{verbatim} |
| 212 | pad = curses.newpad(100, 100) |
| 213 | # These loops fill the pad with letters; this is |
| 214 | # explained in the next section |
| 215 | for y in range(0, 100): |
| 216 | for x in range(0, 100): |
| 217 | try: pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) |
| 218 | except curses.error: pass |
| 219 | |
| 220 | # Displays a section of the pad in the middle of the screen |
| 221 | pad.refresh( 0,0, 5,5, 20,75) |
| 222 | \end{verbatim} |
| 223 | |
| 224 | The \function{refresh()} call displays a section of the pad in the |
| 225 | rectangle extending from coordinate (5,5) to coordinate (20,75) on the |
| 226 | screen;the upper left corner of the displayed section is coordinate |
| 227 | (0,0) on the pad. Beyond that difference, pads are exactly like |
| 228 | ordinary windows and support the same methods. |
| 229 | |
| 230 | If you have multiple windows and pads on screen there is a more |
| 231 | efficient way to go, which will prevent annoying screen flicker at |
| 232 | refresh time. Use the methods \method{noutrefresh()} and/or |
| 233 | \method{noutrefresh()} of each window to update the data structure |
| 234 | representing the desired state of the screen; then change the physical |
| 235 | screen to match the desired state in one go with the function |
| 236 | \function{doupdate()}. The normal \method{refresh()} method calls |
| 237 | \function{doupdate()} as its last act. |
| 238 | |
| 239 | \section{Displaying Text} |
| 240 | |
| 241 | {}From a C programmer's point of view, curses may sometimes look like |
| 242 | a twisty maze of functions, all subtly different. For example, |
| 243 | \function{addstr()} displays a string at the current cursor location |
| 244 | in the \code{stdscr} window, while \function{mvaddstr()} moves to a |
| 245 | given y,x coordinate first before displaying the string. |
| 246 | \function{waddstr()} is just like \function{addstr()}, but allows |
| 247 | specifying a window to use, instead of using \code{stdscr} by default. |
| 248 | \function{mvwaddstr()} follows similarly. |
| 249 | |
| 250 | Fortunately the Python interface hides all these details; |
| 251 | \code{stdscr} is a window object like any other, and methods like |
| 252 | \function{addstr()} accept multiple argument forms. Usually there are |
| 253 | four different forms. |
| 254 | |
| 255 | \begin{tableii}{|c|l|}{textrm}{Form}{Description} |
| 256 | \lineii{\var{str} or \var{ch}}{Display the string \var{str} or |
| 257 | character \var{ch}} |
| 258 | \lineii{\var{str} or \var{ch}, \var{attr}}{Display the string \var{str} or |
| 259 | character \var{ch}, using attribute \var{attr}} |
| 260 | \lineii{\var{y}, \var{x}, \var{str} or \var{ch}} |
| 261 | {Move to position \var{y,x} within the window, and display \var{str} |
| 262 | or \var{ch}} |
| 263 | \lineii{\var{y}, \var{x}, \var{str} or \var{ch}, \var{attr}} |
| 264 | {Move to position \var{y,x} within the window, and display \var{str} |
| 265 | or \var{ch}, using attribute \var{attr}} |
| 266 | \end{tableii} |
| 267 | |
| 268 | Attributes allow displaying text in highlighted forms, such as in |
| 269 | boldface, underline, reverse code, or in color. They'll be explained |
| 270 | in more detail in the next subsection. |
| 271 | |
| 272 | The \function{addstr()} function takes a Python string as the value to |
| 273 | be displayed, while the \function{addch()} functions take a character, |
| 274 | which can be either a Python string of length 1, or an integer. If |
| 275 | it's a string, you're limited to displaying characters between 0 and |
| 276 | 255. SVr4 curses provides constants for extension characters; these |
| 277 | constants are integers greater than 255. For example, |
| 278 | \constant{ACS_PLMINUS} is a +/- symbol, and \constant{ACS_ULCORNER} is |
| 279 | the upper left corner of a box (handy for drawing borders). |
| 280 | |
| 281 | Windows remember where the cursor was left after the last operation, |
| 282 | so if you leave out the \var{y,x} coordinates, the string or character |
| 283 | will be displayed wherever the last operation left off. You can also |
| 284 | move the cursor with the \function{move(\var{y,x})} method. Because |
| 285 | some terminals always display a flashing cursor, you may want to |
| 286 | ensure that the cursor is positioned in some location where it won't |
| 287 | be distracting; it can be confusing to have the cursor blinking at |
| 288 | some apparently random location. |
| 289 | |
| 290 | If your application doesn't need a blinking cursor at all, you can |
| 291 | call \function{curs_set(0)} to make it invisible. Equivalently, and |
| 292 | for compatibility with older curses versions, there's a |
| 293 | \function{leaveok(\var{bool})} function. When \var{bool} is true, the |
| 294 | curses library will attempt to suppress the flashing cursor, and you |
| 295 | won't need to worry about leaving it in odd locations. |
| 296 | |
| 297 | \subsection{Attributes and Color} |
| 298 | |
| 299 | Characters can be displayed in different ways. Status lines in a |
| 300 | text-based application are commonly shown in reverse video; a text |
| 301 | viewer may need to highlight certain words. curses supports this by |
| 302 | allowing you to specify an attribute for each cell on the screen. |
| 303 | |
| 304 | An attribute is a integer, each bit representing a different |
| 305 | attribute. You can try to display text with multiple attribute bits |
| 306 | set, but curses doesn't guarantee that all the possible combinations |
| 307 | are available, or that they're all visually distinct. That depends on |
| 308 | the ability of the terminal being used, so it's safest to stick to the |
| 309 | most commonly available attributes, listed here. |
| 310 | |
| 311 | \begin{tableii}{|c|l|}{constant}{Attribute}{Description} |
| 312 | \lineii{A_BLINK}{Blinking text} |
| 313 | \lineii{A_BOLD}{Extra bright or bold text} |
| 314 | \lineii{A_DIM}{Half bright text} |
| 315 | \lineii{A_REVERSE}{Reverse-video text} |
| 316 | \lineii{A_STANDOUT}{The best highlighting mode available} |
| 317 | \lineii{A_UNDERLINE}{Underlined text} |
| 318 | \end{tableii} |
| 319 | |
| 320 | So, to display a reverse-video status line on the top line of the |
| 321 | screen, |
| 322 | you could code: |
| 323 | |
| 324 | \begin{verbatim} |
| 325 | stdscr.addstr(0, 0, "Current mode: Typing mode", |
| 326 | curses.A_REVERSE) |
| 327 | stdscr.refresh() |
| 328 | \end{verbatim} |
| 329 | |
| 330 | The curses library also supports color on those terminals that |
| 331 | provide it, The most common such terminal is probably the Linux |
| 332 | console, followed by color xterms. |
| 333 | |
| 334 | To use color, you must call the \function{start_color()} function |
| 335 | soon after calling \function{initscr()}, to initialize the default |
| 336 | color set (the \function{curses.wrapper.wrapper()} function does this |
| 337 | automatically). Once that's done, the \function{has_colors()} |
| 338 | function returns TRUE if the terminal in use can actually display |
| 339 | color. (Note from AMK: curses uses the American spelling |
| 340 | 'color', instead of the Canadian/British spelling 'colour'. If you're |
| 341 | like me, you'll have to resign yourself to misspelling it for the sake |
| 342 | of these functions.) |
| 343 | |
| 344 | The curses library maintains a finite number of color pairs, |
| 345 | containing a foreground (or text) color and a background color. You |
| 346 | can get the attribute value corresponding to a color pair with the |
| 347 | \function{color_pair()} function; this can be bitwise-OR'ed with other |
| 348 | attributes such as \constant{A_REVERSE}, but again, such combinations |
| 349 | are not guaranteed to work on all terminals. |
| 350 | |
| 351 | An example, which displays a line of text using color pair 1: |
| 352 | |
| 353 | \begin{verbatim} |
| 354 | stdscr.addstr( "Pretty text", curses.color_pair(1) ) |
| 355 | stdscr.refresh() |
| 356 | \end{verbatim} |
| 357 | |
| 358 | As I said before, a color pair consists of a foreground and |
| 359 | background color. \function{start_color()} initializes 8 basic |
| 360 | colors when it activates color mode. They are: 0:black, 1:red, |
| 361 | 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The curses |
| 362 | module defines named constants for each of these colors: |
| 363 | \constant{curses.COLOR_BLACK}, \constant{curses.COLOR_RED}, and so |
| 364 | forth. |
| 365 | |
| 366 | The \function{init_pair(\var{n, f, b})} function changes the |
| 367 | definition of color pair \var{n}, to foreground color {f} and |
| 368 | background color {b}. Color pair 0 is hard-wired to white on black, |
| 369 | and cannot be changed. |
| 370 | |
| 371 | Let's put all this together. To change color 1 to red |
| 372 | text on a white background, you would call: |
| 373 | |
| 374 | \begin{verbatim} |
| 375 | curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE) |
| 376 | \end{verbatim} |
| 377 | |
| 378 | When you change a color pair, any text already displayed using that |
| 379 | color pair will change to the new colors. You can also display new |
| 380 | text in this color with: |
| 381 | |
| 382 | \begin{verbatim} |
| 383 | stdscr.addstr(0,0, "RED ALERT!", curses.color_pair(1) ) |
| 384 | \end{verbatim} |
| 385 | |
| 386 | Very fancy terminals can change the definitions of the actual colors |
| 387 | to a given RGB value. This lets you change color 1, which is usually |
| 388 | red, to purple or blue or any other color you like. Unfortunately, |
| 389 | the Linux console doesn't support this, so I'm unable to try it out, |
| 390 | and can't provide any examples. You can check if your terminal can do |
| 391 | this by calling \function{can_change_color()}, which returns TRUE if |
| 392 | the capability is there. If you're lucky enough to have such a |
| 393 | talented terminal, consult your system's man pages for more |
| 394 | information. |
| 395 | |
| 396 | \section{User Input} |
| 397 | |
| 398 | The curses library itself offers only very simple input mechanisms. |
| 399 | Python's support adds a text-input widget that makes up some of the |
| 400 | lack. |
| 401 | |
| 402 | The most common way to get input to a window is to use its |
| 403 | \method{getch()} method. that pauses, and waits for the user to hit |
| 404 | a key, displaying it if \function{echo()} has been called earlier. |
| 405 | You can optionally specify a coordinate to which the cursor should be |
| 406 | moved before pausing. |
| 407 | |
| 408 | It's possible to change this behavior with the method |
| 409 | \method{nodelay()}. After \method{nodelay(1)}, \method{getch()} for |
| 410 | the window becomes non-blocking and returns ERR (-1) when no input is |
| 411 | ready. There's also a \function{halfdelay()} function, which can be |
| 412 | used to (in effect) set a timer on each \method{getch()}; if no input |
| 413 | becomes available within the number of milliseconds specified as the |
| 414 | argument to \function{halfdelay()}, curses throws an exception. |
| 415 | |
| 416 | The \method{getch()} method returns an integer; if it's between 0 and |
| 417 | 255, it represents the ASCII code of the key pressed. Values greater |
| 418 | than 255 are special keys such as Page Up, Home, or the cursor keys. |
| 419 | You can compare the value returned to constants such as |
| 420 | \constant{curses.KEY_PPAGE}, \constant{curses.KEY_HOME}, or |
| 421 | \constant{curses.KEY_LEFT}. Usually the main loop of your program |
| 422 | will look something like this: |
| 423 | |
| 424 | \begin{verbatim} |
| 425 | while 1: |
| 426 | c = stdscr.getch() |
| 427 | if c == ord('p'): PrintDocument() |
| 428 | elif c == ord('q'): break # Exit the while() |
| 429 | elif c == curses.KEY_HOME: x = y = 0 |
| 430 | \end{verbatim} |
| 431 | |
| 432 | The \module{curses.ascii} module supplies ASCII class membership |
| 433 | functions that take either integer or 1-character-string |
| 434 | arguments; these may be useful in writing more readable tests for |
| 435 | your command interpreters. It also supplies conversion functions |
| 436 | that take either integer or 1-character-string arguments and return |
| 437 | the same type. For example, \function{curses.ascii.ctrl()} returns |
| 438 | the control character corresponding to its argument. |
| 439 | |
| 440 | There's also a method to retrieve an entire string, |
| 441 | \constant{getstr()}. It isn't used very often, because its |
| 442 | functionality is quite limited; the only editing keys available are |
| 443 | the backspace key and the Enter key, which terminates the string. It |
| 444 | can optionally be limited to a fixed number of characters. |
| 445 | |
| 446 | \begin{verbatim} |
| 447 | curses.echo() # Enable echoing of characters |
| 448 | |
| 449 | # Get a 15-character string, with the cursor on the top line |
| 450 | s = stdscr.getstr(0,0, 15) |
| 451 | \end{verbatim} |
| 452 | |
| 453 | The Python \module{curses.textpad} module supplies something better. |
| 454 | With it, you can turn a window into a text box that supports an |
| 455 | Emacs-like set of keybindings. Various methods of \class{Textbox} |
| 456 | class support editing with input validation and gathering the edit |
| 457 | results either with or without trailing spaces. See the library |
| 458 | documentation on \module{curses.textpad} for the details. |
| 459 | |
| 460 | \section{For More Information} |
| 461 | |
| 462 | This HOWTO didn't cover some advanced topics, such as screen-scraping |
| 463 | or capturing mouse events from an xterm instance. But the Python |
| 464 | library page for the curses modules is now pretty complete. You |
| 465 | should browse it next. |
| 466 | |
| 467 | If you're in doubt about the detailed behavior of any of the ncurses |
| 468 | entry points, consult the manual pages for your curses implementation, |
| 469 | whether it's ncurses or a proprietary Unix vendor's. The manual pages |
| 470 | will document any quirks, and provide complete lists of all the |
| 471 | functions, attributes, and \constant{ACS_*} characters available to |
| 472 | you. |
| 473 | |
| 474 | Because the curses API is so large, some functions aren't supported in |
| 475 | the Python interface, not because they're difficult to implement, but |
| 476 | because no one has needed them yet. Feel free to add them and then |
| 477 | submit a patch. Also, we don't yet have support for the menus or |
| 478 | panels libraries associated with ncurses; feel free to add that. |
| 479 | |
| 480 | If you write an interesting little program, feel free to contribute it |
| 481 | as another demo. We can always use more of them! |
| 482 | |
| 483 | The ncurses FAQ: \url{http://dickey.his.com/ncurses/ncurses.faq.html} |
| 484 | |
| 485 | \end{document} |