How to interrupt a loop with a keyboard keystroke

1,896 views
Skip to first unread message

Felipe Jiménez

unread,
Nov 10, 2015, 5:07:17 AM11/10/15
to julia-users
I have a long loop going. It solves a solitaire board-game by brute force search, and depending on the initial configuration it could take seconds or years to finish, I never know.

I would like to be able to interrupt the loop at any time and save its state (basically the values in an Array the loop operates on). That would allow me to resume the loop later from where it left, instead of starting all over again.

Of course Ctrl-C is no good because I lose the state of the loop. My idea is something like:

   while true
      # do stuff #
      if (keyboard was pressed) && (key was 'p')      # for "pause"
         save Array to hard disk
         return
      end
   end

But I don't know how to check if "keyboard was pressed" and what key it was. I cannot use  chomp(readline())  because this waits until the user hits Enter, which stops the loop going (unless I leave a spoon pressing the Enter key :-). I need something that looks at the keyboard stack to see if a key was recently pressed, and if none was pressed, it does nothing and lets the loop continue without delay.

I normally work at the REPL.

Any ideas?

Like always, sorry if my Q is too basic, but I did check the documentation and the web and could not solve it.
And a big thank you to the Julia developers and community. I am loving it.

Páll Haraldsson

unread,
Nov 10, 2015, 7:03:13 AM11/10/15
to julia-users
On Tuesday, November 10, 2015 at 10:07:17 AM UTC, Felipe Jiménez wrote:
 
   while true
      # do stuff #
      if (keyboard was pressed) && (key was 'p')      # for "pause"

 
Any ideas?

Hopefully I'm not complicating, something like this seems not be enough (as you could be piping into stdin and something like this would not work):
http://www.cplusplus.com/reference/cstdio/getchar/

You want something like "kbhit()" it seems:

http://www.cprogramming.com/fod/kbhit.html
"Header File: conio.h
Explanation: This function is not defined as part of the ANSI C/C++ standard. It is generally used by Borland's family of compilers."

https://support.microsoft.com/en-us/kb/43993

http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html



I believe this is OS dependent (and last time I did something similar keyboard related, it was on non-Julia supported OS, RISC OS..).

readline is good, would be great if Julia Base would abstract away the differences between the lower-level keyboard access the OSes use.. but since you didn't find anything I guess you can rule out that it has been done already.. There might be one exception. Ctrl-C works I think in all OSes(?) but should kill your program, maybe you can trap that, but probably easier to concentrate on non-Ctrl-C working for you.


The only game library I know available to Julia is kind of an overkill..:

https://github.com/zyedidia/SFML.jl

But this is something (a wrapper for a C++ game library) they have to deal with (and much more..) and you could even let a joystick [button] exit your loop..


Python for sure must have some way (or at least a [wrapper] library). They have SDL game library wrapped with PyGame, and I tried to google something else:

http://stackoverflow.com/questions/676713/is-there-a-cross-platform-python-low-level-api-to-capture-or-generate-keyboard-e


With PyCall.jl you could get at anything Python has access too. I hope its not too slow, you could check e.g. every tenth iteration of the loop then).

Maybe Tk directly is possible directly, best option?) or Tkinter:

http://www.ehow.com/how_10015489_check-keypress-python.html


You could also easily access the OS dependent parts directly.. Might be enough for you, but please (someone) then make a package with that method, so it can be special-cased/extended with @Linux etc. (end eventually incorporated into Base..).

--
Palli.

Cedric St-Jean

unread,
Nov 10, 2015, 7:36:32 AM11/10/15
to julia-users
Couldn't you periodically (every N iterations) save the array to disk? Or even better, put it in a global variable?

Felipe Jiménez

unread,
Nov 10, 2015, 8:23:47 AM11/10/15
to julia-users
Thank you, Palli and Cedri.

Palli's answer shows it's not as easy as I thought. Cedric's answer is practical without overkill, so I'll go that way by now.

Still if someone writes a Julia readchar() or readkey() function that is similar to readline() but does not wait for Enter to be pressed, I am sure many people will find it useful!

Cedric St-Jean

unread,
Nov 10, 2015, 10:50:29 AM11/10/15
to julia-users
This works too:

try
   
while true
   
end
catch x
   
if isa(x, InterruptException)
       
return array
   
end
end

Páll Haraldsson

unread,
Nov 10, 2015, 12:00:56 PM11/10/15
to julia...@googlegroups.com

On þri 10.nóv 2015 12:03, Páll Haraldsson wrote:
> The only game library I know available to Julia is kind of an overkill..:
>
> https://github.com/zyedidia/SFML.jl
>
> But this is something (a wrapper for a C++ game library) they have to
> deal with (and much more..) and you could even let a joystick [button]
> exit your loop..

You could use this or someone could extract (only) the low-level
keyboard code..:


Ironically I could get the library installed, got some spinning graphics
examples in a Window, but couldn't get checking keyboard status to work
at first :)

Just follow the main README, also "install the package libsfml-dev which
will also install all dependencies" (that are 46 MB) if on Linux. On
Windows everything seems handled, and I also saw some OS X specific code.



Anyway, after trying this example also (also copy-pasting it to the REPL):

https://github.com/zyedidia/SFML.jl/blob/master/examples/Graphics/pong.jl


I got this to work:

[This works for me on Linux, after the graphics window is gone]


#38=left SHIFT, see the file above

julia> is_key_pressed(38)
false

julia> is_key_pressed(38) #while pressing left SHIFT
true



https://github.com/zyedidia/SFML.jl/blob/master/src/julia/Window/keyboard.jl

function is_key_pressed(key::Int)
return ccall((:sfKeyboard_isKeyPressed, libcsfml_window), Int32,
(Int32,), key) == 1
end

baremodule KeyCode
const UNKNOWN = -1
const A = 0
const B = 1

[..]


First I made an error with just copy-pasting this:

julia> ccall((:sfKeyboard_isKeyPressed, libcsfml_window), Int32,
(Int32,), key) == 1
ERROR: UndefVarError: key not defined
in anonymous at no file


This still doesn't work (while the is_key_pressed(38) function works
because of libcsfml_window that is not avaiable to me from the REPL):

julia> ccall((:sfKeyboard_isKeyPressed, libcsfml_window), Int32,
(Int32,), 38) == 1
ERROR: UndefVarError: libcsfml_window not defined
in anonymous at no file
Reply all
Reply to author
Forward
0 new messages