From adfc0902a2f46737b6092ee14792a142cc43c56d Mon Sep 17 00:00:00 2001
From: "alonso.torres" <alonso.torres@kaleidos.net>
Date: Thu, 24 Mar 2022 14:45:52 +0100
Subject: [PATCH] :bug: Fix problems with CTRL in MacOS

---
 CHANGES.md                                    |  1 +
 .../app/main/data/workspace/transforms.cljs   | 10 ++--
 frontend/src/app/main/streams.cljs            | 50 ++++++++++++++++---
 .../src/app/main/ui/settings/sidebar.cljs     |  4 +-
 frontend/src/app/main/ui/viewer/handoff.cljs  |  2 +-
 .../main/ui/viewer/handoff/left_sidebar.cljs  |  2 +-
 .../src/app/main/ui/viewer/interactions.cljs  |  2 +-
 .../main/ui/workspace/shapes/path/editor.cljs |  6 +--
 .../app/main/ui/workspace/sidebar/assets.cljs |  2 +-
 .../app/main/ui/workspace/sidebar/layers.cljs |  2 +-
 .../src/app/main/ui/workspace/viewport.cljs   | 12 ++---
 .../main/ui/workspace/viewport/actions.cljs   | 40 +++++++++------
 .../app/main/ui/workspace/viewport/hooks.cljs | 28 +++++------
 frontend/src/app/util/keyboard.cljs           | 30 +++++++----
 14 files changed, 123 insertions(+), 68 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 7d2e71504..98cbee0e8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,6 +7,7 @@
 - Fix crash on iOS when displaying viewer [#1522](https://github.com/penpot/penpot/issues/1522)
 - Fix problems with trackpad zoom and scroll in MacOS [#1161](https://github.com/penpot/penpot/issues/1161)
 - Fix problem with copy/paste in Safari [#1209](https://github.com/penpot/penpot/issues/1209)
+- Improved command support for MacOS [Taiga #2789](https://tree.taiga.io/project/penpot/issue/2789)
 
 ## 1.12.3-beta
 
diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs
index 8f5d3cc85..9a8bc6bbe 100644
--- a/frontend/src/app/main/data/workspace/transforms.cljs
+++ b/frontend/src/app/main/data/workspace/transforms.cljs
@@ -434,13 +434,13 @@
             group           (gsh/selection-rect shapes)
             group-center    (gsh/center-selrect group)
             initial-angle   (gpt/angle @ms/mouse-position group-center)
-            calculate-angle (fn [pos ctrl? shift?]
+            calculate-angle (fn [pos mod? shift?]
                               (let [angle (- (gpt/angle pos group-center) initial-angle)
                                     angle (if (neg? angle) (+ 360 angle) angle)
                                     angle (if (= angle 360)
                                             0
                                             angle)
-                                    angle (if ctrl?
+                                    angle (if mod?
                                             (* (mth/floor (/ angle 45)) 45)
                                             angle)
                                     angle (if shift?
@@ -449,10 +449,10 @@
                                 angle))]
         (rx/concat
          (->> ms/mouse-position
-              (rx/with-latest vector ms/mouse-position-ctrl)
+              (rx/with-latest vector ms/mouse-position-mod)
               (rx/with-latest vector ms/mouse-position-shift)
-              (rx/map (fn [[[pos ctrl?] shift?]]
-                        (let [delta-angle (calculate-angle pos ctrl? shift?)]
+              (rx/map (fn [[[pos mod?] shift?]]
+                        (let [delta-angle (calculate-angle pos mod? shift?)]
                           (set-rotation-modifiers delta-angle shapes group-center))))
               (rx/take-until stoper))
          (rx/of (apply-modifiers (map :id shapes))
diff --git a/frontend/src/app/main/streams.cljs b/frontend/src/app/main/streams.cljs
index 7b5201ffa..759fddd23 100644
--- a/frontend/src/app/main/streams.cljs
+++ b/frontend/src/app/main/streams.cljs
@@ -7,6 +7,7 @@
 (ns app.main.streams
   "User interaction events and streams."
   (:require
+   [app.config :as cfg]
    [app.main.store :as st]
    [app.util.globals :as globals]
    [app.util.keyboard :as kbd]
@@ -20,7 +21,7 @@
   [v]
   (instance? KeyboardEvent v))
 
-(defrecord MouseEvent [type ctrl shift alt])
+(defrecord MouseEvent [type ctrl shift alt meta])
 
 (defn mouse-event?
   [v]
@@ -46,7 +47,7 @@
   (and (mouse-event? v)
        (= :double-click (:type v))))
 
-(defrecord PointerEvent [source pt ctrl shift alt])
+(defrecord PointerEvent [source pt ctrl shift alt meta])
 
 (defn pointer-event?
   [v]
@@ -83,6 +84,20 @@
     (rx/subscribe-with ob sub)
     sub))
 
+(defonce mouse-position-meta
+  (let [sub (rx/behavior-subject nil)
+        ob  (->> st/stream
+                 (rx/filter pointer-event?)
+                 (rx/map :meta)
+                 (rx/dedupe))]
+    (rx/subscribe-with ob sub)
+    sub))
+
+(defonce mouse-position-mod
+  (if (cfg/check-platform? :macos)
+    mouse-position-meta
+    mouse-position-ctrl))
+
 (defonce mouse-position-shift
   (let [sub (rx/behavior-subject nil)
         ob  (->> st/stream
@@ -111,7 +126,7 @@
         ob  (->> (rx/merge
                   (->> st/stream
                        (rx/filter keyboard-event?)
-                       (rx/filter kbd/altKey?)
+                       (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
@@ -119,15 +134,15 @@
                   (->> window-blur
                        (rx/map (constantly false))))
                  (rx/dedupe))]
-        (rx/subscribe-with ob sub)
-        sub))
+    (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/ctrlKey?)
+                       (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
@@ -135,9 +150,30 @@
                   (->> window-blur
                        (rx/map (constantly false))))
                  (rx/dedupe))]
-        (rx/subscribe-with ob sub)
+    (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))))
+                 (rx/dedupe))]
+    (rx/subscribe-with ob sub)
+    sub))
+
+(defonce keyboard-mod
+  (if (cfg/check-platform? :macos)
+    keyboard-meta
+    keyboard-ctrl))
+
 (defonce keyboard-space
   (let [sub (rx/behavior-subject nil)
         ob  (->> st/stream
diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs
index 0b9cce30d..3a5504fe9 100644
--- a/frontend/src/app/main/ui/settings/sidebar.cljs
+++ b/frontend/src/app/main/ui/settings/sidebar.cljs
@@ -14,6 +14,7 @@
    [app.main.ui.dashboard.sidebar :refer [profile-section]]
    [app.main.ui.icons :as i]
    [app.util.i18n :as i18n :refer [tr]]
+   [app.util.keyboard :as kbd]
    [app.util.router :as rt]
    [potok.core :as ptk]
    [rumext.alpha :as mf]))
@@ -55,8 +56,7 @@
          (fn [event]
            (let [version (:main @cf/version)]
              (st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version}))
-             (if (and (.-ctrlKey ^js event)
-                      (.-altKey ^js event))
+             (if (and (kbd/alt? event) (kbd/mod? event))
                (st/emit! (modal/show {:type :onboarding}))
                (st/emit! (modal/show {:type :release-notes :version version}))))))]
 
diff --git a/frontend/src/app/main/ui/viewer/handoff.cljs b/frontend/src/app/main/ui/viewer/handoff.cljs
index f3cbeaa7b..4a00631ea 100644
--- a/frontend/src/app/main/ui/viewer/handoff.cljs
+++ b/frontend/src/app/main/ui/viewer/handoff.cljs
@@ -28,7 +28,7 @@
   [{:keys [local file page frame]}]
   (let [on-mouse-wheel
         (fn [event]
-          (when (or (kbd/ctrl? event) (kbd/meta? event))
+          (when (kbd/mod? event)
             (dom/prevent-default event)
             (let [event (.getBrowserEvent ^js event)
                   delta (+ (.-deltaY ^js event)
diff --git a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs
index 4319c262d..4e05ac409 100644
--- a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs
+++ b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs
@@ -45,7 +45,7 @@
           (dom/prevent-default event)
           (let [id (:id item)]
             (cond
-              (or (kbd/ctrl? event) (kbd/meta? event))
+              (kbd/mod? event)
               (st/emit! (dv/toggle-selection id))
 
               (kbd/shift? event)
diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs
index e3e0b55b4..587b41ac9 100644
--- a/frontend/src/app/main/ui/viewer/interactions.cljs
+++ b/frontend/src/app/main/ui/viewer/interactions.cljs
@@ -61,7 +61,7 @@
 
         on-mouse-wheel
         (fn [event]
-          (when (or (kbd/ctrl? event) (kbd/meta? event))
+          (when (kbd/mod? event)
             (dom/prevent-default event)
             (let [event (.getBrowserEvent ^js event)
                   delta (+ (.-deltaY ^js event) (.-deltaX ^js event))]
diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs
index 2ccc1583d..36d0fcf41 100644
--- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs
+++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs
@@ -47,15 +47,15 @@
             (st/emit! (drp/create-node-at-position (meta position))))
 
           (let [shift? (kbd/shift? event)
-                ctrl? (kbd/ctrl? event)]
+                mod?   (kbd/mod? event)]
             (cond
               last-p?
               (st/emit! (drp/reset-last-handler))
 
-              (and (= edit-mode :move) ctrl? (not curve?))
+              (and (= edit-mode :move) mod? (not curve?))
               (st/emit! (drp/make-curve position))
 
-              (and (= edit-mode :move) ctrl? curve?)
+              (and (= edit-mode :move) mod? curve?)
               (st/emit! (drp/make-corner position))
 
               (= edit-mode :move)
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
index 8ed877406..903e3c7d5 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
@@ -1485,7 +1485,7 @@
          (mf/deps extend-selected-assets selected-assets)
          (fn [asset-type asset-groups event asset-id default-click]
            (cond
-             (kbd/ctrl? event)
+             (kbd/mod? event)
              (do
                (dom/stop-propagation event)
                (st/emit! (dw/toggle-selected-assets asset-id asset-type)))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
index 9e65bbf54..b077c1ee3 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
@@ -133,7 +133,7 @@
               (kbd/shift? event)
               (st/emit! (dw/shift-select-shapes id))
 
-              (or (kbd/ctrl? event) (kbd/meta? event))
+              (kbd/mod? event)
               (st/emit! (dw/select-shape id true))
 
               (> (count selected) 1)
diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs
index a0d0c740f..13321c3fd 100644
--- a/frontend/src/app/main/ui/workspace/viewport.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport.cljs
@@ -73,7 +73,7 @@
 
         ;; STATE
         alt?              (mf/use-state false)
-        ctrl?             (mf/use-state false)
+        mod?              (mf/use-state false)
         space?            (mf/use-state false)
         cursor            (mf/use-state (utils/get-cursor :pointer-inner))
         hover-ids         (mf/use-state nil)
@@ -163,9 +163,9 @@
 
     (hooks/setup-dom-events viewport-ref zoom disable-paste in-viewport?)
     (hooks/setup-viewport-size viewport-ref)
-    (hooks/setup-cursor cursor alt? ctrl? space? panning drawing-tool drawing-path? node-editing?)
-    (hooks/setup-keyboard alt? ctrl? space?)
-    (hooks/setup-hover-shapes page-id move-stream raw-position-ref base-objects transform selected ctrl? hover hover-ids @hover-disabled? zoom)
+    (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing?)
+    (hooks/setup-keyboard alt? mod? space?)
+    (hooks/setup-hover-shapes page-id move-stream raw-position-ref base-objects transform selected mod? hover hover-ids @hover-disabled? zoom)
     (hooks/setup-viewport-modifiers modifiers base-objects)
     (hooks/setup-shortcuts node-editing? drawing-path?)
     (hooks/setup-active-frames base-objects vbox hover active-frames)
@@ -244,7 +244,7 @@
          [:& outline/shape-outlines
           {:objects base-objects
            :selected selected
-           :hover (when (or @ctrl? (not= :frame (:type @hover)))
+           :hover (when (or @mod? (not= :frame (:type @hover)))
                     #{(or @frame-hover (:id @hover))})
            :edition edition
            :zoom zoom}])
@@ -254,7 +254,7 @@
           {:shapes selected-shapes
            :zoom zoom
            :edition edition
-           :disable-handlers (or drawing-tool edition @space? @ctrl?)
+           :disable-handlers (or drawing-tool edition @space? @mod?)
            :on-move-selected on-move-selected
            :on-context-menu on-menu-selected}])
 
diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs
index bbdbddfa1..2be7787c1 100644
--- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs
@@ -41,8 +41,10 @@
 
        (let [event  (.-nativeEvent bevent)
              ctrl?  (kbd/ctrl? event)
+             meta?  (kbd/meta? event)
              shift? (kbd/shift? event)
              alt?   (kbd/alt? event)
+             mod?   (kbd/mod? event)
 
              left-click?   (and (not panning) (= 1 (.-which event)))
              middle-click? (and (not panning) (= 2 (.-which event)))
@@ -54,7 +56,7 @@
            middle-click?
            (do
              (dom/prevent-default bevent)
-             (if ctrl?
+             (if mod?
                (let [raw-pt   (dom/get-client-position event)
                      viewport (mf/ref-val viewport-ref)
                      pt       (utils/translate-point-to-viewport viewport zoom raw-pt)]
@@ -64,7 +66,7 @@
 
            left-click?
            (do
-             (st/emit! (ms/->MouseEvent :down ctrl? shift? alt?))
+             (st/emit! (ms/->MouseEvent :down ctrl? shift? alt? meta?))
 
              (when (and (not= edition id) text-editing?)
                (st/emit! dw/clear-edition-mode))
@@ -79,7 +81,7 @@
                  ;; Handle path node area selection
                  (st/emit! (dwdp/handle-area-selection shift?))
 
-                 (and @space? ctrl?)
+                 (and @space? mod?)
                  (let [raw-pt   (dom/get-client-position event)
                        viewport (mf/ref-val viewport-ref)
                        pt       (utils/translate-point-to-viewport viewport zoom raw-pt)]
@@ -91,8 +93,8 @@
                  drawing-tool
                  (st/emit! (dd/start-drawing drawing-tool))
 
-                 (or (not id) (and frame? (not selected?)) ctrl?)
-                 (st/emit! (dw/handle-area-selection shift? ctrl?))
+                 (or (not id) (and frame? (not selected?)) mod?)
+                 (st/emit! (dw/handle-area-selection shift? mod?))
 
                  (not drawing-tool)
                  (st/emit! (dw/start-move-selected id shift?)))))))))))
@@ -104,11 +106,11 @@
    (fn [bevent]
      (let [event (.-nativeEvent bevent)
            shift? (kbd/shift? event)
-           ctrl?  (kbd/ctrl? event)
+           mod?   (kbd/mod? event)
            left-click?   (= 1 (.-which event))]
 
        (when (and left-click?
-                  (not ctrl?)
+                  (not mod?)
                   (not shift?)
                   (not @space?)
                   (or (not @hover)
@@ -153,12 +155,15 @@
        (let [ctrl? (kbd/ctrl? event)
              shift? (kbd/shift? event)
              alt? (kbd/alt? event)
+             meta? (kbd/meta? event)
+             mod? (kbd/mod? event)
+
              hovering? (some? @hover)
              frame? (= :frame (:type @hover))]
-         (st/emit! (ms/->MouseEvent :click ctrl? shift? alt?))
+         (st/emit! (ms/->MouseEvent :click ctrl? shift? alt? meta?))
 
          (when (and hovering?
-                    (or (not frame?) ctrl?)
+                    (or (not frame?) mod?)
                     (not @space?)
                     (not edition)
                     (not drawing-path?)
@@ -174,13 +179,14 @@
      (let [ctrl? (kbd/ctrl? event)
            shift? (kbd/shift? event)
            alt? (kbd/alt? event)
+           meta? (kbd/meta? event)
 
            {:keys [id type] :as shape} @hover
 
            frame? (= :frame type)
            group? (= :group type)]
 
-       (st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt?))
+       (st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt? meta?))
 
        ;; Emit asynchronously so the double click to exit shapes won't break
        (timers/schedule
@@ -239,12 +245,13 @@
            ctrl? (kbd/ctrl? event)
            shift? (kbd/shift? event)
            alt? (kbd/alt? event)
+           meta? (kbd/meta? event)
 
            left-click? (= 1 (.-which event))
            middle-click? (= 2 (.-which event))]
 
        (when left-click?
-         (st/emit! (ms/->MouseEvent :up ctrl? shift? alt?)))
+         (st/emit! (ms/->MouseEvent :up ctrl? shift? alt? meta?)))
 
        (when middle-click?
          (dom/prevent-default event)
@@ -340,11 +347,13 @@
          (st/emit! (ms/->PointerEvent :delta delta
                                       (kbd/ctrl? event)
                                       (kbd/shift? event)
-                                      (kbd/alt? event)))
+                                      (kbd/alt? event)
+                                      (kbd/meta? event)))
          (st/emit! (ms/->PointerEvent :viewport pt
                                       (kbd/ctrl? event)
                                       (kbd/shift? event)
-                                      (kbd/alt? event))))))))
+                                      (kbd/alt? event)
+                                      (kbd/meta? event))))))))
 
 (defn on-pointer-move [viewport-ref raw-position-ref zoom move-stream]
   (mf/use-callback
@@ -369,8 +378,7 @@
          (let [pt     (->> (dom/get-client-position event)
                            (utils/translate-point-to-viewport viewport zoom))
 
-               ctrl? (kbd/ctrl? event)
-               meta? (kbd/meta? event)
+               mod? (kbd/mod? event)
 
                delta-mode (.-deltaMode ^js event)
 
@@ -386,7 +394,7 @@
                delta-x (-> (.-deltaX ^js event)
                            (* unit)
                            (/ zoom))]
-           (if (or ctrl? meta?)
+           (if mod?
              (let [delta (* -1 (+ (.-deltaY ^js event) (.-deltaX ^js event)))
                    scale (-> (+ 1 (/ delta 100)) (mth/clamp 0.77 1.3))]
                (st/emit! (dw/set-zoom pt scale)))
diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
index f9b7ca0c2..00361b7d1 100644
--- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
@@ -58,13 +58,13 @@
        ;; We schedule the event so it fires after `initialize-page` event
        (timers/schedule #(st/emit! (dw/initialize-viewport size)))))))
 
-(defn setup-cursor [cursor alt? ctrl? space? panning drawing-tool drawing-path? path-editing?]
+(defn setup-cursor [cursor alt? mod? space? panning drawing-tool drawing-path? path-editing?]
   (mf/use-effect
-   (mf/deps @cursor @alt? @ctrl? @space? panning drawing-tool drawing-path? path-editing?)
+   (mf/deps @cursor @alt? @mod? @space? panning drawing-tool drawing-path? path-editing?)
    (fn []
      (let [new-cursor
            (cond
-             (and @ctrl? @space?)            (utils/get-cursor :zoom)
+             (and @mod? @space?)            (utils/get-cursor :zoom)
              (or panning @space?)            (utils/get-cursor :hand)
              (= drawing-tool :comments)      (utils/get-cursor :comments)
              (= drawing-tool :frame)         (utils/get-cursor :create-artboard)
@@ -80,9 +80,9 @@
        (when (not= @cursor new-cursor)
          (reset! cursor new-cursor))))))
 
-(defn setup-keyboard [alt? ctrl? space?]
+(defn setup-keyboard [alt? mod? space?]
   (hooks/use-stream ms/keyboard-alt #(reset! alt? %))
-  (hooks/use-stream ms/keyboard-ctrl #(reset! ctrl? %))
+  (hooks/use-stream ms/keyboard-mod #(reset! mod? %))
   (hooks/use-stream ms/keyboard-space #(reset! space? %)))
 
 (defn group-empty-space?
@@ -108,10 +108,10 @@
                   (map dom/bounding-rect->rect))]
          (not (some #(gshr/contains-point? % pos) collisions)))))
 
-(defn setup-hover-shapes [page-id move-stream raw-position-ref objects transform selected ctrl? hover hover-ids hover-disabled? zoom]
+(defn setup-hover-shapes [page-id move-stream raw-position-ref objects transform selected mod? hover hover-ids hover-disabled? zoom]
   (let [;; We use ref so we don't recreate the stream on a change
         zoom-ref (mf/use-ref zoom)
-        ctrl-ref (mf/use-ref @ctrl?)
+        mod-ref (mf/use-ref @mod?)
         transform-ref (mf/use-ref nil)
         selected-ref (mf/use-ref selected)
         hover-disabled-ref (mf/use-ref hover-disabled?)
@@ -121,7 +121,7 @@
          (mf/deps page-id)
          (fn [point]
            (let [zoom (mf/ref-val zoom-ref)
-                 ctrl? (mf/ref-val ctrl-ref)
+                 mod? (mf/ref-val mod-ref)
                  rect (gsh/center->rect point (/ 5 zoom) (/ 5 zoom))]
              (if (mf/ref-val hover-disabled-ref)
                (rx/of nil)
@@ -130,7 +130,7 @@
                   :page-id page-id
                   :rect rect
                   :include-frames? true
-                  :clip-children? (not ctrl?)
+                  :clip-children? (not mod?)
                   :reverse? true}))))) ;; we want the topmost shape to be selected first
 
         over-shapes-stream
@@ -157,8 +157,8 @@
      #(mf/set-ref-val! zoom-ref zoom))
 
     (mf/use-effect
-     (mf/deps @ctrl?)
-     #(mf/set-ref-val! ctrl-ref @ctrl?))
+     (mf/deps @mod?)
+     #(mf/set-ref-val! mod-ref @mod?))
 
     (mf/use-effect
      (mf/deps selected)
@@ -178,17 +178,17 @@
 
              selected (mf/ref-val selected-ref)
 
-             ctrl? (mf/ref-val ctrl-ref)
+             mod? (mf/ref-val mod-ref)
 
              remove-xfm (mapcat #(cph/get-parent-ids objects %))
              remove-id? (cond-> (into #{} remove-xfm selected)
                           :always
                           (into (filter #(check-text-collision? objects (mf/ref-val raw-position-ref) %)) ids)
 
-                          (not ctrl?)
+                          (not mod?)
                           (into (filter #(group-empty-space? % objects ids)) ids)
 
-                          ctrl?
+                          mod?
                           (into (filter is-group?) ids))
 
              hover-shape (->> ids
diff --git a/frontend/src/app/util/keyboard.cljs b/frontend/src/app/util/keyboard.cljs
index 0fb84f09d..52077fb30 100644
--- a/frontend/src/app/util/keyboard.cljs
+++ b/frontend/src/app/util/keyboard.cljs
@@ -4,37 +4,47 @@
 ;;
 ;; Copyright (c) UXBOX Labs SL
 
-(ns app.util.keyboard)
+(ns app.util.keyboard
+  (:require
+   [app.config :as cfg]))
 
 (defn is-key?
-  [key]
-  (fn [e]
+  [^string key]
+  (fn [^js e]
     (= (.-key e) key)))
 
 (defn ^boolean alt?
-  [event]
+  [^js event]
   (.-altKey event))
 
 (defn ^boolean ctrl?
-  [event]
+  [^js event]
   (.-ctrlKey event))
 
 (defn ^boolean meta?
-  [event]
+  [^js event]
   (.-metaKey event))
 
 (defn ^boolean shift?
-  [event]
+  [^js event]
   (.-shiftKey event))
 
+(defn ^boolean mod?
+  [^js event]
+  (if (cfg/check-platform? :macos)
+    (meta? event)
+    (ctrl? event)))
+
 (def esc? (is-key? "Escape"))
 (def enter? (is-key? "Enter"))
 (def space? (is-key? " "))
 (def up-arrow? (is-key? "ArrowUp"))
 (def down-arrow? (is-key? "ArrowDown"))
-(def altKey? (is-key? "Alt"))
-(def ctrlKey? (or (is-key? "Control")
-                  (is-key? "Meta")))
+(def alt-key? (is-key? "Alt"))
+(def ctrl-key? (is-key? "Control"))
+(def meta-key? (is-key? "Meta"))
+(def comma? (is-key? ","))
+(def backspace? (is-key? "Backspace"))
 
 (defn editing? [e]
   (.-editing ^js e))