Subject: Re: read-char vs. read-char-no-hang
From: rpw3@rpw3.org (Rob Warnock)
Date: Wed, 08 Apr 2009 20:24:00 -0500
Newsgroups: comp.lang.lisp
Message-ID: <tOadnQykJJOt00DUnZ2dnUVZ_t6dnZ2d@speakeasy.net>
jurgen_defurne  <jurgen.defurne@pandora.be> wrote:
+---------------
| My problem is that I want to emulate a keyboard, not a terminal, in
| CL, sending and interpreting each character typed on the keyboard. One
| solution I have found is to use stty, but this interferes with using
| e.g. CLISP on the command line. I know that CLISP e.g. has separate
| extensions to deal with the issue, but then my code gets less portable
| across compilers. I haven't found a similar extension in SBCL ...
+---------------

The non-portability is simply something you're going to have to
live with, since TTY handling isn't part of the ANSI standard.
Feature expressions should be able to encapsulate the non-portable
buts easily enough, though. I don't know what facilities CLISP
provides, but here's what I use in CMUCL when running on FreeBSD:

    (use-package :alien)
    (use-package :unix)

    (defun read-char-no-echo-cbreak (&optional (stream *query-io*))
      (with-alien ((old (struct termios))
		   (new (struct termios)))
	(let ((e0 (unix-tcgetattr 0 old))
	      (e1 (unix-tcgetattr 0 new))
	      (bits (logior tty-icanon tty-echo tty-echoe
			    tty-echok tty-echonl)))
	  (declare (ignorable e0 e1))
	  (unwind-protect
	      (progn
		(setf (slot new 'c-lflag) (logandc2 (slot old 'c-lflag) bits))
		(setf (deref (slot new 'c-cc) vmin) 1)
		(setf (deref (slot new 'c-cc) vtime) 0)
		(unix-tcsetattr 0 tcsadrain new)
		(read-char stream))
	    (unix-tcsetattr 0 tcsadrain old)))))

Depending on your exact application, you might want to change that
READ-CHAR near the end to a READ-CHAR-NO-HANG [and also change the
function name], but for a character-at-a-time command-style program
such as an editor, pager, mail reader, or non-realtime game, the
READ-CHAR should be fine.

[Also, if you're going to be doing this a lot you'll probably
want to cache the "new" and "old" TERMIOS structs in globals
to reduce consing.]


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607