I'd like to implement a "SpaceFN" layer (ie. while space is held down, activate another layer).
Here's a small example showing how to map Space+J to "left":
{
"description": "Space + J = LEFT",
"from": {
"key_code": "j",
"modifiers": {
"mandatory": [
"fn"
]
}
},
"to": [
{
"key_code": "left_arrow"
}
],
"type": "basic"
},
{
"description": "Space as fn",
"from": {
"key_code": "spacebar"
},
"to": [
{
"key_code": "fn"
}
],
"to_if_alone": [
{
"key_code": "spacebar"
}
],
"type": "basic"
},
The problem is, space is pressed very often during normal typing, so it is all too easy for this kind of set-up to produce unwanted "fn" presses instead of spacebar presses when typing fast.
With the old Karabiner, __BlockUntilKeyUp__ took care of this quite nicely, or at least, I think it did if I understand its purpose. It basically meant, I think, that it wouldn't fire one of the layer events unless Space were pressed before another key, and released after the other key:
# This triggers a layer event (ie. LEFT)
Space down ---> J down ---> J up ---> Space up
# This normal roll-over does not trigger a layer event, just SPACE then J:
Space down ---> J down ---> Space up ---> J up
Here's the full version of the old Karabiner config: https://github.com/wincent/wincent/blob/c250a81d235bef574d3a7cf2f2bb7a585bcd9686/roles/keyboard/files/spacefn.xml
{
"description": "Second Layer",
"manipulators": [
{
"from": {
"key_code": "spacebar"
},
"to": [
{
"set_variable": {
"name": "another_layer",
"value": 1
}
}
],
"to_if_alone": [
{
"key_code": "spacebar"
}
],
"to_after_key_up": [
{
"set_variable": {
"name": "another_layer",
"value": 0
}
}
],
"type": "basic"
},
{
"conditions": [
{
"type": "variable_if",
"name": "another_layer",
"value": 1
}
],
"from": {
"key_code": "j"
}
},
"to": [
{
"key_code": "left_arrow"
}
],
"type": "basic"
},
{
"conditions": ...
@michelkoga: That's much better. Thanks.
However, I still think I need an equivalent for __BlockUntilKeyUp__. Without this, configurations like the above don't handle rollover well. I am going to keep playing around and see if I can come up with something in terms of variables and to_if_alone_timeout_milliseconds perhaps, but ultimately I think I need something else.
The new to_if_held_down property allows us to get pretty close to what we would need here, but it is not quite there; given this config:
"description": "SpaceFN layer",
"manipulators": [
{
"from": {
"key_code": "spacebar",
"modifiers": {
"optional": [
"any"
]
}
},
"to_if_held_down": [
{
"set_variable": {
"name": "SpaceFN",
"value": 1
}
}
],
"to_after_key_up": [
{
"set_variable": {
"name": "SpaceFN",
"value": 0
}
}
],
"to": [
{
"key_code": "spacebar",
"repeat": false
}
],
"type": "basic"
},
We can prevent the SpaceFN layer from kicking in until the key is pressed for a while, and we can still enjoy normal rollover while typing fast. The only gotcha is that initial press of the space bar causes an immediate key-down/key-up to be sent, even if you end up just pressing and holding (ie. your intention is to enter SpaceFN mode). This is very close to being usable now, but I think we still need something like __BlockUntilKeyUp__.
I'm looking for something very similar: using the spacebar as normal space when short pressed, and as left_control when held down _and_ pressed with something else. (Mainly for use with Spacemacs.)
I tried many variations of configurations so far and no matter what I do I always end up tripping up on this "rollover" that you mention and issuing a left_control+letter when what I type fast and wish for is a SPC+letter.
I think __BlockUntilKeyUp__ would help, and I would also like to advocate for @jonathankau's solution here which would be to have a configurable overlap/rollover threshold. In his words, "If spacebar is only held for less than that threshold, then it will always be treated as a spacebar press (Even if I press another key during that initial spacebar press)."
I'm voicing my support for both things and will open a separate issue for the latter. Many thanks for Karabiner Elements!
Let me throw in here the set if heuristics that I'm using in my Linux implementation (in the Xorg input driver): http://www.ljosa.com/~ljosa/software/spacefn-xorg/
I found that simple timeouts were not enough, and that I needed to buffer other keypresses (not just space) until their intention became clear.
Would the new "simultaneous" feature help with this?
I don't think so.
Yes, simultaneous is not the replacement of __BlockUntilKeyUp__ yet.
Seems like it is now though. 馃槃
For example:
https://github.com/wincent/wincent/commit/8fe03134e1c5201264ed2f1e5373c8720e2019f8
I updated karabiner.json Reference Manual about simultaneous_options.
https://pqrs.org/osx/karabiner/json.html#simultaneous-options
Thanks, @tekezo, the docs contained the crucial information that I was missing: "simultaneous_options is available only in the beta versions." Once I upgraded from the released 11.6.0 to the beta 11.6.6, I was able to get @wincent's config (https://github.com/wincent/wincent/commit/8fe03134e1c5201264ed2f1e5373c8720e2019f8) to work.
Once issue that I haven't been able to resolve is how to disable autorepeat for spacebar. (SpaceFn relies on this because it uses space as a modifier when held. Spacebar+b, which emits a space, should continue to autorepeat.) A manipulator like the following is effective at preventing autorepeat, but also stops @wincent's SpaceFn manipulators from working:
{
"from": {
"key_code": "spacebar",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "spacebar",
"repeat": false
}
],
"type": "basic"
}
Do you (or anyone) have a solution for that? Thanks!
@ljosa are you still having this problem with the latest version? It's working as desired for me
@olets, yes, with Karabiner-Elements 12.1.0, it is still the case that I have not found a way to disable autorepeat for space without breaking SpaceFn.
This is the configuration I'm using: https://gist.github.com/ljosa/66b0c9194c23a20be6a542784c322906
Adding the manipulator that I posted above (https://github.com/tekezo/Karabiner-Elements/issues/877#issuecomment-371568571) breaks SpaceFn.
Have you managed to get it to work, @olets?
I'd second sven's request. It would have saved me a fair few hours of banging my head against the wall!
Should this issue be reopened? Seems like it is only resolved for @wincent, but everyone else is still waiting for a fix before spacefn is usable :)
@yzhuang: SpaceFN works well for me with this config: https://gist.github.com/ljosa/df7a08953a050f8b49997840095d132d
It's definitely usable. You just need to configure it correctly. I am on phone now so I can't post full example config but this is the script I use to generate it.
Yup. I was speaking for the people waiting for the complex modification repository to be updated, and advocating for a longer term fix.
For myself, I took the same route ljosa did --- I took the fix in https://github.com/wincent/wincent/commit/8fe03134e1c5201264ed2f1e5373c8720e2019f8 and modified it by hand to suite my needs. It was quite tedious, and now I am on a forked version of the spacefn config.
Will give the javascript generation script a try tonight. Thanks for helping!
This SpaceFn thing is the only reason I'm trying out Karabiner Elements and the version I've downloaded from https://pqrs.org/osx/karabiner/complex_modifications/ has no effect; my spacebar works the same way as before.
I've also tried the _Change caps_lock to control if pressed with other keys, to escape if pressed alone._ mod. That didn't work either first, even after an upgrade to the latest (12.7.0) version.
After a reinstall, at least the capslock->ctrl/esc works, but spacefn still does not :(
I will look at the links in the last 3 comments; but I wanted to indicate that there is 1 more person how cares about this :)
(I bought a Minidox and soldered together my own Troy Fletcher's Signum 3.0, but I'm curious if I can implement at least these 2 basic layout enhancement ideas without custom keyboard firmwares for my colleagues at the company I'm working for currently)
After checking out @ljosa 's karabiner.json, I've just realised it starts with a _SpaceFn layer_ rule, which is required for the rest of the config to work.
The published SpaceFN configuration also has a similar rule, called _SpaceFN: Space enables SpaceFN mode (see: https://geekhack.org/index.php?topic=51069.0)_, which I've have not enabled, because I have not understood its relevance, but it actually works.
I have to say though, it's rather annoying that space only gets registered on release and I did not expect this side effect. I understand there is no way around it, but it's still sad... :)
Thanks everyone for their useful comments; great script @wincent and great, clean rule descriptions @ljosa!
Can I turn off the space repeat somehow with a recent Karabiner-Elements version (12.7.0) without having rollover issues?
After trying to use both solutions (the official one and ljosa's) I finally understood the problems you were discussing here.
The official version misbehaves during quick typing because it interprets a space-down/k-down/space-up/k-up sequence as down arrow, but at least it doesn't repeat space when held long without pressing any other key.
The ljosa version takes into account the release sequence of keys, but repeats space.
I already linked a working config above that suffers from none of the problems you described.
Most helpful comment
@michelkoga: That's much better. Thanks.
However, I still think I need an equivalent for
__BlockUntilKeyUp__. Without this, configurations like the above don't handle rollover well. I am going to keep playing around and see if I can come up with something in terms of variables andto_if_alone_timeout_millisecondsperhaps, but ultimately I think I need something else.