1
1
module Test.Keyboard where
2
2
3
+ import Prelude
4
+
3
5
import Concur.Core.Types (Widget )
4
6
import Concur.React (HTML )
5
7
import Concur.React.DOM as D
@@ -19,7 +21,20 @@ import Effect.Aff (Aff)
19
21
import Effect.Aff.Class (liftAff )
20
22
import Effect.Aff.Compat (EffectFnAff , fromEffectFnAff )
21
23
import Effect.Class (liftEffect )
24
+ import FRP.Event (Event )
25
+ import FRP.Event as FRP.Event
22
26
import React.SyntheticEvent as R
27
+ import Web.Event.Event (EventType (..))
28
+ import Web.Event.Event as Web.Event.Event
29
+ import Web.Event.EventTarget as Web.Event.EventTarget
30
+ import Web.HTML as Web.HTML
31
+ import Web.HTML.Window as Web.HTML.Window
32
+ import Web.UIEvent.KeyboardEvent (KeyboardEvent )
33
+ import Web.UIEvent.KeyboardEvent as Web.UIEvent.KeyboardEvent
34
+ import Web.DOM.Document as Web.DOM.Document
35
+ import Web.HTML.HTMLDocument as Web.HTML.HTMLDocument
36
+ import Effect.AVar as Effect.AVar
37
+ import Effect.Aff.AVar as Effect.Aff.AVar
23
38
24
39
25
40
-- A virtual keyboard, that also demonstrates how to handle document level events
@@ -30,34 +45,45 @@ import React.SyntheticEvent as R
30
45
-- A never-ending virtual keypad widget.
31
46
-- Allows the user to navigate and select a key. Displays the selected key.
32
47
keypadWidget :: forall a . Widget HTML a
33
- keypadWidget = go Enter " " <|> toggleEvents
34
- where
35
- go focus msg = do
36
- keyPressed <- virtualKeyInput focus <|> D .div' [D .text msg]
37
- go keyPressed $ " You clicked: " <> show keyPressed
48
+ keypadWidget = do
49
+ keyboardRef <- liftEffect $ do
50
+ keyboardRef <- Effect.AVar .empty
51
+
52
+ -- TODO: don't silently fail to put, use Channel instead of EVar
53
+ stopListeningKeydownEvent <- FRP.Event .subscribe documentKeydownEvent \keyboardEvent -> void $ Effect.AVar .tryPut keyboardEvent keyboardRef
54
+
55
+ pure keyboardRef
56
+
57
+ let (awaitKeyboardEvent :: Aff KeyboardEvent ) = Effect.Aff.AVar .take keyboardRef
58
+
59
+ go awaitKeyboardEvent Enter " "
38
60
39
- -- On off button for key events
40
- toggleEvents :: forall a . Widget HTML a
41
- toggleEvents = go false
42
61
where
43
- go enabled = do
44
- _ <- D .button [P .onClick] [D .text $ if enabled then " stop listening" else " start listening" ]
45
- liftEffect (if enabled then stopListening else startListening)
46
- go (not enabled)
62
+ go awaitKeyboardEvent focus msg = do
63
+ keyPressed <- virtualKeyInput awaitKeyboardEvent focus <|> D .div' [D .text msg]
64
+ go awaitKeyboardEvent keyPressed (" You clicked: " <> show keyPressed)
65
+
66
+ -- | -- On off button for key events
67
+ -- | toggleEvents :: forall a. Widget HTML a
68
+ -- | toggleEvents = go false
69
+ -- | where
70
+ -- | go enabled = do
71
+ -- | _ <- D.button [P.onClick] [D.text $ if enabled then "stop listening" else "start listening"]
72
+ -- | liftEffect (if enabled then stopListening else startListening)
73
+ -- | go (not enabled)
47
74
48
75
-- Displays a keypad with the supplied initial focus.
49
76
-- Allows the user to navigate and select a key. Returns the selected key.
50
- virtualKeyInput :: Focus -> Widget HTML Key
51
- virtualKeyInput focus = do
52
- evt <- liftAff awaitKey <|> keypadButtons focus
53
- key <- liftEffect $ toKey evt
77
+ virtualKeyInput :: Aff KeyboardEvent -> Focus -> Widget HTML Key
78
+ virtualKeyInput awaitKeyboardEvent focus = do
79
+ (key :: Maybe Key ) <- liftAff (map toKey awaitKeyboardEvent) <|> keypadButtons focus
54
80
case key of
55
81
Just Enter -> pure focus
56
- Nothing -> virtualKeyInput focus
57
- Just ArrowUp -> virtualKeyInput (transition focus U )
58
- Just ArrowDown -> virtualKeyInput (transition focus D )
59
- Just ArrowLeft -> virtualKeyInput (transition focus L )
60
- Just ArrowRight -> virtualKeyInput (transition focus R )
82
+ Nothing -> virtualKeyInput awaitKeyboardEvent focus
83
+ Just ArrowUp -> virtualKeyInput awaitKeyboardEvent (transition focus U )
84
+ Just ArrowDown -> virtualKeyInput awaitKeyboardEvent (transition focus D )
85
+ Just ArrowLeft -> virtualKeyInput awaitKeyboardEvent (transition focus L )
86
+ Just ArrowRight -> virtualKeyInput awaitKeyboardEvent (transition focus R )
61
87
62
88
-- Dispay only. Renders the keypad buttons with the supplied focus
63
89
keypadButtons :: forall a . Focus -> Widget HTML a
@@ -82,15 +108,24 @@ keypadButtons focus = D.table' $ pure $ D.tbody'
82
108
83
109
-- FFI ------------------------------------------------------------
84
110
85
- -- Start and stop listening for keyboard events
86
- foreign import startListening :: Effect Unit
87
- foreign import stopListening :: Effect Unit
111
+ documentKeydownEvent :: Event KeyboardEvent
112
+ documentKeydownEvent = FRP.Event .makeEvent \push -> do
113
+ window <- Web.HTML .window
114
+
115
+ document <- Web.HTML.Window .document window
116
+
117
+ eventListener <- Web.Event.EventTarget .eventListener
118
+ (\event ->
119
+ case Web.UIEvent.KeyboardEvent .fromEvent event of
120
+ Nothing -> pure unit
121
+ Just event' -> push event'
122
+ )
123
+
124
+ let eventType = EventType " keydown"
88
125
89
- -- Await a key input. Requires that we are listening for events.
90
- foreign import _awaitKey :: EffectFnAff R.SyntheticKeyboardEvent
91
- awaitKey :: Aff R.SyntheticKeyboardEvent
92
- awaitKey = fromEffectFnAff _awaitKey
126
+ Web.Event.EventTarget .addEventListener eventType eventListener false (Web.HTML.HTMLDocument .toEventTarget document)
93
127
128
+ pure $ Web.Event.EventTarget .removeEventListener eventType eventListener false (Web.HTML.HTMLDocument .toEventTarget document)
94
129
95
130
-- Data structures ------------------------------------------------
96
131
@@ -120,10 +155,9 @@ type Focus = Key
120
155
121
156
data Dir = U | D | L | R
122
157
123
- toKey :: R.SyntheticKeyboardEvent -> Effect (Maybe Key )
124
- toKey event = do
125
- k <- R .key event
126
- pure $ case k of
158
+ toKey :: KeyboardEvent -> Maybe Key
159
+ toKey event =
160
+ case Web.UIEvent.KeyboardEvent .key event of
127
161
" ArrowUp" -> Just ArrowUp
128
162
" ArrowDown" -> Just ArrowDown
129
163
" ArrowLeft" -> Just ArrowLeft
0 commit comments