# Keyboard input monitoring

**URL:** <https://discourse.julialang.org/t/keyboard-input-monitoring/87078>\
**Category:** General Usage\
**Tags:** question, io\
**Created:** [September 11, 2022, 1:07pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078 "2022-09-11T13:07:12Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [September 11, 2022, 1:07pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/1 "2022-09-11T13:07:12Z")

</div>

Hello all,

I have a “simple” problem, but I can’t seem to find a simple solution.

Basically what I want is to monitor key strokes for user input in an interactive application, with a couple requirements:

1. it should not “hang” the application when the user is not providing an input
2. it should not disrupt the terminal output while it’s running (I’m working on a Terminal application). For example the user input should not be displayed.

I’ve seen a few solutions like [this](https://discourse.julialang.org/t/polling-keyboard-input-looking-for-e-g-q-in-a-loop-to-gracefully-terminate-execution/812/3) and others on SO, and had a look at how REPL.TerminalMenus does it, but none of it seems to work yet.

Any help would be great!

---

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [September 11, 2022, 2:56pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/2 "2022-09-11T14:56:06Z")

</div>

Perhaps gamezero.jl might be useful?

---

<div class="post-metadata">

**Author:** ![t-bltg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/t-bltg/32/25526_2.png) [@t-bltg](https://discourse.julialang.org/u/t-bltg)\
**Post date:** [September 11, 2022, 3:02pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/3 "2022-09-11T15:02:47Z")

</div>

Maybe [`Observables.jl`](https://github.com/JuliaGizmos/Observables.jl), used in `Makie.jl`: [Observables & Interaction](https://makie.juliaplots.org/stable/documentation/nodes/).

E.g. keyboard and mouse handling: [Events](https://makie.juliaplots.org/stable/documentation/events/).

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [September 11, 2022, 3:10pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/4 "2022-09-11T15:10:18Z")

</div>

Thanks both, I’ll have a look.

I think I’ve found a solution to make it work without halting, using `byteavailable` before reading from `stdin`. Though for some reason this seems to only work with `Base.start_reading(stdin)`, otherwise it returns 0.  
This seems to work fine in a normal Terminal, though it’s not working in VSCode yet

---

<div class="post-metadata">

**Author:** ![rmsmsgood](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rmsmsgood/32/20544_2.png) [@rmsmsgood](https://discourse.julialang.org/u/rmsmsgood)\
**Post date:** [September 11, 2022, 3:27pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/5 "2022-09-11T15:27:41Z")

</div>

Then perhaps it’s up to vscode extension and probably those issues are not of interest. Maybe you should metion more detail things what you doing, exactly you want.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [September 11, 2022, 3:39pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/6 "2022-09-11T15:39:53Z")

</div>

You could run a get-input loop asynchronously from the main application task. E.g. the loop could `read(stdin, Char)` continually and put it into a Channel, which the main task could check periodically.

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [September 11, 2022, 3:41pm UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/7 "2022-09-11T15:41:01Z")

</div>

That’s fair.

I’m working on [Term.jl](https://github.com/FedeClaudi/Term.jl) adding interactive terminal visualizations.  
Basically, you have a function that creates some output to the terminal which gets updated continuously, and I need to capture user input to modify what gets displayed.  
For example in the example below:  
 ![ezgif.com-gif-maker(12)](https://global.discourse-cdn.com/julialang/original/3X/3/6/36e88f96035a53a1bf189cf12b885a1a77ab2784.gif)

I have a `Pager` display which shows some (random) text and the user can move up and down using the arrow keys. So I want to capture the user input to modify what gets displayed.

To do that , I start with:

```julia
        Base.start_reading(stdin)

        # prepare terminal 
        raw_mode_enabled = try
            REPL.Terminals.raw!(terminal, true)
            true
        catch err
            @warn "Unable to enter raw mode: " exception=(err, catch_backtrace())
            false
        end
        # hide the cursor
        raw_mode_enabled && print(terminal.out_stream, "\x1b[?25l")

```

and then in the code that handles updating the display I call this function

```julia
function keyboard_input(live::AbstractLiveDisplay)
    if bytesavailable(terminal.in_stream) > 0
        c = readkey(terminal.in_stream) |> Int
        return if Int(c) in keys(KEYs)
            out = key_press(live, KEYs[Int(c)])
            out isa Bool && return out
            return true
        else
            Char(c)
        end
    end
    return true
end

```

which uses [readkey](https://github.com/JuliaLang/julia/blob/5d9807ddefc147f6f005a3fe8b66011b2c7af7a5/stdlib/REPL/src/TerminalMenus/util.jl#L20) defined in REPL.

using `bytesavailable` I can avoid calling `readkey` if there’s no input so I don’t end up halting the program. In a normal terminal it all works correctly: the user input is not shown but can be captured to change the display.

In VSCode it doesn’t work at all… the user input is not detected, but rather it messes up the REPL - not sure how to get around that

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [September 12, 2022, 6:14am UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/8 "2022-09-12T06:14:01Z")

</div>

In VSCode, it makes a difference whether you run code blocks from the editor or type commands directly into the repl. This seems to be due to the communication pipeline and still sometimes trips me up, things like Infiltrator should always be run from the repl. Does that make a difference for you here?

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [September 12, 2022, 11:31am UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/9 "2022-09-12T11:31:50Z")

</div>

it does, thank you!

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 27, 2022, 8:04am UTC](https://discourse.julialang.org/t/keyboard-input-monitoring/87078/10 "2022-09-27T08:04:55Z")

</div>

The terminal part from [Gameoji](https://github.com/c42f/Gameoji) from @c42f could be of inspiration too. I’ve highjacked some part of it for what I’m very sporadically (read: I would if I had more time) playing with in [TUIseer](https://github.com/louisponet/TUIseer.jl). I’m trying to develop some sort of modal tui there.
