Skip to content

Instantly share code, notes, and snippets.

@joshuawagner
Last active March 17, 2024 19:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshuawagner/b6d53fba5e361906f38832feee027cb3 to your computer and use it in GitHub Desktop.
Save joshuawagner/b6d53fba5e361906f38832feee027cb3 to your computer and use it in GitHub Desktop.
karabiner.edn - goku file for my karabiner setup
{
;; ----------------------------------
;; This is my goku file for karabiner.
;; I started with this template: https://gist.github.com/nikolai-cc/02f6b070972840323ae355ef847e91a6
;; ~/Library/Logs/goku.log -- I watch this to make sure that I'm not getting errors.
;; ----------------------------------
;; more info about goku: https://github.com/yqrashawn/GokuRakuJoudo
;; more info about karabiner: https://karabiner-elements.pqrs.org/docs
;; ----------------------------------
;; article karabiner god mode by nikita: https://medium.com/@nikitavoloboev/karabiner-god-mode-7407a5ddc8f6
;; examples: https://github.com/yqrashawn/GokuRakuJoudo/blob/master/examples.org#profiles-wip
;; tutorial: https://github.com/yqrashawn/GokuRakuJoudo/blob/master/tutorial.md#basic8
;; another article: https://kau.sh/blog/hacking-your-keyboard/
;; very well documented edn file by Kaushik Gopal: https://github.com/kaushikgopal/dotfiles/blob/master/.karabiner.edn
;; key names: https://github.com/yqrashawn/GokuRakuJoudo/blob/master/src/karabiner_configurator/keys_info.clj
:profiles {
:Default {
:default true
:sim 50 ;; if keydown event for two different keys are pressed within :sim ms, the keypresses are considered simultaneous
:delay 500 ;; after :delay ms, the key press is considered to be delayed (TODO WHAT IS THIS??)
:alone 1000 ;; if keyup event comes within :alone ms from keydown, the key is not just pressed but held
:held 500 ;; key is fired twice when :held ms is elapsed (otherwise seen as a hold command) (TODO WHAT IS THIS??)
}
} ;; profiles
;; you can create templates for running shell commands. These follow clojure string template syntax.
:templates {
:echo "echo \"%s\""
:open "open \"%s\""
:open-app "open -a \"%s\""
:alfred "osascript -e 'tell application id \"com.runningwithcrayons.Alfred\" to run trigger \"%s\" in workflow \"%s\" with argument \"%s\"'"
:km "osascript -e 'tell application \"Keyboard Maestro Engine\" to do script \"%s\"'"
:km2 "osascript -e 'tell application \"Keyboard Maestro Engine\" to do script \"%s\"' & osascript -e 'tell application \"Keyboard Maestro Engine\" to do script \"%s\"'"
:launch "osascript -e 'tell application \"%s\" to activate'"
} ;; templates
:applications {
:slack ["com.tinyspeck.slackmacgap"]
:vscode ["com.microsoft.VSCode"]
:notion ["notion.id"]
:spotify ["com.spotify.client"]
:intellij ["com.google.android.studio", "^com\\.jetbrains\\..*$"]
:firefox ["org.mozilla.firefox"]
:chrome ["com.google.Chrome"]
:mail ["com.apple.mail"]}
:terminals [ "^com\\.apple\\.Terminal$",
"^com\\.googlecode\\.iterm2$"]
;; layers are active while :FROM is held. Only recommended for non-typing keys like . or tab. Otherwise use simlayers.
:layers {
:tab-mode {:key :tab} ;; move cursor by letter
;;How to have tab and ctrl-tab as layers? Error 'Duplicate key' :layers {:ctrl-tab-mode {:key :!Ttab}} ;; move cursor by letter
;; :caps-mode {:key :caps_lock :alone {:key :escape}}
}
:simlayers {
:o-mode {:key :o }
:p-mode {:key :p }
:space-mode {:key :spacebar}
}
;; :simlayer-threshold 250
;; ☝️ from https://oliverfalvai.com/notes/posts/karabiner-setup/
;; with tos you can predefine 'to' keypresses to easily parse them
:tos {
;; in order for OSX to register a caps lock press, it has to be held for a little under 100ms
:toggle_caps {:key :caps_lock :hold_down_ms 100}
}
;; ----------------------------------
;; Key mappings
;; ----------------------------------
;; This is where you define the modifications
:main [
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ right_command to Alfred"
:rules [
[
:right_command ;; FROM
[:!Cspacebar [:km "right_command"]] ;; TO
nil ;; with no conditionals
]
]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ o mode: quick launch applications"
:rules [
:o-mode ;; when open-mode is active (o is held)
[:t [:open-app "iTerm"]] ;; and t is pressed, open Terminal
[:f [:open-app "finder"]] ;; and f is pressed, open Finder
[:d [:open "/users/josh/Desktop"]] ;; and d is pressed, open the Desktop in finder
[:m [:open "https://theministry.co"]] ;; and m is pressed, open the Ministry website
]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ p mode: palette launcher"
:rules [
:p-mode ;; when open-mode is active (o is held)
[:1 [:km "0878B851-9985-4E67-8EFC-4DA56AEE33D1"]] ;; and t is pressed, open Terminal
[:f [:open-app "finder"]] ;; and f is pressed, open Finder
[:d [:open "/users/josh/Desktop"]] ;; and d is pressed, open the Desktop in finder
[:m [:open "https://theministry.co"]] ;; and m is pressed, open the Ministry website
]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ Tab mode arrow keys"
:rules [:tab-mode
[:##h :left_arrow]
[:##j :down_arrow]
[:##k :up_arrow]
[:##l :right_arrow]
[:##u :delete_or_backspace]]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ simultaneous jk"
:rules [
[[:h :j]
:!Cspacebar ;; TO
]
]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ simultaneous kl"
:rules [
[[:k :l]
:!Cspacebar] ;; TO
]
}
{:des "⚪️⚪️⚪️⚪️⚪️⚪️ Quit application by command + Q only when pressing twice"
:rules [[:!Cq
[:!Cq ["command-q" 0]]
["command-q" 1]]
[:!Cq
["command-q" 1]
nil
{:delayed {:invoked ["command-q" 0] :canceled ["command-q" 0]}}]]}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ if leftShift isAlone, ctrlOptCmd+0, +shell"
:rules [
[
:left_shift ;; FROM left_shift
:left_shift ;; TO left_shift (same)
nil ;; with no conditionals
{:alone [:km2 "ECCACE86-8137-4E29-AE1B-F72A372AFF98" "left_shift"] }
]
]
}
{
:des "⚪️⚪️⚪️⚪️⚪️⚪️ Caps lock to hyper key when held and toggle_caps when tapped"
:rules [
[
:##caps_lock ;; FROM caps lock key
:!COTleft_shift ;; TO hyper
nil ;; with no conditionals
{:alone :delete_or_backspace} ;; OPTIONS: if pressed alone, press caps_lock event, but hold it for 100ms
]
]
}
]
}
;; PASTEBIN
;; "osascript -e 'tell app \"System Events\" to sleep'"
;; MODIFIERS
;; ! | means mandatory
;; # | means optional
;; C | left_command
;; T | left_control
;; O | left_option
;; S | left_shift
;; F | fn
;; Q | right_command
;; W | right_control
;; E | right_option
;; R | right_shift
;; P | caps_lock
;; !! | mandatory command + control + optional + shift (hyper)
;; ## | optional any
;; FROM modifiers
;; to understand better how modifiers work in karabiner
;; karabiner definition of mandatory and optional
;; https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/modifiers/
;; | no modifier
;; input key maps to output key exactly
;; adding any modifier will cancel the event
;; ! | mandatory
;; specified modifier is removed in output (to event)
;; specified modifiers must be present for event to occur
;; adding any other modifier will cancel the event
;; # | optional (single)
;; specified modifier is kept in output (to event)
;; one (or none) of the specified modifiers must be present
;; adding any other modifier will cancel the event
;; ## | optional any
;; specified modifier is removed in output (to event)
;; specified modifiers *must* be present for event to occur
;; adding any other modifier will add to output event
;; (what you typically expect, additional modifiers tacked on)
;;
;; need to prefix C T O S F with ! or #
(def keys-info
{:button1 {:button true}
:button2 {:button true}
:button3 {:button true}
:button4 {:button true}
:button5 {:button true}
:button6 {:button true}
:button7 {:button true}
:button8 {:button true}
:button9 {:button true}
:button10 {:button true}
:button11 {:button true}
:button12 {:button true}
:button13 {:button true}
:button14 {:button true}
:button15 {:button true}
:button16 {:button true}
:button17 {:button true}
:button18 {:button true}
:button19 {:button true}
:button21 {:button true}
:button22 {:button true}
:button23 {:button true}
:button24 {:button true}
:button25 {:button true}
:button26 {:button true}
:button27 {:button true}
:button28 {:button true}
:button29 {:button true}
:button30 {:button true}
:button31 {:button true}
:button32 {:button true}
;; :x {:mouse_key true}
;; :y {:mouse_key true}
:any {:modifier true :both true}
:command {:modifier true :both true}
:shift {:modifier true :both true}
:option {:modifier true :both true}
:control {:modifier true :both true}
:caps_lock {:modifier true}
:left_control {:modifier true}
:left_shift {:modifier true}
:left_option {:modifier true}
:left_command {:modifier true}
:right_control {:modifier true}
:right_shift {:modifier true}
:right_option {:modifier true}
:right_command {:modifier true}
:fn {:modifier true}
:return_or_enter {:label "enter" :display true}
:escape {:display true}
:delete_or_backspace {:label "backspace" :display true}
:delete_forward {:label "del" :display true}
:tab {:display true}
:spacebar {:display true}
:hyphen {:label "hyphen (-)" :display true}
:equal_sign {:label "equal_sign (=)" :display true}
:open_bracket {:label "open_bracket [" :display true}
:close_bracket {:label "close_bracket ]" :display true}
:backslash {:label "backslash (\\)" :display true}
:non_us_pound {}
:semicolon {:label "semicolon (;)" :display true}
:quote {:label "quote (')" :display true}
:grave_accent_and_tilde {:label "grave_accent_and_tilde ()" :display true}
:comma {:label "comma (,)" :display true}
:period {:label "period (.)" :display true}
:slash {:label "slash (/)" :display true}
:non_us_backslash {}
:up_arrow {:display true}
:down_arrow {:display true}
:left_arrow {:display true}
:right_arrow {:display true}
:page_up {:display true}
:page_down {:display true}
:home {:display true}
:end {:display true}
:a {:display true}
:b {:display true}
:c {:display true}
:d {:display true}
:e {:display true}
:f {:display true}
:g {:display true}
:h {:display true}
:i {:display true}
:j {:display true}
:k {:display true}
:l {:display true}
:m {:display true}
:n {:display true}
:o {:display true}
:p {:display true}
:q {:display true}
:r {:display true}
:s {:display true}
:t {:display true}
:u {:display true}
:v {:display true}
:w {:display true}
:x {:display true}
:y {:display true}
:z {:display true}
:1 {:display true}
:2 {:display true}
:3 {:display true}
:4 {:display true}
:5 {:display true}
:6 {:display true}
:7 {:display true}
:8 {:display true}
:9 {:display true}
:0 {:display true}
:f1 {:display true}
:f2 {:display true}
:f3 {:display true}
:f4 {:display true}
:f5 {:display true}
:f6 {:display true}
:f7 {:display true}
:f8 {:display true}
:f9 {:display true}
:f10 {:display true}
:f11 {:display true}
:f12 {:display true}
:f13 {}
:f14 {}
:f15 {}
:f16 {}
:f17 {}
:f18 {}
:f19 {}
:f20 {}
:f21 {:not-to true}
:f22 {:not-to true}
:f23 {:not-to true}
:f24 {:not-to true}
:display_brightness_decrement {:not-from true :consumer-key true}
:display_brightness_increment {:not-from true :consumer-key true}
:mission_control {:not-from true}
:launchpad {:not-from true}
:dashboard {:not-from true}
:illumination_decrement {:not-from true}
:illumination_increment {:not-from true}
:rewind {:not-from true :consumer-key true}
:play_or_pause {:not-from true :consumer-key true}
:fastforward {:not-from true :consumer-key true}
:dictation {:not-from true :consumer-key true}
:mute {:consumer-key true}
:volume_decrement {:consumer-key true}
:volume_increment {:consumer-key true}
:eject {:consumer-key true}
:apple_display_brightness_decrement {:not-from true}
:apple_display_brightness_increment {:not-from true}
:apple_top_case_display_brightness_decrement {:not-from true}
:apple_top_case_display_brightness_increment {:not-from true}
:keypad_num_lock {:display true}
:keypad_slash {:display true}
:keypad_asterisk {:display true}
:keypad_hyphen {:display true}
:keypad_plus {:display true}
:keypad_enter {:display true}
:keypad_1 {:display true}
:keypad_2 {:display true}
:keypad_3 {:display true}
:keypad_4 {:display true}
:keypad_5 {:display true}
:keypad_6 {:display true}
:keypad_7 {:display true}
:keypad_8 {:display true}
:keypad_9 {:display true}
:keypad_0 {:display true}
:keypad_period {:display true}
:keypad_equal_sign {:display true}
:keypad_comma {:display true}
:vk_none {:label "vk_none (disable this key)" :not-from true}
:print_screen {:display true}
:scroll_lock {:display true}
:pause {:display true}
:insert {:display true}
:application {}
:help {}
:power {}
:execute {:not-to true}
:menu {:not-to true}
:select {:not-to true}
:stop {:not-to true}
:again {:not-to true}
:undo {:not-to true}
:cut {:not-to true}
:copy {:not-to true}
:paste {:not-to true}
:find {:not-to true}
:international1 {}
:international2 {}
:international3 {}
:international4 {}
:international5 {}
:international6 {}
:international7 {}
:international8 {}
:international9 {}
:lang1 {}
:lang2 {}
:lang3 {:not-to true}
:lang4 {:not-to true}
:lang5 {:not-to true}
:lang6 {:not-to true}
:lang7 {:not-to true}
:lang8 {:not-to true}
:lang9 {:not-to true}
:japanese_eisuu {:label "英数キー" :display true}
:japanese_kana {:label "かなキー" :display true}
:japanese_pc_nfer {:label "PCキーボードの無変換キー" :not-to true}
:japanese_pc_xfer {:label "PCキーボードの変換キー" :not-to true}
:japanese_pc_katakana {:label "PCキーボードのかなキー" :not-to true}
:keypad_equal_sign_as400 {:not-to true}
:locking_caps_lock {:not-to true}
:locking_num_lock {:not-to true}
:locking_scroll_lock {:not-to true}
:alternate_erase {:not-to true}
:sys_req_or_attention {:not-to true}
:cancel {:not-to true}
:clear {:not-to true}
:prior {:not-to true}
:return {:label "rarely used return (HID usage 0x9e)" :not-to true}
:separator {:not-to true}
:out {:not-to true}
:oper {:not-to true}
:clear_or_again {:not-to true}
:cr_sel_or_props {:not-to true}
:ex_sel {:not-to true}
:left_alt {:label "left_alt (equal toleft_option)"}
:left_gui {:label "left_gui (equal toleft_command)"}
:right_alt {:label "right_alt (equal toright_option)"}
:right_gui {:label "right_gui (equal toright_command)"}
:vk_consumer_brightness_down {:label "vk_consumer_brightness_down (equal todisplay_brightness_decrement)" :not-from true}
:vk_consumer_brightness_up {:label "vk_consumer_brightness_up (equal todisplay_brightness_increment)" :not-from true}
:vk_mission_control {:label "vk_mission_control (equal tomission_control)" :not-from true}
:vk_launchpad {:label "vk_launchpad (equal tolaunchpad)" :not-from true}
:vk_dashboard {:label "vk_dashboard (equal todashboard)" :not-from true}
:vk_consumer_illumination_down {:label "vk_consumer_illumination_down (equal toillumination_decrement)" :not-from true}
:vk_consumer_illumination_up {:label "vk_consumer_illumination_up (equal toillumination_increment)" :not-from true}
:vk_consumer_previous {:label "vk_consumer_previous (equal torewind)" :not-from true}
:vk_consumer_play {:label "vk_consumer_play (equal toplay)" :not-from true}
:vk_consumer_next {:label "vk_consumer_next (equal tofastforward)" :not-from true}
:volume_down {:label "volume_down (equal tovolume_decrement)"}
:volume_up {:label "volume_up (equal tovolume_increment`)"}})
@kaushikgopal
Copy link

🙏 thanks for the reference. any chance you can correct those links to:

;; another article: https://kau.sh/blog/hacking-your-keyboard/
;; very well documented edn file by Kaushik Gopal: https://github.com/kaushikgopal/dotfiles/blob/master/.karabiner.edn

(changed my domain names)

@joshuawagner
Copy link
Author

🙏 thanks for the reference. any chance you can correct those links to:

;; another article: https://kau.sh/blog/hacking-your-keyboard/
;; very well documented edn file by Kaushik Gopal: https://github.com/kaushikgopal/dotfiles/blob/master/.karabiner.edn

(changed my domain names)

Hey, sorry for the delay! I've updated those links.

@kaushikgopal
Copy link

kaushikgopal commented Mar 17, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment