How to get trigger from keyboard?

Dear all,

In my dash app, I have succeeded to have undo/redo functions from callbacks with a button component. Now, I want to upgrade it with shortcut using keyboard press (such as Ctrl+Z and Ctrl+Y). So, I wonder if there is any way to get triggers when I press keyboard keys?

Screenshot 2023-07-17 234008

Cheers,

1 Like

Hello @addsc6,

You can make your own event listeners via JS that listen to the keydown event and test that event.ctrlKey && event.key == 'Z' and event.ctrlKey && event.key == 'X' respectively. And place these functions in a JS file.

Or, you could use dash-extensions event listener:

3 Likes

Many thanks!
I have obtained the pressed key data from JS and seen it in the browser. However, I’m not be able to print out data in console.
I prepared a script below, what actually went wrong with it?
It seems like the data from keyboard bypassing python server.

import dash
from dash import Input, Output, State, ClientsideFunction, html

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button("Button", id="button"),
    html.Div(id="output"),
    html.Div(id="output2", children="This is output2")
])

app.clientside_callback(
    """
        function(n_clicks) {
            window.addEventListener("keydown", function(event) {
                document.getElementById("output").textContent = event.key;
                return "key has pressed!!"; ///event.key;
            });
            return null; // Return null to prevent any updates on the output        
        }
    """,
    Output("output", "children"),
    [Input("button", "n_clicks")]
)

@app.callback(
    Output("output2", "children"),
    Input("output", "children"),
)
def show_value(value):
    print(value)

    return dash.no_update


if __name__ == "__main__":
    app.run_server(debug=True)

JS event listeners cannot directly adjust react/dash props.

You can have the event listener trigger a click event on something that is set up to do what you want to.

1 Like

This kind of trigger is exactly what I wanted.
Could you pls explain a bit more detail?

Yes. Now, I’m seeking for the way to trigger a dash callback function upon an event of keyboard press.
Any idea how to do so?

Sure thing, here you are:

import dash
from dash import Input, Output, State, ClientsideFunction, html, dcc, ctx

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button("Undo-Button", id="undoButton"),
    html.Button("Redo-Button", id="redoButton"),
    html.Div(id='output')
])

app.clientside_callback(
    """
        function(id) {
            document.addEventListener("keydown", function(event) {
                if (event.ctrlKey) {
                    if (event.key == 'z') {
                        document.getElementById('undoButton').click()
                        event.stopPropogation()
                    }
                    if (event.key == 'x') {
                        document.getElementById('redoButton').click()
                        event.stopPropogation()
                    }
                }
            });
            return window.dash_clientside.no_update       
        }
    """,
    Output("undoButton", "id"),
    Input("undoButton", "id")
)

@app.callback(
    Output("output", "children"),
    Input("undoButton", "n_clicks"),
    Input("redoButton", "n_clicks"),
    prevent_initial_call=True
)
def show_value(n1, n2):
    return ctx.triggered_id


if __name__ == "__main__":
    app.run_server(debug=True)
3 Likes

Excellent!!! This works perfectly well.
Many many thanks!!

1 Like

Wow this is great. Didn’t know this was even possible!

2 Likes

Try this component, pretty easy, no need to write any javascript:

https://fuc.feffery.tech/FefferyKeyPress

1 Like

Hello @CNFeffery,

There is this same thing available from dash-extensions, the cool thing about using Js is that you can associate the commands with specific elements on the page rather than having the whole document listen.

That’s right, and it’s also the reason I created so many components in feffery-utils-components ( https://fuc.feffery.tech/what-is-fuc ) to prevent writing unnecessary javascript code.:blush: