linux textui programming

setup terminal input and output

int ttyfd = open("/dev/tty", O_RDWR);
struct termios termattr;
// get terminal attr from tty
tcgetattr(ttyfd, &termattr);
// set terminal to "raw" mode
cfmakeraw(&termattr);
// turn off input buffer
termattr.c_cc[VMIN] = 1;
termattr.c_cc[VTIME] = 0;
// apply terminal attr to tty
tcsetattr(ttyfd, TCSAFLUSH, &termattr);

move cursor

you can use termcap to control terminal:

// from: busybox editors/vi.c
// VT102 ESC sequences.
// See "Xterm Control Sequences"
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
#define ESC "\033"

// Cursor to given coordinate (1,1: top left)
#define ESC_SET_CURSOR_POS     ESC"[%u;%uH"

int textui_setcur(int ttyfd, unsigned int col, unsigned int row)
{
  char buf[32];
  snprintf(buf, 32, ESC_SET_CURSOR_POS, row, col);
  return write(ttyfd, buf, strlen(buf));
}

move cursor to 2, 5:

textui_setcur(ttyfd,2,5);

clear screen

// from: busybox editors/vi.c
// Clear-to-end-of-screen.
// (We use default param here.
// Full sequence is "ESC [ <num> J",
// <num> is 0/1/2 = "erase below/above/all".)
#define ESC_CLEAR2EOS          ESC"[J"
int textui_clearterm(int ttyfd)
{
  int ret;
  ret = textui_setcur(ttyfd, 1, 1);
  if (ret < 0)
    return ret;
  char buf[32];
  snprintf(buf, 32, ESC_CLEAR2EOS);
  return write(ttyfd, buf, strlen(buf));
}

make screen blank:

textui_clearterm(ttyfd);

draw a string

it will draw “Hello World” on 4, 5

char *msg = "Hello World";
textui_setcur(ttyfd,4,5);
write(ttyfd,msg,strlen(msg));

erase a string

erase a string is also simple:

it will clean “Hello World” on 4, 5 (just fill space)

msg = "           ";
textui_setcur(ttyfd,4,5);
write(ttyfd,msg,strlen(msg));

get a char from input

after setup terminal, getchar() is like getch();

int c;

while (1) {
  c = getchar();
  textui_setcur(ttyfd,4,5);    
  write(ttyfd,&c,1);
  if (c == 'q')
    break;
}

get terminal size

struct winsize wsz;
ioctl(ttyfd, TIOCGWINSZ, &wsz);
printf("COL: %d, ROW: %d\n", wsz.ws_col, wsz.ws_row);

Last updated: 2023-06-28