我試圖檢測是否有數據標準輸入框讓我讀。選擇(2)和ioctl(2)返回0,而標準輸入有數據
具體而言,我已經使用tcsetattr
關閉了規範模式,所以我可以一次讀取一個字符(阻止)。我想要檢測像箭頭鍵生成的轉義序列,但將它們與單獨的轉義鍵區分開來。另外,我想快速知道輸入的內容;我假設我的終端相當快,並且在^[
之後的其他轉義序列相當快。
假設我已經知道(例如使用select(2)
)在標準輸入框中需要讀取內容。我使用getchar()
讀取了一個字符,它是一個^[
,ASCII 27。現在我想知道是否有更多內容在某個時間間隔內進入,或者此轉義字符是所有內容(這將指示轉義鍵的命中)。使用select(2)
這似乎不工作,因爲(我注意到,並在其他地方讀)其餘的字符已經被緩衝,所以select(2)
已經沒有什麼可以檢測了。所以我轉向ioctl(2)
使用FIONREAD
,但這似乎並不奏效。
最小(非)工作實施例:
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <assert.h>
struct termios tios_bak;
void initkeyboard(void){
struct termios tios;
tcgetattr(0,&tios_bak);
tios=tios_bak;
tios.c_lflag&=~ICANON;
tios.c_cc[VMIN]=1; // Read one char at a time
tios.c_cc[VTIME]=0; // No timeout on reading, make it a blocking read
tcsetattr(0,TCSAFLUSH,&tios);
}
void endkeyboard(void){
tcsetattr(0,TCSAFLUSH,&tios_bak);
}
int main(void){
initkeyboard();
atexit(endkeyboard);
printf("Press an arrow key or the escape key, or the escape key followed by something else.\n");
char c=getchar();
if(c!=27){
printf("Please input an escape sequence or key\n");
exit(1);
}
// Now we use select(2) to determine whether there's anything more to read.
// If it was a lone escape key, there won't be anything new in a while.
fd_set rdset;
FD_ZERO(&rdset);
FD_SET(0,&rdset);
struct timeval tv;
tv.tv_sec=1; // Here we wait one second; this is just to illustrate. In a real environment
tv.tv_usec=0; // I'd wait something like 100ms, since that's reasonable for a terminal.
int ret=select(1,&rdset,NULL,NULL,&tv);
assert(ret!=-1); // (Error checking basically omitted)
if(ret==0){
printf("select(2) returned 0.\n");
int n;
assert(ioctl(0,FIONREAD,&n)>=0);
assert(n>=0);
if(n==0){
printf("ioctl(2) gave 0; nothing to read: lone escape key\n");
// INSERT printf("%c\n",getchar()); HERE TO DEMONSTRATE THIS IS WRONG IN CASE OF ESCAPE SEQUENCE
} else {
c=getchar();
printf("ioctl(2) says %d bytes in read buffer (first char=%c)\n",n,c);
}
} else {
c=getchar();
printf("select(2) returned %d: there was more to read (first char=%c)\n",ret,c);
}
}
很抱歉的長碼。會發生什麼如下:
- 當您只需按下轉義鍵,它會成功檢測到。
- 當你按下轉義鍵,然後快速的一些其他鍵(如'a'),代碼成功檢測到有更多的閱讀,這是好的;特定的轉義序列檢測超出了範圍。
- 當您生成轉義序列時,例如通過按箭頭鍵,都
select(2)
和ioctl(2)
返回沒有什麼可讀,雖然顯然有;這可以通過在指定位置插入printf("%c\n",getchar());
來輕鬆檢查。這將打印[
(至少在箭頭鍵的情況下)。
問題:如何正確檢測輸入情況(3)?
謝謝,這就是它!還沒有看到這個需求在別的地方解釋過。 – tomsmeding
@tomsmeding,編輯 –