Linux пишем свой терминал

Writing a «real» interactive terminal program like vim, htop, . in C/C++ without ncurses

No, I don’t want to use ncurses, because I want to learn how the terminal works and have fun programming it on my own. 🙂 It doesn’t have to be portable, it has to work on linux xterm-based terminal emulators only.

  1. how to get mouse interactions like clicking on a character and scrolling the mouse wheel (when the mouse is at a specific character) to implement scrolling [EDIT: in a terminal emulator of course], and
  2. how to completely save and restore the output of the parent process and seperate my printing from its output, so after leaving my application nothing but the command I entered in the shell should be there, like when running htop and quitting it again: nothing is visible from this application anymore.

I really don’t want to use ncurses. But of course, if you know which part of ncurses is responsible for these tasks, you’re welcome to tell me where in the source code I can find it, so I will study it.

I said this because I am sure I don’t know the ncurses source code as good as someone using it all day. 🙂

most people use its API but doesn’t change its implementation, so there’s small chance you’ll meet such people. Just read the sources, for example, I found file «lib_mvcur.c» in one minute (including downloading sources) which contains «The routines for moving the physical cursor and scrolling». Check file comments, documentation looks fine

Most terminals emulate atleast a vt220, so you could start implementing the control for that. (Though few programs are crazy enough to do that, including vim, and they rather use ncurses or at least termcap)

First you need to know how to set the terminal into raw mode, second you at least need termcap (libtermcap) or roll your own tput and abstraction layer. Without the mouse, I’d estimate this would require a few months of work for someone with C and unix experience. The tgetc with timeout on ESC is nasty for parsers. Certainly not for the faint at heart.

Читайте также:  Find build of linux

3 Answers 3

In order to manipulate the terminal you have to use control sequences. Unfortunately, those codes depend on the particular terminal you are using. That’s why terminfo (previously termcap ) exists in the first place.

You don’t say if you want to use terminfo or not. So:

  • If you will use terminfo, it will give you the correct control sequence for each action your terminal supports.
  • If you won’t use terminfo. well, you have to manually code every action in every terminal type you want to support.

As you want this for learning purposes, I’ll elaborate in the second.

You can discover the terminal type you are using from the environment variable $TERM . In linux the most usual are xterm for terminal emulators (XTerm, gnome-terminal, konsole), and linux for virtual terminals (those when X is not running).

You can discover the control sequences easily with command tput . But as tput prints them on the console, they will apply immediately, so if you want to really see them, use:

$ TERM=xterm tput clear | hd 00000000 1b 5b 48 1b 5b 32 4a |.[H.[2J| $ TERM=linux tput clear | hd 00000000 1b 5b 48 1b 5b 4a |.[H.[J| 

That is, to clear the screen in a xterm you have to output ESC [ H ESC [ 2J in an xterm but ESC [ H ESC [ J in a linux terminal.

About the particular commands you ask about, you should read carefully man 5 terminfo . There is a lot of information there.

There are many ways to skin a cat. And there are many ways to clear the screen. Particularly, IIRC, ESC[2J clears the whole screen while ESC[J clears from the cursor to the end-of-screen. But since ESC[H moves the cursor to the HOME, those should be equivalent. Not surprisingly xterm and linux terminals tend to be quite similar.

Читайте также:  Установка драйверов видеокарту линукс

Only really obscure stuff actually varies heavily between real-world terminals, which all roughly conform to the ANSI/ECMA standard. If you just treat both ^H and ^? as backspace key and otherwise follow the standard, curses/termcap/terminfo is pretty much obsolete.

@R.. I would say the opposite, that only the most used stuff is common . For example, pressing F2 ( tput kf2 ) will generate ESC OQ in xterm but ESC[[B in linux. However pressing right-arrow ( tput cuf1 ) will do ESC [C on both.

Although this is question a bit old, I thought I should share a short example of how to do this without using ncurses, it’s not difficult but I’m sure it won’t be as portable.

This code sets stdin in raw mode, switches to an alternate buffer screen (which saves the state of the terminal before launching it), enables mouse tracking and prints the button and the coordinates when the user clicks somewhere. After quitting with Ctrl + C the program reverts the terminal configuration.

#include #include #include int main (void) < unsigned char buff [6]; unsigned int x, y, btn; struct termios original, raw; // Save original serial communication configuration for stdin tcgetattr (STDIN_FILENO, &original); // Put stdin in raw mode so keys get through directly without // requiring pressing enter. cfmakeraw (&raw); tcsetattr (STDIN_FILENO, TCSANOW, &raw); // Switch to the alternate buffer screen write (STDOUT_FILENO, "\e[?47h", 6); // Enable mouse tracking write (STDOUT_FILENO, "\e[?9h", 5); while (1) < read (STDIN_FILENO, &buff, 1); if (buff[0] == 3) < // User pressd Ctr+C break; >else if (buff[0] == '\x1B') < // We assume all escape sequences received // are mouse coordinates read (STDIN_FILENO, &buff, 5); btn = buff[2] - 32; x = buff[3] - 32; y = buff[4] - 32; printf ("button:%u\n\rx:%u\n\ry:%u\n\n\r", btn, x, y); >> // Revert the terminal back to its original state write (STDOUT_FILENO, "\e[?9l", 5); write (STDOUT_FILENO, "\e[?47l", 6); tcsetattr (STDIN_FILENO, TCSANOW, &original); return 0; > 

Note: This will not work properly for terminals that have more than 255 columns.

Читайте также:  Как переименовать файл в linux

The best references for escape sequences I’ve found are this and this one.

For anyone wondering why buff[0] == 3 means Ctrl+C was pressed, it’s because in ASCII 0x03 is the ETX symbol, which stands for «End of Text».

I’m a bit confused. You speak of a “terminal application”, like vim; terminal applications don’t get mouse events, and don’t respond to the mouse.

If you’re talking about real terminal applications, which run in an xterm , the important thing to note is that many of the portability issues concern the terminal, and not the OS. The terminal is controlled by sending different escape sequences. Which ones do what depend on the terminal; the ANSI escape codes are now fairly widespread, however, see http://en.wikipedia.org/wiki/ANSI_escape_code. These are generally understood by xterm , for example.

You may have to output an additional sequence at the start and at the end to enter and leave “full screen” mode; this is necessary for xterm .

Finally, you’ll have to do something special at the input/output level to ensure that your output driver doesn’t add any characters (e.g. convert a simple LF into a CRLF), and ensure that input doesn’t echo, is transparent, and returns immediately. Under Linux, this is done using ioctl . (Again, don’t forget to restore it when you finish.)

Источник

Оцените статью
Adblock
detector