jtroo / kanata

Improve keyboard comfort and usability with advanced customization
GNU Lesser General Public License v3.0
2.15k stars 110 forks source link

leader key needs optional layer toggle #251

Closed santhoshr closed 5 months ago

santhoshr commented 1 year ago

When I'm "switched" to symbols or navigational layer like arrows or mouse, leader key will be useless without input layer

I tried combining various options with multi, macro, fakekey but could not get leader to work when in non input layer

An optional leader construct with default layer to process sequence will be useful

Also is it possible to get multiple leader 'sldr' might stand for sequence leader, can we have 'sldr' for 's' character leader, so I define (defldr sldr input-layer) | (keyword ldr-name layer-to-be-held) on defining sequence (defseq insert-mode (i) sldr) | (keyword seq-name seq ldr-name)

This way I can create cldr, slashldr etc

jtroo commented 1 year ago

It sounds like there are two asks:

  1. go to a different layer while sequence mode is active
  2. allow multiple sequence leaders, which can have different sequences with the same characters but different outputs

For 1, I agree that this doesn't seem like it can be emulated properly purely in the configuration. For the code changes, could add code here to save the current layer and enter a new layer

                        CustomAction::SequenceLeader => {
                            log::debug!("entering sequence mode");
                            self.sequence_state = Some(SequenceState {
                                sequence: vec![],
                                ticks_until_timeout: self.sequence_timeout,
                            });
                        }

And in the various locations of this line occurring, can restore the old layer:

                        self.sequence_state = None;

The SequenceLeader custom action could optionally contain a layer to temporarily switch to.


For 2., this sounds like a lot more work to do in the code. But perhaps you can emulate it in the configuration with:

(defalias
  ald (multi sldr (macro 1 a))
  bld (multi sldr (macro 1 b))
)

(defseq
  fake_key_a  (a c)
  fake_key_b  (b c)
)

This configuration would allow @ald followed by c and @bld followed by c to have different behaviour. I haven't tested this though, so maybe there's something about it that doesn't work properly.

santhoshr commented 1 year ago

For 1, I have to try setting up Rust and customize code, haven't done that with Rust code yet

For 2, Your example worked, but requires specific keys, when I changed keys, it complains of conflict and earlier defined sequence. Also it achieves different leader with same key, on closer look these are dedicated buttons doing different things, so two buttons are required as well as the sldr is used with just one particular trigger through macro not sure if the 'sldr' is going to take other keys without other dedicated buttons like ald, bld

I also think the leader and sequence is adequate as it is, the improvement I suggested are good to have and the config can be made without using leader on number or special layers, and also in a different way to trigger stuff.

update: I tried again and the second approach should work, as well as the 'sldr' will take different keys, as my post below using this technique triggers two different keys

santhoshr commented 1 year ago

The first problem also works without changing source code based on your example, the below code changes to different layer while grv key is held and any one of a, s, d or space pressed, irrespective of current layer not having exact keys required for sequence to trigger,

(defcfg)

(defsrc
    grv   1   2   3 
    tab   a   s   d
    spc
)

(deflayer   default
    @gld   1   2   3
    tab    a   s   d
    @spc
)

(deflayer   nav
    @gld   XX   XX       XX  
    tab    XX   C-rght   XX 
    spc
)

(deflayer   rnv
    @gld   XX    XX     XX 
    tab    esc   pgup   up
    spc
)

(deflayer   snv
    @gld   XX    XX    XX
    XX     C-q   C-w   XX
    spc
)

(deflayer   insert
    @gli   1   2   3  
    tab    a   s   d 
    spc
)

(defseq 
    imode (grv a)
    nvs (grv s)
    rnav (grv d)
    defm (grv spc)
)
(deffakekeys 
    imode (layer-switch insert)
    nvs (layer-switch nav)
    rnav (layer-switch rnv)
    defm (layer-switch default)
)
(defalias
  grv (multi sldr (macro 1 grv))
  gld (multi @grv (layer-toggle insert))
  gli (multi @grv (layer-toggle default))
  nvs (layer-switch nav)
  rnv (layer-switch rnv)
  snv (layer-toggle snv)
  spc (tap-hold-release 150 150 spc lctl)
)

This works but one small bug or not I don't know, when in insert mode I have to use @gli instead of @gld and switch to different input mode layer to work, otherwise it locks up and further leader presses doesn't work, likely not re-launching current layer when it is already present is the reason

(unrelated if anyone searching for vim style navigation, the below link to configuration does that based on above code, I use caps lock for triggering Enso launcher so caps is used everywhere https://github.com/santhoshr/Scripts/blob/main/kanata/c2ns2c.kbd)

jtroo commented 1 year ago

This works but one small bug or not I don't know, when in insert mode I have to use @gli instead of @gld and switch to different input mode layer to work

Interesting, I'm not sure if that's a bug or not either. I'll look into it.

jtroo commented 1 year ago

I can't reproduce anything that seems like incorrect behaviour when I test. If I change the insert layer to use @gld, it seems to work fine:

03:26:05 [INFO] Entered layer:

(deflayer   insert
    @gld   1   2   3
    tab    a   s   d
    spc
)
03:26:13 [DEBUG] (1) kanata::kanata::windows::llhook: event loop: KeyEvent { code: KEY_GRAVE, value: Press }
03:26:13 [DEBUG] (2) kanata::kanata: entering sequence mode
03:26:13 [INFO] Entered layer:

(deflayer   insert
    @gld   1   2   3
    tab    a   s   d
    spc
)
03:26:13 [DEBUG] (2) kanata::kanata: sequence got Grave
03:26:13 [DEBUG] (2) kanata::kanata: key release   Grave
03:26:13 [DEBUG] (1) kanata::kanata::windows::llhook: event loop: KeyEvent { code: KEY_S, value: Press }
03:26:13 [DEBUG] (2) kanata::kanata: sequence got S
03:26:13 [DEBUG] (2) kanata::kanata: sequence complete; tapping fake key
03:26:13 [DEBUG] (2) kanata::kanata: key release   S
03:26:14 [DEBUG] (1) kanata::kanata::windows::llhook: event loop: KeyEvent { code: KEY_S, value: Release }
03:26:14 [DEBUG] (1) kanata::kanata::windows::llhook: event loop: KeyEvent { code: KEY_GRAVE, value: Release }
03:26:14 [INFO] Entered layer:

(deflayer   nav
    @gld   XX   XX       XX
    tab    XX   C-rght   XX
    spc
)

Aside: running kanata from the command line with the --debug flag can show you more of what's happening in the code.