LinuxovΘ noviny | 11-12/98 | |||
| ||||
Tento Φlßnek by m∞l b²t malou rychlokucha°kou do sv∞ta ncurses. Snad jen na zaΦßtek, malΘ vysv∞tlenφ co to ncurses jsou. Nßzev "ncurses" je slo╛eninou ze slov "new curses". Jednß se o voln∞ distibuovateln² klon System V Release 4.0 (SVr4) curses. A jak °φkajφ FAQ, je to slovnφ h°φΦka k "cursor optimization". Ale jinak (a vß╛n∞) jednß se o knihovnu k managamentu v²stupu na "character-cell terminals" tedy na znakov∞ orientovanΘ terminßly. Ale rychle k programovßnφ. Tato knihovna nenφ ╛ßdn²m drobeΦkem (p°i pohledu do adresß°e /lib je - alespo≥ na mΘm disku - po libc tou nejv∞t╣φ) tak╛e snad n∞kte°φ prominou pokud se o n∞kter²ch mo╛nostech nezmφnφm. Pokusφm se zam∞°it pouze na to jak nenßsiln∞ a rychle dosßhnout "poΦmßrßnφ screenu ve stylu ncurses" :-) InicializaceJako prvnφ by si m∞l program nainicializovat obrazovku do curses m≤du. To se provede funkcφ initscr(). Po provedenφ tΘto funkce, by programßtor nikdy nem∞l zapomenout, ╛e po ukonΦenφ programu by v╣e m∞lo b²t jako p°ed jeho spu╣t∞nφm. Nßvrat z curses m≤du se provede funkcφ endwin(). Pokud si nejste jisti, ╛e jste tuto funkci zavolali tak se o tom m∙╛ete p°esv∞dΦit pomocφ isendwin(). Proto╛e nikdy nenφ tak ·pln∞ jistΘ kdy a kde program skonΦφ, tak nap°. jß to d∞lßm tak, ╛e si do atexit() p°idßm endwin(), tedy
atexit((void *) endwin) Pokud se divφte, proΦ takovß p°emφra starostφ o endwin(), tak proto, ╛e program, kter² se ukonΦφ bez zavolßnφ tΘto funkce nechß vß╣ terminßl v tom lep╣φm stavu. Funkce initscr() vracφ pointer stdscr typu WINDOW (jednß se o globßlnφ prom∞nnou, ke kterΘ ncurses vztahuje funkce, kterΘ nepou╛φvajφ okno jako parametr. Po inicializaci je mo╛nΘ si doopravit n∞kterΘ dal╣φ vlastnosti screenu / terminßlu. Nap°φklad:
U poslednφ zmφn∞nΘ funkci snad je╣t∞ poznßmka: pokud pou╛φvßte ve svΘm programu WINDOW, tak je nutnΘ pro ka╛dΘ novΘ okno tuto funkci volat, jinak p°i nepou╛φvßnφ oken je mo╛nΘ zavolat na poΦßtku
keypad(stdscr, TRUE) Po p°epnutφ do curses m≤du jsou dostupnΘ dv∞ globßlnφ prom∞nnΘ (int) LINES a COLS, ve kter²ch je ulo╛ena aktußlnφ velikost obrazovky. ╚astΘ je nap°. po°adφ inicializace: initscr(), cbreak(), noecho() - pak u╛ je obrazovka p°ipravena ve stavu "ne°ßdkovßnφ", ale naopak ve stavu "kam p°esn∞ co chce╣" (na jakou °ßdku a do jakΘho sloupce). N∞kdy je nutnΘ se z ncurses programu p°epnout nazp∞t do p∙vodnφho (v terminologii ncurses - shell) m≤du. To je nutnΘ nap°φklad p°i volßnφ n∞jakΘho externφho programu, kter² pou╛φvß terminßl standardnφm zp∙sobem. K tomu se pou╛φvß skupina funkcφ okolo reset_shell_mode() (vφce manußl). Pochopiteln∞, ze ncurses obsahujφ je╣t∞ dal╣φ p°epφnaΦe, ale to u╛ by mohlo b²t otßzkou samostudia nad manußly :-) Podobn∞ jako zßle╛itosti t²kajφcφ se mo╛nosti otev°φt si vlastnφ screen pomocφ funkce newterm().
V²stup a oknaU╛ jsem se zmφnil o WINDOW. NovΘ okno si vytvo°φte pomocφ funkce newwin(). Jako parametry se zadßvajφ poloha okna a to vzhledem k levΘmu hornφmu rohu a velikost okna. Po vytvo°enφ okna je mo╛nΘ s nφm zachßzet jako se samostatnou podmno╛inou a tedy volat pak funkce s parametry °ßdek a sloupc∙ vzhledem k levΘmu hornφmu roku okna. Funkce newwin() vracφ pointer na novΘ okno (funkce sama alokuje pomocφ malloc strukturu WINDOW) proto se okno deklaruje jako pointer (podobn∞ jako FILE). Naopak uvoln∞nφ pam∞ti a zru╣enφ okna se provede funkcφ delwin(). Smazßnφ ze screenu se provede funkcφ werase() (a pak je vhodnΘ wrefresh()). V okn∞ m∙╛e existovat i tzv. subwin, jednß se to samΘ jako WINDOW, ale vzhledem k rodiΦovskΘmu oknu (narozdφl od okna, kterΘ je definovßno vzhledem ke screenu). S okny lze vytvß°et docela zajφmavΘ v∞ci. Nap°φklad zapsat do souboru a pak naopak naΦφst okno ze souboru. ╚asto je vyu╛φvßna i nap°φklad funkce redrawwin(), kterß znova nakreslφ okno na screen. Je mo╛nΘ s okny pohybovat pomocφ mvwin(), duplikovat okna - dupwin() atd.Funkce zachßzejφcφ s okny lze jednodu╣e poznat dle prefixu mvw- nebo samotnΘho w-. Tak╛e obdoba klasickΘho printf() je v ncurses p°i pou╛itφ oken
mvwprintw(okno, °ßdka, sloupec,\ "n∞co: %s", °et∞zec); (pozor na znak \n - v ncurses se dostßvßme na dal╣φ °ßdku tφm, ╛e zv²╣φme "°ßdku" o jedna).
Dal╣φ mo╛nostφ jak tisknout na screen je nevyu╛φvat WINDOW a vyu╛φvat funkcφ, kterΘ nepo╛adujφ WINDOW jako sv∙j parametr. Lines a cols v parametrech t∞chto funkcφ se pak vztahujφ k levΘmu hornφmu rohu screenu. Tyto funkce pak v∞t╣inou zaΦφnajφ prefixem mv- nap°. mvaddstr(y,x, str). Ncurses je╣t∞ umo╛≥ujφ pou╛φvat funkce bez parametr∙ line a cols. TakovΘ funkce pak vypisujφ sv∙j v²stup na aktußlnφ pozici kursoru. Nutno °φct, ╛e tento zp∙sob je asi nejmΘn∞ programßtorsky p°φjemn². Takovouto funkcφ je nap°. addstr(str). Jak je z uveden²ch p°φklad∙ z°ejmΘ, tak u v∞t╣iny funkcφ existujφ v╣echny t°i alternativy, tedy nap°. mvwaddstr, mvaddstr i addstr. V ncurses jsou pak je╣t∞ alternativy t∞chto funkcφ umo╛≥ujφcφ p°esnΘ zachßzenφ se °et∞zci (podobn∞ jako znßmΘ stringovΘ strcpy a strncpy), tedy nap°. addstr() a addnstr(). Pokud pot°ebujete tisknout n∞kterΘ specißlnφ znaky tak doporuΦuji podφvat se na man addch, kde jsou popsßna makra ASC_n∞co obsahujφcφ tyto znaky (nap°. Φßry, r∙znΘ ╣ipky apod.). Ke snadn∞j╣φmu kreslenφ Φar existujφ i funkce hline() (horizontßlnφ) a vline() (vertikßlnφ) a jejich alternativy pro okna. ╚asto se u oken pou╛φvajφ rßmeΦky. RßmeΦek m∙╛ete nakreslit pomocφ v²╣e zmφn∞n²ch funkcφ a nebo pomocφ, k t∞mto ·Φel∙m p°eddefinovanΘ, funkce wborder(). Pro p°esnost snad je╣t∞ poznßmku - v∞t╣ina funkcφ kterΘ nepo╛adujφ WINDOW jsou ve skuteΦnosti makra typu:
#define mvaddstr(y, x, str)\ mvwaddstr(stdscr, y, x, str) Pro dobrΘ zachßzenφ s v²stupem je╣t∞ doporuΦuji prohlΘdnut si manußly k funkcφm refresh(), wrefresh(), redrawwin() atd. Co tyto d∞lajφ je myslφm patrnΘ u╛ z jejich nßzvu. Zazn∞lo zde ji╛ i n∞co o pozici kursoru, i tu lze pochopiteln∞ m∞nit. Pomocφ wmove(y, x, win) v rßmci okna a pomocφ move() vzhledem ke screenu. Dal╣φ a ji╛ zmφn∞nou mo╛nostφ je zapφnanφ resp. vypφnanφ cursoru a to pomocφ curs_set(0) a curs_set(1). Mo╛nß se ptßte, co je lep╣φ - pou╛φvat v programu okna nebo ne? Abych up°φmn∞ odpov∞d∞l - tak nevφm. Pou╛φvßnφ oken s sebou nese n∞kolik v²hod. ╚ßsti v²stupu jsou umφst∞ny v podmno╛inßch, se kter²mi lze samostatn∞ zachßzet. Nap°φklad pokud jednφm oknem p°ekryjete druhΘ, pak snadno to p°ekrytΘ obnovφte pomocφ redrawwin(), zatφmco pokud okna nepou╛φvßte tak tφm, co na screen napφ╣ete nenßvratn∞ p°epφ╣e to, co tam bylo (na danΘ pozici). Ale p°i nepou╛φvßnφ oken ve va╣em programu ubude volßnφ malloc (p°i ka╛dΘm newwin), nebudete muset programem vlßΦet struktury WINDOW a pravd∞podobn∞ program bude rychlej╣φ. Na zamy╣lenφ snad uvedu, ╛e nap°. v Midnight Commanderu okna pou╛φvßna nejsou, jß sßm jsem (malß reklama :-)) nap°. v programu kim (mana╛er proces∙) okna pou╛il, ale v nßsledujφcφ verzi u╛ nebudou. To v╣e, ale neznamenß, ╛e okna jsou n∞co nedobrΘho, jen je n∞kdy dobrΘ, pokud se program starß o n∞kterΘ v∞ci sßm, a i v programovßnφ platφ, ╛e mΘn∞ je n∞kdy vφce. Za v²stup snad lze je╣t∞ pova╛ovat to, co d∞lß funkce beep(). Jak u╛ je z nßzvu patrno, jednß se o zvukovΘ znamenφ.
VstupAby mohl program "vnφmat" u╛ivatele tak pochopiteln∞ knihovna obsahuje funkce vracejφcφ znaky nebo °et∞zce zadanΘ z klßvesnice. Zßkladnφ je getch() a p°i pou╛itφ oken wgetch(). Pozor, nezapomφnat p°i pou╛φvßnφ oken volat po vytvo°enφ okna funkci keypad(). T∞mito funkcemi vrßcenß hodnota (int) obsahuje znak nebo v p°φpad∞ stisku n∞jakΘ specißlnφ (funkΦnφ) klßvesy v curses.h nadefinovanΘ makro majφcφ prefix KEY_, nap°. p°i stisku klßvesy![]() Klßvesu je mo╛nΘ i vrßtit (podobn∞ jako u souboru znak) pomocφ ungetch(). Pochopiteln∞ jsou definovßny i funkce vracejφcφ znak nejen do programu, ale opisujφcφ ho takΘ na screen nebo okno (pozor - nesmφ b²t vypnuto echo pomocφ noecho()). Nap°. mvgetch(), mwvgetch(). TakΘ je mo╛nΘ pomocφ has_key() zjistit, znß-li terminßl n∞kterou klßvesu (ta je jako parametr tΘto funkce) nebo nap°φklad jmΘno klßvesy a to pomocφ keyname(). Pro p°ijetφ celΘho °et∞zce lze vyu╛φt funkce z rodiny getstr(). Tyto naΦφtajφ v╣echny zadanΘ znaky a╛ do stisku klßvesy Enter do °et∞zce. Existujφ pochopiteln∞ i bezpeΦn∞j╣φ varianty t∞chto funkcφ, tedy getnstr(). Zajφmavostφ m∙╛e b²t nastavenφ timeout∙ pro Φtenφ klßvesy. Toho lze efektivn∞ vy╛φt nap°φklad k tomu, ╛e b∞hem toho co program Φekß na to a╛ se u╛ivatel rozhodne n∞co stisknout tak m∙╛e nap°. testovat n∞jakou udßlost. Jß to nap°φklad pou╛φvßm pokud chci provΘst n∞jakou slo╛it∞j╣φ a nßroΦn∞j╣φ reakci na signßl, kdy nenφ vhodnΘ, aby tuto Φinnost vykonßval handler signßlu. Nastavenφ timeoutu se provede funkcφ timeout() nebo wtimeout() s parametrem v milisekundßch. Pokud do nastavenΘ doby nedo╣lo k stisknutφ n∞jakΘ klßvesy vracφ nap°. funkce getch() hodnotu ERR. Dal╣φ mo╛nostφ jak naΦφtat "n∞co" do va╣φ aplikace je mo╛nost Φφst ze screenu nebo okna znak nebo °et∞zec le╛φcφ na zadan²ch sou°adnicφch a to pomocφ rodiny funkcφ inch a instr (mvinch(), mvwinch(), mvinstr()). U funkcφ inch lze nejen zjistit znak na danΘ pozici, ale i jeho barvu a atributy.
BarvyChcete-li pou╛φvat ve svΘm programu barvy musφ b²t spln∞no n∞kolik zßkladnφch podmφnek. Prvn∞ je nutnΘ po inicializaci screenu zavolat funkci start_color(), kterou sd∞lφte ncurses, ╛e mßte takov²to ·mysl. Podporuje-li terminßl barvy zjistφte funkcφ has_colors().Jak bude vypadat v²stup je mo╛nΘ nastavit pomocφ attron() nebo pro okno watrron() a naopak zru╣it pomocφ attroff() (wattroff()). Kde jako parametr je uvßdφ po╛adovan² stav, tedy nap°. A_BOLD, A_BLINK, A_NORMAL atd. Od chvφle nastavenφ pomocφ attron v╣echen v²stup pou╛φvß toto nastavenφ a to a╛ do dal╣φ zm∞ny pomocφ attron nebo do jeho zru╣enφ pomocφ attroff.
![]() P°ed pou╛φvßnφm barev je nutnΘ je nadefinovat. To se provede pomocφ init_pair(barva, pop°edφ, pozadφ). Kde barva je Φφslo a pop°edφ (pφsmo) a pozadφ jsou jedna z nadefinovan²ch barev (COLOR_RED, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE a COLOR_MAGENTA). Chceme-li pak pou╛φt takto nadefinovan²ch barev provedeme to zase pomocφ attron(). A to takto: attron(COLOR_PAIR(barva));. Pochopiteln∞ lze kombinovat i s bold. Pou╛itφ bude asi nejlΘpe viditelnΘ na p°φkladu a na jeho v²stupu. Ncurses pochopiteln∞ dovolujφ i dal╣φ operace s barvami, ale to je nad rßmec tohoto Φlßnku a lze to pom∞rn∞ pohodln∞ nastudovat z manußlu.
ResizeJe to takΘ trochu nad rßmec tohoto Φlßnku, ale proto╛e je to Φast²m dotazem na r∙zn²ch konferencφch, tak to zde zmφnφm. Pokud provozujete ncurses program pod xtermem, tak se b∞╛n∞ stßvß, ╛e u╛ivatel m∞nφ velikost okna xtermu. Je tedy vhodnΘ zjistit novou velikost LINES a COLS. O zm∞n∞ velikosti okna je aplikace informovßna signßlem SIGWINCH. ObΦerstvit LINES a COLS m∙╛ete nap°. takto:
struct winsize size; size.ws_row = size.ws_col = 0; ioctl(0, TIOCGWINSZ, &size); if (size.ws_row && size.ws_col) { LINES = size.ws_row; COLS = size.ws_col; }
My╣kaP°i d∙kladnΘm proΦφtßnφ manußlu ncurses zjistφte, ╛e ncurses obsahujφ funkce getmouse() atd. Tyto funkce, ale nejsou v p∙vodnφm SVr4. Jß osobn∞ jsem t∞chto funkcφ nikdy nepou╛il. Stalo se zvykem pou╛φvat gpm a jsem toho nßzoru, ╛e n∞kterΘ zvyky jsou dobrΘ, tak proΦ je m∞nit. Knihovna gpm dokonce na programy s ncurses pamatuje, tak╛e jsou zde vytvo°enΘ alternativy getch() a wgetch() (Gpm_Getch() a Gpm_Wgetch()) pro pou╛φvßnφ my╣i. Ka╛dopßdn∞ gpm s ncurses pracuje bezvadn∞. Ale o gpm a╛ n∞kdy p°φ╣t∞.
Zßv∞rProto╛e n∞kter²m programßtor∙m nevyhovovaly pouze zßkladnφ mo╛nosti ncurses, tak vznikla °ada nßstaveb. Standardn∞ jsou s ncurses distribuovanΘ menu, panel, form. Je otßzkou jak moc jsou tyto r∙znß "ud∞lßtka" ╣ikovnß a hlavn∞ ·tlß a jestli nßhodou programßtora nesvazujφ a koneΦnΘmu produktu nevtiskujφ tvß° jakou cht∞jφ oni.K p°ilo╛en²m p°φklad∙m: kompilace programu s knihovnou se provede nap°. takto:
gcc -Wall -O3 program.c -o program -lncurses (to -Wall doporuΦuji, Φasto ukß╛e programßtor∙m v∞ci "netu╣enΘ" :-) Ti dloubav∞j╣φ si mo╛nß v mφstech, kde se zmi≥uji o mc vzpomn∞li na knihovnu slang. Ano, v souΦasnΘ dob∞ se tento program distribuuje kompilovan² s touto knihovnou (s ncurses to ale jde kompilovat takΘ). Programy psanΘ pro ncurses, lze po mal²ch ·pravßch kompilovat i s knihovnou slang. Je jen nutnΘ mφsto curses.h includovat slcurses.h. Jako dal╣φ studijnφ materißl doporuΦuji obsßhl² man curses a je╣t∞ (a to nejlΘpe) zdrojßky n∞jakΘho ncurses programu.
P°ilo╛en² p°φklad lze najφt vΦetn∞ Makefile v adresß°i
s Linuxov²mi novinami nebo na adrese http://home.zf.jcu.cz/~zakkr/LN/.
|