YASCREEN(3)
π YASCREEN(3) β the yascreen manual, bestie edition π
User-Manual Β· YASCREEN(3)
β¨ NAME β¨
yascreen β Yet Another Screen Library (aka your new fave curses replacement for daemons and embedded apps π«Ά)
πΈ SYNOPSIS πΈ
#include <yascreen.h>
π¦ DESCRIPTION π¦
π Main features
okay so here's the whole vibe, no cap:
- tiny footprint, she's smol π
- zero external dependencies β she doesn't need anybody
- both internal and external event loops are supported, pick your fighter
- works with
stdin/stdoutor external input/output (yes bestie, she can literally run over a socket π₯) - supports a basic set of telnet sequences, which makes her perfect for built-in terminal interfaces for daemons
- supports a limited set of input keystroke sequences
- fully unicode compatible (tho parts of this depend on
wcwidthinlibc, just so you know) - utf8 verification of input? supported β¨
- utf8 input and wide character input? also supported β¨
- non-utf8 input mode? yup, that too
- relies only on a limited subset of ansi/xterm ESC sequences, so she plays nice with basically all modern terminals (inspired by linenoise β¨https://github.com/antirez/linenoiseβ©)
- there is no curses API and no ancient terminal compatibility, hence less bloat β we don't do that here
- there is no autoconf β there is no need to have one, periodt
- clean API with opaque private data, usable from C/C++ π
- easy cross compilation setup (just by setting
CC,ARandRANLIB)
Current development is done on Linux, with additional testing on OpenBSD/FreeBSD; other platforms may need minimal fixes.
On *BSD a gmake is required to build. not optional, bestie π
π§ Architecture
yascreen uses an opaque data structure, allocated by the library and dynamically resized when needed β that's yascreen_init(int sx, int sy) / yascreen_resize(yascreen *s, int sx, int sy). An application may specify (0,0) for both calls to let yascreen detect the size, or use a fixed size. In case the terminal has zero size or does not support the TIOCGWINSZ ioctl, the size will default to 80x24.
There are two modes of operation β telnet protocol over socket or running in terminal. For sockets the event loop would typically be handled outside of the library, while for terminals a built-in event loop may be used.
Modes of operation can be modified at runtime. β¨
For terminal use, signal handling (SIGWINCH) should always be handled by the application. always always, don't skip this one π
π Example initialization for terminal and handling of SIGWINCH
yascreen *s;
int winch=0;
void sigwinch(int sign) {
winch=1;
}
s=yascreen_init(0,0); // let yascreen get term size
yascreen_term_set(s,YAS_NOBUFF|YAS_NOSIGN|YAS_NOECHO);
signal(SIGWINCH,sigwinch);
for (;;) { // main loop
if (winch) {
winch=0;
if (yascreen_resize(s,0,0))
// handle a fatal error - no memory
// get the new sizes and redraw
newsizex=yascreen_sx(s);
newsizey=yascreen_sy(s);
}
β¦
// option 1
// input is handled in external event loop and fed to yascreen via yascreen_feed
if (FD_ISSET(STDIN_FILENO,&r)&&sizeof c==read(STDIN_FILENO,&c,sizeof c))
yascreen_feed(s,c); // pump state machine with bytestream
// keys are processed only when available without delay/blocking
while ((ch=yascreen_getch_nowait(s))!=YAS_K_NONE) {
// handle processed keys
}
β¦
// option 2
// input is handled by yascreen and key or YAS_K_NONE is returned not longer than TIMEOUT ms
// note: if screen update is based on this, keypresses will force it
while ((ch=yascreen_getch_to(s,TIMEOUT))!=YAS_K_NONE) {
// handle processed keys
}
β¦
// option 3
// input is handled by yascreen and the following call will block until a key is pressed
if ((ch=yascreen_getch(s))!=YAS_K_NONE) {
// handle processed key
}
}
For sockets, input is handled like option 1 in the example above, and yascreen needs to be provided with a callback for output.
In multiprocess mode daemons where stdin/stdout are redirected to a socket, the same model from the example above can be used. Obviously SIGWINCH will work only for terminals, and for sockets the screen size can get to be known either via telnet or ASNI sequences.
π Example initialization for socket with external event loop and telnet sequences processing
yascreen *s;
s=yascreen_init(80,25); // there is no guarantee that screen size detection is supported on the remote end
yascreen_setout(s,output_cb); // set callback for output
yascreen_set_telnet(s,1); // enable processing of telnet sequences
yascreen_init_telnet(s); // try to negotiate telnet options (regardless if telnet processing is enabled)
yascreen_reqsize(s); // request initial screen size
for (;;) { // main loop
β¦
yascreen_feed(s,c); // feed input from the socket to yascreen
// keys are processed only when available without delay/blocking
while ((ch=yascreen_getch_nowait(s))!=YAS_K_NONE) {
// handle processed keys
// screen size change is reported as a special keypress code:
if (ch==YAS_TELNET_SIZE||ch==YAS_SCREEN_SIZE) // screen size change reported via telnet or ANSI sequence
// redraw
}
}
π API Reference π
π Predefined constants and Helper macros
Internally, style is kept into bitfields in a single integer variable β and that includes foreground/background colors plus style modifiers (bold, italic, underline, inverse and blink).
β Style codes
YAS_ITALICβ italicYAS_UNDERLβ underlineYAS_STRIKEβ strikeoutYAS_INVERSEβ inverseYAS_BOLDβ boldYAS_BLINKβ blink
πΈ Color codes
YAS_BLACKβ blackYAS_REDβ redYAS_GREENβ greenYAS_YELLOWβ yellowYAS_BLUEβ blueYAS_MAGENTAβ magentaYAS_CYANβ cyanYAS_WHITEβ whiteYAS_FGCOLORDEFβ default terminal foregroundYAS_BGCOLORDEFβ default terminal background
π¦ Helper macros
YAS_FG(attribute)β extract foreground colorYAS_BG(attribute)β extract background colorYAS_FGCOLOR(color)β shift simple color value into foreground colorYAS_BGCOLOR(color)β shift simple color value into background colorYAS_FGXCOLOR(color)β shift 256 palette color value into foreground colorYAS_BGXCOLOR(color)β shift 256 palette color value into background color
All of the above can be or'ed into attribute, provided that the bits for foreground/background color are all zeroes. π
π Key codes
- Special, generated internally
Okay so real talk, bestie β previous versions of the library used -1 and 0x100+ for these codes. But to get that unicode wide character compatibility and a simpler API, the reserved Unicode range 0xf0000-0xffffd is now used for the special codes, both in narrow and wide character input modes. π
There's a macro YAS_IS_CC(code) that will evaluate to non-zero for the special codes and to zero for normal characters. Note that all ASCII control characters in the range 0x00-0x7f are treated as normal ones. No cap. π§
Here's the special-codes vibe check:
YAS_K_NONEβ0xf0000β no key is available; in time limited mode means that the time limit expired πYAS_SCREEN_SIZEβ0xf0701β notification for screen size change (may come because of telnet or ANSI sequence) π¦YAS_TELNET_SIZEβ0xf0702β notification for a possible screen size change, reported via telnet without valid size data; the size should be redetected (e.g. withyascreen_reqsize) π- Normal keys β¨
YAS_K_NUL(0x00) β the Nul key, bestie. on some terminals that's Ctrl-2 πYAS_K_C_A(0x01) β Ctrl-A β¨YAS_K_C_B(0x02) β Ctrl-BYAS_K_C_C(0x03) β Ctrl-CYAS_K_C_D(0x04) β Ctrl-DYAS_K_C_E(0x05) β Ctrl-EYAS_K_C_F(0x06) β Ctrl-FYAS_K_C_G(0x07) β Ctrl-GYAS_K_C_H(0x08) β Ctrl-H, but ngl it depends on the terminal π go look atYAS-K-BSPandYAS-K-C-8for the whole situationYAS_K_C_I(0x09) β Ctrl-IYAS_K_TAB(0x09) β Tab π (same byte as above, iconic twin behaviour)YAS_K_C_J(0x0a) β Ctrl-JYAS_K_C_K(0x0b) β Ctrl-KYAS_K_C_L(0x0c) β Ctrl-LYAS_K_C_M(0x0d) β Enter, Return, Ctrl-M; peep below for the tea πYAS_K_RET(0x0d) β Enter, Return, Ctrl-M; see above, it's the same vibe π«ΆYAS_K_C_N(0x0e) β Ctrl-NYAS_K_C_O(0x0f) β Ctrl-OYAS_K_C_P(0x10) β Ctrl-PYAS_K_C_Q(0x11) β Ctrl-QYAS_K_C_R(0x12) β Ctrl-RYAS_K_C_S(0x13) β Ctrl-SYAS_K_C_T(0x14) β Ctrl-TYAS_K_C_U(0x15) β Ctrl-UYAS_K_C_V(0x16) β Ctrl-VYAS_K_C_W(0x17) β Ctrl-WYAS_K_C_X(0x18) β Ctrl-XYAS_K_C_Y(0x19) β Ctrl-YYAS_K_C_Z(0x1a) β Ctrl-ZYAS_K_ESC(0x1b) β Esc, Ctrl-3; see below π every single ANSI sequence starts with Esc, and this is what gets returned after a timeout or a double Esc β³YAS_K_C_3(0x1b) β Esc, Ctrl-3; see above π all ANSI sequences start with Esc, and this is returned after a timeout or double Esc, same as its twin πYAS_K_C_4(0x1c) β Ctrl-4YAS_K_C_5(0x1d) β Ctrl-5YAS_K_C_6(0x1e) β Ctrl-6YAS_K_C_7(0x1f) β Ctrl-7YAS_K_SPACE(0x20) β Space πΈYAS_K_EXCL(0x21) β !YAS_K_DQUOT(0x22) β "YAS_K_HASH(0x23) β #YAS_K_POUND(0x24) β $YAS_K_PERC(0x25) β %YAS_K_AND(0x26) β AmpersandYAS_K_QUOT(0x27) β 'YAS_K_OBRA(0x28) β ( -YAS_K_CBRAβ0x29, that's your)right curly baby πYAS_K_STARβ0x2a, the*asterisk bestie β¨YAS_K_PLUSβ0x2b,+plus, iconic πYAS_K_COMMAβ0x2c,,comma, yes she pauses βYAS_K_MINUSβ0x2d,-minus, lowkey underratedYAS_K_DOTβ0x2e,.periodt. literally periodt πYAS_K_SLASHβ0x2f,/forward slash, main character of every path π¦YAS_K_0β0x30, the0key πΈYAS_K_1β0x31, the1key πΈYAS_K_2β0x32, the2key πΈYAS_K_3β0x33, the3key πΈYAS_K_4β0x34, the4key πΈYAS_K_5β0x35, the5key πΈYAS_K_6β0x36, the6key πΈYAS_K_7β0x37, the7key πΈYAS_K_8β0x38, the8key πΈYAS_K_9β0x39, the9key πΈYAS_K_COLONβ0x3a,:colon, it's giving explaining things πYAS_K_SEMIβ0x3b,;semicolon, the C programmer's roman empire πYAS_K_LTβ0x3c,<less-than, redirecting ur vibes π«ΆYAS_K_EQβ0x3d,Equalβ (yes bestie, the table literally just saysEqual, no=glyph, and we respect the source π)YAS_K_GTβ0x3e,>greater-than, the other half of every redirect π₯YAS_K_QUESTβ0x3f,?question mark, curious girly πYAS_K_ATβ0x40,@at sign, tagging everyone in the group chat π£YAS_K_Aβ0x41,AπYAS_K_Bβ0x42,BπYAS_K_Cβ0x43,CπYAS_K_Dβ0x44,DπYAS_K_Eβ0x45,EπYAS_K_Fβ0x46,FπYAS_K_Gβ0x47,GπYAS_K_Hβ0x48,HπYAS_K_Iβ0x49,IπYAS_K_Jβ0x4a,JπYAS_K_Kβ0x4b,KπYAS_K_Lβ0x4c,LπYAS_K_Mβ0x4d,MπYAS_K_Nβ0x4e,NπYAS_K_Oβ0x4f,OπYAS_K_Pβ0x50,PπYAS_K_Qβ0x51,QπYAS_K_Rβ0x52,RπYAS_K_Sβ0x53,SπYAS_K_Tβ0x54,TπYAS_K_Uβ0x55,UπYAS_K_Vβ0x56,VπYAS_K_Wβ0x57,WπYAS_K_Xβ0x58,XπYAS_K_Yβ0x59,YπYAS_K_Zβ0x5aβZπYAS_K_OSQβ0x5bβOpenSquareBracketYAS_K_BSLASHβ0x5cβBackslashYAS_K_CSQβ0x5dβCloseSquareBracketYAS_K_CARRETβ0x5eβ^YAS_K_USCOREβ0x5fβUnderscoreYAS_K_BTICKβ0x60βBacktickYAS_K_aβ0x61βaYAS_K_bβ0x62βbYAS_K_cβ0x63βcYAS_K_dβ0x64βdYAS_K_eβ0x65βeYAS_K_fβ0x66βfYAS_K_gβ0x67βgYAS_K_hβ0x68βhYAS_K_iβ0x69βiYAS_K_jβ0x6aβjYAS_K_kβ0x6bβkYAS_K_lβ0x6cβlYAS_K_mβ0x6dβmYAS_K_nβ0x6eβnYAS_K_oβ0x6fβoYAS_K_pβ0x70βpYAS_K_qβ0x71βqYAS_K_rβ0x72βrYAS_K_sβ0x73βsYAS_K_tβ0x74βtYAS_K_uβ0x75βuYAS_K_vβ0x76βvYAS_K_wβ0x77βwYAS_K_xβ0x78βxYAS_K_yβ0x79βyYAS_K_zβ0x7aβzYAS_K_OCURβ0x7bβ{YAS_K_PIPEβ0x7cβPipeYAS_K_CCURβ0x7dβ}YAS_K_TLDβ0x7eβTildeYAS_K_C_8β0x7fβBackspace; see below; depends on terminal see YAS-K-C-HYAS_K_BSPβ0x7fβBackspace; see below; depends on terminal see YAS-K-C-H
okay bestie, we literally just did the whole lowercase alphabet π
like every single letter a through z got its own little glow-up with a name that is justβ¦ the letter. no cap, YAS_K_a is a. iconic. no notes. π
and yes, <pink>YAS_K_C_8 and <pink>YAS_K_BSP are both sitting on 0x7f β same byte, two names, and the description is doing the most: <yellow>Backspace; see below; depends on terminal see YAS-K-C-H. that "see below" is not me being vague, that's genuinely what it says, so hold that thought because the explanation is further down the page. iykyk. π
- Extended keys, parsed from ANSI sequences β¨
and those? oh bestie, those are a whole other vibe, and they're coming right upβ¦ π
okay so this is the part where we get into the actual key codes, and bestie there are so many of them π every function key comes in four flavors β plain, Shift, Ctrl, and Alt β and each one gets its own special number. Keep these handy, you're gonna be matching them in your event loop like:
YAS_K_F1β0xf0001β the F1 key πYAS_K_F2β0xf0002β F2YAS_K_F3β0xf0003β F3YAS_K_F4β0xf0004β F4YAS_K_F5β0xf0005β F5YAS_K_F6β0xf0006β F6YAS_K_F7β0xf0007β F7YAS_K_F8β0xf0008β F8YAS_K_F9β0xf0009β F9YAS_K_F10β0xf000aβ F10YAS_K_F11β0xf000bβ F11YAS_K_F12β0xf000cβ F12
and now the Shift era begins β¨ same keys, new attitude:
YAS_K_S_F1β0xf000dβ Shift-F1YAS_K_S_F2β0xf000eβ Shift-F2YAS_K_S_F3β0xf000fβ Shift-F3YAS_K_S_F4β0xf0010β Shift-F4YAS_K_S_F5β0xf0011β Shift-F5YAS_K_S_F6β0xf0012β Shift-F6YAS_K_S_F7β0xf0013β Shift-F7YAS_K_S_F8β0xf0014β Shift-F8YAS_K_S_F9β0xf0015β Shift-F9YAS_K_S_F10β0xf0016β Shift-F10YAS_K_S_F11β0xf0017β Shift-F11YAS_K_S_F12β0xf0018β Shift-F12
Ctrl girlies, this one's for you π:
YAS_K_C_F1β0xf0019β Ctrl-F1YAS_K_C_F2β0xf001aβ Ctrl-F2YAS_K_C_F3β0xf001bβ Ctrl-F3YAS_K_C_F4β0xf001cβ Ctrl-F4YAS_K_C_F5β0xf001dβ Ctrl-F5YAS_K_C_F6β0xf001eβ Ctrl-F6YAS_K_C_F7β0xf001fβ Ctrl-F7YAS_K_C_F8β0xf0020β Ctrl-F8YAS_K_C_F9β0xf0021β Ctrl-F9YAS_K_C_F10β0xf0022β Ctrl-F10YAS_K_C_F11β0xf0023β Ctrl-F11YAS_K_C_F12β0xf0024β Ctrl-F12
and closing out the set, Alt nation πΈ the numbers literally just keep climbing, no skips, no gaps, it's giving organized:
YAS_K_A_F1β0xf0025β Alt-F1YAS_K_A_F2β0xf0026β Alt-F2YAS_K_A_F3β0xf0027β Alt-F3YAS_K_A_F4β0xf0028β Alt-F4YAS_K_A_F5β0xf0029β Alt-F5YAS_K_A_F6β0xf002aβ Alt-F6YAS_K_A_F7β0xf002bβ Alt-F7YAS_K_A_F8β0xf002cβ Alt-F8YAS_K_A_F9β0xf002dβ Alt-F9YAS_K_A_F10β0xf002eβ Alt-F10YAS_K_A_F11β0xf002fβ Alt-F11YAS_K_A_F12β0xf0030β Alt-F12
so that's 0xf0001 all the way up to 0xf0030, twelve keys times four modifiers, a whole lil family tree of function key constants π«Ά ngl the fact that the values are sequential and hex is such a slay β you can literally do math on them if you're feeling spicy. π
okay the keycode list just keeps going and honestly? iconic of it π so here's the rest of the arrow-key-adjacent squad:
YAS_K_LEFTβ0xf0031β LeftYAS_K_UPβ0xf0032β UpYAS_K_DOWNβ0xf0033β DownYAS_K_RIGHTβ0xf0034β RightYAS_K_HOMEβ0xf0035β HomeYAS_K_ENDβ0xf0036β EndYAS_K_PGUPβ0xf0037β PageUpYAS_K_PGDNβ0xf0038β PageDownYAS_K_INSβ0xf0039β InsertYAS_K_DELβ0xf003aβ DeleteYAS_K_C_LEFTβ0xf003bβ Ctrl-LeftYAS_K_C_UPβ0xf003cβ Ctrl-UpYAS_K_C_DOWNβ0xf003dβ Ctrl-DownYAS_K_C_RIGHTβ0xf003eβ Ctrl-RightYAS_K_S_LEFTβ0xf003fβ Shift-LeftYAS_K_S_UPβ0xf0040β Shift-UpYAS_K_S_DOWNβ0xf0041β Shift-DownYAS_K_S_RIGHTβ0xf0042β Shift-RightYAS_K_A_LEFTβ0xf0043β Alt-LeftYAS_K_A_UPβ0xf0044β Alt-UpYAS_K_A_DOWNβ0xf0045β Alt-DownYAS_K_A_RIGHTβ0xf0046β Alt-RightYAS_K_S_TABβ0xf0047β Shift-Tab (Backtab)YAS_K_C_HOMEβ0xf0048β Ctrl-HomeYAS_K_C_ENDβ0xf0049β Ctrl-EndYAS_K_C_INSβ0xf004aβ Ctrl-InsertYAS_K_C_DELβ0xf004bβ Ctrl-DeleteYAS_K_C_PGUPβ0xf004cβ Ctrl-PageUpYAS_K_C_PGDNβ0xf004dβ Ctrl-PageDownYAS_K_S_HOMEβ0xf004eβ Shift-HomeYAS_K_S_ENDβ0xf004fβ Shift-EndYAS_K_S_INSβ0xf0050β Shift-InsertYAS_K_S_DELβ0xf0051β Shift-DeleteYAS_K_S_PGUPβ0xf0052β Shift-PageUpYAS_K_S_PGDNβ0xf0053β Shift-PageDownYAS_K_A_HOMEβ0xf0054β Alt-HomeYAS_K_A_ENDβ0xf0055β Alt-EndYAS_K_A_INSβ0xf0056β Alt-InsertYAS_K_A_DELβ0xf0057β Alt-DeleteYAS_K_A_PGUPβ0xf0058β Alt-PageUpYAS_K_A_PGDNβ0xf0059β Alt-PageDownYAS_K_KP5β0xf005aβ Keypad 5 with NumLock off
okay and then there's this whole other lil corner of the keyboard that doesn't even have "normal" keys, bestie π
F13-F20 β those get sent by the Linux console and by some other terminals when you hit Shift-F1 through Shift-F8 β they get reported as YAS_K_S_F1 all the way up to YAS_K_S_F8. so like, Shift-F1 = YAS_K_S_F1, Shift-F8 = YAS_K_S_F8, you get the vibe β¨
- Alt-<letter>
and these codes? they're not hardcoded one by one, nope β they get generated by a helper macro: YAS_K_ALT(keycode) π«Ά so you feed it the keycode and it does the thing for you. slay.
Okay so continuing the key list, no interruptions, we're locked in π Every one of these is an Alt-something constant, and here's the whole lineup:
YAS_K_A_BTβ Alt-BacktickYAS_K_A_1β Alt-1YAS_K_A_2β Alt-2YAS_K_A_3β Alt-3YAS_K_A_4β Alt-4YAS_K_A_5β Alt-5YAS_K_A_6β Alt-6YAS_K_A_7β Alt-7YAS_K_A_8β Alt-8YAS_K_A_9β Alt-9YAS_K_A_0β Alt-0YAS_K_A_MINUSβ Alt-MinusYAS_K_A_EQβ Alt-=YAS_K_A_BSPβ Alt-BackspaceYAS_K_A_C_Hβ Alt-Backspace, but specifically on terminals where Backspace sends^Hπ«YAS_K_A_TABβ Alt-Tab (if not used by the window manager)YAS_K_A_RETβ Alt-EnterYAS_K_A_SPACEβ Alt-SpaceYAS_K_A_TLDβ Alt-TildeYAS_K_A_EXCLβ Alt-!YAS_K_A_ATβ Alt-@YAS_K_A_HASHβ Alt-#YAS_K_A_POUNDβ Alt-$YAS_K_A_PERCβ Alt-%YAS_K_A_CARRETβ Alt-^YAS_K_A_ANDβ Alt-AmpersandYAS_K_A_STARβ Alt-StarYAS_K_A_OBRAβ Alt-(YAS_K_A_CBRAβ Alt-)YAS_K_A_UNDβ Alt-_YAS_K_A_PLUSβ Alt-+YAS_K_A_aβ Alt-aYAS_K_A_bβ Alt-bYAS_K_A_cβ Alt-cYAS_K_A_dβ Alt-dYAS_K_A_eβ Alt-eYAS_K_A_fβ Alt-fYAS_K_A_gβ Alt-gYAS_K_A_hβ Alt-hYAS_K_A_iβ Alt-iYAS_K_A_jβ Alt-jYAS_K_A_kβ Alt-kYAS_K_A_lβ Alt-lYAS_K_A_mβ Alt-mYAS_K_A_nβ Alt-nYAS_K_A_oβ Alt-oYAS_K_A_pβ Alt-pYAS_K_A_qβ Alt-qYAS_K_A_rβ Alt-rYAS_K_A_sβ Alt-sYAS_K_A_tβ Alt-tYAS_K_A_uβ Alt-uYAS_K_A_vβ Alt-vYAS_K_A_wβ Alt-wYAS_K_A_xβ Alt-x
Like, the naming is lowkey so consistent it's basically a pattern bestie β YAS_K_A_ and then the thing, and the thing is just the character. Once you clock the vibe you can guess the rest, no cap. πΈ
YAS_K_A_yβ Alt-yYAS_K_A_zβ Alt-zYAS_K_A_Aβ Alt-Shift-aYAS_K_A_Bβ Alt-Shift-bYAS_K_A_Cβ Alt-Shift-cYAS_K_A_Dβ Alt-Shift-dYAS_K_A_Eβ Alt-Shift-eYAS_K_A_Fβ Alt-Shift-fYAS_K_A_Gβ Alt-Shift-gYAS_K_A_Hβ Alt-Shift-hYAS_K_A_Iβ Alt-Shift-iYAS_K_A_Jβ Alt-Shift-jYAS_K_A_Kβ Alt-Shift-kYAS_K_A_Lβ Alt-Shift-lYAS_K_A_Mβ Alt-Shift-mYAS_K_A_Nβ Alt-Shift-nYAS_K_A_Oβ Alt-Shift-o; defined for completeness but cannot be received, because\eOis a key sequence prefixYAS_K_A_Pβ Alt-Shift-pYAS_K_A_Qβ Alt-Shift-qYAS_K_A_Rβ Alt-Shift-rYAS_K_A_Sβ Alt-Shift-sYAS_K_A_Tβ Alt-Shift-tYAS_K_A_Uβ Alt-Shift-uYAS_K_A_Vβ Alt-Shift-vYAS_K_A_Wβ Alt-Shift-wYAS_K_A_Xβ Alt-Shift-xYAS_K_A_Yβ Alt-Shift-yYAS_K_A_Zβ Alt-Shift-z
β¨ Functions β¨
okay so every single function in the API works with a pointer to an opaque yascreen structure. that structure is allocated internally in the library by yascreen_init, and it is literally the job of your user program to keep track of it. also: the library is thread safe, as long as each struct yascreen object is only ever accessed by a single thread. periodt π
yascreen_init
inline yascreen *yascreen_init(int sx,int sy);
allocates and initializes screen data π
output defaults to stdout
if the output is a terminal and the initial size is (0,0), the screen size gets autodetected. if autodetection fails or returns 0x0, it defaults to 80x24
in case of error, returns NULL π
yascreen_ver
inline const char *yascreen_ver(void);
returns a string with the library version β¨
yascreen_setout
inline int yascreen_setout(yascreen *s,ssize_t (*out)(yascreen *s,const void *data,size_t len));
sets the callback that handles output π«Ά
if out=NULL, the output goes to stdout
the callback may implement internal buffering; a flush is signalled by calling out with len=0
yascreen_set_unicode
inline void yascreen_set_unicode(yascreen *s,int on);
enables unicode input processing (on is non-zero) or disables it (on=0) π
by default, unicode mode is on
changing the unicode input processing will flush all pending input π
yascreen_set_telnet
inline void yascreen_set_telnet(yascreen *s,int on);
enables telnet sequence processing (on is non-zero) or disables it (on=0) πΈ
by default, telnet mode is off
yascreen_init_telnet
inline void yascreen_init_telnet(yascreen *s);
depending on telnet sequence processing, sends a set of telnet initialization sequences π§
yascreen_resize
inline int yascreen_resize(yascreen *s,int sx,int sy);
resizes the screen π¦
you should redraw afterwards
since allocation is involved, this may fail and return -1
yascreen_free
inline void yascreen_free(yascreen *s);
finishes the lifecycle of struct yascreen β all internally allocated memory is freed π
yascreen_term_save
inline void yascreen_term_save(yascreen *s);
saves the current terminal state on top of the state stack π
yascreen_term_restore
inline void yascreen_term_restore(yascreen *s);
restores the previously saved terminal state from the top of the state stack β¨
yascreen_term_push
inline void yascreen_term_push(yascreen *s);
pushes the current terminal state to the state stack π
yascreen_term_pop
inline void yascreen_term_pop(yascreen *s);
pops and restores the previously saved terminal state from the state stack π«Ά
yascreen_term_set
inline void yascreen_term_set(yascreen *s,int mode);
sets the terminal for proper screen operation π
mode is a bitmask, containing one of:
YAS_NOBUFF(1) β turn off canonical mode (disableICANONandIEXTEN)YAS_NOSIGN(2) β disableISIGYAS_NOECHO(4) β disable local echo (ECHO)YAS_ONLCR(8) βONLCRorOPOST
yascreen_printxy
inline int yascreen_printxy(yascreen *s,int x,int y,uint32_t attr,const char *format,...) __attribute__((format(printf,5,6)));
prints at position; if data exceeds the buffer, then it gets truncated βοΈ
yascreen_putsxy
inline int yascreen_putsxy(yascreen *s,int x,int y,uint32_t attr,const char *str);
prints at position; if data exceeds the buffer, then it gets truncated βοΈ
yascreen_printxyu
inline int yascreen_printxyu(yascreen *s,int x,int y,uint32_t attr,const char *format,...) __attribute__((format(printf,5,6)));
prints at position; if data exceeds the buffer, then it gets truncated βοΈ
the screen is immediately updated π₯
yascreen_putsxyu
inline int yascreen_putsxyu(yascreen *s,int x,int y,uint32_t attr,const char *str);
prints at position; if data exceeds the buffer, then it gets truncated βοΈ
the screen is immediately updated π₯
yascreen_update
inline int yascreen_update(yascreen *s);
syncs memory state to the screen π₯οΈ
since allocation is involved, this may fail and return -1
yascreen_redraw
inline void yascreen_redraw(yascreen *s);
sets the next update to be a full redraw π
yascreen_clear_mem
inline void yascreen_clear_mem(yascreen *s,uint32_t attr);
clears the memory buffer π§Ό
all cells in the screen are set to Space, using attr for colors and style π¨
yascreen_cursor
inline void yascreen_cursor(yascreen *s,int on);
hides the cursor (on=0) or shows it (on is non-zero) π
the screen is updated immediately β‘
yascreen_cursor_xy
inline void yascreen_cursor_xy(yascreen *s,int x,int y);
bestie, this one moves the cursor to a position π
the screen gets updated immediately, no waiting around
yascreen_altbuf
inline void yascreen_altbuf(yascreen *s,int on);
flips between the regular buffer and the alternative buffer π
screen updates immediately again, she does not do queues
yascreen_clear
inline void yascreen_clear(yascreen *s);
clears the real screen, and literally zero change to the memory buffers π§Ή
yascreen_clearln
inline void yascreen_clearln(yascreen *s);
clears just the current line, and again, no change to memory buffers β¨
yascreen_update_attr
inline void yascreen_update_attr(yascreen *s,uint32_t oattr,uint32_t nattr);
applies the difference between two attrs and outputs the optimized ANSI sequence to switch from oattr to nattr π₯
if oattr=0xffffffff, the full ANSI sequence gets generated
no change to memory buffers, okay? none.
yascreen_set_attr
yascreen_set_attr(s,attr)
resets all attrs and sets one specific attr (attr) π
yascreen_print
inline int yascreen_print(yascreen *s,const char *format,...) __attribute__((format(printf,2,3)));
yascreen_write
inline int yascreen_write(yascreen *s,const char *str,int len);
yascreen_puts
inline int yascreen_puts(yascreen *s,const char *str);
yascreen_clearln_s
inline const char *yascreen_clearln_s(yascreen *s);
prints in line mode π
yascreen_sx
inline int yascreen_sx(yascreen *s);
gets the current x size π
yascreen_sy
inline int yascreen_sy(yascreen *s);
gets the current y size π
yascreen_x
inline int yas<|place_holder_mm_span_0442|>in int yascreen_x(yascreen *s);
wait no, that's not it, let me not be chaotic π it's exactly this:
inline int yascreen_x(yascreen *s);
gets the current x π
yascreen_y
inline int yascreen_y(yascreen *s);
gets the current y π
yascreen_esc_to
inline void yascreen_esc_to(yascreen *s,int timeout);
sets the timeout for a single ESC key press β³
yascreen_ckto
inline void yascreen_ckto(yascreen *s);
if you're running an external event loop, this call checks for a single ESC key π
it should be called regularly enough that the timeout we specified above doesn't get extended too much
if it's not called often enough, then a single ESC gets yielded after a longer timeout π¬
if it's not called at all, then a single ESC gets yielded with the next key press
yascreen_willto
inline uint64_t yascreen_willto(yascreen *s);
a single ESC key plus a timeout after it is quite the rare event, fr fr
so help your application optimize its event loop by not constantly polling yascreen_ckto π«Ά
yascreen_willto tells you if there's a pending timeout, and when
returns 0 if there is no pending timeout, otherwise the remaining time in milliseconds β±οΈ
yascreen_getch_to
inline int yascreen_getch_to(yascreen *s,int timeout);
waits for a key, returns ASCII or extended keycode, and waits no more than timeout in milliseconds β¨οΈ
yascreen_getch
yascreen_getch(s)
gets a key with no timeout, periodt
this macro expands to yascreen_getch_to(s,0)
zero timeout = wait forever π
yascreen_getch_nowait
yascreen_getch_nowait(s)
gets a key, if there's one available, and returns immediately β‘
this macro expands to yascreen_getch_to(s,-1)
negative timeout = do not wait
yascreen_ungetch
inline void yascreen_ungetch(yascreen *s,int key);
puts a key value back into the key buffer β©οΈ
the internal key buffer is dynamically allocated, so there's literally no limit on how many key codes you can put back π but if memory allocation fails, the error will not be reported and the key will not be put into the buffer
yascreen_pushch
inline void yascreen_pushch(yascreen *s,int key);
pushes a key value at the end of the key buffer β‘οΈ
similar to yascreen_ungetch, but the key code gets returned after all the other key codes currently in the buffer
the internal key buffer is dynamically allocated, so again, no limit on how many key codes may be put back π but if memory allocation fails, the error will not be reported and the key will not be put into the buffer
yascreen_feed
inline void yascreen_feed(yascreen *s,unsigned char c);
feeds the key sequence state machine with a byte stream π
this is useful for implementing an external event loop and reading key codes with yascreen_getch_nowait until it returns YAS_K_NONE
yascreen_peekch
inline int yascreen_peekch(yascreen *s);
peeks for a key without removing it from the input queue πβ¨
yascreen_getsize
inline void yascreen_getsize(yascreen *s,int *sx,int *sy);
gets the last reported screen size π
sets both to 0 if there isn't one
this yields a valid result after YAS_SCREEN_SIZE is returned as a keypress
yascreen_reqsize
inline void yascreen_reqsize(yascreen *s);
asks the terminal to report its size via an ANSI sequence πββοΈ
yascreen_set_hint_i
inline void yascreen_set_hint_i(yascreen *s,int hint);
yascreen_get_hint_i
inline int yascreen_get_hint_i(yascreen *s);
yascreen_set_hint_p
inline void yascreen_set_hint_p(yascreen *s,void *hint);
yascreen_get_hint_p
inline void *yascreen_get_hint_p(yascreen *s);
get/set opaque hint values π
integer and pointer hints are stored separately and both can be used at the same time
these are useful to link the yascreen instance to user program data
for example, a single output callback may output to a socket or a terminal, depending on the hint values π
yascreen_line_flush
inline void yascreen_line_flush(yascreen *s,int on);
enables/disables auto flush for line and direct screen oriented operations π°
yascreen versions before 1.77 didn't use buffered output and would immediately send the output to the screen
disabling internal flush can help an application optimize the number of write calls, at the cost of performing an explicit flush after each group of operations
explicit flush example:
yascreen_write(s,"",0);
yascreen_getwch_to
inline wchar_t yascreen_getwch_to(yascreen *s,int timeout);
waits for a key, returns a wide character or extended keycode, and waits no more than timeout in milliseconds πΈ
yascreen_getwch_to does not work in non-unicode mode and will always return YAS_K_NONE π
mixing the utf8 and wide character input modes will break on multibyte utf8 sequences and is not supported π«
yascreen_getwch
yascreen_getwch(s)
gets a key as a wide character, no timeout π
this macro expands to yascreen_getwch_to(s,0)
zero timeout = wait forever
yascreen_getwch does not work in non-unicode mode and will always return YAS_K_NONE π
yascreen_getwch_nowait
yascreen_getwch_nowait(s)
gets a key as a wide character, if there's one available, and returns immediately β‘
this macro expands to yascreen_getwch_to(s,-1)
negative timeout = do not wait
yascreen_getwch_nowait does not work in non-unicode mode and will always return YAS_K_NONE π
yascreen_ungetwch
inline void yascreen_ungetwch(yascreen *s,wchar_t key);
puts a wide character key value back into the key buffer β©οΈ
the internal key buffer is dynamically allocated, so no limit on how many key codes may be put back π but if memory allocation fails, the error will not be reported and the key will not be put into the buffer
the internal key buffer contains utf8, and the wide character will be expanded to the appropriate utf8 sequence π¦
yascreen_ungetwch does not do anything in non-unicode mode π
yascreen_peekwch
inline wchar_t yascreen_peekwch(yascreen *s);
peeks for a key without removing it from the input queue π
yascreen_peekwch does not work in non-unicode mode and will always return YAS_K_NONE π
okay bestie that's the whole page, we did it π every single function, no skips, no cap. this page is from yascreen, dated July 29, 2026, and lives at YASCREEN(3) β go forth and slay your terminal UI π β¨π
π¦ where this page comes from
- epel 10: yascreen-devel 2.14-1.el10_3 Β· LGPL-3.0-only
- epel 9: yascreen-devel 2.14-1.el9 Β· LGPL-3.0-only
- fedora 43: yascreen-devel 2.14-1.fc43 Β· LGPL-3.0-only
- fedora 43: yascreen-devel 2.14-1.fc43 Β· LGPL-3.0-only
- fedora 44: yascreen-devel 2.14-1.fc44 Β· LGPL-3.0-only
- fedora 44: yascreen-devel 2.14-1.fc44 Β· LGPL-3.0-only
- ubuntu stonking: libyascreen-dev 2.14-1 Β· LGPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms