{"id":7495,"date":"2024-09-11T03:00:00","date_gmt":"2024-09-11T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=7495"},"modified":"2024-09-07T11:58:41","modified_gmt":"2024-09-07T15:58:41","slug":"a-gentle-introduction-to-ncurses","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=7495","title":{"rendered":"A gentle introduction to ncurses"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"7495\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>In days past, Unix programs ran in \u201cteletype\u201d mode, reading from <em>standard input<\/em> and writing to <em>standard output<\/em> such as the <strong>ls<\/strong> and <strong>awk<\/strong> commands. In more modern times, Linux programs might run in a graphical user interface like GNOME or KDE, allowing the user to interact with the program using a mouse, by clicking on menus and buttons. But another way that programs can interact with the user is via <em>screen control<\/em>, by manipulating the screen directly. Examples of such text user interfaces include the <strong>vi<\/strong> editor, implemented on modern systems as <strong>Vim<\/strong>.<\/p>\n\n\n\n<p>You can create your own programs that use a text user interface to control the screen. The classic way to do this is with the <strong>curses<\/strong> library from BSD Unix, but Linux systems provide the same interface using <strong>ncurses<\/strong>, or <em>new curses<\/em>. Let\u2019s explore ncurses by writing a simple \u201cHello world\u201d program.<\/p>\n\n\n\n<p>To follow along, you\u2019ll need to have the ncurses development library installed. On most Linux systems, this is in the <code>ncurses-devel<\/code> package, which you can install like this on Fedora Linux:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ sudo dnf install ncurses-devel<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"starting-up-and-shutting-down\">Starting up and shutting down<\/h2>\n\n\n\n<p>To use screen addressing, you first need to use <code>initscr<\/code> to initialize the screen. This does several things at once, but all behind the scenes: ncurses determines if the screen is addressable\u2014and if so, prepares the screen for direct addressing. Finally, ncurses also sets the <code>LINES<\/code> and <code>COLS<\/code> global variables with the current screen dimensions.<\/p>\n\n\n\n<p>In the process of doing all of this, ncurses may also clear the screen, although your program should still clear the screen on its own to ensure that the terminal is in the right \u201cstate.\u201d<\/p>\n\n\n\n<p>When your program is finished, you should use the <code>endwin<\/code> function to reset the terminal back to its normal state.<\/p>\n\n\n\n<p>Let\u2019s test this by writing a simple program to initialize the screen and then immediately exit the program. I\u2019ve also used the <code>getch<\/code> function, which is part of ncurses, to get a single keystroke from the keyboard. That way, the program starts up, waits for a key, then exits. This sample program doesn\u2019t do any other work such as clearing the screen or printing text, but it\u2019s a demonstration of the <em>minimum<\/em> that you need to write a program with ncurses:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;curses.h&gt;\n\nint main()\n{\n    initscr();\n\n    getch();\n\n    endwin();\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>You compile the program like any other C program, but you need to include the <code>ncurses<\/code> library at link-time like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ gcc -o demo demo.c -lncurses<\/code><\/pre>\n\n\n\n<p>And when you run the program, you\u2019ll just see the cursor in the upper left corner, waiting for you to press a key. As soon as you press any key on the keyboard, the program immediately exits:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"827\" height=\"638\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/09\/ncurses1.png\" alt=\"\" class=\"wp-image-7496\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"printing-text\">Printing text<\/h2>\n\n\n\n<p>Let\u2019s add to this program by printing a short message. When using ncurses, you can position text anywhere on the screen. The standard way to reposition the cursor is with the <code>move<\/code> function, which takes the <em>line<\/em> and <em>column<\/em> of the new screen position. Screen coordinates always start from zero, so <code>move(0,0)<\/code> would put the cursor in the upper left corner.<\/p>\n\n\n\n<p>For this demonstration, let\u2019s add some text to start at line 5 and column 10. To do that, we\u2019ll move the cursor with <code>move(5,10)<\/code> and then <em>add a string<\/em> to the screen using the <code>addstr<\/code> function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;curses.h&gt;\n\nint main()\n{\n    initscr();\n\n    move(5, 10);\n    addstr(\"Hello world!\");\n    refresh();\n\n    getch();\n\n    endwin();\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>When updating the screen, such as to print text with <code>addstr<\/code>, you also need to redraw the screen with the <code>refresh<\/code> function. The screen update in ncurses is quite clever, and only updates the on screen characters that have changed; it doesn\u2019t actually \u201crepaint\u201d the entire screen from scratch every time.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"827\" height=\"638\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/09\/ncurses2.png\" alt=\"\" class=\"wp-image-7497\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"centering-a-message\">Centering a message<\/h2>\n\n\n\n<p>Let\u2019s make another update to the \u201cHello world\u201d program, to center the message on the screen. In this version, we\u2019ll write a new function called <code>center_text<\/code> that prints the text so it\u2019s on the middle line, and positions the text appropriately so it\u2019s centered on the line.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;curses.h&gt;\n#include &lt;string.h&gt;\n\nvoid center_text(const char *s)\n{\n    int line, col;\n\n    line = LINES \/ 2;\n    col = (COLS \/ 2) - (strlen(s) \/ 2);\n\n    mvaddstr(line, col, s);\n    refresh();\n}\n\nint main()\n{\n    initscr();\n\n    center_text(\"Hello world\");\n\n    getch();\n\n    endwin();\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Because <em>moving to a new coordinate<\/em> and <em>printing text<\/em> is a common thing to do in a program, ncurses provides a function that combines the two actions. The <code>mvaddstr<\/code> function first uses <code>move<\/code> to go to a new screen coordinate, then uses <code>addstr<\/code> to print the text.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"827\" height=\"638\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2024\/09\/ncurses3.png\" alt=\"\" class=\"wp-image-7498\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"theres-more-to-explore\">There\u2019s more to explore<\/h2>\n\n\n\n<p>This program is a simple example of how to use the curses functions to draw characters to the screen. You can do so much more with curses, depending on what you need your program to do. If you are interested in getting a head start with curses, I encourage you to read the ncurses manual page, in section 3 of the <strong>man<\/strong> pages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ man 3 ncurses<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>You can create your own programs that use a text user interface to control the screen.<\/p>\n","protected":false},"author":33,"featured_media":6830,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[5,150],"tags":[91,152],"class_list":["post-7495","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-programming","tag-linux","tag-programming"],"modified_by":"Jim Hall","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/7495","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7495"}],"version-history":[{"count":1,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/7495\/revisions"}],"predecessor-version":[{"id":7499,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/7495\/revisions\/7499"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/6830"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7495"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7495"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7495"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}