I want to calculate the speed of events, for example, key keystroke events and display them. I also want to start calculating the rate only after the first event has occurred. Another requirement is that the speed calculation must stop after a certain number of keypress events. My current approach to this is
(defn keypress-chan
"Returns a channel that receives keys"
[]
(let [out (chan) handler (fn [e] (put! out (.-key e)))]
(js/document.addEventListener "keypress" handler false)
out))
(defn tick
"Pushes to `out` 1000 ms later"
[out]
(go
(<! (timeout 1000))
(>! out 1)))
(defn get-rate
"Calculates keypress per minute rate"
[ticks pressed]
(quot (* pressed 60) ticks))
(defn complete?
[count]
(>= count 100))
(defn main-loop []
(let [key-chan (keypress-chan) ticker-chan (chan)]
(go-loop [pressed 0 ticks 0]
(let [[value ch] (alts! [key-chan ticker-chan])]
(if (= ch key-chan)
(do
;; Start timer to calculate keypress rate
(if (zero? pressed)
(tick ticker-chan))
;; Do something with `value`, i. e. the key being pressed
(when-not (complete?)
(recur (inc pressed) ticks)))
(let [speed (get-rate ticks pressed)]
(swap! app-state assoc :rate rate)
(tick ticker-chan)
(recur pressed (inc ticks))))))))
So this works, but the code in main-loopit seems to me ugly. I was thinking about having a “trigger” that only fires when the first value appears in key-chanand starts the timer. Then another trigger stops the timer when necessary. But I am new to Clojure and don’t know how to work with async, so I could not create anything better than the code above.
?
key-chan?
?