From b6ef21e1216b745cd3b71d9c4f7af2386bfebf90 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 28 Nov 2023 10:40:24 +0100 Subject: [PATCH] :zap: Add performance oriented refactor for keyboard streams --- .../app/main/data/workspace/transforms.cljs | 4 +- frontend/src/app/main/streams.cljs | 138 +++++------------- .../main/ui/workspace/viewport/actions.cljs | 18 ++- .../app/main/ui/workspace/viewport/hooks.cljs | 66 +++++++-- frontend/src/app/util/keyboard.cljs | 38 ++++- 5 files changed, 135 insertions(+), 129 deletions(-) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 951962aa3..2855b1686 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -33,6 +33,7 @@ [app.main.snap :as snap] [app.main.streams :as ms] [app.util.dom :as dom] + [app.util.keyboard :as kbd] [beicon.core :as rx] [potok.core :as ptk])) @@ -673,7 +674,8 @@ (rx/switch-map #(rx/merge (rx/timer 1000) (->> stream - (rx/filter ms/key-up?) + (rx/filter kbd/keyboard-event?) + (rx/filter kbd/key-up-event?) (rx/delay 250)))) (rx/take 1)) diff --git a/frontend/src/app/main/streams.cljs b/frontend/src/app/main/streams.cljs index 24c8c49a1..124ab9360 100644 --- a/frontend/src/app/main/streams.cljs +++ b/frontend/src/app/main/streams.cljs @@ -15,23 +15,9 @@ ;; --- User Events -(defrecord KeyboardEvent [type key shift ctrl alt meta editing event]) - -(defn keyboard-event? - [v] - (instance? KeyboardEvent v)) - -(defn key-up? - [v] - (and (keyboard-event? v) - (= :up (:type v)))) - -(defn key-down? - [v] - (and (keyboard-event? v) - (= :down (:type v)))) - (defrecord MouseEvent [type ctrl shift alt meta]) +(defrecord PointerEvent [source pt ctrl shift alt meta]) +(defrecord ScrollEvent [point]) (defn mouse-event? [v] @@ -57,21 +43,17 @@ (and (mouse-event? v) (= :double-click (:type v)))) -(defrecord PointerEvent [source pt ctrl shift alt meta]) - (defn pointer-event? [v] (instance? PointerEvent v)) -(defrecord ScrollEvent [point]) - (defn scroll-event? [v] (instance? ScrollEvent v)) (defn interaction-event? [event] - (or (keyboard-event? event) + (or (kbd/keyboard-event? event) (mouse-event? event))) ;; --- Derived streams @@ -126,55 +108,54 @@ (rx/subscribe-with ob sub) sub)) - -(defonce window-blur +(defonce ^:private window-blur (->> (rx/from-event globals/window "blur") + (rx/map (constantly false)) + (rx/share))) + +(defonce keyboard + (->> st/stream + (rx/filter kbd/keyboard-event?) (rx/share))) (defonce keyboard-alt (let [sub (rx/behavior-subject nil) - ob (->> (rx/merge - (->> st/stream - (rx/filter keyboard-event?) - (rx/filter kbd/alt-key?) - (rx/map #(= :down (:type %)))) - ;; Fix a situation caused by using `ctrl+alt` kind of shortcuts, - ;; that makes keyboard-alt stream registering the key pressed but - ;; on blurring the window (unfocus) the key down is never arrived. - (->> window-blur - (rx/map (constantly false)))) + ob (->> keyboard + (rx/filter kbd/alt-key?) + (rx/map kbd/key-down-event?) + ;; Fix a situation caused by using `ctrl+alt` kind of + ;; shortcuts, that makes keyboard-alt stream + ;; registering the key pressed but on blurring the + ;; window (unfocus) the key down is never arrived. + (rx/merge window-blur) (rx/dedupe))] (rx/subscribe-with ob sub) sub)) (defonce keyboard-ctrl (let [sub (rx/behavior-subject nil) - ob (->> (rx/merge - (->> st/stream - (rx/filter keyboard-event?) - (rx/filter kbd/ctrl-key?) - (rx/map #(= :down (:type %)))) - ;; Fix a situation caused by using `ctrl+alt` kind of shortcuts, - ;; that makes keyboard-alt stream registering the key pressed but - ;; on blurring the window (unfocus) the key down is never arrived. - (->> window-blur - (rx/map (constantly false)))) + ob (->> keyboard + (rx/filter kbd/ctrl-key?) + (rx/map kbd/key-down-event?) + ;; Fix a situation caused by using `ctrl+alt` kind of + ;; shortcuts, that makes keyboard-alt stream + ;; registering the key pressed but on blurring the + ;; window (unfocus) the key down is never arrived. + (rx/merge window-blur) (rx/dedupe))] (rx/subscribe-with ob sub) sub)) (defonce keyboard-meta (let [sub (rx/behavior-subject nil) - ob (->> (rx/merge - (->> st/stream - (rx/filter keyboard-event?) - (rx/filter kbd/meta-key?) - (rx/map #(= :down (:type %)))) - ;; Fix a situation caused by using `ctrl+alt` kind of shortcuts, - ;; that makes keyboard-alt stream registering the key pressed but - ;; on blurring the window (unfocus) the key down is never arrived. - (->> window-blur - (rx/map (constantly false)))) + ob (->> keyboard + (rx/filter kbd/meta-key?) + (rx/map kbd/key-down-event?) + ;; Fix a situation caused by using `ctrl+alt` kind of + ;; shortcuts, that makes keyboard-alt stream + ;; registering the key pressed but on blurring the + ;; window (unfocus) the key down is never arrived. + (rx/merge window-blur) (rx/dedupe))] (rx/subscribe-with ob sub) sub)) @@ -184,57 +165,12 @@ keyboard-meta keyboard-ctrl)) -(defonce keyboard-minus-or-underscore - (let [sub (rx/behavior-subject nil) - ob (->> st/stream - (rx/filter keyboard-event?) - (rx/filter key-down?) - (rx/filter #(kbd/mod? (:event %))) - (rx/filter #(or (kbd/minus? %) (kbd/underscore? %))) - (rx/dedupe))] - (rx/subscribe-with ob sub) - sub)) - -(defonce keyboard-=-or-+ - (let [sub (rx/behavior-subject nil) - ob (->> st/stream - (rx/filter keyboard-event?) - (rx/filter key-down?) - (rx/filter #(kbd/mod? (:event %))) - (rx/filter #(or (kbd/equals? %) (kbd/plus? %))) - (rx/dedupe))] - (rx/subscribe-with ob sub) - sub)) - (defonce keyboard-space (let [sub (rx/behavior-subject nil) - ob (->> st/stream - (rx/filter keyboard-event?) + ob (->> keyboard (rx/filter kbd/space?) - (rx/filter (comp not kbd/editing?)) - (rx/map #(= :down (:type %))) - (rx/dedupe))] - (rx/subscribe-with ob sub) - sub)) - -(defonce keyboard-z - (let [sub (rx/behavior-subject nil) - ob (->> st/stream - (rx/filter keyboard-event?) - (rx/filter kbd/z?) - (rx/filter (comp not kbd/editing?)) - (rx/map #(= :down (:type %))) - (rx/dedupe))] - (rx/subscribe-with ob sub) - sub)) - -(defonce keyboard-shift - (let [sub (rx/behavior-subject nil) - ob (->> st/stream - (rx/filter keyboard-event?) - (rx/filter kbd/shift-key?) - (rx/filter (comp not kbd/editing?)) - (rx/map #(= :down (:type %))) + (rx/filter (complement kbd/editing-event?)) + (rx/map kbd/key-down-event?) (rx/dedupe))] (rx/subscribe-with ob sub) sub)) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index f0a33100f..7c2280c42 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -314,29 +314,33 @@ shift? (kbd/shift? event) alt? (kbd/alt? event) meta? (kbd/meta? event) + mod? (kbd/mod? event) target (dom/get-target event) + editing? (or (some? (.closest ^js target ".public-DraftEditor-content")) (= "rich-text" (obj/get target "className")) (= "INPUT" (obj/get target "tagName")) (= "TEXTAREA" (obj/get target "tagName")))] (when-not (.-repeat bevent) - (st/emit! (ms/->KeyboardEvent :down key shift? ctrl? alt? meta? editing? event))))))) + (st/emit! (kbd/->KeyboardEvent :down key shift? ctrl? alt? meta? mod? editing? event))))))) (defn on-key-up [] (mf/use-callback (fn [event] - (let [key (.-key event) - ctrl? (kbd/ctrl? event) - shift? (kbd/shift? event) - alt? (kbd/alt? event) - meta? (kbd/meta? event) + (let [key (.-key event) + ctrl? (kbd/ctrl? event) + shift? (kbd/shift? event) + alt? (kbd/alt? event) + meta? (kbd/meta? event) + mod? (kbd/mod? event) target (dom/get-target event) + editing? (or (some? (.closest ^js target ".public-DraftEditor-content")) (= "rich-text" (obj/get target "className")) (= "INPUT" (obj/get target "tagName")) (= "TEXTAREA" (obj/get target "tagName")))] - (st/emit! (ms/->KeyboardEvent :up key shift? ctrl? alt? meta? editing? event)))))) + (st/emit! (kbd/->KeyboardEvent :up key shift? ctrl? alt? meta? mod? editing? event)))))) (defn on-pointer-move [move-stream] (let [last-position (mf/use-var nil)] diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index d7eef5be7..1e6758d80 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -31,6 +31,7 @@ [app.util.debug :as dbg] [app.util.dom :as dom] [app.util.globals :as globals] + [app.util.keyboard :as kbd] [beicon.core :as rx] [goog.events :as events] [rumext.v2 :as mf]) @@ -99,20 +100,57 @@ (when (not= @cursor new-cursor) (reset! cursor new-cursor)))))) -(defn setup-keyboard [alt? mod? space? z? shift?] - (hooks/use-stream ms/keyboard-alt #(reset! alt? %)) - (hooks/use-stream ms/keyboard-mod #(do - (reset! mod? %) - (when-not % (reset! z? false)))) ;; In mac after command+z there is no event for the release of the z key - (hooks/use-stream ms/keyboard-space #(reset! space? %)) - (hooks/use-stream ms/keyboard-=-or-+ #(do - (dom/prevent-default (:event %)) - (st/emit! (dw/increase-zoom)))) - (hooks/use-stream ms/keyboard-minus-or-underscore #(do - (dom/prevent-default (:event %)) - (st/emit! (dw/decrease-zoom)))) - (hooks/use-stream ms/keyboard-z #(reset! z? %)) - (hooks/use-stream ms/keyboard-shift #(reset! shift? %))) +(defn setup-keyboard + [alt* mod* space* z* shift*] + (let [kbd-zoom-s + (mf/with-memo [] + (->> ms/keyboard + (rx/filter kbd/key-down-event?) + (rx/filter kbd/mod-event?) + (rx/filter (fn [kevent] + (or ^boolean (kbd/minus? kevent) + ^boolean (kbd/underscore? kevent) + ^boolean (kbd/equals? kevent) + ^boolean (kbd/plus? kevent)))) + (rx/dedupe))) + + kbd-shift-s + (mf/with-memo [] + (->> ms/keyboard + (rx/filter kbd/shift-key?) + (rx/filter (complement kbd/editing-event?)) + (rx/map kbd/key-down-event?) + (rx/dedupe))) + + kbd-z-s + (mf/with-memo [] + (->> ms/keyboard + (rx/filter kbd/z?) + (rx/filter (complement kbd/editing-event?)) + (rx/map kbd/key-down-event?) + (rx/dedupe)))] + + (hooks/use-stream ms/keyboard-alt (partial reset! alt*)) + (hooks/use-stream ms/keyboard-space (partial reset! space*)) + (hooks/use-stream kbd-z-s (partial reset! z*)) + (hooks/use-stream kbd-shift-s (partial reset! shift*)) + (hooks/use-stream ms/keyboard-mod + (fn [value] + (reset! mod* value) + ;; In mac after command+z there is no event + ;; for the release of the z key + (when-not ^boolean value + (reset! z* false)))) + + (hooks/use-stream kbd-zoom-s + (fn [kevent] + (dom/prevent-default kevent) + (st/emit! + (if (or ^boolean (kbd/minus? kevent) + ^boolean (kbd/underscore? kevent)) + (dw/decrease-zoom) + (dw/increase-zoom))))))) + (defn group-empty-space? "Given a group `group-id` check if `hover-ids` contains any of its children. If it doesn't means diff --git a/frontend/src/app/util/keyboard.cljs b/frontend/src/app/util/keyboard.cljs index f94d65ad6..5151b2f50 100644 --- a/frontend/src/app/util/keyboard.cljs +++ b/frontend/src/app/util/keyboard.cljs @@ -9,15 +9,44 @@ [app.config :as cfg] [cuerdas.core :as str])) +(defrecord KeyboardEvent [type key shift ctrl alt meta mod editing native-event] + Object + (preventDefault [_] + (.preventDefault native-event)) + + (stopPropagation [_] + (.stopPropagation native-event))) + +(defn keyboard-event? + [o] + (instance? KeyboardEvent o)) + +(defn key-up-event? + [^KeyboardEvent event] + (= :up (.-type event))) + +(defn key-down-event? + [^KeyboardEvent event] + (= :down (.-type event))) + +(defn mod-event? + [^KeyboardEvent event] + (true? (.-mod event))) + +(defn editing-event? + [^KeyboardEvent event] + (true? (.-editing event))) + (defn is-key? [^string key] - (fn [^js e] + (fn [^KeyboardEvent e] (= (.-key e) key))) (defn is-key-ignore-case? [^string key] - (fn [^js e] - (= (str/upper (.-key e)) (str/upper key)))) + (let [key (str/upper key)] + (fn [^KeyboardEvent e] + (= (str/upper (.-key e)) key)))) (defn ^boolean alt? [^js event] @@ -62,6 +91,3 @@ (def home? (is-key? "Home")) (def tab? (is-key? "Tab")) -(defn editing? [e] - (.-editing ^js e)) -