Examples for users to check as quick reference and source of inspiration. Most docs are comments (starting with ;;) in the code blocks.
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 work because of the ”
##
” prefix. If you replace##
with#C
(C
forleft_command
), only> left_command + right_command -> left_command + f16 will work.
Others combinations would simply act 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 [[[:j :l] :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"]]]}]}
use left_control+w
as simlayer key
{: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
;; can omit the vector if only one modifier is used
;; :modi {:mandatory :left_control}
;; more examples
;; :modi {:optional :any}
;; :modi {:optional [:left_shift :left_command]
;; :mandatory :left_control}
:modi {:mandatory [:left_control]}}}
:main [{:des "character key as modifier key rules"
:rules [:launch-mode
;; lctrl down and w+k run shell script "open /Applications/Emacs.app"
[: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"
;; you can also find bundle_identifiers using command line:
;; osascript -e 'id of app "Google Chrome"'
"^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 profiles and working profiles. Goku doesn’t support that well for now.
However, you can define your multiple profiles. Only one profile 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 an empty profile for gaming, you can create one in the 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 many milliseconds counts a "held" ?
:held 500}}}
same key in different mode, from @nikitavoloboev’s config
You can use karabiner command-line interface to set variables when you open specifc type of files in your editor. See ISSUE #79.
{: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
{:des "disable all pointing buttons"
:rules [[{:any :pointing_button} :vk_none]]}
{:des "Quit application by pressing command-q twice"
:rules [[
;; <from> second cmd-q (when variable "command-q" is 1)
:!C#Pq
;; <to>, 3 to action
;; 1. call cmd-q
;; 2. set variable "command-q" to 0
;; 3. cleanup the :cmdq notification (omit the thrid item to cleanup notification)
[:!Cq ["command-q" 0] [:noti :cmdq]]
;; <condition> when variable "command-q" is 1
["command-q" 1]]
[
;; <from> first cmd-q (when variable "command-q" is 0)
:!C#Pq
;; <to>, 2 to action
;; 1. show notification with :id :cmdq, :text "Press Again to QUIT"
;; 2. set variable "command-q" to 1 (for the second press)
[[:noti :cmdq "Press Again to QUIT"] ["command-q" 1]]
;; <condition> nil means no required condition
nil
;; <additional-option>
{
;; to_delayed_action documentation
;; https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/to-delayed-action/
:delayed {
;; run 2 actions when no other key presses after basic.to_delayed_action_delay_milliseconds
;; 1. set variable "command-q" to 0
;; 2. cleanup notification :id :cmdq
:invoked [["command-q" 0] [:noti :cmdq]]
;; run 2 actions when another key presses within basic.to_delayed_action_delay_milliseconds
;; 1. set variable "command-q" to 0
;; 2. cleanup notification :id :cmdq
:canceled [["command-q" 0] [:noti :cmdq]]}}]]}
This setup can be used for keybindings where you press one key, then quickly another key to execute a to action. The order is important: all the conditional bindings must come before the line with the delayed declaration
{:des "tap right shift then keys"
:rules [
; If right-shift-mode is on, run this command when a is pressed. Anything that depends
; on the mode being set must come _before_ the delayed declaration.
[:a "open https://github.com/yqrashawn/GokuRakuJoudo" [:right-shift-mode]]
; Send right_shift unconditionally (so it still works as a modifier key)
[:right_shift :right_shift nil
; and if pressed alone, trigger right-shift-mode
{:alone [:right_shift ["right-shift-mode" 1]]
; when another key is invoked, or after a timeout, set the mode back to zero
:delayed {:invoked ["right-shift-mode" 0] :canceled ["right-shift-mode" 0]}}]]}