My end goal is to distinguish between my pressing Esc (ASCII 27
) on my keyboard, and me pressing the → key on my keyboard (which translates to a sequence of 27 91 67
). I am using termios
to put my terminal into non-Canonical mode.
I think I understand there are two options:
- Wait some arbitrary amount of time to see if something comes in (seems hacky)
- Check STDIN to see if it is empty
I'm trying to do the latter. To that end, I'm trying to use select
to see if stdin
is empty or not.
The Problem
select
always seems to return 0 (timeout expires). That seems odd for two reasons:
- I figured that if I didn't type anything after hitting Esc, then it would return -1 since it doesn't see anything left in stdin to read
- I figured that if I typed →, then I would get a
1
returned since it sees that right after27
there is a91
and a67
to read
Neither of those things happens, so I'm afraid I just don't understand select
or standard in/out like I thought I did.
The Question(s)
Why doesn't select
return anything except 0 in my example? Is it possible to check if stdin
is empty? How do other libraries handle this?
Minimal, Complete, and Verifiable Example
I am running this on both MacOS High Sierra and Ubuntu 16 with equal results.
Source:
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
int main() {
// put terminal into non-canonical mode
struct termios old;
struct termios new;
int fd = 0; // stdin
tcgetattr(fd, &old);
memcpy(&new, &old, sizeof(old));
new.c_lflag &= ~(ICANON | ECHO);
tcsetattr(fd, TCSANOW, &new);
// loop: get keypress and display (exit via 'x')
char key;
printf("Enter a key to see the ASCII value; press x to exit.\n");
while (1) {
key = getchar();
// check if ESC
if (key == 27) {
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int selret = select(1, &set, NULL, NULL, &timeout);
printf("selret=%i\n", selret);
if (selret == 1) {
// input available
printf("possible sequence\n");
} else if (selret == -1) {
// error
printf("err=%s\n", strerror(errno));
} else {
// just esc key
printf("esc key standalone\n");
}
}
printf("%i\n", (int)key);
if (key == 'x') { break; }
}
// set terminal back to canonical
tcsetattr(fd, TCSANOW, &old);
return 0;
}
Output
gns-mac1:sandbox gns$ ./seltest
Enter a key to see the ASCII value; press x to exit.
selret=0
esc key standalone
27
selret=0
esc key standalone
27
91
67
120