Polling keyboard input looking for e.g. 'q' in a loop to 'gracefully' terminate execution

I have a main loop that continuously acquires camera frames and some digital signals and progressively stores all data using the HDF5 module. I want this loop to terminate when the user presses a single keyboard key, e.g. ‘q’, by ‘gracefully’ releasing all the open files and hardware resources. The key idea behind this loop is that it should never block or otherwise spend a significant amount of time executing a single statement. Ideally I want the time spent inside the loop body on all statements to be less than 20 ms. So, what is a good way to detect the event of pressing a keyboard key in Julia without blocking or significantly slowing down the loop?

This is not an answer to your question, but a solution I used in a similar situation is to check for a file, say isfile("/tmp/stop"), and terminate the loop when it returns true. To stop the loop, I just touch /tmp/stop from a shell.

6 Likes

I spent some time about a month ago trying to get something like this to work. What I came up with is kind of clumsy, but it does the job. The basic issue is that julia doesn’t provide a good way to check an input stream without blocking. My solution was to call read asynchronously; it still blocks while waiting for input, but it will yield if there is no input, and allow your main computation to continue.

If you use this script, you will want to replace the sleep(0.1) with yield() to ensure that you check the input buffer each iteration.

function monitorInput()
    # Put STDIN in 'raw mode'
    ccall(:jl_tty_set_mode, Int32, (Ptr{Void}, Int32), STDIN.handle, true) == 0 || throw("FATAL: Terminal unable to enter raw mode.")

    inputBuffer = Channel{Char}(100)

    @async begin
        while true
            c = read(STDIN, Char)
            put!(inputBuffer, c)
        end
    end
    return inputBuffer
end


inputBuffer = monitorInput()
for i in 1:100
    if isready(inputBuffer) && take!(inputBuffer) == 'q'
        break
    end
    print('\r', i)
    sleep(0.1)
end

println("\nPlease have a nice day!")

Also, I was never able to get julia back out of “raw mode” to say, ask for a filename to store the partially finished computation. If anyone has a pointer on that, I would love to hear about it.

4 Likes