icsu7039@nero.cs.montana.edu (Spannring) (12/28/90)
I am currently porting some menu routines from MS-DOG to Unix. What is the proper (terminal independent) way of reading the arrow and/or function keys? -- ==================================================================== Six of one, 110 (base 2) of | Craig Spannring another. | icsu7039@caesar.cs.montana.edu ----------------------------------+--------------------------------
hagins@gamecock.rtp.dg.com (Jody Hagins) (12/29/90)
In article <3080@dali>, icsu7039@nero.cs.montana.edu (Spannring) writes: |> |> I am currently porting some menu routines from MS-DOG to Unix. |> What is the proper (terminal independent) way of reading the arrow |> and/or function keys? |> |> |> -- |> ==================================================================== |> Six of one, 110 (base 2) of | Craig Spannring |> another. | icsu7039@caesar.cs.montana.edu |> ----------------------------------+-------------------------------- |> The best way to implement terminal independent interfaces is with curses. Read the manpage, and it will answer all your questions. However, if you still have problems, no problem in asking. -- Jody Hagins hagins@gamecock.rtp.dg.com Data General Corp. 62 Alexander Dr. RTP, N.C. 27709 (919) 248-6035
meissner@osf.org (Michael Meissner) (12/29/90)
I tried mailing to icsu7039@nero.cs.montana.edu, but got a mail bounce: | From: icsu7039@nero.cs.montana.edu (Spannring) | Newsgroups: comp.unix.programmer | Date: 27 Dec 90 19:20:24 GMT | Organization: Montana State University, Dept. of Computer Science, Bozeman | | | I am currently porting some menu routines from MS-DOG to Unix. | What is the proper (terminal independent) way of reading the arrow | and/or function keys? If your vendor's curses package is based on System V.2 then that is provided. If you have the old broken BSD curses, lots of luck -- you can read what the function keys send with tgetstr and the capabilities kd, ku, kl, and kr for the arrow keys -- you will have to do the parsing yourself. Quoting from the manual on curses: int getch ( void ); Get a character from stdscr. May be used with mini- curses. The following function keys might be returned by the getch() function if keypad() has been enabled: KEY_BREAK Break key (unreliable) KEY_DOWN Down arrow key KEY_UP Up arrow key KEY_LEFT Left arrow key KEY_RIGHT Right arrow key KEY_HOME Home key KEY_BACKSPACE Backspace (unreliable) KEY_F(n) Function key Fn, where n is an integer from 0 to 63 KEY_DL Delete line KEY_IL Insert line KEY_DC Delete character KEY_IC Insert character or enter insert mode KEY_EIC Exit insert character mode KEY_CLEAR Clear screen KEY_EOS Clear to end of screen KEY_EOL Clear to end of line KEY_SF Scroll one line forward KEY_SR Scroll one line backwards (reverse) KEY_NPAGE Next page KEY_PPAGE Previous page KEY_STAB Set tab KEY_CTAB Clear tab KEY_CATAB Clear all tabs KEY_ENTER Enter or send (unreliable) KEY_SRESET Soft (partial) reset (unreliable) KEY_RESET Reset or hard reset (unreliable) KEY_PRINT Print or copy KEY_LL Home down or bottom (lower left) KEY_A1 Upper left key of keypad KEY_A3 Upper right key of keypad KEY_B2 Center key of keypad KEY_C1 Lower left key of keypad KEY_C3 Lower right key of keypad Due to lack of definitions in terminfo, or due to the terminal not transmitting a unique code when the key is pressed, not all of these keys are supported. ... int keypad( WINDOW *win, bool bool_flag ); Enable keypad input on window win if bool_flag is true. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142 Considering the flames and intolerance, shouldn't USENET be spelled ABUSENET?
iverson@ivy.uucp (Tim Iverson) (12/29/90)
In article <3080@dali> icsu7039@nero.cs.montana.edu (Spannring) writes: > I am currently porting some menu routines from MS-DOG to Unix. >What is the proper (terminal independent) way of reading the arrow >and/or function keys? Reading special keys is relatively easy - just look up the arrow/function key definitions you wish to interpret in termcap or terminfo (whichever your users are more likely to be using) and decode them as they come in. The most general way to decode them is to build a key fetching FSM that represents the current terminal and then ask it for keys; it, in turn, gets byte strings from the terminal and turns them into keys. There're going to be alot of responses about getting curses to decode your keys for you. And, yes, it will do it, but it has a major problem: no timeouts; e.g. left arrow on a vt100 (or pc ansi console) is <esc>[D, so if your user hits <esc>, curses waits for the next char to come along before it knows to return the <esc> as a key. This is a failing of every package I've seen that purports to handle arrow keys in a device independent manner, although, it's such a basic problem that I assume someone somewhere is offering a package that does do it right. Marc Rochkind has a good book on terminal style I/O (Advanced C Programming for Displays) that covers all of the pieces of a comprehensive screen I/O library, read it, but don't use the C code - each piece lacks some major feature (like early prefix recognition for key input). > Six of one, 110 (base 2) of | Craig Spannring > another. | icsu7039@caesar.cs.montana.edu - Tim Iverson uunet!xstor!iverson
richard@calvin.ee.cornell.edu (Richard Brittain - VOS hacker) (12/29/90)
In article <1990Dec28.195518.26577@ivy.uucp> iverson@ivy.uucp (Tim Iverson) writes: >In article <3080@dali> icsu7039@nero.cs.montana.edu (Spannring) writes: >> I am currently porting some menu routines from MS-DOG to Unix. >>What is the proper (terminal independent) way of reading the arrow >>and/or function keys? > >There're going to be alot of responses about getting curses to decode your >keys for you. And, yes, it will do it, but it has a major problem: no >timeouts; e.g. left arrow on a vt100 (or pc ansi console) is <esc>[D, so if >your user hits <esc>, curses waits for the next char to come along before >it knows to return the <esc> as a key. Also, be prepared to make the timeout delay configurable if you want this to work over a network of any kind. I have read function keys in several programs using a 9600 bps direct connect terminal, with no problems, and using a very short timeout to detect partial escape sequences. When I first tried them from a networked workstation via xterm, I couldn't recognise any sequences because of network delays. Increasing the timeout (up to 500ms per byte sometimes) was needed to fix it. It would certainly be nice if there was a standard library that did this reliably in all cases. -- Richard Brittain, School of Elect. Eng., Eng. and Theory Center Cornell university, Ithaca, NY 14853 INTERNET: richard@calvin.ee.cornell.edu UUCP: {uunet,uw-beaver,rochester,cmcl2}!cornell!calvin!richard
john@jwt.UUCP (John Temples) (12/30/90)
In article <1990Dec28.195518.26577@ivy.uucp> iverson@ivy.uucp (Tim Iverson) writes: >There're going to be alot of responses about getting curses to decode your >keys for you. And, yes, it will do it, but it has a major problem: no >timeouts; e.g. left arrow on a vt100 (or pc ansi console) is <esc>[D, so if >your user hits <esc>, curses waits for the next char to come along before >it knows to return the <esc> as a key. From the System V/386 Release 3.2 curses man page, under getch(): "If keypad(win, TRUE) has been called, and a function key is pressed, the token for that function key will be returned instead of the raw characters. [...] If a character is received that could be the beginning of a function key (such as escape), curses will set a timer. If the remainder of the sequence is not received within the designated time, the character will be passed through, otherwise the function key value will be returned." I've used this in curses programs I've written which accept both cursor keys and the escape key as input, and it works fine. I guess it's only available in certain versions of curses? -- John W. Temples -- john@jwt.UUCP (uunet!jwt!john)
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (12/30/90)
In article <1990Dec28.195518.26577@ivy.uucp> iverson@ivy.uucp (Tim Iverson) writes: [ on the problem of interpreting <esc> given escape sequences ] > This is a failing of every package I've seen that purports to handle arrow > keys in a device independent manner, although, it's such a basic problem > that I assume someone somewhere is offering a package that does do it right. 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. A terminal could, for example, produce two <esc>s when you hit the escape key. This solves the problem trivially. Using timeouts isn't ``doing it right.'' It's an unfortunate kludge to deal with the failings of current hardware. ---Dan
kreed@telesys.cts.com (Kevin W. Reed) (12/30/90)
john@jwt.UUCP (John Temples) writes: >From the System V/386 Release 3.2 curses man page, under getch(): > >"If keypad(win, TRUE) has been called, and a function key is pressed, >the token for that function key will be returned instead of the raw >characters. [...] If a character is received that could be the >beginning of a function key (such as escape), curses will set a >timer. If the remainder of the sequence is not received within the >designated time, the character will be passed through, otherwise the >function key value will be returned." > >I've used this in curses programs I've written which accept both >cursor keys and the escape key as input, and it works fine. I guess >it's only available in certain versions of curses? It is not available on SCO Xenix when using termcap curses. It is supposed to be available via terminfo curses. Has anyone ever come up with a way to access function keys and arrow keys using SCO curses termcap? >-- >John W. Temples -- john@jwt.UUCP (uunet!jwt!john) -- Kevin W. Reed --- TeleSys Development Systems -- PO 17821, San Diego, CA 92177 TeleSys-II BBS & telesys.UUCP 619-483-3890 ----- Telebit PEP Line 619 483 0965 UUCP: {nosc,ucsd}!crash!telesys!kreed -------- Internet: kreed@telesys.cts.com
mike@bria.AIX (Mike Stefanik/78125) (12/30/90)
In article <1990Dec28.195518.26577@ivy.uucp>, iverson@ivy.uucp (Tim Iverson) writes: > There're going to be alot of responses about getting curses to decode your > keys for you. And, yes, it will do it, but it has a major problem: no > timeouts; e.g. left arrow on a vt100 (or pc ansi console) is <esc>[D, so if > your user hits <esc>, curses waits for the next char to come along before > it knows to return the <esc> as a key. Actually, this isn't true, at least with the curses packages that I've been using. The idea is to do something like this: ttystate(mode) int mode; { static struct termio old, new; if ( mode == 1 ) { ioctl(0,TCGETA,&old); ioctl(0,TCGETA,&new); new.c_lflag &= ~ECHO; new.c_lflag &= ~ICANON; new.c_lflag &= ~ISIG; new.c_cc[VMIN] = MAXCHARS; new.c_cc[VTIME] = TIMEOUT; ioctl(0,TCSETA,&new); } else ioctl(0,TCSETA,&old); } Where MAXCHARS is approx. the longest number of characters that can be returned by a function/editing key, and TIMEOUT is usually 1 (1/10th of a second). When stdin is read, the read() will return when either: a) MAXCHARS have been read b) TIMEOUT has expired Therefore, if the user just presses ESC, it is easy to determine if it was an escape key or part of a sequence such as ESC[D ... just look at the number of characters returned by read(). It gets trickier if the pesky user is holding down the arrow key, which can generate multiple escape sequences within the timeframe of the read; that's why it's good to set the MAXCHARS value to something approximating the length of the escape sequence ... if the user is holding down the key, the first sequence with satisfy MAXCHARS, and cause the read() to return, with the remaining sequences still in the input buffer. Hope this helps. ----------------------------------------------------------------------------- Michael Stefanik, Systems Engineer (JOAT), Briareus Corporation UUCP: ...!uunet!bria!mike "If it was hard to code, it should be harder to use!"
allbery@NCoast.ORG (Brandon S. Allbery KB8JRR) (01/01/91)
As quoted from <4927:Dec2920:17:4790@kramden.acf.nyu.edu> by brnstnd@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. ++Brandon -- Me: Brandon S. Allbery VHF/UHF: KB8JRR on 220, 2m, 440 Internet: allbery@NCoast.ORG Packet: KB8JRR @ WA8BXN America OnLine: KB8JRR AMPR: KB8JRR.AmPR.ORG [44.70.4.88] uunet!usenet.ins.cwru.edu!ncoast!allbery Delphi: ALLBERY
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/01/91)
In article <1991Jan1.035656.27394@NCoast.ORG> allbery@ncoast.ORG (Brandon S. Allbery KB8JRR) writes: > As quoted from <4927:Dec2920:17:4790@kramden.acf.nyu.edu> by brnstnd@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 [ followed by fifty lines of description ] That is not a nice solution. First of all, it's slow: most of the time taken by at least one editor I've tested is in reading keys using a similar method. Second, many networks will split packets at random spots, so the method will fail every once in a while. Third, it forces the editor to play with the terminal in ways it should not have to. Fourth, it is a lot more complex than a simple FSA. Fifth, it introduces time dependencies into what should be an untimed byte stream; this leads to race conditions and serves no useful purpose. It's the only kludge that works given our current broken terminals, but that doesn't make it nice. ---Dan
karl@robot.in-berlin.de (Karl-P. Huestegge) (01/02/91)
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >iverson@ivy.uucp (Tim Iverson) writes: > [ on the problem of interpreting <esc> given escape sequences ] >> This is a failing of every package I've seen that purports to handle arrow >> keys in a device independent manner, although, it's such a basic problem >> that I assume someone somewhere is offering a package that does do it right. >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. >A terminal could, for example, produce two <esc>s when you hit the >escape key. This solves the problem trivially. >Using timeouts isn't ``doing it right.'' It's an unfortunate kludge to >deal with the failings of current hardware. You're right, but a lot of terminals are able to send 8bit iso-8859 Control codes (CSI instead of 'ESC [' and DCS instead of 'ESC P' etc). DEC's VT220/VT320 can handle this for example. But I don't know if the termcap/terminfo libs can handle it... I havn't tried yet. -- Karl-Peter Huestegge karl@robot.in-berlin.de Berlin Friedenau ..unido!fub!geminix!robot!karl
karl@robot.in-berlin.de (Karl-P. Huestegge) (01/02/91)
In <1990Dec30.020124.4083@telesys.cts.com> kreed@telesys.cts.com (Kevin W. Reed) writes: >john@jwt.UUCP (John Temples) writes: >>I've used this in curses programs I've written which accept both >>cursor keys and the escape key as input, and it works fine. I guess >>it's only available in certain versions of curses? >It is not available on SCO Xenix when using termcap curses. It is >supposed to be available via terminfo curses. >Has anyone ever come up with a way to access function keys and arrow >keys using SCO curses termcap? No problem here with SCO 386GT 2.3.3. It's defined in /etc/termcap (kd,ku,kl,kr) and in /usr/include/tcap.h. -- Karl-Peter Huestegge karl@robot.in-berlin.de Berlin Friedenau ..unido!fub!geminix!robot!karl
john@jwt.UUCP (John Temples) (01/04/91)
In article <1991Jan1.035656.27394@NCoast.ORG> allbery@ncoast.ORG (Brandon S. Allbery KB8JRR) writes: >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"). Did you mean "timeout of 0" here? Timeout of 1 activates a .1 second timeout on systems I've used -- although VTIME seems to have no effect when VMIN == 1. My playing with termio shows that VTIME only takes effect between characters of multi-character reads. So how does curses halfdelay() mode work? This lets a single-character read time out in as little as .1 second. Does the fact that halfdelay() seems to be broken on many systems imply that there's something more to it than just a termio call? -- John W. Temples -- john@jwt.UUCP (uunet!jwt!john)
allbery@NCoast.ORG (Brandon S. Allbery KB8JRR) (01/05/91)
As quoted from <1991Jan3.191845.4767@jwt.UUCP> by john@jwt.UUCP (John Temples): +--------------- | In article <1991Jan1.035656.27394@NCoast.ORG> allbery@ncoast.ORG (Brandon S. Allbery KB8JRR) writes: | >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"). | | Did you mean "timeout of 0" here? Timeout of 1 activates a .1 second | timeout on systems I've used -- although VTIME seems to have no effect when | VMIN == 1. My playing with termio shows that VTIME only takes effect +--------------- Correct as to VMIN=1 disabling timeout: the packet timer starts *after the first character is received*, so it can block waiting for a packet. That's why I specified that it is a packet driver, not a general read with a timeout. I have seen and used a number of implementations; at least two use VTIME=0 to cause the driver to essentially become non-blocking, at least if VMIN=1. Weird, no? +--------------- | between characters of multi-character reads. So how does curses | halfdelay() mode work? This lets a single-character read time out in | as little as .1 second. Does the fact that halfdelay() seems to be | broken on many systems imply that there's something more to it than | just a termio call? +--------------- I strongly suspect that halfdelay breaks because of the common misconception that VTIME makes the tty driver do general reads with timeouts, when in fact it merely times out reads of packets after the first character is received. The proper way to do halfdelay() is to make the tty driver select()able or poll()able and use that with a timeout. (Most 386/486 SVR3.2's treat select() as poll() with a different calling sequence, so there's no difference in the way they work.) ++Brandon (P.S. I also suspect that the packet driver mode of the termio driver was intended as a more general alternative to the UUCP packet device driver in some V7's --- mainly because I once checked the stty settings on a port under System III when there was a uucico talking on it, and VMIN was set to the size of a UUCP G protocol packet....) -- Me: Brandon S. Allbery VHF/UHF: KB8JRR on 220, 2m, 440 Internet: allbery@NCoast.ORG Packet: KB8JRR @ WA8BXN America OnLine: KB8JRR AMPR: KB8JRR.AmPR.ORG [44.70.4.88] uunet!usenet.ins.cwru.edu!ncoast!allbery Delphi: ALLBERY