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 t
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.)
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:
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.
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 <stdio.h>
#include <unistd.h>
#include <termios.h>
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.
The best references for escape sequences I've found are this and this one.