jtroo / kanata

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

Question: is it possible to de-shift input for one alias #270

Closed ShrykeWindgrace closed 1 year ago

ShrykeWindgrace commented 1 year ago

I am trying to make an almost standard qwerty layout with only one change - the numbers on the top row are interchanged with their S- counterparts.

For example,

(defcfg
  linux-dev /dev/input/by-id/usb-Logitech_USB_Multimedia_Keyboard-event-kbd
)
(defsrc
 9 0 a s lsft rsft
)

(deflayer default
  @lpar @rpar  a     s   _    @tst
)

(deflayer Num
  9     0   _     _   lrld  _
)
(defalias
  lpar S-9
  rpar S-0
  tst (layer-toggle Num)
  ;; tst (multi rshift (layer-toggle Num))
)

I have shifted characters, I get parentheses upon tapping '9' and '0'. However, I do not quite understand how to elegantly get '9' and '0' upon kb input S-0 and not remap the whole KB in the process.

I wonder if it possible to - for the lack of better term - "de-shift" input? Pretend that the shift modifier is not active, but only for the lifetime of one defalias? If it is impossible and/or hard to do, I'll bite the bullet and remap the whole layout, of course, but if an elegant solution exists, it would be much better =)

I am running latest master (as of this morning) on a debian machnine.

jtroo commented 1 year ago

Here's a still-not-very-elegant way that does it. One does not get key repeat for either layer of the number row though. I suppose you could modify the source code to get key repeat working by modifying this code to add Sequence keys to outputs (which will enable key repeat).

https://github.com/jtroo/kanata/blob/d28a4c3bd38c9e7a662d155de1ee56894305f799/src/cfg/mod.rs#L1971

Configuration:

(defcfg)

(deffakekeys 
  lsft lsft
)

(defalias
  sft (multi
    (layer-while-held shifted)
    (on-press-fakekey lsft press)
    (on-release-fakekey lsft release)
  )

  0 0
  !0 (macro
    (on-press-fakekey lsft release)
    @0
    (on-release-fakekey lsft press)
  )

  1 1
  !1 (macro
    (on-press-fakekey lsft release)
    @1
    (on-release-fakekey lsft press)
  )

  2 2
  !2 (macro
    (on-press-fakekey lsft release)
    @2
    (on-release-fakekey lsft press)
  )

  3 3
  !3 (macro
    (on-press-fakekey lsft release)
    @3
    (on-release-fakekey lsft press)
  )

  4 4
  !4 (macro
    (on-press-fakekey lsft release)
    @4
    (on-release-fakekey lsft press)
  )

  5 5
  !5 (macro
    (on-press-fakekey lsft release)
    @5
    (on-release-fakekey lsft press)
  )

  6 6
  !6 (macro
    (on-press-fakekey lsft release)
    @6
    (on-release-fakekey lsft press)
  )

  7 7
  !7 (macro
    (on-press-fakekey lsft release)
    @7
    (on-release-fakekey lsft press)
  )

  8 8
  !8 (macro
    (on-press-fakekey lsft release)
    @8
    (on-release-fakekey lsft press)
  )

  9 9
  !9 (macro
    (on-press-fakekey lsft release)
    @9
    (on-release-fakekey lsft press)
  )

  s1 (macro S-1)
  s2 (macro S-2)
  s3 (macro S-3)
  s4 (macro S-4)
  s5 (macro S-5)
  s6 (macro S-6)
  s7 (macro S-7)
  s8 (macro S-8)
  s9 (macro S-9)
  s0 (macro S-0)
)

(defsrc   
  1    2    3    4    5    6    7    8    9    0    lsft
)

(deflayer default 
  @s1  @s2  @s3  @s4  @s5  @s6  @s7  @s8  @s9  @s0  @sft
)

(deflayer shifted 
  @!1  @!2  @!3  @!4  @!5  @!6  @!7  @!8  @!9  @!0  _
)
jtroo commented 1 year ago

I suppose it's fairly reasonable to add the last key of a sequence to the key outputs, since if it's a long macro, one shouldn't be holding the key. But if it's a short macro, frequently used as a workaround, one might frequently want key repeats.

Edit: hmm, turns out that doesn't work so simply as I thought it would, since the macro doesn't keep the key actually held down. Makes me think of a different feature for macros of press-only or release-only of keys.

gerhard-h commented 1 year ago

QMK has the KO-feature https://docs.qmk.fm/#/feature_key_overrides maybe that would be cool for kanata because it is easy understand.

ShrykeWindgrace commented 1 year ago

I'll give it a try, thank you.

mklcp commented 1 year ago

Feels like the new improvement on input chords could be useful, as they can intercept different keys life rsft and 1.

So this code works not so badly:

(defcfg
)

(defsrc
1    2   rsft 
)

(deflayer base
@c1   @c2  @cSS 
)

(defchords n 200
    (S) rsft
    (1) S-1
    (2) S-2
    (S 1) 1
    (S 2) 2
)

(defalias
    cSS (chord n S)
    c1 (chord n 1)
    c2 (chord n 2)
)

It handles repeating with and without shift.

It just feels lagging because input chords can intercept combinations of keycodes under a certain timeout (here 200ms).

So a new feature like QMK's Key override could be necessary, but simply base itself on the existing input chords.

jtroo commented 1 year ago

So a new feature like QMK's Key override could be necessary, but simply base itself on the existing input chords.

This is possible. Input chords operate inside the keyberon state machine and with physical inputs. One would have to add extra code to replace all possible actions that could output the participating "key override" characters with chord actions instead.

Another approach is to operate on keyberon outputs and do post-processing to replace keys there.

https://github.com/jtroo/kanata/blob/707f38560b1a14e8cc4b99ff343d898fc3254c4b/src/kanata/mod.rs#L847

This seems like an approach that would more closely match how it's configured. There shouldn't be any lag or timeout issues this way as well. From my reading of the documentation, QMK's key override only operates on (multiple modifier keys)+(single non-modifier key). To avoid lag issues, kanata could send the presses of the original modifiers, then when it detects an override (from the press of the non-modifier key), release the old modifiers, press the new modifiers, and output the new key. An issue with this though is that a press+release of single modifiers can activate actions in the desktop or application, e.g. single press of Alt, or single press of Win/GUI. Shouldn't be a problem for shift though.

I'm curious as to how QMK implements this feature.

jtroo commented 1 year ago

@ShrykeWindgrace the linked PR may be of interest to you.

Documentation: https://github.com/jtroo/kanata/blob/key-override/docs/config.adoc#global-overrides

ShrykeWindgrace commented 1 year ago

Indeed it is, thanks for the ping!

jtroo commented 1 year ago

Leaving open for visibility/discussion for now

ShrykeWindgrace commented 1 year ago

I wonder if we can implement a "local overrides" in the same spirit as "global overrides". The usecase would be a heavily customized personal layout, but with an escape hatch to a default( == defsrc) layout - e.g. to be able to give my keyboard for a minute to someone else. I can of course just exit kanata for that period of time.

Not that I am actively advocating for such feature; for the initial question in this issue one could just explicitly write a "shifted" layer. Given the amount of customization and configuration required via other approaches, it could be a more readable option.

gerhard-h commented 1 year ago

If we could define one different .kbd file name in defcfg livereload could load that file instead of the current. that way we could cycle through completely different configurations.

jtroo commented 1 year ago

After some thought, I like the idea of cycling through configurations more for the use case of "I need to give my keyboard to someone else". I think it satisfies more potentially unserved use cases than local overrides would.

Layer-wide overrides could still be created at some point, if there's a compelling enough use case that isn't possible using other features.