Dealing with hotkey complexity


#1

I am currently adding some pretty generic hotkeys to a visual editing app. You can select elements on a an artboard, move them around and edit their properties. Not too far into my journey I encountered the following problems:

  • The Delete hotkey - I mapped the Delete hotkey onto the backspace and delete keys. When I now have an element selected and change some text property and hit backspace, the element gets removed rather than just changing the text property. I can think of a few solutions for this problem:
    • The input event fires before keyup. Remember that an input event happens and consider that when using delete. Pro: only done once. Con: Hacky and Procedural.
    • stop propagation on input event. Pro: clean, Con: Has to be done for every single element.
    • remember that a text input is focused and do not listen to key press events then.
  • The undo / redo keys: The app also has history buttons. The state of the currently edited project is persisted on a server. I find it tricky to figure out when to identity undo keys, apply the undo operation and persist the data afterwards - without having an undo operation push to the redo queue BUT persisting the state of the project.

Do you have any experience with these complexities? How did you handle this.

Thanks!


#2

I decoded event.target.tagName and checked if it was an input to solve a similar problem.

Either fail the decoder if target is an input if you don’t want to receive the events:


decoder : Decoder String
decoder =
    Decode.field "key" Decode.string
        |> Decode.andThen
            (\keyname ->
                Decode.at ["target", "nodeName"] Decode.string
                    |> Decode.andThen
                        (\targetName ->
                            if targetName == "INPUT" || targetName == "TEXTAREA" then
                                Decode.fail ""
                            else
                                Decode.succeed keyname
                        )
            )

Or just decode the target data and implement all conditions in your update instead


type alias KeyEvent =
    { key : String
    , target : String
    }

decoder : Decoder KeyEvent
decoder =
    Decode.field "key" Decode.string
        |> Decode.andThen
            (\keyname ->
                Decode.at ["target", "nodeName"] Decode.string
                    |> Decode.andThen
                        (\targetName ->
                            Decode.succeed
                                { key = keyname
                                , target = targetName
                                }
                        )
            )

#3

Interesting. I’ll try making it work with Browser.Events.


closed #4

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.