From: thorsten kracht
Subject: single keystrokes, cbreak mode
Date: 
Message-ID: <ctlhpl$h4gf$1@claire.desy.de>
Dear all,
I am running Lisp on Linux and I would like to read single
keystrokes from the terminal without supplying a newline
(cbreak mode, no echo).
The function read-char-no-hang doesn't do it:

(loop
   (setf l (read-char-no-hang *standard-input*))
   (unless (null l) (format t "-> ~D~%" l))
   (if (equal l #\x ) (return))
   (sleep 0.5))

If I run the above lines, i have to terminate the input
with a newline before the characters that I typed are
printed.

Any help would be appreciated, thanks in advance,
Thorsten

From: Pascal Bourguignon
Subject: Re: single keystrokes, cbreak mode
Date: 
Message-ID: <87u0oxh9uf.fsf@thalassa.informatimago.com>
thorsten kracht <···············@desy.de> writes:

> Dear all,
> I am running Lisp on Linux and I would like to read single
> keystrokes from the terminal without supplying a newline
> (cbreak mode, no echo).
> The function read-char-no-hang doesn't do it:
> 
> (loop
>    (setf l (read-char-no-hang *standard-input*))
>    (unless (null l) (format t "-> ~D~%" l))
>    (if (equal l #\x ) (return))
>    (sleep 0.5))
> 
> If I run the above lines, i have to terminate the input
> with a newline before the characters that I typed are
> printed.

Obviously, this feature will be highly implementation dependent.

In clisp, you can use the keyboard:

(EXT:WITH-KEYBOARD
     (loop for ch = (system::input-character-char
                        (read-char EXT:*KEYBOARD-INPUT*)) 
           until (and ch (char= #\return ch)) 
           do (print `(got character ,ch))))

but of course, this works only from a _terminal_, not from slime for example.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w--- 
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++ 
G e+++ h+ r-- z? 
------END GEEK CODE BLOCK------
From: thorsten kracht
Subject: thanks Re: single keystrokes, cbreak mode
Date: 
Message-ID: <ctlog8$h27j$1@claire.desy.de>
Pascal Bourguignon wrote:
> thorsten kracht <···············@desy.de> writes:
> 
> 
>>Dear all,
>>I am running Lisp on Linux and I would like to read single
>>keystrokes from the terminal without supplying a newline
>>(cbreak mode, no echo).
>>The function read-char-no-hang doesn't do it:
>>
>>(loop
>>   (setf l (read-char-no-hang *standard-input*))
>>   (unless (null l) (format t "-> ~D~%" l))
>>   (if (equal l #\x ) (return))
>>   (sleep 0.5))
>>
>>If I run the above lines, i have to terminate the input
>>with a newline before the characters that I typed are
>>printed.
> 
> 
> Obviously, this feature will be highly implementation dependent.
> 
> In clisp, you can use the keyboard:
> 
> (EXT:WITH-KEYBOARD
>      (loop for ch = (system::input-character-char
>                         (read-char EXT:*KEYBOARD-INPUT*)) 
>            until (and ch (char= #\return ch)) 
>            do (print `(got character ,ch))))
> 
> but of course, this works only from a _terminal_, not from slime for example.
> 
> 

Dear Pascal,
thanks for Your answer. Your code solved my problem.
With best regards, Thorsten
From: Pascal Bourguignon
Subject: Re: thanks Re: single keystrokes, cbreak mode
Date: 
Message-ID: <87is5dh3ex.fsf@thalassa.informatimago.com>
thorsten kracht <···············@desy.de> writes:

> Pascal Bourguignon wrote:
> > thorsten kracht <···············@desy.de> writes:
> >
> >>Dear all,
> >>I am running Lisp on Linux and I would like to read single
> >>keystrokes from the terminal without supplying a newline
> >>(cbreak mode, no echo).
> >>The function read-char-no-hang doesn't do it:
> >>
> >>(loop
> >>   (setf l (read-char-no-hang *standard-input*))
> >>   (unless (null l) (format t "-> ~D~%" l))
> >>   (if (equal l #\x ) (return))
> >>   (sleep 0.5))
> >>
> >>If I run the above lines, i have to terminate the input
> >>with a newline before the characters that I typed are
> >>printed.
> > Obviously, this feature will be highly implementation dependent.
> > In clisp, you can use the keyboard:
> > (EXT:WITH-KEYBOARD
> >      (loop for ch = (system::input-character-char
> >                         (read-char EXT:*KEYBOARD-INPUT*))
> > until (and ch (char= #\return ch))            do (print `(got
> > character ,ch))))
> > but of course, this works only from a _terminal_, not from slime for
> > example.
> >
> 
> Dear Pascal,
> thanks for Your answer. Your code solved my problem.
> With best regards, Thorsten

Ok. For finest results, you should have a look at the
input-character-char structure
(EXT:WITH-KEYBOARD (print (read-char EXT:*KEYBOARD-INPUT*)))
and use judiciously the other fields:
system::input-character-bits
system::input-character-key
and even:
system::input-character-font
depending on the kind of input you can do.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay
From: Rob Warnock
Subject: Re: single keystrokes, cbreak mode
Date: 
Message-ID: <leOdnUq8TrkqymLcRVn-tw@speakeasy.net>
Pascal Bourguignon  <····@mouse-potato.com> wrote:
+---------------
| thorsten kracht <···············@desy.de> writes:
| > I am running Lisp on Linux and I would like to read single
| > keystrokes from the terminal without supplying a newline
| > (cbreak mode, no echo).  ...
| 
| Obviously, this feature will be highly implementation dependent.
| In clisp, you can use the keyboard:
|    (EXT:WITH-KEYBOARD
|         (loop for ch = (system::input-character-char
|                            (read-char EXT:*KEYBOARD-INPUT*)) 
|               until (and ch (char= #\return ch)) 
|               do (print `(got character ,ch))))
+---------------

For comparison, this is what I use in CMUCL (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)))))

[And people say Lisp can't be used for bitbanging... Hah!  ;-}  ]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Edi Weitz
Subject: Re: single keystrokes, cbreak mode
Date: 
Message-ID: <u4qgxpp0o.fsf@agharta.de>
On Mon, 31 Jan 2005 16:10:44 +0100, thorsten kracht <···············@desy.de> wrote:

> I am running Lisp on Linux

I suppose you're talking about Common Lisp but still you have to tell
us which implementation you're using.  CMUCL?  SBCL?  CLISP?  ECL?
GCL?  AllegroCL?  LispWorks?

> and I would like to read single keystrokes from the terminal without
> supplying a newline (cbreak mode, no echo).  The function
> read-char-no-hang doesn't do it:
>
> (loop
>    (setf l (read-char-no-hang *standard-input*))

The line above invokes undefined behaviour unless you've previously
declared the variable L with DEFPARAMETER or DEFVAR.

>    (unless (null l) (format t "-> ~D~%" l))
>    (if (equal l #\x ) (return))
>    (sleep 0.5))
>
> If I run the above lines, i have to terminate the input with a
> newline before the characters that I typed are printed.

This is implementation-dependent (see above).

HTH,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")