Examples for users to check as quick reference and source of inspiration. Most docs are comments (start with ;;) in code block.
Below is the minimal configuration. It does nothing. Make sure you have a profile named “Default” in karabiner.json.
{}
from | to |
---|---|
; | : |
shift + ; | ; |
command + ; | command + ; |
option + ; | option + ; |
control + ; | control + ; |
{:main [{:des "swap ; :"
:rules [[:semicolon :!Ssemicolon]
[:!Ssemicolon :semicolon]]}]}
You can find all keycodes here or using the Karabiner-EventViewer.app.
{:main [{:des "demo modifier keys"
:rules [
;; shift 1 to 1
;; !S here means shift
[:!S1 :1]
;; 1 to !
[:1 :!S1]
;; control shift 1 to 12
;; !TS means control shift
[:!TS1 [:1 :2]]]}]}
;; C T O S stands for left_command left_control left_option left_shift
;; Q W E R stands for right_command right_control right_option right_shift
;;;; hyper
;; !! stands for left_command + left_control + left_option + left_shift
;; :!!1 left_command + left_control + left_option + left_shift + 1
from | to |
---|---|
right_command | f16 |
left_command + right_command | left_command + f16 |
option + right_command | option + f16 |
shift + right_command | shift + f16 |
control + right_command | control + f16 |
{:main [{:des "right_command to f16"
:rules [[:##right_command :f16]]}]}
Note: Other modifier keys works because of the ”
##
” prefix. If you replace##
with#C
(C
forleft_command
), only> left_command + right_command -> left_command + f16 will work.
Others will be treated like
> control + right_command -> control + right_command
{:main [{:des "caps_lock to esc when pressed alone, to ctrl as modifier"
:rules [[:##caps_lock :left_control nil {:alone :escape}]]}]}
{:main [{:des "press j and l simultaneously to f16"
:rules [[[:h :j] :f16]]}]}
simlayer, templates example
{:templates {:open "open \"%s\""}
:layers {}
:simlayers {;; make w key a simlayer key
;; layers works too, but only recommended for none typing keys
;; like . , tab
;; or keys like z, which used less often
:launch-mode {:key :w}}
:main [{:des "launch mode"
:rules [:launch-mode
[:k [:open "/Applications/Emacs.app"]]
[:l [:open "/Applications/Google Chrome.app"]]]}]}
same as below config, all conditions (layer, simlayer, application, input-source, device) works this way.
{:templates {:open "open \"%s\""}
:layers {}
:simlayers {:launch-mode {:key :w}}
:main [{:des "launch mode"
:rules [[:k [:open "/Applications/Emacs.app"] :launch-mode]
[:l [:open "/Applications/Google Chrome.app"] :launch-mode]]}]}
layer example
{:templates {:open "open \"%s\""
:alfred "osascript -e 'tell application \"Alfred 3\" to run trigger \"%s\" in workflow \"%s\" with argument \"%s\"'"}
:layers {:alfred-layer {:key :z}}
:simlayers {:launch-mode {:key :w}}
:main [{:des "launch mode"
:rules [:launch-mode
[:k [:open "/Applications/Emacs.app"]]
[:l [:open "/Applications/Google Chrome.app"]]]}
{:des "alfred mode"
:rules [:alfred-mode
[:h [:alf "search repos" "me.lachlan.githubjump"]]
[:x [:alf "killProcess" "com.ngreenstein.alfred-process-killer"]]]}]}
below config works as well
{:templates {:open "open \"%s\""
:alfred "osascript -e 'tell application \"Alfred 3\" to run trigger \"%s\" in workflow \"%s\" with argument \"%s\"'"}
:layers {:alfred-layer {:key :z}}
:simlayers {:launch-mode {:key :w}}
:main [{:des "character key as modifier key rules"
:rules [:launch-mode
[:k [:open "/Applications/Emacs.app"]]
[:l [:open "/Applications/Google Chrome.app"]]
:alfred-mode ;; all conditions works this way
[:h [:alf "search repos" "me.lachlan.githubjump"]]
[:x [:alf "killProcess" "com.ngreenstein.alfred-process-killer"]]]}]}
{:main [{:des "alfred"
:rules [;; set f16 as the trigger key of alfred
;; press h + l will trigger alfred and set "in-alfred" to 1
[[:h :j] [:f16 ["in-alfred" 1]]]
:in-alfred ;;;; when "in-alfred" is 1
;; press enter will select one alfred result and set "in-alfred" to 0
[:##return_or_enter [:return_or_enter ["in-alfred" 0]]]
;; press esc will exit alfred and set "in-alfred" to 0
[:##escape [:escape ["in-alfred" 0]]]
;; press ctrl + j will invoke down_arrow
[:!Tj :down_arrow]
;; press ctrl + k will invoke up_arrow
[:!Tk :up_arrow]
;; press ctrl + l will invoke return_or_enter and set "in-alfred" to 0
[:!Tl [:return_or_enter ["in-alfred 0"]]]]}]}
{:des "Press right_shift twice to enter double shift mode, press right_shift once to leave it"
:rules [[:right_shift ["double-right-shift-mode" 1] ["shift-pressed-once" 1]]
[:right_shift [:right_shift ["shift-pressed-once" 1]] ["double-right-shift-mode" 0] {:delayed {:invoked ["shift-pressed-once" 0] :canceled ["shift-pressed-once" 0]}}]
:double-right-shift-mode
[:right_shift ["double-right-shift-mode" 0]]
[:a "say 'know we are in double shift mode'"]]}
use the multitouch feature
{:des "ctrl+y to command+v (trackpad example)"
:rules
[;; ctrl+y to command+v
[:!Ty :!Cv]
;; ctrl+y to command+v when one finger on trackpad
[:!Ty :!Cv :multitouch_extension_finger_count_total]
;; ctrl+y to command+v when one finger on trackpad
[:!Ty :!Cv ["multitouch_extension_finger_count_total" 1]]
;; ctrl+y to command+v when two finger on trackpad
[:!Ty :!Cv ["multitouch_extension_finger_count_total" 2]]
;; ctrl+y to command+v when three finger on the upper half of trackpad
[:!Ty :!Cv ["multitouch_extension_finger_count_upper_half_area" 3]]]}
This syntax don’t support specify negative multitouch conditions. For example:
Don't map a to b when there are three fingers on the trackpad.
{:layers {:z-mode {:key :z}}
:devices {;; define devices
;; vendor_id and product_id can be found in Karabiner EventViewer gui
:hhkb [{:vendor_id 2131 :product_id 256}]}
:applications {;; define applications
:Browsers [;; these strings are regex to match applications bundle_identifiers
;; you can find bundle_identifiers in the Info.plist file of an applications
;; eg. in /Applications/Mail.app/Contents/Info.plist
;; search for "CFBundleIdentifier"
"^org\\.mozilla\\.firefox$"
"^org\\.mozilla\\.firefoxdeveloperedition$"
"^com\\.google\\.Chrome$"
"^org\\.chromium\\.Chromium$"
"^com\\.google\\.Chrome\\.canary$"
"^com\\.apple\\.Safari$"]}
:input-sources {;; define input-source, these data can be founhd in Karabiner EventViewer gui
:us {:input_mode_id ""
:input_source_id "com.apple.keylayout.US"
:language "en"}}
;; can config like this
:main [{:des "contions demo"
:rules [;; multiple conditions
;;;; when
;; the input-method is :us
;; the activated application is one of app in :Browsers
;; the key is triggered by :hhkb
;; may l key to command + optional + l
[:condi :us :hhkb :Browsers :z-mode]
[:l :!COi]]}]
;; or
:main [{:des "contions demo"
:rules [[:l :!COi [:us :hhkb :Browsers :z-mode]]]}]
;; or
:main [{:des "contions demo"
:rules [[:condi :us :hhkb]
[:l :!COi [:Browsers :z-mode]]]}]}
Skip this section if you don’t use profiles.
Since karabiner cli now supports set variables, profiles are mainly used for multiple users using the same machine or between different usages like gaming profile and working profile. Goku doesn’t support that well for now.
Basically, you can define your multiple profiles. Only one of them can be set
as the default profile (:default true
).
Then you can use profile keyword :Default
as conditions or layers keyword.
You need to specify each rule to a profile or they will be considered in the
default profile.
If you want to have a empty profile for gaming. You can create one in karabiner gui (no need to change anything in goku).
{:profiles {:Default {;; "default true means" rules default goes into this rule if no profiles specified
:default true
;; simultaneous key press threshold
;; simlayer is implemented with to_if_alone and simultaneous key press feature
:sim 250
;; to_delayed_action_delay_milliseconds
;; checkout karabiner's documentation
;; https://pqrs.org/osx/karabiner/json.html
;; basically it means time after which the key press is count delayed
:delay 500
;; https://pqrs.org/osx/karabiner/json.html#to-if-alone
;; to_if_alone_timeout_milliseconds
;; affects to_if_alone behavior
;; simlayer is implemented with to_if_alone and simultaneous key press feature
:alone 1000
;; to_if_held_down_threshold_milliseconds
;; check the doc, I don't know what does this mean.
;; maybe press this milliseconds counts a "held" ?
:held 500}}}
same key in different mode, from @nikitavoloboev’s config
Use karabiner command-line interface to set variables when you open specifc type of files in your editor.
{:profiles
{:Default {:default true
:sim 50
:delay 80
:alone 120
:held 70}}
:simlayers {:js-mode {:key :period :condi ["in-js" 1]} ;; karabiner_cli --set-variables {"in-js": 1}
:go-mode {:key :period :condi ["in-go" 1]} ;; karabiner_cli --set-variables {"in-go": 1}
:py-mode {:key :period :condi ["in-python" 1]} ;; karabiner_cli --set-variables {"in-python": 1}
:elixir-mode {:key :period :condi ["in-elixir" 1]} ;; karabiner_cli --set-variables {"in-elixir": 1}
:rust-mode {:key :period :condi ["in-rust" 1]}} ;; karabiner_cli --set-variables {"in-rust": 1}
:main [{:des "jsdot"
:rules [:js-mode
[:a [:c :o :n :s :o :l :e :period :l :o :g :!S9 :!S0 :left_arrow]] ; -> console.log()
[:v [:j :a :v :a :s :c :r :i :p :t :spacebar]]]} ; -> javascript
{:des "godot"
:rules[:go-mode
[:a [:f :m :t :period :!Sp :r :i :n :t :l :n :!S9 :!S0 :left_arrow]] ; -> fmt.Println()
[:v [:g :o :l :a :n :g :spacebar]]]} ; -> golang
{:des "pydot"
:rules[:py-mode
[:a [:p :r :i :n :t :!S9 :!S0 :left_arrow]] ; -> print()
[:v [:p :y :t :h :o :n :spacebar]]]} ; -> python
{:des "elixdot"
:rules[:elixir-mode
[:a [:!Si :!So :period :p :u :t :s :!S9 :!S0 :left_arrow]] ; -> IO.puts()
[:v [:e :l :i :x :i :r :spacebar]]]} ; -> elixir
{:des "rustdot"
:rules[:rust-mode
[:a [:p :r :i :n :t :l :n :!S1 :!S9 :!S0 :left_arrow]] ; -> println!()
[:v [:r :u :s :t :spacebar]]]}]} ; -> rust