yqrashawn / GokuRakuJoudo

config karabiner with ease
GNU General Public License v3.0
1.16k stars 119 forks source link

Delay when pressing sublayer key that isn't first in rule list #72

Open NickvanDyke opened 4 years ago

NickvanDyke commented 4 years ago

I have

{:des "numpad"
 :rules [:numpad-mode
   [:m :1]
   [:comma :2]
    ...
]}

And it seems that for every rule that isn't first in the list, when it's the first rule I've triggered since activating the layer, there's a delay equal to simlayer-threshold before the from triggers (assuming I don't release the layer key before then). But the first rule in the list seems to trigger immediately. If I continue holding the layer key, all froms trigger immediately from then on. What's the cause? Do I have it set up wrong somehow? I have about 7 layers and this is true throughout them.

yqrashawn commented 4 years ago

Hi, I just reproduced the problem. There's nothing wrong with the generated JSON config. Seems this is caused by karabiner itself. Would you mind to post this issue to karabiner with the generated JSON config?

For me, I set simultaneous_threshold_milliseconds to 210 so it's not noticeable.

NickvanDyke commented 4 years ago

Sure, can do. To make sure I understand for when posting it, the problem is that Karabiner waits the full threshold before sending the <to>, when it could/should send it immediately upon the sublayer keydown?

NickvanDyke commented 4 years ago

Also, unrelated, but @yqrashawn how would I use the same sublayer key but with a different modifier? For example, holding f and pressing j mapping to a different <to> than holding shift + f and pressing j (or holding f and then pressing shift + j, does the order matter here?). I've tried putting the modifier everywhere I can think of in the config but can't get it. My layer even seemed to be active when I wasn't holding a modifier that I had specified as mandatory in the simlayer section, so I must be misunderstanding something. Is the trick to have the modifier in the simlayer definition, or on the rule that's under the simlayer, or both?

My apologies if it's covered somewhere, I couldn't find anything in the examples or glean it from my own experimenting and the karabiner docs.

NickvanDyke commented 4 years ago

I tinkered some more, and more accurately, I'm struggling with both using modifiers with a layer, and using modifiers with <from>s that are under a layer. For example, I have a function layer that activates when q is held, and I have a rule under that layer that maps m to f1. How would I use modifiers with that f1? E.g. how would I send shift + f1 by pressing m while holding q and shift? I've tried adding optional modifiers to both the simlayer definition and the rule's to and/or from definition, with no luck; it seems to just trigger the rule without the modifier having any effect at all on whether the layer or the rule activates.

yqrashawn commented 4 years ago

the problem is that Karabiner waits the full threshold before sending the , when it could/should send it immediately upon the sublayer keydown?

The problem is karabiner only waits on rules other than the first one.

does the order matter here?

It matters. shift + f then j means there's a shift+f layer with a rule triggered by j. f then shift+j means there's an f layer with a rule triggered by shift+j. You need to define different layers (f layer and shift+f layer) for the first circumstance.

how would I send shift + f1 by pressing m while holding q and shift?

Two options. Say the q layer is already defined

The first approach:

[:q-layer
 [:##m :f1]] ;; '##' means the 'm' key optionally accepts any combination of modifiers

q m -> f1 q shift+m -> shift+f1 q control+m -> control+f1 q shift+control+m -> shift+control+f1

The second approach:

[:q-layer
 [:m :f1]
 [:!Sm :!Sf1]
 [:!Tm :!Tf1]]

q m -> f1 q shift+m -> shift+f1 q control+m -> control+f1

NickvanDyke commented 4 years ago

The problem is karabiner only waits on rules other than the first one.

So is the expected/proper behavior the one of the first rule (triggering immediately) or of the later rules (waiting)?

Thanks for the detailed examples. Perhaps I'm misunderstanding, but there seems to be unexpected behavior with both of the approaches you gave. That or my expectations are wrong. It seems that for simlayers, Goku generates two manipulators for each rule that has that simlayer as a condition - one for entering the layer (setting the variable) and sending the <to> when the layer key and one of its rules' <from>s are pressed simultaneously, and one for when we're already in the layer that just sends the <to>. In both of the given approaches, only the generated manipulator for when we're already in the layer seems to be affected.

When I do

[:q-layer
 [:##m :f1]]

the modifier is passed through as expected if I'm already in the layer - that is, I've already triggered a rule in the layer, and have continued holding the layer key. But if I enter the layer with this rule, the modifier is never passed through. Holding q, then holding any modifier and pressing m always outputs f1 with no modifiers.

The second approach seems to have the same problem. Additionally, if I have just

[:q-layer
 [:!Sm :f1]]

then, since the simultaneous manipulator is not affected by the mandatory shift, holding q and pressing m (without shift held) will still trigger the rule and enter the layer.

This is all with

:simlayers {
    :q-layer {:key :q}
}

I tried changing that to

:simlayers {
    :q-layer {:key :q :modi {:optional :any}}
}

for the first approach and

:simlayers {
    :q-layer {:key :q :modi {:mandatory :shift}}
}

for the second approach, thinking that might affect the simultaneous manipulator, but it didn't. Am I implementing this wrong? I don't understand the :modi for simlayers. You said shift + f then j means there's a shift+f layer, and adding :modi {:mandatory :shift} to the simlayer definition seems like how you'd define that, but it hasn't seemed to change anything that's generated for me

yqrashawn commented 4 years ago

But if I enter the layer with this rule, the modifier is never passed through

Check this line in my config, goku will generate the json config as

[
  {
    "from": {
      "key_code": "j",
      "modifiers": {
        "optional": [
          "any"
        ]
      }
    },
    "to": [
      {
        "key_code": "down_arrow"
      }
    ],
    "conditions": [
      {
        "name": "vi-mode",
        "value": 1,
        "type": "variable_if"
      }
    ],
    "type": "basic"
  },
  {
    "type": "basic",
    "parameters": {
      "basic.simultaneous_threshold_milliseconds": 210
    },
    "to": [
      {
        "key_code": "down_arrow"
      },
      {
        "set_variable": {
          "name": "vi-mode",
          "value": 1
        }
      }
    ],
    "from": {
      "simultaneous": [
        {
          "key_code": "d"
        },
        {
          "key_code": "j"
        }
      ],
      "simultaneous_options": {
        "detect_key_down_uninterruptedly": true,
        "key_down_order": "strict",
        "key_up_order": "strict_inverse",
        "key_up_when": "any",
        "to_after_key_up": [
          {
            "set_variable": {
              "name": "vi-mode",
              "value": 0
            }
          }
        ]
      }
    }
  }
]

There's no options in from.simultaneous part. Cause karabiner don't support optional modifier in it like below

      "simultaneous": [
        {
          "key_code": "d"
        },
        {
          "key_code": "j",
          "modifiers": {
             "optional": ["any"]
          }
        }
      ],

The log shows

image

It only supports add the modifiers options outside of simultaneous like the example in the doc.

Seems I missed this feature. I'll find time to implement this. The logic here will be combining the modifiers specified in both simlayer definition and in the <from> section of the rule. And better default it to ## as it's more intuitive.

You can use layer instead of simlayer for now to achieve this. Although it's not recommended to use frequently used keys to trigger layer.

NickvanDyke commented 4 years ago

Great! Thank you, I appreciate the responses. I look forward to being able to use Goku that way, it's been a great help so far.

yqrashawn commented 2 years ago

Hi, modifier for sim key is implemented now. Check this comment https://github.com/yqrashawn/GokuRakuJoudo/issues/114#issuecomment-813238316

Although it's not supported in the :simlayers definition, you can implement the simlayer logic in rules with it

yqrashawn commented 2 years ago

Hi modifier support for :simlayers is released in https://github.com/yqrashawn/GokuRakuJoudo/releases/tag/v0.5.0

although the logic is a bit different the :modi specified in :simlayers will override those in :rules

you can check the link in changelog for example config