Building on @jdharrison and @gringer, I wanted a listener that would track not just whether a key has been pressed, but which keys are presently pressed/down.
This gives me the following:
library(shiny)
ui = bootstrapPage(
verbatimTextOutput("results"),
## keydown
tags$script('
downKeyCount = 0;
$(document).on("keydown", function (e) {
Shiny.onInputChange("downKey", downKeyCount++);
Shiny.onInputChange("downKeyId", e.code);
});'
),
## keyup
tags$script('
upKeyCount = 0;
$(document).on("keyup", function (e) {
Shiny.onInputChange("upKey", upKeyCount++);
Shiny.onInputChange("upKeyId", e.code);
});'
)
)
server = function(input, output, session){
keyRecords = reactiveValues()
output$results = renderPrint({
keys = reactiveValuesToList(keyRecords);
names(keys[unlist(keys)]);
})
observeEvent(input$downKey, { keyRecords[[input$downKeyId]] = TRUE });
observeEvent(input$upKey, { keyRecords[[input$upKeyId]] = FALSE });
}
shinyApp(ui = ui, server = server)
Key details/changes from above:
- We use
e.code
instead of e.which
as this gives us a more useful description of what keys are pressed. E.g. "KeyA"
instead of 65
. However, this means we can not distinguish between capitals and lower case.
- We use
keydown
and keyup
instead of keypress
as keypress
appears to timeout. So if you press-and-hold a key, keypress
will be active (return TRUE) for 1-2 seconds and then be inactive (return FALSE).
- We initially used the simple listener by @jdharrison. However we use the key-pressed-count method by @gringer in our code above as otherwise pressing or releasing the same key twice in a row does not respond. But if you want to force users to alternate key presses, then we recommend the simple listener.
Shiny v1.4, R v3.6.2