你如何阅读箭头键?
How do you read the arrow keys?
对使用 termios 和 xterm 的原始模式的广泛搜索导致大量参考 "timing trick" 需要区分 escape-sequence 和单独的外观escape 字符。
那么你是怎么做到的?
我不想使用诅咒,因为我不想清屏。这是一个计算器风格的程序,所以保留 "ticker-tape" 界面很重要。
终于在 old usenet thread 中找到了一个很好的详细描述。我把相关消息全文引述出来。
Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!usenet.ins.cwru.edu!ncoast!allbery
From: all...@NCoast.ORG (Brandon S. Allbery KB8JRR)
Newsgroups: comp.unix.programmer
Subject: Re: How do you read the arrow keys?
Message-ID:
Date: 1 Jan 91 03:56:56 GMT
References:
Reply-To: all...@ncoast.ORG (Brandon S. Allbery KB8JRR)
Followup-To: comp.unix.programmer
Organization: North Coast Computer Resources (ncoast)
Lines: 68
As quoted from by brn...@kramden.acf.nyu.edu (Dan Bernstein):
+---------------
| It's really the terminal's fault, not the programmer's fault. Codes
| coming from the terminal should be uniquely decodable as untimed byte
| streams. In the best situation, no code is a prefix of another.
+---------------
AT&T has a very nice solution to this problem; unfortunately, it depends on
AT&T termio (or POSIX termios), so implementing it under a BSD variant is
difficult. Although one could conceivably come up with a hack using select,
it would not be quite as reliable. At least one commercial product I know of
uses this method (termio, not select), but it was documented in at least one
programmer's manual I've read as well.
Termio(s) doesn't really have a "raw" mode; it has a "packet" mode. The most
common use is with a packet size of 1 and a timeout of 1 (which is treated as
"no timeout"). However, one can set it for other combinations. The most
useful in this case is to set the packet size to the size of the longest
function key sequence and the timeout to the longest time needed for it to be
sent as a function key. The assumption (usually correct) being that if the
user types it, it will take longer.
Once this is done, you attempt to read() that longest number of characters at
the same time. read() returns the actual number of characters read before the
timeout, which starts after the first character of the packet is received.
Thus, single keystrokes like ESC are read as such, but given something like a
VT100, PF1 would return 3 characters --- ESC O P (ESC [ P if, like me, you
detest the applications cursor and keypad modes).
struct termio tbuf; /* POSIX: struct termios */
int maxlen = 3, len;
char buf[3];
ioctl(0, TCGETA, &tbuf); /* POSIX: tcgetattr(0, &tbuf); */
tbuf.c_lflags &= ~(ICANON|ECHO);
tbuf.c_cc[VMIN] = maxlen;
tbuf.c_cc[VTIME] = 2; /* 2/10 sec, good at 9600 baud and up */
ioctl(0, TCSETAW, &tbuf); /* POSIX: tcsetattr(0, X???WAIT, &tbuf); */
/* I forget the exact flag */
len = read(0, buf, maxlen);
if (len == 1)
{
/* single character */
}
else
{
/* function key sequence */
}
Getting VTIME correct for various baud rates can be tricky; but it's also a
one-time task. And I've used this trick in my own programs; it works well.
I believe the function key support in SVR3 curses can be coerced into doing
this if halfdelay() is enabled and works in your port.
For BSD, the most I can say is check to see if your version (e.g. Ultrix 3.x
or SunOS 4.x, etc.) supports a termio interface, or wait for BSD4.4 which
supposedly will have POSIX termios. (Since BSD4.4 is either out or will be
very soon --- I've been out of touch with it --- no doubt someone will chime in
and tell us.) Be warned that earlier Ultrix versions claimed to have termio
support, but it didn't work.
这个作者的签名区我删了,反正他承认不是原作者
对使用 termios 和 xterm 的原始模式的广泛搜索导致大量参考 "timing trick" 需要区分 escape-sequence 和单独的外观escape 字符。
那么你是怎么做到的?
我不想使用诅咒,因为我不想清屏。这是一个计算器风格的程序,所以保留 "ticker-tape" 界面很重要。
终于在 old usenet thread 中找到了一个很好的详细描述。我把相关消息全文引述出来。
Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!usenet.ins.cwru.edu!ncoast!allbery From: all...@NCoast.ORG (Brandon S. Allbery KB8JRR) Newsgroups: comp.unix.programmer Subject: Re: How do you read the arrow keys? Message-ID: Date: 1 Jan 91 03:56:56 GMT References: Reply-To: all...@ncoast.ORG (Brandon S. Allbery KB8JRR) Followup-To: comp.unix.programmer Organization: North Coast Computer Resources (ncoast) Lines: 68 As quoted from by brn...@kramden.acf.nyu.edu (Dan Bernstein): +--------------- | It's really the terminal's fault, not the programmer's fault. Codes | coming from the terminal should be uniquely decodable as untimed byte | streams. In the best situation, no code is a prefix of another. +---------------
AT&T has a very nice solution to this problem; unfortunately, it depends on AT&T termio (or POSIX termios), so implementing it under a BSD variant is difficult. Although one could conceivably come up with a hack using select, it would not be quite as reliable. At least one commercial product I know of uses this method (termio, not select), but it was documented in at least one programmer's manual I've read as well.
Termio(s) doesn't really have a "raw" mode; it has a "packet" mode. The most common use is with a packet size of 1 and a timeout of 1 (which is treated as "no timeout"). However, one can set it for other combinations. The most useful in this case is to set the packet size to the size of the longest function key sequence and the timeout to the longest time needed for it to be sent as a function key. The assumption (usually correct) being that if the user types it, it will take longer.
Once this is done, you attempt to read() that longest number of characters at the same time. read() returns the actual number of characters read before the timeout, which starts after the first character of the packet is received. Thus, single keystrokes like ESC are read as such, but given something like a VT100, PF1 would return 3 characters --- ESC O P (ESC [ P if, like me, you detest the applications cursor and keypad modes).
struct termio tbuf; /* POSIX: struct termios */
int maxlen = 3, len;
char buf[3];
ioctl(0, TCGETA, &tbuf); /* POSIX: tcgetattr(0, &tbuf); */
tbuf.c_lflags &= ~(ICANON|ECHO);
tbuf.c_cc[VMIN] = maxlen;
tbuf.c_cc[VTIME] = 2; /* 2/10 sec, good at 9600 baud and up */
ioctl(0, TCSETAW, &tbuf); /* POSIX: tcsetattr(0, X???WAIT, &tbuf); */
/* I forget the exact flag */
len = read(0, buf, maxlen);
if (len == 1)
{
/* single character */
}
else
{
/* function key sequence */
}
Getting VTIME correct for various baud rates can be tricky; but it's also a one-time task. And I've used this trick in my own programs; it works well. I believe the function key support in SVR3 curses can be coerced into doing this if halfdelay() is enabled and works in your port.
For BSD, the most I can say is check to see if your version (e.g. Ultrix 3.x or SunOS 4.x, etc.) supports a termio interface, or wait for BSD4.4 which supposedly will have POSIX termios. (Since BSD4.4 is either out or will be very soon --- I've been out of touch with it --- no doubt someone will chime in and tell us.) Be warned that earlier Ultrix versions claimed to have termio support, but it didn't work.
这个作者的签名区我删了,反正他承认不是原作者