From: Rob Warnock on
Bigos <ruby.object(a)googlemail.com> wrote:
+---------------
| Jurgen Defurne <jurgen.defu...(a)telenet.be> wrote:
| > schreef Bigos:
| > > I think I have found something about cl-ncurses which might be useful.
| > > Maybe I was giving up too soon. ooops
| >
| > I used a combination of stty and the standard input functions of
| > Common Lisp. I really did not want to screw around with calling C
| > functions inside Common Lisp.
| >
| > stty-raw; <common Lisp program here>;stty-cooked
|
| I know Jurgen's idea should work, but can anybody provide simple
| example? Help will be appreciated.
+---------------

Here's a little function I hacked up in CMUCL some years ago when I
needed single character terminal input for an interactive program
[running on FreeBSD & Linux]:

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

#| What "less" does:
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
s.c_oflag |= (OPOST|ONLCR|TAB3);
s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
s.c_cc[VMIN] = 1;
s.c_cc[VTIME] = 0;
|#

(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 here's a typical use of it:

(defun space-or-q-p (&optional (prompt "[More... (q to quit)] "))
(format *query-io* "~A" prompt)
(force-output *query-io*)
(let* ((c (read-char-no-echo-cbreak *query-io*))
(bs (make-string (1+ (length prompt)) :initial-element #\backspace))
(sp (make-string (1+ (length prompt)) :initial-element #\space)))
(format *query-io* "~A~A~A" bs sp bs)
(force-output *query-io*)
(char-equal c #\q)))

As I said, this is CMUCL-specific, but almost any CL implementation
should provide you *some* way to make "ioctl()" calls...


-Rob

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

From: Thomas F. Burdick on
On Nov 13, 12:48 am, Bigos <ruby.obj...(a)googlemail.com> wrote:

> Also I am willing to consider some alternatives, for example some
> simple GUI tool-kit.

Since you mention this, if you use Ltk you can easily bind keypress
events. It wouldn't be based around a read-keypress function, but
instead, whenever your program is in the idle loop and the user
presses a key, your callback function gets called. It's the easiest
way in Lisp to get text in a window and/or circles, lines, rectangles,
etc.
From: Bigos on
On Nov 14, 1:28 pm, r...(a)rpw3.org (Rob Warnock) wrote:
> Bigos <ruby.obj...(a)googlemail.com> wrote:
>
> +---------------
> | Jurgen Defurne <jurgen.defu...(a)telenet.be> wrote:
> | > schreef Bigos:
> | > > I think I have found something about cl-ncurses which might be useful.
> | > > Maybe I was giving up too soon. ooops
> | >
> | > I used a combination of stty and the standard input functions of
> | > Common Lisp. I really did not want to screw around with calling C
> | > functions inside Common Lisp.
> | >
> | > stty-raw; <common Lisp program here>;stty-cooked
> |
> | I know Jurgen's idea should work, but can anybody provide simple
> | example? Help will be appreciated.
> +---------------
>
> Here's a little function I hacked up in CMUCL some years ago when I
> needed single character terminal input for an interactive program
> [running on FreeBSD & Linux]:
>
> (use-package :alien)
> (use-package :unix)
>
> #| What "less" does:
> s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
> s.c_oflag |=  (OPOST|ONLCR|TAB3);
> s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
> s.c_cc[VMIN] = 1;
> s.c_cc[VTIME] = 0;
> |#
>
> (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 here's a typical use of it:
>
> (defun space-or-q-p (&optional (prompt "[More... (q to quit)] "))
>   (format *query-io* "~A" prompt)
>   (force-output *query-io*)
>   (let* ((c (read-char-no-echo-cbreak *query-io*))
>          (bs (make-string (1+ (length prompt)) :initial-element #\backspace))
>          (sp (make-string (1+ (length prompt)) :initial-element #\space)))
>     (format *query-io* "~A~A~A" bs sp bs)
>     (force-output *query-io*)
>     (char-equal c #\q)))
>
> As I said, this is CMUCL-specific, but almost any CL implementation
> should provide you *some* way to make "ioctl()" calls...
>
> -Rob
>
> -----
> Rob Warnock                     <r...(a)rpw3.org>
> 627 26th Avenue                 <URL:http://rpw3.org/>
> San Mateo, CA 94403             (650)572-2607

I use sbcl and it doesn't seem to work for me. I get lots of error
messages, which I don't understand. I think it's something to do with
the packages.

Also I am surprised that you need so much code for such seemingly
trivial function. I the other language I use it's only 3 lines of
code.

system("stty raw -echo") #execute command in subshell raw mode, no
echo
char=STDIN.getc #read character from standard input
system("stty -raw echo") #reset terminal mode

Is something similar possible with sbcl?

From: Bigos on
On Nov 14, 7:38 pm, Bigos <ruby.obj...(a)googlemail.com> wrote:
> On Nov 14, 1:28 pm, r...(a)rpw3.org (Rob Warnock) wrote:
>
>
>
>
>
> > Bigos <ruby.obj...(a)googlemail.com> wrote:
>
> > +---------------
> > | Jurgen Defurne <jurgen.defu...(a)telenet.be> wrote:
> > | > schreef Bigos:
> > | > > I think I have found something about cl-ncurses which might be useful.
> > | > > Maybe I was giving up too soon. ooops
> > | >
> > | > I used a combination of stty and the standard input functions of
> > | > Common Lisp. I really did not want to screw around with calling C
> > | > functions inside Common Lisp.
> > | >
> > | > stty-raw; <common Lisp program here>;stty-cooked
> > |
> > | I know Jurgen's idea should work, but can anybody provide simple
> > | example? Help will be appreciated.
> > +---------------
>
> > Here's a little function I hacked up in CMUCL some years ago when I
> > needed single character terminal input for an interactive program
> > [running on FreeBSD & Linux]:
>
> > (use-package :alien)
> > (use-package :unix)
>
> > #| What "less" does:
> > s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
> > s.c_oflag |=  (OPOST|ONLCR|TAB3);
> > s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
> > s.c_cc[VMIN] = 1;
> > s.c_cc[VTIME] = 0;
> > |#
>
> > (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 here's a typical use of it:
>
> > (defun space-or-q-p (&optional (prompt "[More... (q to quit)] "))
> >   (format *query-io* "~A" prompt)
> >   (force-output *query-io*)
> >   (let* ((c (read-char-no-echo-cbreak *query-io*))
> >          (bs (make-string (1+ (length prompt)) :initial-element #\backspace))
> >          (sp (make-string (1+ (length prompt)) :initial-element #\space)))
> >     (format *query-io* "~A~A~A" bs sp bs)
> >     (force-output *query-io*)
> >     (char-equal c #\q)))
>
> > As I said, this is CMUCL-specific, but almost any CL implementation
> > should provide you *some* way to make "ioctl()" calls...
>
> > -Rob
>
> > -----
> > Rob Warnock                     <r...(a)rpw3.org>
> > 627 26th Avenue                 <URL:http://rpw3.org/>
> > San Mateo, CA 94403             (650)572-2607
>
> I use sbcl and it doesn't seem to work for me. I get lots of error
> messages, which I don't understand. I think it's something to do with
> the packages.
>
> Also I am surprised that you need so much code for such seemingly
> trivial function. I the other language I use it's only 3 lines of
> code.
>
>     system("stty raw -echo") #execute command in subshell raw mode, no
> echo
>     char=STDIN.getc          #read character from standard input
>     system("stty -raw echo") #reset terminal mode
>
> Is something similar possible with sbcl?

is sb-ext:run-program similar to Ruby's system()
From: Rob Warnock on
Bigos <ruby.object(a)googlemail.com> wrote:
+---------------
| r...(a)rpw3.org (Rob Warnock) wrote:
....[how to do raw/cbreak input from within CMCUL]...
| > As I said, this is CMUCL-specific, but almost any CL implementation
| > should provide you *some* way to make "ioctl()" calls...
|
| I use sbcl and it doesn't seem to work for me.
+---------------

(*Ahem!*) As I *SAID*, my code is CMUCL-specific, but almost any CL
implementation should provide you *some* way to make "ioctl()" calls.

SBCL certainly provides such a way, but it's not at all surprising
that it's *different* from CMUCL -- see the SBCL documentation for
how to do the corresponding thing.

+---------------
| Also I am surprised that you need so much code for such seemingly
| trivial function. I the other language I use it's only 3 lines of
| code.
|
| system("stty raw -echo") #execute command in subshell raw mode, no
| echo
| char=STDIN.getc #read character from standard input
| system("stty -raw echo") #reset terminal mode
+---------------

You're "fork()/exec()"-ing *two* external programs!!
My example code does everything those two external
program executions do *inside* the original process.

Anyway, who cares how much code it is? You're going to
use an application-specific wrapper function around it
anyway, aren't you?

+---------------
| Is something similar possible with sbcl?
+---------------

Yes. RTFM.


-Rob

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