Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to simulate QMK home row mods in karabiner? #3559

Open
jaroslaw-weber opened this issue Jul 25, 2023 · 10 comments
Open

how to simulate QMK home row mods in karabiner? #3559

jaroslaw-weber opened this issue Jul 25, 2023 · 10 comments

Comments

@jaroslaw-weber
Copy link

https://precondition.github.io/home-row-mods

i want to use home row mods on my native keyboard. is there a way to do this with karabiner?

@jluckyiv
Copy link

I'm struggling with the same issue. I see a few common approaches, but there may be more.

to.if_alone

The first approach uses to and to.if_alone (example):

{
    "type": "basic",
    "from": {
        "key_code": "s",
        "modifiers": {
            "optional": ["any"]
        }
    },
    "to": [
        {
            "key_code": "left_alt",
            "lazy": true
        }
    ],
    "to_if_alone": [
        {
            "key_code": "s"
        }
    ]
}
  • Advantage: simple.
  • Disadvantage 1: unintentional activation. For instance, when I type the word "fast" I get "fa†" because my s and t keypresses overlap, triggering ⌥+t instead of "st". I have tried playing with the settings for to_if_alone_timeout_milliseconds and to_if_held_down_threshold_milliseconds, but I haven't solved this problem.
  • Disadvantage 2: key repeat is disabled. If you rely on holding down a key to repeat it, to_if_alone disables repeat for that key.

from.simultaneous

The second approach uses the simultaneous modification (example). I'm reading up on this now, so I can't give a decent example on my own.

  • Advantage: from what I'm reading, key repeat still works and it solves the simultaneous keypress situation because you enforce key sequence, e.g., simultaneous means s down -> t down -> t up -> s up, and not s down -> t down -> s up -> t up.
  • Disadvantage: (I believe) this approach involves a lot more configuration because you have to remap every key combination.

to.set_variable

I am just learning about this one. This setting (un)sets a variable on key down and key up. When other keys trigger, you can customize their behavior based on the variable being set.

  • Advantage: (I think) this approach has the same advantages as simultaneous.
  • Disadvantage: (I think) this approach involves a lot of configuration.

Tooling

There are tools to ease configuration. A popular one is Goku, which generates a karabiner.json file from the .edn format.

John Lindquist has used Goku to make home-row mods. His dotfiles repo has his karabiner files. He has a couple of YouTube videos and an Egghead.io video.

I've been spelunking Lindquist's karabiner.edn and his karabiner-starter.edn.

Chords?

While I've been typing this post, I ran across a TypeScript configuration tool, karabiner.ts. The tool even has a playground.

The author, Evan Liu posted his config file as an example. He uses home-row key combos, e.g., f + d / j + k = . That would probably solve the fast/fa† problem, but means learning a bunch of chords for modifiers like ⌘+^.

Sorry for the long answer. I'm figuring it out too.

@eytanhanig
Copy link

@jluckyiv Fantastic summary! I've been playing with this and am increasingly disappointed at the complexity necessary to do this.

It is possible to improve the to_alone approach using these instructions. I'm still fiddling with the parameters and suspect that they will vary per person (it's easier to iterate if you just tweak them in the Karabiner UI). However based on the snappy behavior I've seen with a number of the complex modification rules that use simultaneous and/or variables I also believe that those approaches are necessary to achieve our goal.

Before turning to 3rd party tooling I recommend that you check out using ruby to generate rules, which is natively supported by the make command. This repo currently contains a whopping 41 examples of how to do so in src/json.

I've created this gist demonstrating how to use a .json.rb file to implement the improved if_alone approach.

@jluckyiv
Copy link

jluckyiv commented Aug 8, 2023

@eytanhanig Thanks for the tip! I have not used any generators myself. I've been hand-rolling the json.

The to_delayed_actions.to_if_canceled, to_if_alone, and to_if_held_down approach in the link you gave worked well. I looked at your gist, especially the timing parameters. I'm still fine-tuning, but around 100–120 ms seems to mitigate most of my unintentional triggers.

@MartinBernstorff
Copy link

Super happy to find this!

One challenge I'm struggling with is multi-key shortcuts. E.g. if I press S & D at the same time, only one of them trigger the hold command, the other is interrupted and triggers the to_if_canceled. Are you guys experiencing the same thing?

@amiorin
Copy link

amiorin commented Sep 11, 2023

I've replaced Karabiner with KMonad. My guide

@willpuckett
Copy link

Just switched to kmonad from Karabiner/ karabiner.ts. Everything actually works now. It's a relief, and far more responsive as well. Thanks 🪣s for the guide.

@MShahzaib
Copy link

I will try kMonad too

@emadb
Copy link

emadb commented Nov 23, 2023

I used karabiner.ts to recreate a better configuration.
My home row now works pretty well, and I add a chord modificator too a s to enable the arrows with the letters jkli

Here is my configuration:
https://github.com/emadb/karabiner-config/blob/main/karabiner.json

In case some of you are interested here it is the typescript definition:

layer(['caps_lock', 'return_or_enter'], 'mod-layer').manipulators([
    map('a').to('left_shift'),
    map('s').to('left_control'),
    map('d').to('left_option'),
    map('f').to('left_command'),
    
    map('quote').to('right_shift'),
    map(';').to('right_control'),
    map('l').to('right_option'),
    map('k').to('right_command'),
  ]),

  duoLayer('a', 's').manipulators([
    map('i').to('up_arrow'), 
    map('j').to('left_arrow'), 
    map('k').to('down_arrow'), 
    map('l').to('right_arrow'),
  ])

@rajasegar
Copy link

I configured just now for MacOS Sonoma
https://github.com/rajasegar/karabiner-config/blob/master/karabiner.json
works fine for me now

@argenkiwi
Copy link

I am working on a keyboard layout and I would also like to know what the recommended implementation of home row modifiers is using Karabiner. I attempted to achieve this using Goku but I have not succeded so far. Kanata (and Kmonad) do seem to achieve this a lot more easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants