How to get the global keydown event in Reflex?

175 views Asked by At

My current attempt at getting an event of global keypress (eg: user hits a keyboard shortcut, from anywhere in the UI, to trigger opening of modal dialog) is:

  prerender_ blank $ do
    -- ctx <- askJSM
    doc <- currentDocumentUnchecked
    win <- currentWindowUnchecked
    let clicked = traceEvent "hit" $ keydown Enter win
    widgetHold_ (text "Waiting") $
      ffor clicked $ \() -> do
        text "CLICKED"

However, this fails to typecheck

    • Could not deduce: DomEventType JSDOM.Types.Window 
'KeydownTag ~ Word arising from a use of ‘keydown’

Looking at the source, only Element EventResult d t has an instance, but not Window or Document.

What is the idiomatic way to achieve what I'm trying to do here, in reflex / ghcjs?

1

There are 1 answers

0
jecaro On

Here is how this can be done in reflex current version:

import qualified JSDOM as DOM
import qualified JSDOM.EventM as EventM
import qualified JSDOM.Generated.GlobalEventHandlers as Events
import Reflex.Dom.Core

globalKeyEventDemo :: (DomBuilder t m, Prerender t m) => m ()
globalKeyEventDemo =
  prerender_ blank $ do
    document <- DOM.currentDocumentUnchecked
    evEnter <- wrapDomEventMaybe document (`EventM.on` Events.keyDown) $ do
      key <- getKeyEvent
      pure $
        if keyCodeLookup (fromIntegral key) == Enter
          then Just ()
          else Nothing
    let evEnterTraced = traceEvent "hit" evEnter
    widgetHold_ (text "Waiting") . ffor evEnterTraced $ \() -> do
      text "ENTER"

Basically wrapDomEventMaybe lets you bind a low-level DOM event to a reflex event. I use a similar approach to get a global click event in my app Diverk.

This is not something I came up with from nowhere tho. I have found an example of its use in rhyolite repo.