Skip to content

Latest commit

 

History

History
1733 lines (1444 loc) · 92.7 KB

uncursed.md

File metadata and controls

1733 lines (1444 loc) · 92.7 KB

About this document: Last modified by Alex Smith, 2015-02-02

Copyright © 2013, 2014, 2015 Alex Smith.

This documentation for the uncursed rendering library is provided under the same terms as libuncursed itself: it may be distributed under either of the following licenses:

  • the NetHack General Public License
  • the GNU General Public License v2 or later

If you obtained this documentation as part of NetHack 4, you can find these licenses in the files libnethack/dat/license and libnethack/dat/gpl respectively.

The uncursed rendering library

uncursed is a library intended primarily for roguelikes and similarly graphically simple screen-oriented applications which are designed to be played in a terminal. It has three main purposes:

  • If players are playing in a terminal, to aim for correct, consistent rendering on a wide range of terminal types (even if its output is recorded and later played back on a different terminal);
  • For players who cannot, or do not wish to, play in a terminal (perhaps because their platform does not have a high-quality terminal emulator), to provide a similar play experience via other means (e.g. via simulating a terminal);
  • To provide support for optional, advanced features (such as tiles play or mouse support) in a way that requires as little extra effort as possible by the developers of the game that uses libuncursed.

Some things that are not goals of uncursed:

  • uncursed aims for compatibility with commonly used operating systems and platforms, but not for perfect compatibility with every terminal ever created. Thus, in applications where you want to communicate with an actual, physical VT100, for instance, a library like ncurses will be a better fit; libuncursed would try to send control codes too fast for the terminal, whereas libncurses will intentionally insert delays.
  • uncursed will not aim to produce substitute codes on primitive terminals in order to approximate rendering that would exist on more complex terminals. For instance, on terminals that do not understand background colors, it will not attempt to approximate the background color using inverse colors, like might happen with a terminal-capability-aware application.
  • uncursed will not use, or provide access to, terminal features that are not widely available; if a feature does not exist on a wide range of terminals, it's likely to be inexpressible in libuncursed.

This guide documents the use of libuncursed for users of programs that use it, for developers who want to write a game using libuncursed (or to convert an existing program to use it), and for developers who want to write new plugins for libuncursed.

Using a libuncursed program

uncursed has a plugin-based architecture. Thus, the main customization option for a user (apart from any options that the program you are using might give you) is as to which plugins you load.

The main choice is as to which plugin will be responsible for the main interface of the application. You can specify this in several ways:

  • On the command line, using --interface plugin at the start of the command you use to invoke the application (e.g. --interface tty if you want to use the tty interface);
  • Via creating a symbolic link to the application (or renaming the application) to end with a hyphen and the name of a plugin (e.g. if you create a symbolic link to program as program-sdl), running the program via that symbolic link will run it using the sdl interface;
  • Using a default depending on your current platform and the way that libuncursed and the application are configured, otherwise.

Here are the main interface plugins available:

tty

The tty interface is available for UNIX platforms (such as Mac OS X) and UNIX-like platforms (such as Linux), and produces output suitable for use in a modern terminal that uses VT100-inspired control codes. (The terminal does not necessarily have to be running on the same operating system as libuncursed itself; roguelikes are commonly played over ssh or telnet, and the tty interface is specifically supported in this sort of configuration.)

This interface is tested and known to work on the following terminals:

  • Terminals built into operating systems:
    • The terminal provided by fbcon (the Linux Framebuffer Console Support), which is typically compiled into the Linux kernel and used for the text consoles if no graphical interface is loaded;
    • The terminal used to render text by DOSBox (the terminal used by DOS itself probably also works if ANSI.SYS is loaded, but this is very hard to test because it would require finding an old DOS implementation with a working network stack and telnet program);
  • Terminal emulation software:
    • xterm (traditionally used as the terminal emulator under X11, the most commonly used graphical interface under Linux and BSD);
    • gnome-terminal (typically used as the terminal emulator under Gnome-based environments such as Gnome, MATE, and Ubuntu Unity);
    • konsole (typically used as the terminal emulator under KDE and KDE-based environments);
    • lxterminal (typically used as the terminal under LXDE);
    • PuTTY (the most commonly used terminal emulator for ssh and telnet connections under Windows);
    • urxvt (the Unicode-aware version of rxvt, which was once the main competitor to xterm);
  • Terminal multiplexers:
    • screen, tmux (both typically used in order to keep a program running while disconnected from the computer it runs on, or to allow switching between multiple screen-oriented programs or to allow multiple people to drive the same screen-oriented program);
  • Terminal recording renderers:
    • termplay (commonly used to play back terminal recordings on Windows, and which also works on other systems);
    • jettyplay (a portable Java-based GUI terminal recording renderer);
    • and any terminal recording player that uses the terminal it runs in for rendering (such as ttyplay), if that terminal is supported by the uncursed tty interface.

The most notable terminals on which this interface does not work are:

  • rxvt, which relies on its font files for encoding support in a way that typically produces garbled output of non-ASCII characters when this interface is used (if you can, use urxvt instead, which does not have this problem);
  • ipbt, whose problem is that it can parse codes for 16-color-aware terminals but subsequently does not know how to render them (this may be a bug in ipbt);
  • any physical terminal that requires the application using it to insert delays into the data it sends;
  • and the console that ships with Windows 2000 and later (which does not parse terminal control codes at all; if you really want to use this console for some reason, use the wincon interface plugin).

Unlike with ncurses, the uncursed tty interface plugin does not require any help from environment variables such as TERM, or support files such as terminal capabilities databases, to function correctly; instead, it aims to produce codes that will be recognised by as many terminals as possible (if necessary, via concatenating codes for different terminals in a way that will cause all the supported terminals to parse the bits intended for them, and ignore the bits intended for other terminals). This means that the terminal will render the data correctly even if TERM is set incorrectly (a common problem over ssh; although ssh sends the value of TERM correctly, it can often has a different meaning on the source and target machines if the operating systems differ), and even if the terminal capabilities database is wrong or insufficient (which is a common cause of dark gray rendering incorrectly on terminals; some terminals will render dark gray incorrectly on ncurses but correctly via libuncursed).

This interface supports most of the features of libuncursed: 8 foreground and 8 background colors, bold, underlining (if the terminal supports it), cursor movement / showing / hiding, resizing, and (if the terminal supports it) mouse support; it will attempt to use either code page 437 ("IBMgraphics") or UTF-8 for handling non-ASCII characters, depending on what the terminal supports. It cannot (for obvious reasons) handle features like tiles support that require a GUI, and will just ignore any information about fonts or tiles that the application sends it.

wincon

The wincon interface plugin is similar to the tty interface plugin in terms of what it does: it renders the program in a terminal emulator. However, instead of using VT100-like control codes, it uses the Windows console API (introduced in Windows 2000, although this interface has only currently been tested on Windows 7), and thus renders into the Windows console, rather than a terminal emulator, working only for native play (i.e. not over telnet or ssh) and only on Windows.

The main thing to bear in mind with this interface is that the Windows console has exceptionally bad performance, as terminal emulators go. The wincon interface plugin attempts to alleviate this problem somewhat via favouring speed over correctness (e.g. it will delay redraws requested by the underlying program until it requests a key or a timed delay), but it will still be noticeably slower than other interfaces.

One other issue is that the way that the Windows console handles resizing is bizarre: a window acts as a scrollable viewport into a larger underlying terminal, and both the window and underlying terminal can be resized. (This is why the Windows console cannot by default be resized wider, only taller, and why it always has a constant amount of scrollback even if there's nothing to scroll back to.) The wincon interface will, by default, set the underlying terminal to the size of the screen, and render only within the area shown in the viewport, meaning that the terminal can effectively be resized via dragging the window borders, just like on the other interfaces. However, you need to press a key after resizing, because Windows does not notify console programs of changes to the viewport size (only to the underlying terminal size), and scrollbars will be constantly visible (but cause rendering issues if not scrolled to the top left). If you resize the underlying terminal while the uncursed-using program is open, the wincon interface will instead start acting like Windows programs are "meant" to act, rendering on the entire underlying terminal and ignoring the viewport size, meaning that you can scroll around within the view or have a view larger than the screen, but will not be able to resize the terminal via dragging the window borders until you restart the program.

sdl

The sdl interface plugin uses version 2 of the Simple DirectMedia Layer library (SDL) to render a simulated terminal in a portable way across a very wide range of systems. It aims to simulate, as far as possible, the experience of the tty interface plugin running in a terminal emulator (although it does not bother with a conversion to VT100 control codes and back, because this would be invisible to a user anyway). Thus, it gives a grid-based view with foreground and background colors and a cursor, just like a real terminal emulator does.

In order to be able to draw characters, this interface needs a font file; the program that loads libuncursed is responsible for telling libuncursed where it is. If no font file is available, the sdl interface plugin will not be able to render characters, and will render everything as a solid block of color. (If you see this symptom when running a program with this interface plugin, try running the program from a terminal; it will send any error messages about failure to find fonts to that terminal.)

This plugin can also handle mouse input, and extended graphical capabilities such as tiles, if requested to do so by the program that uses it.

Writing a program that uses libuncursed

libuncursed's API is designed to be reminisent of that of the older terminal rendering libraries ncurses and pdcurses (which are in turn based on the API of curses). It does not aim to be a curses implementation, nor 100% compatible with the curses standard; however, it tries to be close enough that porting existing curses programs to uncursed does not require major changes.

uncursed is currently only compatible with C programs (although other languages can use its features via using whatever methods they would typically use to interface with a library written in C). To use libuncursed's capabilities within a program, you will need to link that program with the appropriate shared library, import library or static library for the platform (libuncursed.so, libuncursed.dll.a, or libuncursed.a); typically, you would just place -luncursed on your linker or compiler driver's command line and let it figure out the details. You will also need to include the header file, #include <uncursed.h>, in every C source file that mentions a libuncursed function or variable. (This header includes <stddef.h>, <stdarg.h>, and <wchar.h>; it also defines a number of private macros, typedefs, and the like, all of which start with uncursed_ or UNCURSED_, in addition to the functions, typedefs, and macros that are part of the public API.)

There is a standard naming convention for API functions (that is also used by curses):

  • Functions with no prefix operate on stdscr and the current cursor location;
  • Functions with a w prefix are identical to functions without the prefix, except that they take an extra WINDOW * argument as their first argument, which specifies which window to operate on;
  • Functions with a mv prefix are identical to functions without the prefix, except that they take two extra ints as their first and second arguments (which represent a y and x coordinate in that order), and move the cursor to the specified location before doing anything else;
  • Functions with a mvw prefix combine the above cases; they operate on a window specified as the first argument, and move the cursor to the coordinates specified by their second and third arguments before performing the requested operation.

Not all functions allow all prefixes; where prefixes are allowed, they will be mentioned in the API reference below.

Typedefs

wchar_t is a standard C94 definition (that is included from your system header files by libuncursed); there is also wint_t (which can fit either a wchar_t or an int, whichever is larger). The size of a wchar_t depends on your platform, and it represents one Unicode codepoint (libuncursed works using Unicode internally). Note that on some operating systems, characters outside the Basic Multilingual Plane do not fit in a wchar_t, and thus are not supported by libuncursed; this is typically not a problem, as those operating systems would be unable to render the characters in question anyway. Whenever libuncursed sees a plain char, it's interpreted as being encoded in code page 437 (a superset of ASCII, and the one most generally accepted by terminal emulators); although you should confine yourself to code page 437 if you can for portability reasons, we recommend using the Unicode versions of functions where possible so as to have the best possible Unicode support on systems and terminals where it exists.

WINDOW (a typedef for struct WINDOW) represents an uncursed window: these are rectangular buffers stored in memory, that contain characters and attributes. The fields of the structure should only be accessed via accessors, not directly. A window has a size, some contents, and a suggested screen location (as well as several settings that can be toggled, and a current attribute and cursor location); however, there is no particular reason why a window should necessarily fit within the screen, or indeed ever be drawn to the screen, so they can be used to store information independently of their screen coordinates. It is also possible to create multiple windows that are views into the same memory buffer; a "parent" window that is the buffer itself, and "child" windows that look at rectangular regions of it.

An attr_t is a numeric type that represents a text attribute: everything about one character on screen (color, underlining, etc.) apart from the codepoint that's being rendered itself. For curses compatibility, it is possible to bitwise OR an attr_t with a char to form a chtype, a character with a codepoint and attributes; however, this is unsatisfactory as it only works on code page 437 characters, rather than Unicode as a whole. Instead, we recommend using the cchar_t type (a typedef for a struct), which can be packed and unpacked from an attr_t and some wchar_ts using the setcchar and getcchar functions (as in ncursesw, the Unicode version of ncurses).

Finally, there is the uncursed_color type, which is a numerical type with a sufficient range to store color codes and color pair codes, and the uncursed_bool type, with enough range to store 0 and 1 (and possibly other values). Both these values can be safely stored in an int.

Global variables

Perhaps unfortunately, curses has a history of using global variables as one method of communication between the rendering library and the program using it.

WINDOW *stdscr is the default window created when uncursed is initialised. It is always the same size as the screen of the terminal that uncursed renders onto (which is likely to be a window in a GUI in practice, but "screen" will be used to describe it in this document because "window" is used to mean something else), and always has that entire screen as its suggested screen location. It should not be moved, resized, etc. by the program using libuncursed (although it can be resized by the user of the program, via resizing the terminal that uncursed is rendering onto).

int COLORS, int COLOR_PAIRS are integers that should be treated as read-only uncursed_color values. They specify the maximum number of colors in existence, and maximum number of color pairs (palette entries) that can be used at any one time. In curses, these would have been dynamically decided depending on the terminal; at present, libuncursed always gives these the values 16 and 32767 respectively, although it is probably best to read their values rather than hardcode the numbers in case they ever change.

int TABSIZE, defaulting to 8, is used to work out how far the cursor should advance if a program attempts to output a tab character. (It advances to the next column that's a multiple of TABSIZE.) This can be assigned to freely by the application that uses uncursed.

int LINES, int COLS give the screen dimensions. (You could also access these via querying the size of stdscr, but the existence of these variables is traditional and makes for shorter code.) These will be written to by libuncursed upon initialization and if the terminal is resized; programs that use libuncursed should only read from them, not assign to them.

Constants

These might be declared as macros, or as const global variables; don't rely on a particular implementation.

ERR, OK are the standard return values from libuncursed functions that return integers (unless they have some more meaningful value to return), and represent failure and success respectively. (There's also KEY_CODE_YES which is used only by get_wch, because apparently ncursesw's developers couldn't resist the concept of three-valued booleans.)

CCHARW_MAX gives the maximum number of characters (the base character plus any combining characters) that an be packed into a cchar_t. Note that in practice, terminals tend to be quite limited in their support for combining characters (even more so than in their support for Unicode in general); it's reasonable to use combining characters if you have no other option, but in general, it's going to be more portable if you just assume that this is 1. Terminals each have their own effective CCHARW_MAX limits, which might be lower or higher than libuncursed's; if you try to draw more combining charaters onto a part of the screen than the terminal can handle, expect rendering issues.

The 8 colors used by libuncursed are COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE. Terminals supported by libuncursed typically support 16 colors, but vary in the way that this is specified; some will use 8 colors, and then a brighter set of 8 colors to render bold (making 16 in total), and some just have 16 colors and make bold have no effect on color. libuncursed will transparently translate between the two methods according to what the terminal wants; thus, if you want a bright color, you can either use the A_BOLD attribute, or add 8 to a color code, or both, with all three methods having the same visual effect. (Going above 8 for a background color is not recommended; libuncursed will attempt to tell the terminal to produce a bright background color, but some terminals will react to this in some entirely unwanted way, such as via producing blinking text, and there is no way that libuncursed can detect this.)

There are likewise constants for the various text attributes. The constants supported by libuncursed are A_NORMAL, A_BOLD, and (on many but not all terminals) A_UNDERLINE. It also recognises some other names for compatibility with ncurses: A_INVIS and A_REVERSE are rendered via setting the foreground to the background, and swapping the foreground and background, respectively (and thus do not do anything that could not be accomplished simply using color), A_STANDOUT is a combination of various attributes that increase visibility (and should be avoided in favour of something more specific), and A_BLINK, A_DIM, A_PROTECT, A_ALTCHARSET are recognised but do not do anything at all.

There are also A_CHARTEXT (a mask that can be bitwise-ANDed to a chtype to get a char, or its complement bitwise-ANDed to a chtype to get an attr_t); COLOR_PAIR(x), a macro which constructs an attr_t from a color pair number; and PAIR_NUMBER(x), a macro that does the opposite, extracting a color pair number from an attr_t.

A large number of constants represent special characters by name (line-drawing characters and the like). There are WACS_* constants of type cchar_t *; and for constants in the first column, ACS_* constants of type char that approximate the WACS_* constants as closely as possible with codepage 437 characters (for backwards compatibility with curses programs, or if you really strongly don't care about Unicode support):

ACS_BLOCK    WACS_BLOCK     ▮
ACS_BOARD    WACS_BOARD     ▒
ACS_BULLET   WACS_BULLET    ·
ACS_CKBOARD  WACS_CKBOARD   ▒
ACS_DARROW   WACS_DARROW    ↓
ACS_DEGREE   WACS_DEGREE    °
ACS_DIAMOND  WACS_DIAMOND   ◆
ACS_GEQUAL   WACS_GEQUAL    ≥
ACS_LANTERN  WACS_LANTERN   ☃
ACS_LARROW   WACS_LARROW    ←
ACS_LEQUAL   WACS_LEQUAL    ≤
ACS_NEQUAL   WACS_NEQUAL    ≠
ACS_PI       WACS_PI        π
ACS_PLMINUS  WACS_PLMINUS   ±
ACS_RARROW   WACS_RARROW    →
ACS_S1       WACS_S1        ⎺
ACS_S3       WACS_S3        ⎻
ACS_S5       WACS_S5        ⎼
ACS_S7       WACS_S7        ⎽
ACS_STERLING WACS_STERLING  £
ACS_UARROW   WACS_UARROW    ↑

ACS_BTEE     WACS_BTEE      ┴    WACS_T_BTEE      ┻    WACS_D_BTEE      ╩
ACS_HLINE    WACS_HLINE     ─    WACS_T_HLINE     ━    WACS_D_HLINE     ═
ACS_LLCORNER WACS_LLCORNER  └    WACS_T_LLCORNER  ┗    WACS_D_LLCORNER  ╚
ACS_LRCORNER WACS_LRCORNER  ┘    WACS_T_LRCORNER  ┛    WACS_D_LRCORNER  ╝
ACS_LTEE     WACS_LTEE      ┤    WACS_T_LTEE      ┫    WACS_D_LTEE      ╣
ACS_PLUS     WACS_PLUS      ┼    WACS_T_PLUS      ╋    WACS_D_PLUS      ╬
ACS_RTEE     WACS_RTEE      ├    WACS_T_RTEE      ┣    WACS_D_RTEE      ╠
ACS_TTEE     WACS_TTEE      ┬    WACS_T_TTEE      ┳    WACS_D_TTEE      ╦
ACS_ULCORNER WACS_ULCORNER  ┌    WACS_T_ULCORNER  ┏    WACS_D_ULCORNER  ╔
ACS_URCORNER WACS_URCORNER  ┐    WACS_T_URCORNER  ┓    WACS_D_URCORNER  ╗
ACS_VLINE    WACS_VLINE     │    WACS_T_VLINE     ┃    WACS_D_VLINE     ║

Key codes

The other major group of constants is key codes. curses implementations are historically limited to a relatively small number of recognised keypresses, meaning that frequently if an unusual combination of keys were pressed, your application would not be able to respond to it at all. uncursed uses a much larger number of keypresses than in curses; KEY_MAX, the highest possible keypress code, is a much larger number than before, and thus should probably not be used if you're trying to do something like enumerate all possible keypresses or something like that.

Another deviation from curses is that key codes can potentially be produced even if there is no constant for them. This most frequently happens if the user presses a key on their keyboard that sends a code that is correctly formatted for the key-sending protocol in use (i.e. uncursed can parse it), but it doesn't correspond to any key that uncursed is aware of. In such cases, the key will be given an otherwise unallocated code based on what uncursed parsed from the representation of the key that it was sent; keyname will return a representation of a C expression that would produce this code, and friendly_keyname will return a string along the lines of Unknown101 that is (as far as possible) the same for the same keypress, and different for different keypresses. (Thus, although uncursed does not know what the key is, and thus your application doesn't either, your application will nonetheless be able to bind commands to the key via treating the key number as an opaque and meaningless identifier.)

One other thing to mention is an unfortunate historical accident. The DEC VT100, on which the protocol used to communicate with modern terminals was based, had a numeric keypad with four general-use keys above it (PF1, PF2, PF3, PF4); it also had a row of function keys (F1, F2, etc.), but the first few of these were not available to applications. Thus, when more modern keyboard layouts were introduced, such as the IBM PC layout used by the vast majority of modern systems, terminal emulator designers had to make a choice as to how to map their function keys so that they worked with the existing programs that were designed to work with a VT100. There were two major designs: some terminal emulators mapped F1-F4 on the PC keyboard (which aren't usable on a DEC) to PF1-PF4 in the protocol; and others associated the key codes with physical locations on the keyboard, thus PF1-PF4 would be produced via NumLock, numpad plus, numpad times, numpad divide. Therefore, if libuncursed sees a code of "PF1" arriving from the terminal, it can't know whether the user actually pressed F1, or NumLock. (Or is using a terminal that actually has a physical PF1 key.) In such a situation, it will return KEY_PF1 to the application, and leave the application to figure out what to do with it.

There are two sets of key codes that can be generated: keys that represent printable characters, and keys that represent other things. When using the Unicode function to obtain a key, get_wch, the two sets of key codes are separate; get_wch will return OK and store a (wchar_t) Unicode codepoint in its wint_t * argument if a Unicode character is entered by the user (either as a single key, or using some sort of input method such as dead keys or a compose key); and it will return KEY_CODE_YES and store a key code (an int) in its wint_t * argument if the user pressed a key that does not correspond to a Unicode character. None of the codes from 0 to 255 are used for key codes; thus, the backwards compatibility non-Unicode API, getch, will return either a single character or a key code, with the value determining which. Most functions that deal with a char interpret it as a character encoded in code page 437; however, the overwhelmingly most common way to produce a code from 128 up in a non-Unicode terminal is to use the Meta key (or sometimes the Alt key), which literally means "add 128 to the character code", and thus a code of, say, 193 should typically be interpreted as a capital 'A' (code 65) with 128 added to it, and rendered by applications as Meta-A. (It could also mean Á, Unicode and Latin-1 codepoint 193, but this is less likely; perhaps the most reasonable behaviour for an application is to use the Unicode/Latin-1 behaviour if they were expecting text to be input, and to treat it as a Meta-modified character otherwise.) uncursed will attempt to, as far as possible, distinguish between Meta and Alt, to help avoid this problem (Alt-A will, if possible, send the key code KEY_ALT | 'A', rather than the printable character code 193), but on some terminals it is impossible to distinguish.

One other point to note is the keys sent by the numeric keypad. uncursed will attempt to distinguish between numeric keypad keys and main keyboard keys, via using codes like KEY_A3 for the key on the numeric keypad that sends PgUp or 9 depending on the NumLock setting. (On most terminals, it is not possible to simultaneously determine the NumLock state, and also distinguish between main keyboard and numeric keypad 9; distinguishing which 9 was pressed is more useful to most roguelikes, which would want to use the numeric keypad 9 for movement but not the main keyboard 9.) There are commonly used terminals (such as gnome-terminal) for which it is impossible to distinguish; thus, the key in question would be sent as the printable '9' if NumLock were on, or as the key code KEY_PPAGE if NumLock were off.

There are also KEY_ALT, KEY_SHIFT, KEY_CTRL, that can be bitwise-ORed into any nonprintable key code. For printable keys, Shift and Ctrl tend to produce other printable keys; e.g. there is a code point in Unicode for Ctrl-A, and Shift-A is just a capital 'A' (with the A key on the keyboard normally generating a lowercase 'a'). There are no Unicode codepoints for Alt-combinations; thus, Alt-A has its own nonprintable key code defined, KEY_ALT | 'A'. (Unicode codepoints cannot normally be bitwise-ORed with modifiers like that; however, there is a KEY_ALT | code defined for all printable ASCII characters, as an exception to this rule.)

All KEY_ macros are reserved by uncursed for future expansion. Here are the currently defined key codes (for nonprintable keys):

Main keyboard keys

KEY_HOME       Home                 KEY_END        End
KEY_IC         Insert               KEY_DC         Delete
KEY_PPAGE      PgUp                 KEY_NPAGE      PgDn
KEY_UP         Up arrow             KEY_DOWN       Down arrow
KEY_RIGHT      Right arrow          KEY_LEFT       Left arrow
KEY_BREAK      Pause/Break          KEY_BTAB       Backtab (Shift+Tab)
KEY_BACKSPACE  Backspace            KEY_ESCAPE     Escape
KEY_PRINT      Print Screen

There are also KEY_F1 to KEY_F20 for function keys; some terminal emulators can simulate function keys beyond F12 using key combinations (even though keyboards rarely have more than 12 function keys nowadays), and uncursed will report these keys literally if it receives them. Bear in mind that F1 to F4 might be sent as KEY_PF1 to KEY_PF4 instead. KEY_PRINT is also a special case, because terminal emulators typically refuse to send it; it may be available via interface plugins other than tty, however.

The other common main keyboard keys send Unicode codepoints; Tab is in unicode at code point 9, and Return is at code point 13 (carriage return), or occasionally at code point 10 (newline), although libuncursed will attempt to tell the terminal to send code point 13. There's apparently a long standing flamewar over which code Backspace should send; it generally has its own code nowadays (which is why KEY_BACKSPACE exists), but some terminals will send it as code point 8 (making it indistinguishable from control-H). Escape also has a Unicode code point, at 27, but given that this code point is often used as part of a longer key code, libuncursed has to go to quite some trouble to disambiguate, and will send KEY_ESCAPE for a code 27 that appears to have been sent by the Escape key specifically.

Numeric keypad keys

KEY_A1  7/Home    KEY_A2  8/Up      KEY_A3  9/PgUp
KEY_B1  4/Left    KEY_B2  5         KEY_B3  6/Right
KEY_C1  1/End     KEY_C2  2/Down    KEY_C3  3/PgDn
KEY_D1  0/Ins                       KEY_D3  ./Del

KEY_ENTER      Enter
KEY_NUMPLUS    +
KEY_NUMMINUS   -
KEY_NUMTIMES   *
KEY_NUMDIVIDE  /

Remember that NumLock, divide, times, minus might be sent as KEY_PF1 to KEY_PF4. (In fact, terminals that send a code for NumLock at all tend to send it as KEY_PF1; thus, there is no separate KEY_NUMLOCK.) Some terminals send the same codes for numeric keypad keys as main keyboard keys; as such, we recommend that applications treat, say, KEY_A1 and KEY_HOME identically by default (thus allowing users with these terminals to be able to use the main keyboard and numeric keypad numbers differently simply via turning off NumLock).

Other key codes

If uncursed receives a key that it does not recognise, it will synthesize a key code for it; it will have no corresponding macro, but can be treated like an opaque identifier by the application (and will produce sensible output in response to keyname and friendly_keyname). There are also some key codes that do not correspond to keys on the keyboard, but to other things that might happen in response to a request for a key, and thus have to be returned by get_wch and getch:

KEY_UNHOVER  The mouse is no longer hovering over a defined hover region
KEY_SIGNAL   A message from a signal handler or another thread
KEY_OTHERFD  Input is available on a socket or pipe
KEY_RESIZE   The terminal was resized
KEY_INVALID  The terminal sent a malformed key code
KEY_HANGUP   The terminal no longer exists

KEY_MAX is the highest possible key code that will be generated by libuncursed (and, as a result of key modifier combinations and a large number of codes reserved for unknown keys, is quite large). You can use key codes strictly higher than KEY_MAX for your own uses (such as mouse callbacks).

KEY_SIGNAL and KEY_OTHERFD are only ever sent by your own application. Their purpose is to allow a program to accept input from multiple sources at once; you can call get_wch or similar in your main loop, and it will return KEY_OTHERFD if the data arrived on a file descriptor it was told to monitor, or KEY_SIGNAL if you called uncursed_signal_getch (most likely via use of a signal handler or a different thread). See the documentation for uncursed_signal_getch and uncursed_watch_fd for more information.

Note that KEY_RESIZE requires special handling by the application, and behaves differently from its behaviour in ncurses. In ncurses, when the terminal is resized, all windows will be moved and/or resized to fit, which normally completely garbles the screen. In uncursed, windows don't necessarily have to fit on the screen (they merely have a suggested screen location), but if a window protrudes beyond the screen, it cannot be drawn to the screen until it is moved or resized to fit. An application should thus react to KEY_RESIZE via moving, resizing and/or recreating windows itself, in order to adapt to the new screen layout, before it tries to do any more drawing.

KEY_HANGUP also needs special handling. After this is returned, all attempts to request input will return KEY_HANGUP, and no drawing commands will be meaningful, meaning that the application can no longer do user interaction. This code is often sent during system shutdown or in other situations where an application needs to shut down quickly, and there may be an operating-system-imposed time limit on how much time the application will be allowed to run, and thus the application should save or produce autosave data (if relevant), and exit as quickly as possible.

Functions

Unless otherwise stated, all functions returning int return OK on success and ERR on error.

Initialization

void initialize_uncursed(int *p_argc, char **argv)

One of the very first things an uncursed-using program should do is to initialize uncursed using the initialize_uncursed function. This does not do anything visible (like initscr would do); rather, it parses command-line arguments and loads the appropriate libraries that will later be needed. If something goes wrong, such as a library not being available, it will call exit() (which is a good reason to call initialize_uncursed right at the start of the program). The arguments are a pointer to your program's argc, and your program's argv; argc and argv will be modified to remove any arguments parsed by uncursed itself.

The requirement to call this function is the largest reason that uncursed is not a drop-in replacement for ncurses (although the two are very similar).

void uncursed_set_title(char *title)

Plugins that create a window need to know what title to give it, at window creation time. The default is "Uncursed"; if you want to set your own title, call this routine before calling initscr.

WINDOW *initscr(void)

This function tells libuncursed to take control of the terminal, and should be called before any other uncursed functions apart from initialize_uncursed, uncursed_set_title, and isendwin (variables like stdscr and LINES are not meaningful before running this function, although for compatibility with some other curses implementations stdscr will be NULL before initscr is called; and most of the rendering and input functions will cause segfaults or otherwise malfunction). Under most error conditions, it will exit the program (and if uncursed has not been initialized, it will crash the program with an abort signal, because this is a fault of the program itself rather than something like a failure to allocate memory). Otherwise, it will return stdscr (allowing you to avoid the use of global variables, if you wish).

After calling initscr, uncursed may gain control of stdin, stdout and stderr; your application should not try to use these standard file handles without first calling endwin, or it is likely to produce garbled output and/or receive garbled input.

initscr should only be called once per program; if you try to call it a second time, it will do nothing and return NULL. To tell libuncursed to take control of the terminal a second time, after it has relinquished it, use refresh.

When using interface plugins that create their own windows, rather than using an existing terminal, the call to initscr is what creates the window.

int endwin(void)

This function tells libuncursed to relinquish control of the terminal. It should be called just before your program exits in order to restore the terminal's settings to normal, and can also be called at other times if your program needs to write to stdout or stderr for some reason. If uncursed is using an interface plugin that creates its own window, rather than using an existing terminal, this will have no visible effect on the screen (although stdout/stderr will be reconnected to wherever they were connected before uncursed was run, most likely the terminal from which the uncursed-using program was run). If uncursed is using an existing terminal, this will attempt to restore as much of its state as possible to the state when initscr was called.

To undo the effects of endwin, use refresh. After endwin is called, refresh should be the next uncursed function to be called (not counting calls to isendwin, and unless the program just exits); anything else is undefined behaviour, and may garble the terminal or segfault.

uncursed_bool isendwin(void)

Returns a nonzero value if endwin has been called more recently than refresh, or if initscr has not been called yet, or a zero value otherwise. This function is an exception to the general rule that uncursed functions can only be called if uncursed has control of the terminal (because its purpose is to determine whether uncursed has control of the terminal).

void set_faketerm_font_file(char *filename)

Some uncursed interface plugins create their own window for rendering, perhaps because no acceptable terminal is available on the system. In such cases, there is a chance that there might not be an appropriate font available either, and thus such plugins require the use of this function (which should be called after initscr but before the first refresh) in order to specify which font to use. A font file should be a PNG image that contains the 256 characters of code page 437, 16 to a row and 16 rows high, in codepoint order. (All characters should be the same size, meaning that the dimensions of the image will both be divisble by 16.) The image should use a transparent background, and draw the characters themselves in white.

This function will be ignored by interface plugins that do not create a fake terminal; and if something goes wrong reading the file, it will print explanatory messages to the terminal from which the program was loaded, if any (because it cannot print to its own window), and continue to run but with no characters visible.

Input

int [w]get_wch([WINDOW* win], wint_t *codepoint_or_keycode)
int [w]getch([WINDOW* win])
int timeout_get_wch(int milliseconds, wint_t *codepoint_or_keycode)

Performs input; normally this will return a codepoint or a key code, although it can occasionally return other values like KEY_RESIZE or KEY_HANGUP. The Unicode version, get_wch, returns the input value in the wint_t pointed to by its last argument, and returns OK if it input a Unicode codepoint (in which case the wint_t value is a wchar_t, KEY_CODE_YES if it input a key that does not have a Unicode codepoint (in which case the wint_t value is an int that holds a key code value), or ERR if there was no input (typically because the window in question has a timeout set and there was no input within the given timeout). getch will return a key code value, an ASCII or meta-ASCII character, or ERR (these ranges do not overlap); it returns CANCEL CHARACTER (0x94) if the input was a Unicode character that does not fit into the Latin-1 range.

Should these functions return KEY_RESIZE (because the user resized the terminal), stdscr will be resized to match the new terminal size. Thus, a program must be very careful about calling drawing functions after a KEY_RESIZE, until it has moved all its windows back within the bounds of the screen.

The window argument is a legacy from ncurses. For getch (but for ncursesw compatibility, not get_wch), stdscr or the window specified will be refreshed before performing any input; additionally, the length of time to wait before giving up and returning ERR is a property of the specified window. If you prefer your input to be separate from your output, you can use the uncursed-specific function timeout_get_wch, which specifies the timeout to use explicitly rather than considering it to be a property of a window; use a value of -1 to wait indefinitely for a key, and otherwise a timeout in milliseconds. It is otherwise the same as get_wch.

int [w]timeout([WINDOW *win], int milliseconds)

getch and get_wch use the timeout of a window in order to know how long to block for before returning ERR. curses has a great range of functions that can be used to set this, but the preferred method for uncursed is the timeout function, which sets the timeout for a window; -1 means an infinite timeout (blocking until getch has something to return), 0 means to return immediately if no keypresses are already waiting, and positive values set a timeout in milliseconds. (Other functions from curses that set the timeout, and are implemented by uncursed for backwards compatibility but should not be used in new programs: halfdelay which measures in tenths of a second; nodelay that can only set zero or infinite timeouts; and nocbreak which has a lot of effects under curses, such as turning on line-at-a-time input, but whose only effect under uncursed is to set stdscr's timeout to infinite.)

int unget_wch(wchar_t codepoint)
int ungetch(int codepoint)

These functions (Unicode and ASCII respectively) cause the next input request to return the given codepoint (along the same lines of ungetc for getc). They return ERR if there is already a character waiting to be pushed back, OK on success.

wchar_t *wunctrl(wchar_t codepoint)
char *unctrl(char codepoint)
char *key_name(wint_t keycode)
char *keyname(int keycode_or_codepoint)
char *friendly_keyname(int keycode_or_codepoint)

These functions each return strings (which do not have const for backwards compatibility, but which should be considered read-only), that describe the name of a character. (The return value might be a literal string; it might also be a pointer to a static buffer, so it should not be assumed to be valid after the next call to one of these funtions.) unctrl, wunctrl will give a printable name for ASCII and Unicode codepoints respectively (which is typically just the codepoint itself, but which might be, say, ^A or M-e for control- or meta-modified keys); key_name gives a name (of the form KEY_LEFT, i.e. it descrites a key code constant) for a key code. keyname will operate either on (ASCII) codepoints, or on (ASCII or Unicode) key names (i.e., it can handle the values that getch outputs); and friendly_keyname is similar, but gives a more human-readable name (like Left or PrtSc).

Input from sources other than the terminal

uncursed does not input from sources other than its terminal, but it has functions to simplify its use by programs that take input from multiple sources, such as network sockets or signal handlers. (Trying to get a curses program to read from either the terminal or a network socket is very complex; the simplest method I know of involves multithreading, which is not very simple.)

void uncursed_signal_getch(void)

Causes the current or next call to get_wch, getch, or timeout_get_wch to return as if KEY_SIGNAL were pressed. Unlike every other uncursed function (which must be called on the same thread as initialize_uncursed and initscr), this function can safely be called from a signal handler, or a thread other than the thread that the other uncursed functions are running on (and in fact, this is the only way to call it during a call to get_wch). If this function is called multiple times between calls to get_wch, its effects will be queued, causing the same number of calls to get_wch to return KEY_SIGNAL (although those calls will not necessarily be consecutive, because they can be overriden by other unusual return values, such as KEY_RESIZE and KEY_HANGUP). There may be OS-dependent limits on how many signals can be queued up (likely in the low hundreds); when the limit is reached, the function may block, or else signals may be lost.

The intended use for this is to call get_wch in the main loop of your program, while a signal handler or separate thread waits in the background. When an event arrives that your main loop would need to know about, the signal handler or separate thread pushes information about it into an appropriately synchronized queue, then calls uncursed_signal_getch; the main loop will then read the KEY_SIGNAL and pop the information it needs from the queue.

void uncursed_watch_fd(int fd)
void uncursed_unwatch_fd(int fd)

uncursed_watch_fd causes future calls to get_wch, getch, or timeout_get_wch to return KEY_OTHERFD when input is available on the given file descriptor; uncursed_unwatch_fd undoes this effect. What constitutes a "file descriptor" depends on your operating system; on Windows, the only supported file descriptors are network sockets, and on POSIXy systems like Linux, Mac OS X, and BSD, descriptors for open pipes/fifos are also supported, as well as files representing character devices. "Input is available" means that it is possible to read from the given file descriptor without blocking. (Note that a file at EOF can usually be read without blocking; the read is not particularly interesting, but it doesn't block.)

When using libuncursed on Windows, watching a network socket will, as a side effect, cause it to go into nonblocking mode: this is a deficiency of the Windows API. (It may be simplest to manually set the socket to nonblocking mode on every operating system, to avoid having to deal with this special case. Note, however, that it is irrelevant whether the socket is blocking or not if you only read from it upon receiving a KEY_OTHERFD response, because it will already have been established that the reads cannot block.)

The KEY_OTHERFD return does not specify which file descriptor can be read from without blocking, so if you are watching more than one file descriptor, you will need to determine which one is readable via use of nonblocking reads, or perhaps the POSIX API function select().

The given file descriptor, fd, may be limited in range, due to the system calls used to monitor a descriptor for input. (For instance, it may need to be less than FD_SETSIZE on a POSIXy system.) It must also be in a state in which it would reasonably be possible to accept input from it (i.e. open and connected, for a network socket), and should not be closed until after it is unwatched.

The intended use for this is to be able to receive data from either the user or from a network connection; you call uncursed_watch_fd when you open the network connection, then read from it whenever the get_wch in your main loop returns KEY_OTHERFD.

Drawing windows to the screen

One of the major purposes of uncursed is to draw on the screen. The way in which this is accomplished is to first draw on windows (which happens in memory and produces no output on the screen), and then to copy the windows to the screen, which is the only point at which the screen actually updates.

int [w]refresh([WINDOW *win])

This function copies the contents of the specified window (or stdscr) to the screen, at its suggested screen location; and moves the screen's cursor to the same location as the window's cursor. (These routines must not be called, directly or indirectly, for a window that does not fit on the screen; doing so will likely corrupt memory or cause a segfault. This is a good reason to move windows so that they fit on the screen immediately after receiving a KEY_RESIZE.) As usual, they return ERR on error, OK on success.

refresh additionally can be used to undo the effects of endwin, once again giving uncursed control of the terminal.

int redrawwin(WINDOW *win)
int wredrawln(WINDOW *win, int first, int count)

These functions cause uncursed to forget any assumptions that it might have about the contents of the screen behind the suggested screen location of the specified window (or the suggested screen location of a particular range of lines of that window). This will cause the area behind the window to be repainted from scratch at the next refresh.

int wnoutrefresh(WINDOW *win)
int doupdate(void)

When several windows are to be copied to the screen at once, it is possible to gain some extra performance via performing the updates simultaneously. wnoutrefresh is identical to wrefresh, except that the update to the sreen is postponed until the next call to a function that would update the screen, or to doupdate, at which point all the updates happen at once.

Attributes and attributed characters

Each character on the screen has some number of codepoints (typically 1, but potentially more in the case of combining characters), and also some attributes (color, boldness, etc.). Some of the APIs in uncursed use these attributed characters direcly (cchar_t for the Unicode APIs, chtype for the curses compatibility APIs); others treat the character (wchar_t or char) separately from the attribute (attr_t).

Attributes such as bold simply have their own constants (such as A_BOLD), listed earlier. For colors, a palette is used; there are a number of customizable "color pairs", each of which has a background and a foreground color, and the color pairs can be converted from uncursed_color pair numbers to attr_t attributes using the COLOR_PAIR macro. Changing the definition of a color pair will (at the next screen refresh) recolor characters that use that pair.

int init_pair(uncursed_color pairnum,
              uncursed_color fgcolor, uncursed_color bgcolor)
int pair_content(uncursed_color pairnum,
                 uncursed_color *fgcolor, uncursed_color *bgcolor)

init_pair sets the color that the color pair pairnum represents, to the given foreground color fgcolor and background color bgcolor. pair_content retrieves the current definition of a color pair pairnum, storing its foreground and background color in *fgcolor and *bgcolor.

There are also some curses backwards compatibility functions, start_color, init_color, has_colors, can_change_color, color_content; none of these do anything useful in uncursed, simply returning a reasonable return value.

int getcchar(const cchar_t *cchar, wchar_t *characters,
             attr_t *attr, short *pairnum, void *unused)
int setcchar(cchar_t *cchar, const wchar_t *characters,
             sttr_t attr, short pairnum, void *unused)

These are the accessor and mutator functions for cchar_t structures. cchar is the cchar_t to access or mutate; characters is a null-terminated string of wchar_ts (the first character is a regular character that moves the cursor when printed, and all the other characters must be combining characters); attr is the attributes of the character; pairnum is the color pair number (short not uncursed_number for ncursesw compatibility); and unused is ignored (as it is in every curses implementation I know of; XSI Curses added it to allow for future expansion, and it has not yet been given any meaning). Normally, getcchar will place the fields of the cchar_t into the corresponding arguments, and setcchar will place the arguments into the fields of the cchar_t, but there are two exceptions. First, if getcchar is given a null pointer for characters, it will return the length of the string it would unpack there (rather than the usual OK/ERR), and perform no other action; second, any color pair in attr will be ignored by setcchar, in favour of the color pair number in pairnum. (getcchar will include the color pair portion of cchar in both pairum and attr.)

int [w]attrset([WINDOW *win], attr_t attr);
int [w]attron([WINDOW *win], attr_t attr);
int [w]attroff([WINDOW *win], attr_t attr);
int [w]color_set([WINDOW *win], uncursed_color pairnum);
int [w]attr_get([WINDOW *win], attr_t *attr, uncursed_color *pairnum,
                 void *unused);

When drawing to a window, the attribute used for newly drawn characters is based on the character's attributes and the window's default attributes (boolean attributes are simply bitwise-ORed together; it is not recommended to set a nonzero color pair number on both the character and the window). attrset/wattrset will set the default attributes for stdscr or for another window to the given value; attron and attroff include or exclude the given attributes from the window's set of default attributes, leaving any default attributes that weren't mentioned the same. None of those functions should be used to set a color pair attribute (it will frequently work in uncursed, but not if you try to set two color pairs simultaneously for the same window, nor in other curses implementations); use color_set to set a window's default color pair. attr_get allows you to query a window's current default attributes.

For curses compatibility, there are also functions attr_set, attr_on, attr_off that take an extra unused void * argument and are otherwise identical to the versions without the underscores; and functions standout, standend that are equivalent to attron(A_STANDOUT) and attrset(A_NORMAL) respectively.

Printing characters, attributes and strings

int [w]move([WINDOW *win], int y, int x)

Most output functions with no mv prefix draw at the window's current cursor location (actually, they draw at the window's current cursor location even with the prefix, but the prefix sets the cursor location before doing anything else, and thus the previous location is irrelevant). This function sets that location. (The top-left corner of the window is (0,0).)

int [mv][w]add_wch([WINDOW *win], [int y, int x], const cchar_t *ch)
int [mv][w]addch([WINDOW *win], [int y, int x], chtype ch)

int [mv][w]add_wch[n]str([WINDOW *win], [int y, int x],
                         const cchar_t *str, [int length])
int [mv][w]addw[n]str([WINDOW *win], [int y, int x],
                      const wchar_t *str, [int length])
int [mv][w]addch[n]str([WINDOW *win], [int y, int x],
                      const chtype *str, [int length])
int [mv][w]add[n]str([WINDOW *win], [int y, int x],
                     const char *str, [int length])

add_wch and addch output a single attributed character at the cursor location; the other four families functions output a string of attributed or non-attributed characters at the cursor location. (All these functions can use a mv prefix to move the cursor first, and/or a w prefix to output to a window other than stdscr; the string functions use an n infix to bound the length of the string, much like strnlen does.)

In general, the functions that use attributed characters will ignore the current default attribute of the window, whereas the functions that just use plain wchar_t or char wil respect it. The addch family is an exception, for curses backwards compatibility; it will combine the window's default attributes with the attributes given (which might lead to bizarre results if either has a nonzero color pair). Sticking to the Unicode functions, as recommended, will allow you to avoid this special case.

Outputting characters normally moves the cursor; backspace (codepoint 8) moves it backwards, tab (codepoint 9) moves it to the next multiple of TAB_STOP, newline (codepoint 10) moves it to the start of the next line, and other characters move it one space to the right (wrapping onto the next line when the edge of the window is reached). The addchstr family does not move the cursor, however, nor does it interpret cursor movement commands. The other string-related families allow a length of -1 to stop at the edge of the window, rather than wrapping onto the following line.

There are also echo_wchar, echochar variants of add_wch, addch, that call refresh (or wrefresh for wecho_wchar or wechochar) after outputing the character, and otherwise work identically.

int [mv][w]printw([WINDOW *win], [int y, int x], const char *format, ...)
int vw_printw(WINDOW *win, const char *format, va_list args)

These functions are the uncursed equivalents of printf and vprintf respectively; they take a printf-like format string, and arguments to fill in the format specifiers of that string (either as separate arguments for printw, or as a va_list for vw_printw), and print the characters one at a time using the window's default attribute. Sadly, there are no Unicode versions available at the moment.

int [mv][w]chgat([WINDOW *win], [int y, int x], int len,
                 attr_t attr, uncursed_color pairnum, void *unused)

In addition to the functions for drawing strings of characters, there is also a function for drawing strings of attributes; chgat will replace len attributes from the cursor position with the given atribute attr and color pair pairnum (with unused, as always, being ignored). The cursor does not move as a result of the attributes being drawn (although, of course, it can move as a result of any mv prefix).

More complex drawing

int [w]border_set([WINDOW *win],
                  const cchar_t *left_side,   const cchar_t *right_side,
                  const cchar_t *top_side,    const cchar_t *bottom_side,
                  const cchar_t *top_left,    const cchar_t *top_right,
                  const cchar_t *bottom_left, const cchar_t *bottom_right)
int box_set(WINDOW *win,
            cchar_t *vertical_sides, cchar_t *horizontal_sides)
int [mv][w]hline_set([WINDOW *win], [int y, int x],
                     const cchar_t *rendition, int length)
int [mv][w]vline_set([WINDOW *win], [int y, int x],
                     const cchar_t *rendition, int length)

These functions draw lines across, or boxes around, windows. (There are also non-Unicode versions for backwards compatibilty; these have no _set suffix, and use chtype rather than const cchar_t *.) The given renditions will be used to draw the relevant sides of a box, or the characters that make up a line (the window's current default attribute is ignored); for drawing lines, the left or top end of the line starts at the current cursor position (which does not move), and the line will be drawn to the given length, or as much as will fit into the window.

Clearing and copying windows

int [w]erase([WINDOW *win])
int [w]clrtobot([WINDOW *win])
int [w]clrtoeol([WINDOW *win])

These funtions replace the entire window contents, the window contents from the cursor onwards (the rest of the line, and all lines below), and the rest of the line (respectively) with blanks (spaces with no attributes).

int clearok(WINDOW *win)
int [w]clear([WINDOW *win])

The clearok function causes the entire screen to be repainted from scratch the next time the given window is refreshed; clear is a combination of erase and clearok. These functions would typically be used if the application's user had told the application that the screen was corrupted, or requested a full screen redraw, using a key combination designated for the purpose.

int overlay(WINDOW *from, WINDOW *to)
int overwrite(WINDOW *from, WINDOW *to)
int copywin(WINDOW *from, WINDOW *to, int from_miny, int from_minx,
            int to_miny, int to_minx, int to_maxy, int to_maxx,
            int skip_blanks)

These functions copy the contents of one window onto another, or (as an extension to curses) between two non-overlapping rectangles of the same window. overlay and overwrite each copy the entire source window onto the destination window, at the top-left corner, except that overlay does not copy any spaces (regardless of their attributes), leaving the original contents of the window intact. copywin allows an arbitrary rectangle to be copied onto an arbitrary window of the same size (if the windows being copied share storage, the retangles cannot overlap); skip_blanks controls whether spaces are copied or not.

Scrolling and shifting window contents

[w]insdelln([WINDOW *win], int distance)
[w]scrl([WINDOW *win], int distance)
[w]deleteln([WINDOW *win])
[w]insertln([WINDOW *win])
scroll(WINDOW *win)

These functions all shift part of the window contents vertically. insdelln will insert (with a positive argument) or delete (with a negative argument) the given number of lines at the current cursor y position, shifting the part of the window below the cursor downwards or upwards to accommodate the change; scrl is similar, but will scroll the entire window upwards with a positive argument, or downwards with a negative argument. Added lines will be filled with blanks (spaces with no attributes).

[mv][w]delch([WINDOW *win], [int y, int x])

This function will delete the character at the current window cursor location, scrolling the rest of the line to the left to compensate (and adding a blank at the end of the line).

scrollok(WINDOW *win, bool ok_to_scroll)

In addition to scrolling a window manually, windows can also scroll automatically when text is written past their last line. The scrollok function can be used to turn this behaviour on or off.

Window management

All these funtions that return a WINDOW * return NULL on error.

WINDOW *newwin(int height, int width, int top, int left)
WINDOW *subwin(WINDOW *parent, int height, int width, int top, int left)
WINDOW *derwin(WINDOW *parent, int height, int width, int top, int left)

These funtions create new windows; newwin creates a window that does not share its storage with any other window, whereas subwin and derwin create windows that share their storage with the given window (and thus, drawing to either window will automatically change the contents of the other). Subwindows created via subwin or derwin must be destroyed before their parent windows can be. For newwin and subwin, the top and left values are relative to the screen (with (0,0) being the top-left corner), and a value of 0 for height or width means to make the window touch the bottom or right edge of the sreen respectively. For derwin, the height and width must be positive, and the top and left values are measured relative to the parent window's suggested screen location. (Remember that although the height and width are important and determine how much storage is allocated for the window, the top and left are only suggestions, and only relevant upon drawing the window to the screen.)

WINDOW *mvderwin(WINDOW *win, int top, int left)

When creating a subwindow, it is also necessary to specify how the parent's and child's memories overlap. The child's memory will have its top-left corner at the given coordinates relative to the parent's memory. For subwindows created via derwin, the default location is the top and left given when creating the window; for subwindows created via subwin, the default location is the top-left corner of the parent's memory.

It is possible for a subwindow's memory to be outside the bounds of its parent's, as a result of mvderwin or wresize calls (or stdscr being resized because the user resized the terminal). When this happens, any attempt to write to or read from the subwindow may corrupt memory or cause a segmentation fault; the situation should be rectified via use of mvderwin or wresize before any drawing or updating is done on the subwindow.

int mvwin(WINDOW *win, int top, int left)

This function changes a window's suggested screen location; it works on both windows, and subwindows. It will error (and not move the window) if you try to set a suggested screen location that is not on the screen, based on the curses specification; such locations are meaningful, but normally unintended because such windows cannot be drawn.

int delwin(WINDOW *win)

This function deletes a window. (If it has any subwindows, those must be deleted first.)

int wresize(WINDOW *win, int height, int width)

This funtion resizes a window. The contents of the window will stay the same as far as possible, keeping the top-left the same; resizing a subwindow will fill any gained space with contents from its parent, resizing a non-subwindow will fill any gained space with blanks.

void wcursyncup(WINDOW *win)

curses has several functions (wsyncup, wsyncdown, syncok) for synchronizing windows and their subwindows; in uncursed, windows and their subwindows are automatically synchronized, so this is an unnecessary operation (and those functions are no-ops). However, uncursed (as with curses) allows a subwindow's cursor location to be in a different location from its parents'. wcursyncup will recursively set the cursor location of all the parents of a subwindow to be the same as that of the subwindow itself.

Tiles support

uncursed supports mostly transparent support for graphical tiles interfaces, allowing tiles to be easily added to a text-based program. (This is intended for use by games and especially roguelikes, which motivated the creation of uncursed.) All these functions (except get_tile_dimensions) are effectively no-ops in a terminal-based interface; they can create, delete, etc. tiles regions, but those regions will never be drawn to the screen.

void set_tiles_tile_file(char *filename, int height, int width)

This function sets the image file that will be used for the graphical tiles, and the dimensions of each tile within the image. (Tiles support is off by default; it is turned on or off using this function, using NULL for the filename to turn it off.) Changing the tileset will have an effect only on the tileset used by future calls to set_tiles_region; it wil not affect currently exiting tiles regions.

void [w]set_tiles_region([WINDOW *win],
             int tiles_h, int tiles_w, int tiles_t, int tiles_l,
             int char_h, int char_w, int char_t, int char_l)
void [w]delete_tiles_region([WINDOW *win])

Each window can have a "tiles region", that tells uncursed where to draw the tiles. After the window argument, the first four arguments give the height, width, top and left of the area of the window that will be covered by the tiles; the last four arguments give the area of the window that contains the ASCII/Unicode representation that is used for non-tiles interfaces. (In other words, your application draws characters, with associated tiles, to the second rectangle; the characters appear in the second rectangle, and the tiles are drawn in the first.) For most useful uses of this, the first rectangle would entirely contain the second, and in many cases, the two will be identical.

If the tiles are larger than the characters in their ASCII/Unicode representations (which is likely), and the tiles rectangle is not bigger than the character rectangle by enough to compensate, then only part of the character region can be shown in the tiles region. The part that is shown will depend on the window's cursor location, scrolling to attempt to keep the part of the tiles region that corresponds to the part of the character region under the cursor in view, while the cursor is in the character region. (The location of the tiles region is relevant only to determine where on the screen the tiles go; it is ignored for all other purposes.)

delete_tiles_region removes the tiles region of a window. (It is also removed if the window is deleted, resized, or changes suggested screen location.)

void get_tile_dimensions(int down, int across, int *height, int *width)

There is no particular reason in libuncursed why the tiles have to be the same size as the underlying characters (this distinguishes it from terminals such as Ebonhack which replace characters with tiles directly). Tiles-aware programs may thus want to produce a tiles region that is large enough to hold all the tiles (and thus is presumably larger than the character region). This function is given the dimensions of a character region in down and across (i.e. this is the number of tiles you want to appear in the tiles region, which is equal to the number of characters in the corresponding character region); it will assign to *height and *width to specify the minimum size of a tiles region that could fit the given tiles without scrolling (i.e. this is the number of characters that will be invisible due to being behind the tiles region). The function looks at nothing other than the tile file to determine this; it has no side effects, and in particular, there is no requirement that any tiles regions actually exist.

If uncursed is using a non-graphical interface plugin, it will set *height and *width to down and across respectively; this is because there is no visible tiles region in such a case, with the character region serving the purpose that the tiles region normally serves, and thus this gives the most accurate possible indication of how much room the "tiles" (actually just characters) take up on screen.

int [mv][w]set_tiles_tile([WINDOW *win], [int y, int x], int tile)

Sets the tile that corresponds to the character under the cursor; does nothing if the cursor is not in the window's character region. Does not move the cursor. If the tiles are partially transparent, it can be meaningful to call this multiple times in a row without moving the cursor; the first tile drawn (which should be opaque) will be placed at the bottom, and subsequent tiles nearer the top.

There is no way to clear a tile from a character, except by deleting the tiles region altogether (although you can overwrite a tile with another tile, if that other tile is opaque). When a tiles region is introduced, every character in the matching character region should be given an associated tile, otherwise what is drawn in the corresponding part of the tiles region will be undefined.

Windows with a tiles region may not be copied to or from using copywin or related functions.

Mouse support

uncursed supports mostly transparent support for a mouse. (Programs should not rely on a mouse being available.) It understands six sorts of mouse input:

uncursed_mbutton_left      Left click
uncursed_mbutton_middle    Middle click (or pushing in on the mouse wheel)
uncursed_mbutton_right     Right click (or sometimes control-left click)
uncursed_mbutton_wheelup   Mouse wheel moved upwards
uncursed_mbutton_wheeldown Mouse wheel moved downwards
uncursed_mbutton_hover     Mouse pointer moved onto the target

uncursed's API is rather different from ncurses' mouse API; instead of returning KEY_MOUSE on every sort of mouse input (no matter where it happens), you can customize what sort of return value you want from getch and friends for different sort of mouse input over different text. For instance, you can write a string that sends a, or KEY_LEFT, or even KEY_MAX + 1 to the screen when clicked on. This respects windows being covered by other windows; if you write non-mouse-active text above mouse-active text (say by refreshing the mouse-active window, then refreshing an overlapping non-mouse-active window), clicking on it will have no effect.

void uncursed_enable_mouse(int enable)

Use this function to enable (enable == 1) or disable (enable == 0) mouse input. (You probably want to put this under user control; while mouse input is being used, the mouse will not be usable for any commands that a terminal might normally use it for, such as selecting text.)

This function only controls the actual communication with the user. You can set text as mouse-active even with mouse input turned off; the text will be mouse-active but that mouse-active status will not do anything. This is potentially useful, because the mouse-active status will remain if mouse input is turned back on, so there's no need to redraw all your mouse-active text when changing mouse state.

void [w]set_mouse_event([WINDOW *win], enum uncursed_mousebutton button,
                        wint_t char_or_keycode, int which)

This function changes whether future text drawn in the given window is mouse-active, and in which way. You can think of mouse activity like an attribute; "mouse-active text" is not really any different from, say, "blue text" or "underlined text". button is the mouse action you want the text to respond to; char_or_keycode is a Unicode character or KEY_* constant; and which is OK if char_or_keycode is a Unicode character, KEY_CODE_YES if char_or_keycode is a KEY_* constant, or ERR to disable mouse activity for the given button (in future-drawn text). The standard use of the function would be to call wset_mouse_event just before drawing text to a window, draw the text, then do another wset_mouse_event call to undo the effects of the first call. The mouse activity that is set via set_mouse_event is also applied to any regions of the window that are cleared or erased; this is useful if, for instance, you want the entire window to respond to mouse wheel movement, rather than individual lines of text within it.

For the most mouse actions (all actions except hovers), doing the appropriate action while the cursor is above the mouse-active text will cause get_wch and similar functions to return the specified character or keycode. Hovers are slightly more complex; the specified character or keycode will be sent whenever the mouse is moved onto the hover-active text (whether or not it was previously over hover-active text), including from character to character within the hover-active text; and if the mouse is moved off hover-active text onto non-hover-active text, this will cause get_wch to return KEY_UNHOVER.

You can use key codes higher than KEY_MAX for your own purposes; for instance, you could do this to give every character on the screen a unique return for clicks or hovers. This is the only circumstance under which get_wch and friends will return values above KEY_MAX. (KEY_MAX itself should not be used; it might potentially be a valid key). However, you can also use keys that already have an existing meaning, in which case the mouse click will be indistiguishable from the keypress. (This is useful if, say, you have a status bar saying something like "Control-X: exit"; you could make the entire text click-active, sending a Control-X. It's also the easiest way to make menus click-active.)

When using tiles combined with the mouse, a tile in a tiles region will be mouse-active if the corresponding character in the corresponding character region is mouse-active. This preserves the standard API convention in which the tiles region is entirely driven by a character region (typically behind it).

void uncursed_clear_mouse_regions(void)

This function effectively places a transparent, non-mouse-active layer over the entire screen, causing anything currently on it to cease to respond to mouse input. Any mouse-active text in windows will remain mouse-active, though, and cause the area to become mouse-active again when they are next redrawn.

The intended use for this is when producing modal dialog boxes; you can clear mouse regions just before drawing your pop-up box, causing clicks outside it to have no effect (rather than sending keys that might potentially be misinterpreted because the context has changed). Once the dialog box is closed, your program can just refresh all the other windows on the screen (as it normally would upon closing a dialog box), causing them to become correctly mouse-active again.

Miscellaneous

int curs_set(int visibility)

This function changes whether the cursor is visible. Technically, the legal vaues are 0 (invisible), 1 (visible), 2 (very visible); however, 1 and 2 tend to have the same implementations in interface plugins in practice.

int raw(void)
int noraw(void) /* or */ int cbreak(void)

These functions control how the terminal should react to key combinations that normally have a special meaning to it (a common combination is Control-C, which on many operating systems will exit the currently running program). In curses, the difference between raw and cbreak modes is that raw mode will attempt to send these codes to the application, whereas cbreak will send them to the terminal; uncursed respects this distinction, treating the modes the same way. (Unlike curses, uncursed is always in either raw or cbreak mode; it cannot be shifted into, say, cooked mode.) Some terminals or operating systems may have key combinations that override even raw mode (such as Control-Alt-Delete on Windows which cannot be intercepted by applications, or Alt-SysRq-R on Linux which has the specific purpose of forcibly taking terminal applications out of raw mode).

int beep(void)
int flash(void)

These functions trigger an audible and visible bell, respectively.

int delay_output(int milliseconds)

This function causes a delay of the given number of milliseconds. (ncurses uses pipelining for this: the delay can happen on the terminal in parallel with your programming doing processing. libuncursed might implement this optimization in future, but at present, it doesn't.)

int use_default_colors(void)
int assume_default_colors(int foreground, int background)

These functions (which use int rather than uncursed_color for ncurses compatibility) allow the application to change the meaning of color pair 0. assume_default_colors sets the foreground and background of color pair 0 to the given values (-1 means the default value for the terminal); use_default_colors sets them both to the default value for the terminal.

Note that on many terminals, the default color is not one of the 16 colors in the terminal palette (and it can even be something bizarre like "transparent" or "background image"), and it may (in fact, normally does) look different as a foreground and as a background; note also that setting a foreground color but not a background color, or vice versa, is a recipe for having some users unable to see your text because its color is too similar to the background.

After calling use_default_colors, -1 also becomes accepted as a color value for init_pair. (In fact, uncursed also accepts it even without calling use_default_colors, but this is incompatible with ncurses and thus should be avoided.)

Implemented but ignored for curses compatibility

The following extra curses functions are implemented by uncursed with appropriate signatures and return values, but do not do anything useful (mostly because they request uncursed to do something it would do anyway, or because their only effect is to tell curses that a specific optimization is reasonable):

touchwin, touchline, untouchwin, wtouchln, nonl, leaveok, typeahead, notimeout, qiflush, noqiflush, meta, keypad, intrflush, noecho.

Writing a new plugin for uncursed

libuncursed is eventually intended to support multiple kinds of plugins, but at the moment it only supports interface plugins (as they are known internally, "input plugins", because they produce input to the program in addition to handling output).

Plugins should include the "uncursed_hooks.h" file, create a new struct uncursed_hooks structure, and send it to the main part of libuncursed via the uncursed_hook_list variable. (To accomplish this, a C++ wrapper file is used that does the importing, because C files cannot have side effects upon being loaded; the wrapper is both very simple and highly regimented in structure, so it's best to simply copy and modify an existing wrapper.)

The structure contains a number of function pointers, which allow libuncursed to call into the plugin (conventionally named with the plugin name and then _hook_, as in tty_hook_init, although this is not required); the plugin can call back into libuncursed via routines with names starting uncursed_rhook_.

Calls from libuncursed into a plugin

Each of these is a function pointer stored in a field of the plugin's uncursed_hooks structure.

Initialization, shutdown

void (*init)(int *lines, int *cols, char *title)
void (*exit)(void)

The init function implements initscr and the endwin-cancelling effect of refresh, and tells the plugin to do what is necessary to start up and (if necessary) take control of the terminal. The lines and cols arguments should be filled with the size of the terminal, and will be used by libuncursed to allocate data structures, as well as being available to a user of uncursed in the LINES and COLS variables. title specifies the window title, for ports that care. exit handles any shutdown code required to relinquish control of the terminal. (For plugins that create fake terminals, it should be a no-op, or nearly so; if they need to do special handling on exit, it should be in an atexit-registered function, because nothing tells libuncursed when the program is about to exit.)

Cursor handling

void (*setcursorsize)(int size)
void (*positioncursor)(int y, int x)

Sets the cursor size (0 means the cursor should be hidden, 1 and 2 are visible cursors which may or may not be implemented as different from each other, with 2 being more visible than 1), or position (with (0, 0), as always, being the top left corner).

Screen redraws

void (*update)(int y, int x)
void (*fullredraw)(void)
void (*flush)(void)

When libuncursed wants an interface plugin to redraw all or part of the screen, it uses these functions. update tells the plugin to redraw the character at a particular point of the screen; fullredraw tells it to redraw the entire screen from scratch (which might or might not be different from updating each character individually, depending on the plugin); flush will be called at the end of a series of updates, and interface plugins may if they wish postpone any actual updating until the flush is called (or do it immediately, or at any time in between). For instance, double-buffered interfaces would swap buffers on a flush; the tty interface uses stdio buffering for its output, which might be flushed by the stdio library when the buffers get full, and flushes the buffers itself manually on a flush.

These functions do not contain any information about what the plugin should draw; rather, it needs to obtain that information by calling back into libuncursed and asking for it, using the uncursed_rhook_*_at hooks. The interface is allowed to update more than the requested region if it wishes (and can use uncursed_rhook_needsupdate to determine whether updating a character would be useful, if for some reason it wants to do updates out of order), and can request the information of any part of the screen in order to perform its update (e.g. in case if for some reason, updating one character would disturb neighbouring characters). The interface should call uncursed_rhook_updated when it updates any character of the screen (whether it was requested to be updated or not), so that libuncursed does not send spurious requests to update it until the next time it actually changes.

Input

int (*getkeyorcodepoint)(int milliseconds)

libuncursed uses this to request one key or codepoint from the terminal; codepoints should be returned as their Unicode value, whereas keys should be returned as their key code plus KEY_BIAS (a constant declared in "uncursed_hooks.h", chosen so that there will be no clashes between keys and codepoints). If no keys or codepoints are available for milliseconds milliseconds, the interface should instead return KEY_SILENCE + KEY_BIAS; if the terminal is resized during the call to getkeyorcodepoint (or before the call but after the previous call), it should call uncursed_rhook_setsize to notify libuncursed of the new size, and then return KEY_RESIZE + KEY_BIAS.

Graphical

All these hooks are only meaningful for graphical interface plugins; plugins that are entirely text-based can and should set these to NULL.

void (*set_faketerm_font_file)(char *filename)

Informs a graphical interface plugin of the font file it should use to do rendering.

void (*set_tiles_tile_file)(char *filename, int rows, int columns)

Informs a graphical interface plugin of the tile file it should associate with tiles regions that are allocated in the future, together with the size of that file (in tiles).

void *(*allocate_tiles_region)(int height, int width,
   int loc_height, int loc_width, int loc_top, int loc_left)
void (*deallocate_tiles_region)(void *region)

allocate_tiles_region requests a graphical interface plugin to create a new tiles region. A tiles region is a rectangular graphical area on which tiles are drawn, and has a specified size (measured in tiles); it is associated with a rectangular area of the screen, given in characters, which is the location on which the tiles region, or subsets of it, will eventually be drawn. (There is no particular reason why the two areas should be the same size; if the tiles region is smaller, it should be drawn centered on its location, with the remainder filled with a solid color or simple pattern; if the tiles region is larger, only a subset of it should be drawn, aiming to keep the tile associated with the cursor location in view whenever there is a tile associated with a cursor location.) The tiles region itself will be treated as an opaque pointer by libuncursed (although it will in practice most likely be a structure containing an image and some metadata); libuncursed may request its deallocation with deallocate_tiles_region.

void (*draw_tile_at)(int tile, void *region, int y, int x)

Tells a graphical interface to draw a specified tile at the specified location of the specified tile region. (The tile will eventually be drawn to the screen when update is called, and that region is returned by uncursed_rhook_region_at.) It is possible that a badly behaving application may cause libuncursed to send negative or out of range values for the coordinates y and x; interfaces should do their own bounds checks, if necessary.

Miscellaneous

void (*beep)(void)

Produces an audible beep, if possible. (There is no hook for flash; uncursed synthesizes this itself out of palette changes and redraw instructions.)

void (*delay)(int milliseconds)

Produces a delay in the output from the interface plugin. (If there is no threading or pipelining going on, this can simply be implemented via a delay function such as usleep.)

void (*rawsignals)(int capture_all_keys)

The argument to this function is a boolean-like int, which specifies whether the interface plugin should attempt to input all keys, including combinations with special meanings such as Control-C (capture_all_keys is 1); or only the keys which are normally intended as input to applications (capture_all_keys is 0).

Future expansion

The function pointers recordkeyorcodepoint, resized, startrecording, and stoprecording all exist in the uncursed_hooks structure, but should be set to NULL. (They will eventually become part of a recording/broadcast API.)

Calls from plugins into libuncursed

Querying characters to draw

char uncursed_rhook_cp437_at(int y, int x)
char *uncursed_rhook_utf8_at(int y, int x)
unsigned short uncursed_rhook_ucs2_at(int y, int x)

Queries the character at a particular screen location. The function you would use depends on the encoding you want; UTF-8 gives the most information, as it can handle combining characters (the return value is a pointer to a static array, so should be copied if it needs to remain valid past the next call to uncursed_rhook_utf8_at or past the end of the hook function that calls it); UCS-2 can handle a subset of Unicode (the Basic Multilingual Plane), and is provided because this encoding is currently used on Windows; and for interfaces that cannot handle Unicode, code page 437 codepoints are also available.

int uncursed_hook_color_at(int y, int x)
void *uncursed_hook_region_at(int y, int x)

Queries other information about how to render a particular screen location. The "color" uses 17-color codes (which should be converted to 8+bold by the interface if necessary), ranging from 0 to 16; the 16th color represents the terminal default. They are packed into a single integer, treating it as a bitfield; the low 5 bits are the foreground color, the next 5 bits the background color, and the 11th (1024s) bit is set if the interface plugin should underline the character. The region value is non-NULL if the interface should draw from a tile region rather than render a character; the interface is responsible for calculating which part of the tile region to draw, based on the bounds of the region, the location of the character, and the cursor location (and may have to update the entire tile region in response to cursor movements; this is part of the reason that interfaces are allowed to request information proactively without waiting for an update to be sent).

Update control

void uncursed_rhook_updated(int y, int x)
int uncursed_rhook_needsupdate(int y, int x)

Whenever an interface updates a character (whether in response to a request to do so or not), it should notify libuncursed of the fact using the updated reverse hook. It can also query whether a character needs an update or not; this is quite an expensive operation, and mostly useful if it allows an interface to produce lasting improvements in the quality of its output (the tty interface uses this to avoid producing output that has no effect, which would increase the size of recordings).

Miscellaneous

void uncursed_rhook_setsize(int lines, int cols)

This should be called by a interface immediately before returning KEY_RESIZE + KEY_BIAS from getkeyorcodepoint, to notify libuncursed of what the new terminal size is. (Before getkeyorcodepoint is called, the program using libuncursed will be unaware that the size has changed; interfaces must therefore be prepared to tolerate out-of-bounds requests. libuncursed will tolerate out-of-bounds requests in reverse hooks for the same reason, returning plausible data, in order to avoid a crash.)