# How to Detect Key Down Events?

**URL:** <https://discourse.julialang.org/t/how-to-detect-key-down-events/95011>\
**Category:** General Usage\
**Tags:** input-output\
**Created:** [February 22, 2023, 11:28am UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011 "2023-02-22T11:28:35Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [February 22, 2023, 11:28am UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/1 "2023-02-22T11:28:35Z")

</div>

I want to detect key presses while my main program loop runs. Say I’m computing loads of data and printing that in the REPL. I want to be able to detect any keys I press. For example, if the key ‘p’ is pressed, all the computation pauses. However, I don’t JUST wish to pause. Maybe I run a function or anything. Basically, I want to be able to detect key-down events.  
How can I achieve that?  
And of course I’m not talking about readline() since that requires you to press ENTER. Also, that prevents the rest of the program from running (Tell me if that can work with an @async loop. I couldn’t get it to work)  
I don’t want to use 3rd party packages like GTK or Makie. Just simple Key event detection!

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [February 22, 2023, 12:53pm UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/2 "2023-02-22T12:53:10Z")

</div>

I found a similar question on [stackoverflow](https://stackoverflow.com/questions/56888266/how-to-read-keyboard-inputs-at-every-keystroke-in-julia).

Based on that you could do something like this

```julia
using REPL

# Run listener as separate task using channels, put keypresses in channel for main loop
function key_listener(c::Channel)
    t = REPL.TerminalMenus.terminal
    while true
        REPL.Terminals.raw!(t, true) || error("unable to switch to raw mode")
        keypress = Char(REPL.TerminalMenus.readkey(t.in_stream))
        REPL.Terminals.raw!(t, false) || error("unable to switch back from raw mode")
        put!(c, keypress)
    end
end

function main()
    channel = Channel(key_listener, 10) # Start task, 10 is buffer size for channel
    stop = false
    while !stop
        println("Doing some long calculation")
        sleep(1)
        while !isempty(channel) # Process all keypresses
            c = take!(channel)
            if c == 'q'
                println("quitting")
                stop = true
                close(channel)
                break
            else
                println("$c is not a recognized command")
            end
        end
    end
end

```

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [February 22, 2023, 4:41pm UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/3 "2023-02-22T16:41:09Z")

</div>

```plaintext

# Run listener as separate task using channels, put keypresses in channel for main loop
function key_listener(c::Channel)
    t = REPL.TerminalMenus.terminal
    while true
        REPL.Terminals.raw!(t, true) || error("unable to switch to raw mode")
        keypress = Char(REPL.TerminalMenus.readkey(t.in_stream))
        REPL.Terminals.raw!(t, false) || error("unable to switch back from raw mode")
        put!(c, keypress)
    end
end

function main()
    channel = Channel(key_listener, 10) # Start task, 10 is buffer size for channel
    stop = false
    flag = true
    while !stop
        if flag
            println("working")
            sleep(0.5)
        end
    
        while !isempty(channel) # Process all keypresses
            c = take!(channel)
            if c == 'q'
                println("quitting")
                stop = true
                close(channel)
                break
            elseif c == 'p'
                flag = false
            elseif c == 'c'
                flag = true
            else
                println("$c is not a recognized command")
            end
        end
    end
end

```

Somehow adding a flag in the main loop causes a problem. Things work just as I wanted. But I was hoping ‘p’ to pause, ‘c’ to continue. But somehow, ‘p’ freezes the entire thing. No key press seems to work. Can you please help me out with this?

---

<div class="post-metadata">

**Author:** ![albheim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albheim/32/34660_2.png) [@albheim](https://discourse.julialang.org/u/albheim)\
**Post date:** [February 22, 2023, 9:15pm UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/4 "2023-02-22T21:15:03Z")

</div>

Hmm, would guess it is something with task scheduling there, that the `key_listener` task does not get to run enough.

I think the easiest way is to just add a short sleep in the case the flag is off, it seems to do it for me at least.

```julia
        if flag
            println("working")
            sleep(0.5)
        else
            sleep(0.1) # Makes sure we give some cpu time to the key_listener
        end

```

It also seems like the `Channel` constructor can take a `spawn` kwarg which should (may?) give it its own thread. Though this didn’t seem to fix it for me at least.  
[https://docs.julialang.org/en/v1/base/parallel/#Base.Channel-Tuple{Function}](https://docs.julialang.org/en/v1/base/parallel/#Base.Channel-Tuple%7BFunction%7D)

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [February 23, 2023, 5:35am UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/5 "2023-02-23T05:35:41Z")

</div>

![Screenshot (152)](https://global.discourse-cdn.com/julialang/original/3X/2/1/21803effb10b6e3f60da2ff5bfe6b2f47e90cd19.png)

Thanks, man, I was finally able to create this simple clock object. Now I can finally move on with my project 🙂

---

<div class="post-metadata">

**Author:** ![Maddy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maddy/32/210658_2.png) [@Maddy](https://discourse.julialang.org/u/Maddy)\
**Post date:** [February 23, 2023, 5:36am UTC](https://discourse.julialang.org/t/how-to-detect-key-down-events/95011/6 "2023-02-23T05:36:39Z")

</div>

I figured… yield() does the job as well
