-
Notifications
You must be signed in to change notification settings - Fork 141
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
Comments
ZipChord is a cool project! I haven't come across it before, thanks for sharing.
One immediate concern is that Kanata doesn't easily handle this scenario that ZipChord supports:
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.
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 |
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.
As a start, this would be absolutely sufficient!
I don't know enough about the internals of Kanata to know how something like that could work.
I've been thinking about this as well. This would be sufficient for a first prototype with manually defined reverse-mapping. |
Why not use
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. |
There is a cool feature in autohotkey hotstrings missing from e.g. espanso. It |
https://www.autohotkey.com/docs/v1/Hotstrings.htm#EndChars
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 |
I indeed use I found a way to trick ahk:
To me it seems like ahk tracks the latest (partial) word and the latest window that had textinput. |
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 ! |
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 In other words,
|
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:
|
Maybe it might be helpful to summon the ZipChord author here, as he has a lot of experience developing chording functionality. To open up the discussion, here's the main requirements in a chording tool:
To implement the above requirements, the tool needs the following features (in the same order as the requirements):
@psoukie is there anything I'm missing? Do you have any additional pointers/ideas/issues that came up during the development of ZipChord? |
Is this proofen? Because I feel manual spaces would simplify the implementation a lot. Must |
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. I would not have users define punctuation in their dictionary. If it makes sense implementation-wise, it could be an automatically defined chord. |
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 the record helps with things like undo. if I want to get but that is not the only way. another way is just stroking another way to get 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 |
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, 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.) |
@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). |
@psoukie thanks for your input, that is super helpful!! Maybe Kanata can become the cross-platform solution that you are envisioning 😃 |
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
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. |
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. |
So here's the result of more experimentation. I combined both configuration using sequences and chordsv2
I can write all of:
Some random notable thoughts:
using release-key
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 🤔. |
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. ```
) 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. ```
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
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
Implemented by #1301 |
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:
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.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
deflayer
to the requireddefsrc
for the trigger keys(...) (macro ...) 400 first-release ()
in each definitionAdditional 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.
The text was updated successfully, but these errors were encountered: