Reputation: 312
I'm trying to implement a sort of terminal in C. I'm trying to build terminal history on up-down key pressure, but if I press those keys the cursor will go up (or down) one row. How to "control" this feature?
Edit: Let's take an example:
fgets(cmd, sizeof(cmd), stdin);
if (cmd[0] == '\033')
if (cmd[2] == 'A')
printf("up-arrow pressed!\n");
This code is horrible, but it is a good starting point. It works. The problem is that if you press the up arrow key (cursor), it moves on the upper row and print "up-arrow pressed!". How to avoid the cursor up-down movement without external libraries?
Upvotes: 0
Views: 221
Reputation: 54505
A real application would provide for exiting the program other than with a ^C
. Here is an example, amending @ctx's sample to do this (and improving the handling of escape sequences), exiting when two escapes in a row are read:
#include <stdio.h>
#include <termios.h>
int main (void) {
struct termios t, save;
int last;
tcgetattr(0, &t);
save = t;
t.c_lflag &= ~(ECHO | ICANON);
tcsetattr(0, TCSANOW, &t);
while (1) {
int ch = getchar();
if (ch == '\033') {
if (last == ch)
break;
do {
last = ch;
ch = getchar();
} while (ispunct(ch) || isdigit(ch));
if (isalpha(ch)) {
printf("Got escape sequence: ");
switch (ch) {
case 'A':
printf("Cursor up\n");
break;
case 'B':
printf("Cursor down\n");
break;
case 'D':
printf("Cursor left\n");
break;
case 'C':
printf("Cursor right\n");
break;
default:
printf("%c\n", ch);
break;
break;
}
}
} else if (ch > 0) {
printf("Got %c\n", ch);
}
last = ch;
}
tcsetattr(0, TCSANOW, &save);
return 0;
}
The equivalent (with different messages) is simpler in curses:
#include <curses.h>
int main (void) {
int last = 0;
filter();
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
while (1) {
int ch = getch();
if (ch >= 0) {
if (ch >= KEY_MIN) {
printf("Got special key %s\r\n", keyname(ch));
} else {
if (ch == '\033' && last == ch)
break;
printf("Got %s\r\n", unctrl(ch));
}
last = ch;
fflush(stdout);
}
}
endwin();
return 0;
}
Upvotes: 1
Reputation: 18420
For a starter, an example how you could initialize your terminal and some basic code:
#include <stdio.h>
#include <termios.h>
int main (void) {
struct termios t;
tcgetattr(0, &t);
t.c_lflag &= ~(ECHO | ICANON);
tcsetattr(0, TCSANOW, &t);
while (1) {
char ch = getchar();
if (ch == '\x1b') {
do {
ch = getchar();
} while (!isalpha(ch));
printf("Got escape sequence: ");
switch (ch) {
case 'A':
printf("Cursor up\n");
break;
case 'B':
printf("Cursor down\n");
break;
case 'D':
printf("Cursor left\n");
break;
case 'C':
printf("Cursor right\n");
break;
default:
printf("%c\n", ch);
}
// handle escape sequence
} else {
printf("Got %c\n", ch);
}
}
return 0;
}
Now you have to output the typed characters and move around by sending appropriate escape sequences when you receive a cursor-* or some other control sequence (instead of the debug-printf
s above). You have to closely keep track on your current screen-layout for that.
As I already suggested in my comments, this a very tedious work and apart from learning (or maybe embedded systems) I do not see a benefit compared to using libreadline or a similar API.
Upvotes: 1