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

Feature request: Full-fledged chording solution #979

Closed
nightscape opened this issue Apr 24, 2024 · 21 comments
Closed

Feature request: Full-fledged chording solution #979

nightscape opened this issue Apr 24, 2024 · 21 comments
Labels
enhancement New feature or request

Comments

@nightscape
Copy link
Contributor

nightscape commented Apr 24, 2024

Is your feature request related to a problem? Please describe.

With the new defchordsv2-experimental feature, Kanata is very close to being a feasible solution for becoming a rather full-fledged chording solution in the spirit of ZipChord.

Describe the solution you'd like.

I would love for Kanata to be evolved into the direction of the (Autohotkey-based) ZipChord.
It uses a ordinary text file to store a shortcut dictionary.
This file should be rather straight-forward to map to the existing config.
The following additional functionality would be required:

  1. Parse the text file format
  2. Reverse-map from text in the left column to keys in defsrc. I assume this would be the hardest part and might not even be fully deterministic, if e.g. multiple layers can have a mapping to the same output key. One could require the user to manually create this reverse mapping in the first step, either fully, or just for the characters where it is non-deterministic.
  3. Create the current configuration out of the result.

Describe alternatives you've considered.

I'm just setting up a few chords using the existing config functionality. The road-blocks I currently see for using this on a bigger scale are

  1. needing to mentally reverse my keyboard layout in order to get from deflayer to the required defsrc for the trigger keys
  2. having to type the desired target character sequence character by character and having to manually apply the shift key to get a capital letter
  3. needing to type, copy & paste the boilerplate (...) (macro ...) 400 first-release () in each definition

Additional context

I only did a little Rust coding so far, but with AI help, I would dare giving this a try with a few ideas and pointers from your side @jtroo e.g. regarding potential pitfalls.

@nightscape nightscape added the enhancement New feature or request label Apr 24, 2024
@jtroo
Copy link
Owner

jtroo commented Apr 24, 2024

ZipChord is a cool project! I haven't come across it before, thanks for sharing.


This file should be rather straight-forward to map to the existing config.

One immediate concern is that Kanata doesn't easily handle this scenario that ZipChord supports:

da 1	Monday	Pressing D+A followed by 1 produces 'Monday'

If you're fine with the limitation that only chords, but not "shorthands" (if I'm reading ZipChord terminology correctly), are supported, this sounds feasible.

Or maybe you have thoughts about how this would work that I haven't thought of.


  1. Parse the text file format
  2. Reverse-map from text in the left column to keys in defsrc. I assume this would be the hardest part and might not even be fully deterministic, if e.g. multiple layers can have a mapping to the same output key. One could require the user to manually create this reverse mapping in the first step, either fully, or just for the characters where it is non-deterministic.
  3. Create the current configuration out of the result.

An idea here is that doesn't seem like this needs to be part of kanata and thus you don't need to necessarily use Rust. Would an external format translation program, in the language of your choice, suffice? E.g. take a ZipChord file and output the equivalent (defchordsv2-experimental ...) text?

@nightscape
Copy link
Contributor Author

nightscape commented Apr 24, 2024

ZipChord is a cool project! I haven't come across it before, thanks for sharing.

I own a CharaCharder One and the typing speeds one can reach with chording are amazing! But it requires learning a completely new "keyboard layout" and isn't great for on-the-go.
Therefore I've always been looking for ways to achieve the same effect with a familiar keyboard layout (I'm using BONE) on my MacBook's built-in keyboard.
ZipChord is the best tool in this area so far, but as it's based on AutoHotKey, it only works on Windows.

One immediate concern is that Kanata doesn't easily handle this scenario that ZipChord supports:

da 1	Monday	Pressing D+A followed by 1 produces 'Monday'

If you're fine with the limitation that only chords, but not "shorthands" (if I'm reading ZipChord terminology correctly), are supported, this sounds feasible.

As a start, this would be absolutely sufficient!

Or maybe you have thoughts about how this would work that I haven't thought of.

I don't know enough about the internals of Kanata to know how something like that could work.
I know that both for CharaChorder and ZipChord the characters are first normally typed, then the device/program emits backspaces to delete the chord-triggering letters and replaces them with the result.
Something like that might be possible in Kanata as well, but it would probably be a rather big change that would only make sense if you and other Kanata features enjoy chording so much that it makes sense to evolve it into that direction.
Right now I'm just trying to create an MVP for bigger-scale "primitive" chording in Kanata.

An idea here is that doesn't seem like this needs to be part of kanata and thus you don't need to necessarily use Rust. Would an external format translation program, in the language of your choice, suffice? E.g. take a ZipChord file and output the equivalent (defchordsv2-experimental ...) text?

I've been thinking about this as well. This would be sufficient for a first prototype with manually defined reverse-mapping.
Once one wants to implement the (semi-)automatically derived reverse-mapping one needs the parsed Kanata config, best from Kanata itself.
So I think I would write the translation in Rust anyway in order to make a later integration easier.

@wis
Copy link
Contributor

wis commented Apr 25, 2024

Why not use defchordsv1 chords?

(defsrc q w e r t y
t h c n o f)
(deflayer base q w e r t y
@cht @chh @chc @chn @cho @chf)

(defchords insert 200 
  (   t   ) t
  (h      ) h
  (t     h) (macro t h e spc )
  (c      ) c
  (   n   ) n
  (c     n) (macro c a n spc )
  (o      ) o
  (   f   ) f
  (o     f) (macro o f spc)
)
(defalias 
  chf (chord insert f)
  cht (chord insert t)
  chh (chord insert h)
  chc (chord insert c)
  chn (chord insert n)
  cho (chord insert o)
)

also a "shorthands" (Espanso expander) feature would be cool addition to Kanata I think
e.g.

(defshorthand
( l r n)   (macro l e a r n)
)

@jtroo
Copy link
Owner

jtroo commented Apr 25, 2024

also a "shorthands" (Espanso expander) feature would be cool addition to Kanata I think

I've thought about such a thing before but haven't pulled the trigger 🙂. How I would do it is to reuse sequences as-is, no new syntax, and have them be always-on.

antler5 added a commit to antler5/kanata that referenced this issue Apr 25, 2024
@gerhard-h
Copy link
Contributor

There is a cool feature in autohotkey hotstrings missing from e.g. espanso.

It it, is the trigger sequence, then only trigger if the sequence is a word of its own or the start of a sentence. But don't trigger if part of another word like hit, or fit,. But I have no idea how they achieve that.

@jtroo
Copy link
Owner

jtroo commented Apr 25, 2024

https://www.autohotkey.com/docs/v1/Hotstrings.htm#EndChars

you must type an ending character after a hotstring's abbreviation to trigger it

My assumption on how this is implemented is that the ending characters are also "starting characters" in the sense that they reset the accumulated characters that are checked for activation of a hotstring. In kanata terms they would be sldr activations. So the the Space in Spacefit, will reset acculumated characters, then fit, will be collected, which doesn't match the it, hotstring.

@gerhard-h
Copy link
Contributor

I indeed use #Hotstring EndChars , but EndChars are optional the *-flag can disable EndChars :*:jj::jsmith@somedomain.com

I found a way to trick ahk:

i A-tab A-tab t, => triggers (ok)
f A-tab A-tab it, => not triggers (ok)
f A-tab mouse-click A-tab it, => not triggers (ok)
i mouse-click t, => not triggers (ok)
f A-tab almost any key A-tab it, => triggers (failure)

To me it seems like ahk tracks the latest (partial) word and the latest window that had textinput.
that seems hard for kanata :(
(Even deciding if a mouse-click reset the current word or not)

@SequentialDesign
Copy link

this would be amazing ! I stenotype, and earlier in the year I tried switching to linux, but I ultimately failed cuz plover (the program I use to steno) crashed x11, and plover doesn't work on wayland. it would be nice to have an alternative.

+1 on the hotstrings as well !

@jtroo
Copy link
Owner

jtroo commented Apr 27, 2024

I've been giving this some thought and I think that the ZipChord functionality could be implemented all within sequences, assuming sequences has a way to be turned on permanently. To avoid having to move away from a u16, to be lazy and avoid code changes, we still have one bit left unused in mod_mask_for_keycode: 0x0400. This can be a special "simultaneity" flag meaning the key presses must overlap. The parser can also auto-generate the permutations for the user.

In other words, O-(a b) (O- to mean overlap) is the same as O-(b a), and behind-the-scenes, using either one of these generates two sequences automatically in the background.

pub fn mod_mask_for_keycode(kc: KeyCode) -> u16 {
    use KeyCode::*;
    match kc {
        LShift | RShift => 0x8000,
        LCtrl | RCtrl => 0x4000,
        LAlt => 0x2000,
        RAlt => 0x1000,
        LGui | RGui => 0x0800,
        _ => 0,
    }
}

@jtroo
Copy link
Owner

jtroo commented Apr 27, 2024

One might wonder: why do we need yet another way to do chording in Kanata?

Well, I think doing "chording" in sequences has some significant differences. It:

  • operates on outputs rather than on key inputs like how chordsv1 and chordsv2 do
  • is less configurable, e.g. see the customizability of chordsv2
  • is less intrusive with visible-backspaced; typing behaves as normal other than when a sequence activates, at which point the backspacing comes in
  • will hopefully be more forgiving in timing

@nightscape
Copy link
Contributor Author

nightscape commented Apr 28, 2024

Maybe it might be helpful to summon the ZipChord author here, as he has a lot of experience developing chording functionality.
@psoukie: Kanata is a cross-platform keyboard remapper in the spirit of KMonad, implemented in Rust.
Kanata is actually powerful enough to do chording as well, so I gave it a try to convert ZipChord dictionaries to configuration that Kanata understands. I added a short video on the PR which shows that this works reasonably well!
It would be really great if there could be collaboration and exchange of ideas between ZipChord and Kanata w.r.t. chording.
Kanata could then be the solution for Mac and Linux users, or users who want to remap their keyboard layout anyway and ZipChord could be the solution for Windows users with advanced features due to its focus on chording.

To open up the discussion, here's the main requirements in a chording tool:

  1. Having a nice and simple way to define new chords (e.g. the dictionary as ZipChord uses it)
  2. (Optional) Having a (possibly separate) tool that helps you in discovering which words should be added to the dictionary.
  3. Handling capitalization correctly: Pressing Shift and then a chord should only capitalize the first character of the word.
  4. Handling whitespace after chords: You want a space entered after most words, as typing the space manually breaks the flow of chording. When you type a ., ,, : though, the space should not get emitted or removed afterwards.
  5. Handling composite words: You want to be able to compose words, e.g. you want to be able to chord pre validate ionand have the tool convert this to prevalidation (note the space at the end). The tool also needs to handle stopping after fewer chords though. So just pre would become pre , pre validate would become prevalidate . The most common solution to this is to have the tool immediately print the result of the chords you typed so far, but correcting afterwards by backspacing should a trailing space and optionally other letters before it need to be removed (e.g. turning prevalidate into prevalidation by first backspacing and e and then typing ion ). Capitalization also has to be taken into account here, so you don't end up having with capital letters inside a word. This is especially important in languages like German where many words are compositions of others.
  6. Preventing accidental expansion of chords: When you type fitness fast, it shouldn't print fit ness (the space in between coming from an expansion of the chord it). On the other hand, this shouldn't break handling composite words.
  7. Printing the typed chords to screen as fast as possible, i.e. not waiting until one is sure that the user doesn't type a . after a chord or composing a longer word.

To implement the above requirements, the tool needs the following features (in the same order as the requirements):

  1. A parser for the chord dictionary (easy)
  2. (Optional) A way to detect typed words
  3. Applying the Shift modifier only to the first character of a chord expansion
  4. Allowing a space character as part of the expanded chord, or automatically appending one
  5. Being able to backspace previously typed characters
  6. A way to reliably distinguish between fast typing and chording, possibly by detecting when one is inside a word
  7. Backspacing as well

@psoukie is there anything I'm missing? Do you have any additional pointers/ideas/issues that came up during the development of ZipChord?

@gerhard-h
Copy link
Contributor

4. as typing the space manually breaks the flow of chording.

Is this proofen? Because I feel manual spaces would simplify the implementation a lot.

Must . -> ., ! -> ! be part of the dictonary?

@nightscape
Copy link
Contributor Author

nightscape commented Apr 28, 2024

Not proven in a scientific way (at least I don't know of any). I tried chording with a few tools (CharaChorder, ZipChord and now Kanata) and for me it always felt awkward to have to type the space. It might be a matter of getting used to though, and I agree that it complicates the solution. On the other hand, it's the same "backspacing" feature that also enables composing words (e.g. compose to composing). In my opinion, whitespace + composite words carry the weight for the backspacing feature. ZipChord and CharaChorder (independently?) also converged on this solution.

I would not have users define punctuation in their dictionary. If it makes sense implementation-wise, it could be an automatically defined chord.
I guess you're asking because it's somewhat similar to a suffix like ing in so far as the tool would remove a preceding whitespace and add one afterwards?

@SequentialDesign
Copy link

SequentialDesign commented Apr 28, 2024

my two cents coming from the world of stenotypy. (I have been using stenotypy for a year and some months. I gave a talk at EmacsConf about it where I mention Kanata (https://www.youtube.com/watch?v=McHurKmk-rQ). in my opinion, the people from stenotypy are the coldest beasts when it comes to chording and speed)

sending chords based on output is a really fantastic idea. that is how Plover does it. as long as keys overlap, they are all part of a chord (this is super user-friendly and forgiving)

there are different ways of handling compound words. it depends on the theory being used. in my theory to get anyway, I can get it two ways. one way, I stroke ANY/WAY. the / denotes separation of strokes. my first stroke gives me any (that's any and a space). my second stroke will backspace the space and write way (that's way and a space). in other words, there is a record of what has been output so that only the minimum number of backspaces are used to get the proper output, in this case anyway .

the record helps with things like undo.

if I want to get any way (with a space between any and way), I can hit a command called =retro_insert_space after having stroked anyway , which will look up if the words any and way are something by themselves and, if so, will update the output to include space accordingly. another way for me to get any way is to stroke ANY/WY. notice the missing A in WY. I have a definition of "ANY/WY" : "any way" in my dictionary.

but that is not the only way. another way is just stroking ANY and then WAY. then a command known as =retro_delete_space can be used to join them if there isn't a definition for ANY/WAY. I do this a lot with many compound words since not all compound words are in my dictionary.

another way to get anyway is by stroking NWAY. I'm sure you get the point. sometimes it's nice to have more than one way to get something cuz you want to test things out and see which way is truly the best way or the one you like the most

some people apply conditional logic, and that's a whole other thing. totally viable, but I don't use that style. I just define and glue and break words and phrases as needed.

one thing I should mention : I use homerow mods on kanata with a 200 millisecond threshold on Windows OS. if hold my stroke longer than 200 milliseconds, then I will set off the homerow mods if I'm pressing them. (I mention homerow mods at 17:45 in my EmacsConf talk https://youtu.be/McHurKmk-rQ?si=z7LOW0tYkJMxYFyU&t=1066). so I hope any overlap chording system (if indeed it is implemented) will let the user set the overlap time and still allow users to use homerow mods (dual-function keys)

these are merely ideas from the world of stenotypy. I would welcome any overlap feature with open arms

@psoukie
Copy link

psoukie commented Apr 28, 2024

Thanks for pulling me into the conversation, @nightscape. I wasn't aware of Kanata. Very cool. I will check out today, and happy to share ideas and what I've learned about what works in terms of combining regular typing with chording / stenotyping over the three years.

The relevant piece of ZipChord's logic is a classifier that determines potential chords, checking them against a dictionary for chords (there's also one for shorthands but that's not relevant here), and then retroactively adjusting the output by Backspacinng to replace the typing. Because the chords can be optionally chained / combined (just like in stenotyping), it has to keep a representation of the last input and output in memory (until a punctuation, Enter, manual space, or interrupt such as mouse click or arrow keys).

The affixes have been (and can be) handled as their own chords where the expanded text definition indicates the automatic spaces should be removed. But ZipChord also supports the full stenotype approach of combined chords, as described by @SequentialDesign.

With the sliding window of input and output representation, M+N can produce let's say month and change to Monday if it's followed by D+Y. (Single key presses can be part of the chained definitions too.)

In fact, ZipChord inspiration was to have Plover that can be combined with normal typing without switching.

I have users who do not like having the spaces added automatically. For me, the chording experience is much smoother if the spaces around words and punctuation are handled automatically, so the tool supports both.

The addition and removal of spaces and capitalization based on user preferences is a relatively simple part of that process (which in my project is made complicated by the number of combinations of settings).

The relevant parts of ZipChord's logic are in 'io.ahk'. (The project started as a simple AutoHotkey script to see if I could detect chords of more than three keys without interfering with typing; but today, I'd probably go with something like Zig or another language that's cross-platform.)

@psoukie
Copy link

psoukie commented Apr 28, 2024

@SequentialDesign -- if you can get and evaluate the starting and ending timestamps of individual key down and up events, you can do some tricks to allow shorter overlap times for chords, such as rejecting "rolled typing." (When two or more keys are down and one is lifted, and then another key is pressed while at least one key is still held, this can be rejected because in a chord, all keys would be pressed at one point and all released, even if briefly.)

Another optional way to reduce false positives (and to allow shorter minimum time for chord detection), is rejecting chords in the middle of regularly typing a word (detected by spaces and punctuation characters as separators).

@nightscape
Copy link
Contributor Author

nightscape commented Apr 28, 2024

@psoukie thanks for your input, that is super helpful!! Maybe Kanata can become the cross-platform solution that you are envisioning 😃
@jtroo I saw that you started working on a sequence-based chording solution.
Do the features that @psoukie mentioned fit in with what you are implementing, or would this require major changes that you would not feel comfortable with, or maybe would first need to see the benefits to justify the changes?

@jtroo
Copy link
Owner

jtroo commented Apr 28, 2024

One thing that is definitely missing is the shift handling, but should be feasible to do.


I tried experimenting to see what auto-spacing hackery is possible in the current implementation. For now I manually applied antler5's "always on" sequences patch for testing.

I tried using use nop0 to signify "this is a sequence that can potentially continue" and use nop9 to forcefully terminate sequence matching. Doing it this way has a problem where day doesn't get the auto-erased Space on typing Dot; it only works upon full expansion to monday. This is of course a limitation of the implementation; the "forceful termination" to allow the backspaced Dot to work is mutually exclusive with allowing the extra expansion of day->monday - which itself is a work-around due to the Kanata sequence implementation not permitting sequences where an ancestor is fully overlapped by the descendant.

(defcfg process-unmapped-keys yes)
(defsrc)
(deflayer base)
(deftemplate seq (vk-name keyseq action)
	(defvirtualkeys $vk-name $action)
	(defseq $vk-name $keyseq)
)
(t! seq day (O-(d a y)) (macro d a y spc nop0))
(t! seq monday (d a y spc nop0 1) (macro m o n d a y nop9 spc nop0))
(t! seq nospc-dot (spc nop0 .) (macro .))

I suspect it would work more smoothly without trying to do the autospace.

But maybe there's some extra backtracking attempts that can make this possible.

@jtroo
Copy link
Owner

jtroo commented Apr 28, 2024

If one wanted to experiment with adding a fully independent system (i.e. separate from input chords v1/v2 or sequences), the output_logic file might be of interest.

For now I'll be experimenting with what's possible in sequences.

@jtroo
Copy link
Owner

jtroo commented Apr 28, 2024

So here's the result of more experimentation. I combined both defchordsv2-experimental and the new overlap-keys sequences functionality.

configuration using sequences and chordsv2
(defsrc f1)
(deflayer base lrld)
(defcfg process-unmapped-keys yes
	sequence-input-mode visible-backspaced
	concurrent-tap-hold true)
(deftemplate seq (vk-name in out)
	(defvirtualkeys $vk-name $out)
	(defseq $vk-name $in))

(defchordsv2-experimental
  (d a y) (macro sldr d (unshift a y) spc nop0) 200 first-release ()
  (h l o) (macro h (unshift e l) 5 (unshift l o) sldr spc nop0) 200 first-release ()
)
(t! seq Monday (d a y spc nop0 O-(m o n)) (macro S-m (unshift o n d a y) nop9 sldr spc nop0))
(t! seq Tuesday (d a y spc nop0 O-(t u e)) (macro S-t (unshift u e s d a y) nop9 sldr spc nop0))
(t! seq DelSpace_. (spc nop0 .) (macro .))
(t! seq DelSpace_; (spc nop0 ;) (macro ;))

I can write all of:

day;
Day;
day hello 
hello day 
Hello day 
hello Tuesday 
hello Monday 
Tuesday.
Monday.

Some random notable thoughts:

  • the entire macro needs to be unshifted other than the first letter to support capitalization of only the first character
  • see the funny (unshift...) 5 (unshift ...) in hello, which is necessary because of the double l and how unshift works.
  • the unshift does break Day->Monday (note capital D because the end of unshift re-presses shift keys, which messes with the sequence
  • the Day->Monday can be worked around with release-key, but this has the downside of permanently releasing shifts until physically released and then re-pressed.
  • chords-v2-min-idle-experimental can help with differentiating rapid typing vs. chording input
using release-key
(defsrc f1)
(deflayer base lrld)
(defcfg process-unmapped-keys yes
	sequence-input-mode visible-backspaced
	concurrent-tap-hold true)
(deftemplate seq (vk-name in out)
	(defvirtualkeys $vk-name $out)
	(defseq $vk-name $in))

(defvirtualkeys rls-sft (multi (release-key lsft)(release-key rsft)))
(defvar rls-sft (on-press tap-vkey rls-sft))
(deftemplate rls-sft () $rls-sft 5)

(defchordsv2-experimental
  (d a y) (macro sldr d (t! rls-sft) a y spc nop0) 200 first-release ()
  (h l o) (macro h (t! rls-sft) e l l o sldr spc nop0) 200 first-release ()
)
(t! seq Monday (d a y spc nop0 O-(m o n)) (macro S-m $rls-sft o n d a y nop9 sldr spc nop0))
(t! seq Tuesday (d a y spc nop0 O-(t u e)) (macro S-t $rls-sft u e s d a y nop9 sldr spc nop0))
(t! seq DelSpace_. (spc nop0 .) (macro .))
(t! seq DelSpace_; (spc nop0 ;) (macro ;))

My overall thoughts are: seems like some of the basic use cases are possible at least! But this is not at all user-friendly or easily discoverable 😅. Maybe a separate system that reads the outputs would be better 🤔.

jtroo added a commit that referenced this issue Apr 28, 2024
Gets a lot of the way to #979, with the caveat that it is really quite
inconvenient to configure. Perhaps an external parser can help.

For example:
- `defchords` can be used for basic single-chords
- for composite/contextual chords, a `defchords` output action can
trigger sequences, which themselves can use `O-(...)` for subsequent
chords

Example:
```
(defsrc f1)
(deflayer base lrld)
(defcfg process-unmapped-keys yes
	sequence-input-mode visible-backspaced
	concurrent-tap-hold true)
(deftemplate seq (vk-name seq-keys action)
	(defseq $vk-name $seq-keys)
	(defvirtualkeys $vk-name $action))

(defvirtualkeys rls-sft (multi (release-key lsft)(release-key rsft)))
(deftemplate rls-sft () (on-press tap-vkey rls-sft) 5)

(defchordsv2-experimental
	(d a y) (macro sldr d (t! rls-sft) a y spc nop0) 200 first-release ()
	(h l o) (macro h (t! rls-sft) e l l o sldr spc nop0) 200 first-release ()
)
(t! seq Monday (d a y spc nop0 O-(m o n)) (macro S-m (t! rls-sft) o n d a y nop9 sldr spc nop0))
(t! seq Tuesday (d a y spc nop0 O-(t u e)) (macro S-t (t! rls-sft) u e s d a y nop9 sldr spc nop0))
(t! seq DelSpace_. (spc nop0 .) (macro .))
(t! seq DelSpace_; (spc nop0 ;) (macro ;))
```

The configuration can write all of the below without having to manually
add or backspace the spaces, and only using shift+chords+punctuation.

```
day;
Day;
day hello 
hello day 
Hello day 
hello Tuesday 
hello Monday 
Tuesday.
Monday.
```
eugenesvk added a commit to eugenesvk/kanata that referenced this issue May 6, 2024
)

Gets a lot of the way to jtroo#979, with the caveat that it is really quite
inconvenient to configure. Perhaps an external parser can help.

For example:
- `defchords` can be used for basic single-chords
- for composite/contextual chords, a `defchords` output action can
trigger sequences, which themselves can use `O-(...)` for subsequent
chords

Example:
```
(defsrc f1)
(deflayer base lrld)
(defcfg process-unmapped-keys yes
	sequence-input-mode visible-backspaced
	concurrent-tap-hold true)
(deftemplate seq (vk-name seq-keys action)
	(defseq $vk-name $seq-keys)
	(defvirtualkeys $vk-name $action))

(defvirtualkeys rls-sft (multi (release-key lsft)(release-key rsft)))
(deftemplate rls-sft () (on-press tap-vkey rls-sft) 5)

(defchordsv2-experimental
	(d a y) (macro sldr d (t! rls-sft) a y spc nop0) 200 first-release ()
	(h l o) (macro h (t! rls-sft) e l l o sldr spc nop0) 200 first-release ()
)
(t! seq Monday (d a y spc nop0 O-(m o n)) (macro S-m (t! rls-sft) o n d a y nop9 sldr spc nop0))
(t! seq Tuesday (d a y spc nop0 O-(t u e)) (macro S-t (t! rls-sft) u e s d a y nop9 sldr spc nop0))
(t! seq DelSpace_. (spc nop0 .) (macro .))
(t! seq DelSpace_; (spc nop0 ;) (macro ;))
```

The configuration can write all of the below without having to manually
add or backspace the spaces, and only using shift+chords+punctuation.

```
day;
Day;
day hello
hello day
Hello day
hello Tuesday
hello Monday
Tuesday.
Monday.
```
jtroo pushed a commit that referenced this issue May 18, 2024
This PR is a first shot at implementing a more scalable chording
approach using a simple text file for configuration.

See:
- #979
- https://github.com/jtroo/kanata/assets/35170/d51a4669-ce8c-4355-9124-53c47a1cdd47
eugenesvk pushed a commit to eugenesvk/kanata that referenced this issue May 19, 2024
This PR is a first shot at implementing a more scalable chording
approach using a simple text file for configuration.

See:
- jtroo#979
- https://github.com/jtroo/kanata/assets/35170/d51a4669-ce8c-4355-9124-53c47a1cdd47
@jtroo
Copy link
Owner

jtroo commented Nov 3, 2024

Implemented by #1301

@jtroo jtroo closed this as completed Nov 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants