From: jakemiles
Subject: Common Lisp: polling for keyboard input
Date: 
Message-ID: <1161575345.469942.168070@h48g2000cwc.googlegroups.com>
Hello.  I'm writing a game-playing program in common lisp for a class,
and I'd like to have a process run while waiting for the user to enter
input (so the program can do more thinking while the user is thinking).
 I'm familiar with read-char, but I believe this halts everything until
input is read.  Is there any way to just poll an input buffer or
something every once in a while?  I'd prefer not to start playing with
threads, but if anyone knows of a straightforward option like that I'd
be interested in learning about it.

Thanks for any help.

- Jake

From: Bill Atkins
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <m2zmbnelc8.fsf@bertrand.local>
"jakemiles" <···········@gmail.com> writes:

> Hello.  I'm writing a game-playing program in common lisp for a class,
> and I'd like to have a process run while waiting for the user to enter
> input (so the program can do more thinking while the user is thinking).
>  I'm familiar with read-char, but I believe this halts everything until
> input is read.  Is there any way to just poll an input buffer or
> something every once in a while?  I'd prefer not to start playing with
> threads, but if anyone knows of a straightforward option like that I'd
> be interested in learning about it.
>
> Thanks for any help.
>
> - Jake

Will PEEK-CHAR work for you?
From: Rob Warnock
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <sr2dnd_jjrWRCqHYnZ2dnUVZ_oCdnZ2d@speakeasy.net>
jakemiles <···········@gmail.com> wrote:
+---------------
| Hello.  I'm writing a game-playing program in common lisp for a class,
| and I'd like to have a process run while waiting for the user to enter
| input (so the program can do more thinking while the user is thinking).
|  I'm familiar with read-char, but I believe this halts everything until
| input is read.  Is there any way to just poll an input buffer or
| something every once in a while?  I'd prefer not to start playing with
| threads, but if anyone knows of a straightforward option like that I'd
| be interested in learning about it.
+---------------

If you're willing to wait until the user has typed a complete line --
or some other form of "push", such as a ^D under Unix/Linux[1] --
then the CL standard function LISTEN may be what you want. That's
what I use when I'm running a long CPU-bound test and don't want to
use interrupts to stop it. Example:

    > (loop for i from 0
	    until (listen)
	do (format t "tick...~%")
	   (sleep 0.1)
	finally (format t "i = ~d~%" i))
    tick...
    tick...
    tick...
    tick...
    tick...
    tick...
				<== [typed <CR> here]
    i = 6
    NIL
    > 

The <CR> has been read at this point, but it's just leading
whitespace and won't interfere with your next REPL input.

The same thing, but without the (SLEEP 0.1):

    > (loop for i from 0
	    until (listen)
	do (format t "tick...~%")
	finally (format t "i = ~d~%" i))
    tick...
    tick...
    tick...
    ...[many, many lines omitted]...
    tick...
    tick...
    tick...
				<== [typed <CR> here]
    i = 7984
    NIL
    > 


-Rob

[1] Picky details: Most people who haven't dug into it don't understand
    that ^D [or whatever character "stty -a" reports for "eof ="]
    *isn't* really an "EOF" character at all!! It's a "push" character.
    The reason it's normally considered to be the EOF character is that
    it's *usually* typed at the beginning of the line, when there is
    nothing to read. So the Unix/Linux "read()" call returns 0, which
    is the convention for EOF. But if you type one or more characters
    other than #\newline and then type your "EOF" character (normally
    <Ctrl-D> or ^D), then you will "push" those characters into the
    "read()" and it will return however many you had typed. Common
    Lisp's READ-LINE lets you tell the difference with its second
    return value:

      > (read-line)
      hello!

      "hello!"
      NIL
      > (read-line)
      hel^D		<== Note: With CMUCL you may have to type 2 ^D's.
      "hel"
      T
      > 

    Here's an example of that:

      > (loop for i from 0
	      until (listen)
	  do (format t "tick...~%")
	     (sleep 1)
	  finally (format t "i = ~d~%" i)
		  (return (multiple-value-list (read-line))))
      tick...
      tick...
      Atick...		<== [Typed A here]
      tick...
      Btick...		<== [Typed B here]
      tick...
      tick...
      Ctick...		<== [typed C then ^D here]
      i = 8
      ("ABC" T)
      >

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: jakemiles
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <1161620992.602550.294090@f16g2000cwb.googlegroups.com>
Thank you for the help.  (listen) seems perfect, but I'm afraid I've
run into another problem.  The function below works as expected in
LispWorks, but not in Lisp In a Box (EMACS+SLIME+CLISP) on a PC.  I
have a Mac at home, so I will try it under CMUCL, but I'm trying it on
my PC at work and though it sort of reacts to the input, it just keeps
looping.

(defun think-and-listen ()
               (sleep 0.2)
               (print "Thinking...")
               (if (listen)
                   (read)
                 (think-and-listen)))

It doesn't stop no matter what keys I hit - CR, Ctrl-D, Ctrl-C, a
complete lisp expression like (1 1).  I have to kill Emacs with Ctrl-X
Ctrl-C to exit the loop.  In LispWorks, typing an open-paren pauses the
loop as expected, and I can complete the lisp expression with 1 1) and
it returns (1 1) as expected.  In SLIME/CLISP, when I type (1) and hit
enter, it prints some of the "Thinking..."s in bold, which is what
SLIME does when you enter a complete lisp expression and hit CR, but
then keeps looping and printing "Thinking...".

One clue: when I type anything, the minibuffer says

pipelined request... swank:listener-eval "(

My thought is that this is a SLIME problem, not a Lisp problem, but any
thoughts?  I need to get this to work in SLIME+CLISP on a PC, because
that's what my instructor will be running it in.

Also, where on earth is clisp's reference manual?  Where can I look up
that ext:with-keyboared function?

- Jake


Rob Warnock wrote:
> jakemiles <···········@gmail.com> wrote:
> +---------------
> | Hello.  I'm writing a game-playing program in common lisp for a class,
> | and I'd like to have a process run while waiting for the user to enter
> | input (so the program can do more thinking while the user is thinking).
> |  I'm familiar with read-char, but I believe this halts everything until
> | input is read.  Is there any way to just poll an input buffer or
> | something every once in a while?  I'd prefer not to start playing with
> | threads, but if anyone knows of a straightforward option like that I'd
> | be interested in learning about it.
> +---------------
>
> If you're willing to wait until the user has typed a complete line --
> or some other form of "push", such as a ^D under Unix/Linux[1] --
> then the CL standard function LISTEN may be what you want. That's
> what I use when I'm running a long CPU-bound test and don't want to
> use interrupts to stop it. Example:
>
>     > (loop for i from 0
> 	    until (listen)
> 	do (format t "tick...~%")
> 	   (sleep 0.1)
> 	finally (format t "i = ~d~%" i))
>     tick...
>     tick...
>     tick...
>     tick...
>     tick...
>     tick...
> 				<== [typed <CR> here]
>     i = 6
>     NIL
>     >
>
> The <CR> has been read at this point, but it's just leading
> whitespace and won't interfere with your next REPL input.
>
> The same thing, but without the (SLEEP 0.1):
>
>     > (loop for i from 0
> 	    until (listen)
> 	do (format t "tick...~%")
> 	finally (format t "i = ~d~%" i))
>     tick...
>     tick...
>     tick...
>     ...[many, many lines omitted]...
>     tick...
>     tick...
>     tick...
> 				<== [typed <CR> here]
>     i = 7984
>     NIL
>     >
>
>
> -Rob
>
> [1] Picky details: Most people who haven't dug into it don't understand
>     that ^D [or whatever character "stty -a" reports for "eof ="]
>     *isn't* really an "EOF" character at all!! It's a "push" character.
>     The reason it's normally considered to be the EOF character is that
>     it's *usually* typed at the beginning of the line, when there is
>     nothing to read. So the Unix/Linux "read()" call returns 0, which
>     is the convention for EOF. But if you type one or more characters
>     other than #\newline and then type your "EOF" character (normally
>     <Ctrl-D> or ^D), then you will "push" those characters into the
>     "read()" and it will return however many you had typed. Common
>     Lisp's READ-LINE lets you tell the difference with its second
>     return value:
>
>       > (read-line)
>       hello!
>
>       "hello!"
>       NIL
>       > (read-line)
>       hel^D		<== Note: With CMUCL you may have to type 2 ^D's.
>       "hel"
>       T
>       >
>
>     Here's an example of that:
>
>       > (loop for i from 0
> 	      until (listen)
> 	  do (format t "tick...~%")
> 	     (sleep 1)
> 	  finally (format t "i = ~d~%" i)
> 		  (return (multiple-value-list (read-line))))
>       tick...
>       tick...
>       Atick...		<== [Typed A here]
>       tick...
>       Btick...		<== [Typed B here]
>       tick...
>       tick...
>       Ctick...		<== [typed C then ^D here]
>       i = 8
>       ("ABC" T)
>       >
>
> -----
> Rob Warnock			<····@rpw3.org>
> 627 26th Avenue			<URL:http://rpw3.org/>
> San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <87pscisws9.fsf@thalassa.informatimago.com>
"jakemiles" <···········@gmail.com> writes:

> Thank you for the help.  (listen) seems perfect, but I'm afraid I've
> run into another problem.  The function below works as expected in
> LispWorks, but not in Lisp In a Box (EMACS+SLIME+CLISP) on a PC.  

Obviously, emacs do some buffering, and differently from the unix
terminal driver.


> I
> have a Mac at home, so I will try it under CMUCL, but I'm trying it on
> my PC at work and though it sort of reacts to the input, it just keeps
> looping.
>
> (defun think-and-listen ()
>                (sleep 0.2)
>                (print "Thinking...")
>                (if (listen)
>                    (read)
>                  (think-and-listen)))
>
> It doesn't stop no matter what keys I hit - CR, Ctrl-D, Ctrl-C, a
> complete lisp expression like (1 1).  I have to kill Emacs with Ctrl-X
> Ctrl-C to exit the loop.  

Try to send some data to the lisp process!  (Type RET)

With inferior-list:

[769]> (think-and-listen)

"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." 
"Thinking..." das RET

"Thinking..." DAS
[770]> 


> One clue: when I type anything, the minibuffer says
>
> pipelined request... swank:listener-eval "(
>
> My thought is that this is a SLIME problem, not a Lisp problem, but any
> thoughts?  I need to get this to work in SLIME+CLISP on a PC, because
> that's what my instructor will be running it in.

Of course.
You cannot do synchrone I/O thru emacs+slime+swank+clisp.

There are two processes, and the protocol implemented by slime+swank
doesn't allow to send a single character.


slime-net-send
  Function: Send a SEXP to Lisp over the socket PROC.
slime-repl-resend
  Command: (not documented)
slime-repl-send-input
  Function: Goto to the end of the input and send the current input.
slime-repl-send-string
  Function: (not documented)
slime-send
  Function: Send SEXP directly over the wire on the current connection.
slime-send-sigint
  Command: (not documented)


slime-repl-send-string make the form read from the string be evaluated.


Instead, you could do some kind of RPC between emacs and clisp,  or
between clisp and emacs, thru slime+swank. Have a look at:
http://darcs.informatimago.com/emacs/slime-rpc.el


> Also, where on earth is clisp's reference manual?  Where can I look up
> that ext:with-keyboared function?

Not necessarily too readable, but the url is in here somewhere:

[770]> (describe 'ext:with-keyboard)

EXT:WITH-KEYBOARD is the symbol EXT:WITH-KEYBOARD, lies in #<PACKAGE EXT>, is
accessible in 7 packages EXT, FFI, POSIX, READLINE, SCREEN, SYSTEM, ZLIB, names
a macro, has 1 property SYSTEM::DOC.
;; running ["emacsclient" "-n" "-e"
 "(w3-fetch \"http://clisp.cons.org/impnotes/terminal.html#with-kbd\")"
]...done

For more information, evaluate (SYMBOL-PLIST 'EXT:WITH-KEYBOARD).

 #<PACKAGE EXT> is the package named EXT.
 It imports the external symbols of 7 packages POSIX, SOCKET, GSTREAM, GRAY,
 I18N, COMMON-LISP, CUSTOM and exports 723 symbols to 7 packages ZLIB,
 READLINE, POSIX, FFI, CS-COMMON-LISP-USER, SCREEN, SYSTEM.

 #<MACRO #<COMPILED-FUNCTION EXT:WITH-KEYBOARD>> is a macro expander.
 For more information, evaluate
  (DISASSEMBLE (MACRO-FUNCTION 'EXT:WITH-KEYBOARD))
 .

Documentation:
SYSTEM::IMPNOTES:
"terminal.html#with-kbd"
SYSTEM::FILE:
(#P"/tmp/clisp-2.39-pjb1-regexp-build/keyboard.fas" 10 12)


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Litter box not here.
You must have moved it again.
I'll poop in the sink. 
From: jakemiles
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <1161631265.004272.16390@f16g2000cwb.googlegroups.com>
Wow, thank you very much.  That's a lot of information.

I don't have enough time to start playing with the slime/swank
interface, but I found a workaround for my situation.  I installed
clisp on its own via Cygwin, and this function behaves correctly there.
 So I will just have the instructor do that; he seemed willing to
accommodate.

Thanks again.  Long live lisp.

- Jake


Pascal Bourguignon wrote:
> "jakemiles" <···········@gmail.com> writes:
>
> > Thank you for the help.  (listen) seems perfect, but I'm afraid I've
> > run into another problem.  The function below works as expected in
> > LispWorks, but not in Lisp In a Box (EMACS+SLIME+CLISP) on a PC.
>
> Obviously, emacs do some buffering, and differently from the unix
> terminal driver.
>
>
> > I
> > have a Mac at home, so I will try it under CMUCL, but I'm trying it on
> > my PC at work and though it sort of reacts to the input, it just keeps
> > looping.
> >
> > (defun think-and-listen ()
> >                (sleep 0.2)
> >                (print "Thinking...")
> >                (if (listen)
> >                    (read)
> >                  (think-and-listen)))
> >
> > It doesn't stop no matter what keys I hit - CR, Ctrl-D, Ctrl-C, a
> > complete lisp expression like (1 1).  I have to kill Emacs with Ctrl-X
> > Ctrl-C to exit the loop.
>
> Try to send some data to the lisp process!  (Type RET)
>
> With inferior-list:
>
> [769]> (think-and-listen)
>
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..."
> "Thinking..." das RET
>
> "Thinking..." DAS
> [770]>
>
>
> > One clue: when I type anything, the minibuffer says
> >
> > pipelined request... swank:listener-eval "(
> >
> > My thought is that this is a SLIME problem, not a Lisp problem, but any
> > thoughts?  I need to get this to work in SLIME+CLISP on a PC, because
> > that's what my instructor will be running it in.
>
> Of course.
> You cannot do synchrone I/O thru emacs+slime+swank+clisp.
>
> There are two processes, and the protocol implemented by slime+swank
> doesn't allow to send a single character.
>
>
> slime-net-send
>   Function: Send a SEXP to Lisp over the socket PROC.
> slime-repl-resend
>   Command: (not documented)
> slime-repl-send-input
>   Function: Goto to the end of the input and send the current input.
> slime-repl-send-string
>   Function: (not documented)
> slime-send
>   Function: Send SEXP directly over the wire on the current connection.
> slime-send-sigint
>   Command: (not documented)
>
>
> slime-repl-send-string make the form read from the string be evaluated.
>
>
> Instead, you could do some kind of RPC between emacs and clisp,  or
> between clisp and emacs, thru slime+swank. Have a look at:
> http://darcs.informatimago.com/emacs/slime-rpc.el
>
>
> > Also, where on earth is clisp's reference manual?  Where can I look up
> > that ext:with-keyboared function?
>
> Not necessarily too readable, but the url is in here somewhere:
>
> [770]> (describe 'ext:with-keyboard)
>
> EXT:WITH-KEYBOARD is the symbol EXT:WITH-KEYBOARD, lies in #<PACKAGE EXT>, is
> accessible in 7 packages EXT, FFI, POSIX, READLINE, SCREEN, SYSTEM, ZLIB, names
> a macro, has 1 property SYSTEM::DOC.
> ;; running ["emacsclient" "-n" "-e"
>  "(w3-fetch \"http://clisp.cons.org/impnotes/terminal.html#with-kbd\")"
> ]...done
>
> For more information, evaluate (SYMBOL-PLIST 'EXT:WITH-KEYBOARD).
>
>  #<PACKAGE EXT> is the package named EXT.
>  It imports the external symbols of 7 packages POSIX, SOCKET, GSTREAM, GRAY,
>  I18N, COMMON-LISP, CUSTOM and exports 723 symbols to 7 packages ZLIB,
>  READLINE, POSIX, FFI, CS-COMMON-LISP-USER, SCREEN, SYSTEM.
>
>  #<MACRO #<COMPILED-FUNCTION EXT:WITH-KEYBOARD>> is a macro expander.
>  For more information, evaluate
>   (DISASSEMBLE (MACRO-FUNCTION 'EXT:WITH-KEYBOARD))
>  .
>
> Documentation:
> SYSTEM::IMPNOTES:
> "terminal.html#with-kbd"
> SYSTEM::FILE:
> (#P"/tmp/clisp-2.39-pjb1-regexp-build/keyboard.fas" 10 12)
>
>
> --
> __Pascal Bourguignon__                     http://www.informatimago.com/
> Litter box not here.
> You must have moved it again.
> I'll poop in the sink.
From: Pascal Bourguignon
Subject: Re: Common Lisp: polling for keyboard input
Date: 
Message-ID: <87mz7nty4h.fsf@thalassa.informatimago.com>
"jakemiles" <···········@gmail.com> writes:

> Hello.  I'm writing a game-playing program in common lisp for a class,
> and I'd like to have a process run while waiting for the user to enter
> input (so the program can do more thinking while the user is thinking).
>  I'm familiar with read-char, but I believe this halts everything until
> input is read.  Is there any way to just poll an input buffer or
> something every once in a while?  

READ-CHAR-NO-HANG

But this won't remove the buffering done on the keyboard by the OS.
For this, you need implementation dependant stuff. 


In clisp, you can use EXT:WITH-KEYBOARD and EXT:*KEYBOARD-INPUT* 
(and the SCREEN package might be useful for terminal output).


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.