Each implementation supports this differently.
You might want to use an auxiliary library like iolib.termios or cl-charms (interface to libcurses) if you want a portability layer above different implementations.
SBCL
I found a discussion thread about it for SBCL, and here is the code for that implementation, from Richard M. Kreuter:
(require :sb-posix)
(defun echo-off ()
(let ((tm (sb-posix:tcgetattr sb-sys:*tty*)))
(setf (sb-posix:termios-lflag tm)
(logandc2 (sb-posix:termios-lflag tm) sb-posix:echo))
(sb-posix:tcsetattr sb-sys:*tty* sb-posix:tcsanow tm)))
(defun echo-on ()
(let ((tm (sb-posix:tcgetattr sb-sys:*tty*)))
(setf (sb-posix:termios-lflag tm)
(logior (sb-posix:termios-lflag tm) sb-posix:echo))
(sb-posix:tcsetattr sb-sys:*tty* sb-posix:tcsanow tm)))
And so, here is finally an opportunity to talk about PROG2
:
(defun read-silently ()
(prog2
(echo-off)
(read-line sb-sys:*tty*)
(echo-on)))
However, you might want to ensure that the echo is always reset when unwinding the stack, and clear the input before inputting things:
(defun read-silently ()
(echo-off)
(unwind-protect
(progn
(clear-input sb-sys:*tty*)
(read-line sb-sys:*tty*))
(echo-on)))
CL-CHARMS
Here is an alternative using libcurse. The following is sufficient to make a simple test work.
(defun read-silently ()
(let (input)
(charms:with-curses ()
(charms:disable-echoing)
(charms:enable-raw-input)
(clear-input *terminal-io*)
(setf input (read-line *terminal-io*))
(charms:disable-raw-input)
(charms:enable-echoing))
input))
Besides, using libcurse might help you implement a nice-looking hangman console game.