   (if (== 0 tab) content
     (reduce (fn [res _] (dom/ul nil res)) content (range 0 tab))))
 
+(def code->key
+  "map from a character code (read from events with event.which)
+  to a string representation of it.
+  Only need to add 'special' things here."
+  {13 "enter"
+   9  "tab"
+   37 "left"
+   38 "up"
+   39 "right"
+   40 "down"
+   46 "del"
+   186 ";"})
+ 
+(defn event-modifiers
+  "Given a keydown event, return the modifier keys that were being held."
+  [e]
+  (into [] (filter identity [(if (.-shiftKey e) "shift")
+                             (if (.-altKey e) "alt")
+                             (if (.-ctrlKey e) "ctrl")
+                             (if (.-metaKey e) "meta")])))
+
+(def mod-keys
+  "A vector of the modifier keys that we use to compare against to make
+  sure that we don't report things like pressing the shift key as independent events.
+  This may not be desirable behavior, depending on the use case, but it works for
+  what I need."
+  [;; shift
+   (js/String.fromCharCode 16)
+   ;; ctrl
+   (js/String.fromCharCode 17)
+   ;; alt
+   (js/String.fromCharCode 18)
+   ])
+
+(defn event->key
+  "Given an event, return a string like 'up' or 'shift+l' or 'ctrl+;'
+  describing the key that was pressed.
+  This fn will never return just 'shift' or any other lone modifier key."
+  [event]
+  (let [mods (event-modifiers event)
+        which (.-which event)
+        key (or (code->key which) (.toLowerCase (js/String.fromCharCode which)))]
+    (if (and key (not (empty? key)) (not (some #{key} mod-keys)))
+      (string/join "+" (conj mods key)))))
+
 (defn handle-new-note-keydown [e app owner]
-  (js/console.log (str (== (.-which e) 9)))
-  (let [pressed-key (.-which e)]
-  (case (str pressed-key)
-    "13"
+  (let [code (event->key e)]
+  (case code
+    "enter"
     (do
       (let [new-field (om/get-node owner "newNote")]
       (when-not (string/blank? (.. new-field -value trim))

              [clojure.string :as string]
              [om.dom :as dom :include-macros true]))

(def TAB_KEY 9)
(def ENTER_KEY 13)
(defn now [] (new js/Date))
(def custom-formatter (time-format/formatter "dd/MM/yyyy"))
(def app-title (str "Notes " (time-format/unparse custom-formatter (time-core/date-time (.getFullYear (now)) (+ 1 (.getMonth (now))) (.getDate (now))))))

            [:create new-note]))
        (set! (.-value new-field) "")))
        false)
    "tab" (do
      (om/transact! app :tab
        #(+ % 1)
        [:tab nil])
      false)
    "shift+tab" (do
      (om/transact! app :tab
        #(- % 1)
        [:tab nil])
      false)
    nil
