Comments (28)
Currently macro
is quite limited in functionality. It only allows basic typing actions (delays, keys and key-chords), so it probably wouldn't help in emulating tap-macro-release
. The multi
action might help, though it does tend to have some weird interactions.
Activating arbitrary actions on release is not well supported by the underlying key state machine at present. It does however support emitting a release event for Custom
type actions. The Custom
action type is what's used for mouse buttons, live reload, unicode, and command execution.
Given that this functionality seems quite specific, it may be sufficient to provide on-release
for the few relevant use cases. E.g. just provide an on-release-layer-switch
action.
from kanata.
Would I be able to listen to layer switches in order to run a cmd? Because in kmonad, I run a cmd along with the layer switch to change my key layer widget (in AwesomeWM) to display the current layer.
from kanata.
Yea you could write your own code that connects to the kanata TCP server and runs the commands itself. Or another event could be added for on-release-cmd
.
from kanata.
Okay then it seems on-release-layer-switch
would be sufficient for me for now. The TCP server is probably the better solution to run the cmd, but I'm not gonna complain if you also added on-release-cmd
Do you think a general on-release
would eventually possible in the future?
Because I've this concept I named Proxy Mod where, in the base layer, I hold a key (the proxy mod) -> it changes to a layer that lets you pick modifiers like ctrl (via press-only lctl
) on press, then changes back to base layer on release so I can chord with them -> Once I release the proxy mod, it clears all modifiers. Would be nice to be able to do that.
from kanata.
It's certainly possible if I or someone else can think of a design that fits well with keyberon's state machine.
An idea that popped into my head is that rather than have general-case press-only or on-release, have the ability to create fake keys that have arbitrary actions. And then there can be other actions to tap/press/release these fake keys that are disconnected from the keyboard inputs. A specific on-release case could act on these fake keys.
The concept of fake keys works better in keyberon's state machine than general on-release does.
from kanata.
Not sure I follow the whole fake keys concept.
Also, I just want to differentiate between on-press
/on-release
vs. press-only
/release-only
in case of confusion. The former refers to the user's physical press/release of a key. The latter refers to the emitted event.
I believe release-key
and release-layer
works like release-only
.
from kanata.
The fake keys idea would probably make more sense if you look at the design docs as well as the code.
The kanata code leaves the key state management to the keyberon library. The library doesn't have a good way to handle on-release. It also doesn't have a good way to handle press-only; all key states (not layer though) are tied to a physical key being pressed and the state goes away when the physical key is released.
Fake keys would be a way to use the keyberon library to decouple physical key presses and releases from key state.
from kanata.
Okay I think I understand. Basically, use fake keys as a middle-man (or filtering mechanism) to trick the keyberon's state management.
from kanata.
I think #92 should be able to replicate all the functionality you want. It'll require a different setup compared to kmonad, but I think it'll work. See the kanata.kbd file changes for examples.
Please test at your leisure and let me know what you think.
from kanata.
Fake keys seem to work as intended. Thanks! I appreciate how quickly you added it in. I also noticed you can map (layer-switch layer_name)
to a fake key which is cool.
Now my issues are pretty much API-related. (Note: I haven't really studied the source code as I'm not familiar with Rust as much so I'm looking at this from a more UX perspective. Forgive me for my lack of knowledge of the source code's limitations.)
Fake Keys API
For the average user, I think fake keys are probably better of as an implementation detail for some abstraction rather than a direct API, but here are my suggestions to improve the API anyway:
- Remove
deffakekeys
From a UX perspective, it just seems redundant having to manually map a normal key to a fake key alias. Perhaps fake-key-op
should just take a normal key as an argument, then when parsing it, it would automatically map the normal key to a generated fake key or something.
- Rename
fake-key-op
toon-press-fake-key-op
The added prefix makes it more clear. For instance, (fake-key-op ctl tap)
might be confusing whereas with the added prefix, it's not.
A More Composable API
- Decouple the
press-only/release-only/tap
part from theon-press/on-release
part and abstract them into their own general actions (while they use fake keys internally).
This would add a lot of composability. You can still keep the fake keys API if you want, but such composable abstractions would be nice. For instance, I could create a bunch of release-only
aliases, combine them into a single alias, then pack this with layer-switch
into on-release
:
(defalias
;; GENERAL
;;; lock modifiers
po-lalt (press-only lalt)
po-lmeta (press-only lmet)
po-lshift (press-only lsft)
po-lctrl (press-only lctl)
;;; clear modifiers
ro-lalt (release-only lalt)
ro-lmeta (release-only lmet)
ro-lshift (release-only lsft)
ro-lctrl (release-only lctl)
lclear (multi @ro-lalt @ro-lmeta @ro-lshift @ro-lctrl)
ro-ralt (release-only ralt)
ro-rmeta (release-only rmet)
ro-rshift (release-only rsft)
ro-rctrl (release-only rctl)
rclear (multi @ro-ralt @ro-rmeta @ro-rshift @ro-rctrl)
clear (multi @lclear @rclear)
;;; layers
base (layer-switch base)
extend (layer-switch extend)
media (layer-switch media)
navigation (layer-switch navigation)
;;; control/(escape+clear) key
esc-from-ctrl (multi (release-only lctl) esc @clear)
esc-from-ctrl-to-base (multi @esc-from-ctrl @base)
ctrl_maybe-esc (multi lctl (tap-hold-press 200 200 @esc-from-ctrl XX))
ctrl_maybe-esc-base (multi lctl (tap-hold-press 200 200 @esc-from-ctrl-to-base XX))
cte @ctrl_maybe-esc ;; Map to Caps key for base layer
ctb @ctrl_maybe-esc-base ;; Map to Caps key for other layers
;; BASE LAYER
extend-base (multi (on-press @extend) (on-release (multi @base @clear))) ;; The example I was talking about
alt-extend-base (multi lalt @extend-base)
alt @alt-extend-base ;; Map to Alt key
;; EXTEND LAYER
;;; sub-layer keys
;;;; if you release this before releasing @alt, temporarily keep the layer until @alt is released
;;;; if you release this after releasing @alt, permanently keep the layer
media-media (multi (on-press @media) (on-release @media))
navigation-navigation (multi (on-press @navigation) (on-release @navigation))
med @media-media ;; Map to Q key
nav @navigation-navigation ;; Map to W key
;;; proxy mods
;;;; Lock a modifier until @alt is released. Go to base layer
pxc (multi @po-lctrl @base) ;; Map to A key
pxs (multi @po-lshift @base) ;; Map to S key
pxa (multi @po-lalt @base) ;; Map to D key
pxm (multi @po-lmeta @base) ;; Map to F key
)
Other Notes
- For a general
release-only
action, I imagine you'd combinerelease-key
,release-layer
, and a fake key release into one, maybe using a match statement. Or maybe just use fake key release for all of it.
from kanata.
The fake keys API should be composable enough to achieve the effects of what you're describing. I think what you're going for is ergonomics instead, and I can see how the kmonad way of doing it could be more ergonomic than fake keys.
The fake keys API is the simplest possible API implementation that works for generic on-release, press-only, and release-only, since it maps very closely to the underlying state machine.
It may be possible to hide the fake keys functionality behind press/release-only + on-release APIs, but the backing code will need to become more complex to do the bookkeeping for which actions map to which fake keys. It may happen one day, but I'm not particularly motivated to do the work to make an already complex use case more ergonomic, particularly since I don't actually use the feature myself.
from kanata.
One thing to note is that fake key actions currently should also be able to refer to other previously defined fake key, and accept multi as well. This might help get closer to the ergonomics you're describing.
from kanata.
One thing to note is that fake key actions currently should also be able to refer to other previously defined fake key, and accept multi as well. This might help get closer to the ergonomics you're describing.
Ah, I did not test that, but that's good to know. I'll try to convert my kmonad config to kanata using the fake keys API and see how it goes.
In the mean time, what do you think about my suggestions on improving the fake keys API?
from kanata.
In the mean time, what do you think about my suggestions on improving the fake keys API?
To summarize my earlier comment, it's certainly possible but at this time I believe the current API and the suggested improvements have the same expressive power - just with different ergonomics - I'm not currently motivated to design and implement any changes.
from kanata.
I meant just the first 2 suggestions. I assume getting rid of deffakekeys
would currently be a hassle, but what about the rename from fake-key-op
to on-press-fake-key-op
?
from kanata.
Ah I see. It's unclear how removing deffakekeys
would actually be workable without going all-in into implementing the 3rd suggestion.
Renaming to on-press-fake-key-op
seems fine to me.
from kanata.
I've force-pushed the PR branch to make the change to on-press-fake-key-op
as well as added a more complex example to kanata.kbd
.
from kanata.
Found a bug. It seems a multi
containing on-release
in deffakekeys
doesn't mesh well. You can't refer to it in defalias
.
(deffakekeys
flctl lctl
flsft lsft
flmet lmet
flalt lalt
flclear (multi
(on-release-fake-key-op flctl release)
(on-release-fake-key-op flsft release)
(on-release-fake-key-op flmet release)
(on-release-fake-key-op flalt release)
)
)
(defalias
pct (on-press-fake-key-op flctl press)
;; DOESN'T WORK
clr (on-release-fake-key-op flclear press)
;; DOESN'T WORK
clr (on-release-fake-key-op flclear release)
;; DOESN'T WORK
clr (on-press-fake-key-op flclear press)
;; DOESN'T WORK
clr (on-press-fake-key-op flclear release)
;; WORKS
clr (multi
(on-release-fake-key-op flctl release)
(on-release-fake-key-op flsft release)
(on-release-fake-key-op flmet release)
(on-release-fake-key-op flalt release)
)
)
from kanata.
Ah I see. It's unclear how removing
deffakekeys
would actually be workable without going all-in into implementing the 3rd suggestion.
My suggestion is to use normal key (instead of fake key) as arguments in fake-key-op
expressions. Then when parsing it, auto-generate/cache a fake key in place of the normal key.
So anytime you refer to a normal key inside a fake-key-op
expression, it would point to the generated fake key.
from kanata.
Let me check my understanding. The suggestion is that if argument to fake-key-op
happens to map to a real key label like lmet
then the code should auto-generate a fake key for lmet
without needing deffakekeys
. This would be convenient, but eliminating deffakekeys
entirely would lose its flexibility, so it doesn't seem worth doing.
from kanata.
Maybe I'm missing something, but I'm not sure what flexibility you would lose (at least from a user's perspective).
deffakekeys
just feels verbose.
from kanata.
Regarding the bug, I can't reproduce it. Do note that on-release-fake-key-op
doesn't actually activate unless the fake key was actually pressed in the first place. I tested with this:
(deffakekeys
pal (multi
(on-press-fake-key-op ctl press)
(on-press-fake-key-op sft press)
(on-press-fake-key-op met press)
(on-press-fake-key-op alt press)
)
ral (multi
(on-release-fake-key-op ctl release)
(on-release-fake-key-op sft release)
(on-release-fake-key-op met release)
(on-release-fake-key-op alt release)
)
)
(defalias
pal (on-press-fake-key-op pal tap) ;; works
ral (on-release-fake-key-op ral tap) ;; releases on press
rl1 (on-release-fake-key-op ral press) ;; does nothing at first
rl2 (on-release-fake-key-op ral release) ;; activates if activating @rl1 first then @rl2
)
from kanata.
I forgot to try tap
. That works for me. Still, it's confusing having to refer to it that way. I think multi
s are probably better off staying in defalias
instead of deffakekeys
.
from kanata.
Maybe I'm missing something, but I'm not sure what flexibility you would lose (at least from a user's perspective).
I think we're missing some details in each other's understanding of how the feature should work.
The simple case which loses flexibility (in my view) is:
- remove
deffakekeys
- fake-key-op only accepts key actions (e.g.
lmet
,lctl
) and auto-generates a fake key for it
This loses flexibility since fake keys can no longer be arbitrary actions. But it might be that it's unnecessary, not sure.
The complicated case, which if implemented correctly may as well go all the way to suggestion 3 is:
- remove
deffakekeys
- fake-key-op accepts arbitrary actions and generates fake keys for it
This is complicated because designing the code such that press/tap/release on various physical keys will map to the correct intended common fake keys is complex.
from kanata.
Oh I understand now. I was so fixated on key actions, I forgot some other arbitrary action like a layer-switch
action would complicate things.
Maybe you can allow to auto-generate fake keys for normal key actions, but don't remove deffakekeys
in case of other arbitrary actions? Or is that still too much?
from kanata.
It's possible and not so difficult, but to me doesn't seem worth it since the feature then becomes inconsistent, which may harm the user experience more than the inconvenience of always using deffakekeys
.
from kanata.
Fair enough. Thanks for responding quickly.
I suppose my only suggestion left is probably to shorten fake-key-op
expressions even more. Perhaps remove op
suffix (I assume it means operation) since it's implied. Perhaps remove the -
symbol in fake-key
so that it's consistent with deffakekeys
. So the final expressions would be on-press-fakekey
and on-release-fakekey
from kanata.
I'm good with shortening the action names. I'll push to the PR shortly.
from kanata.
Related Issues (20)
- Bug: mouse remapping not working (Wintercept) HOT 4
- MacOS privilege violation error
- Feature request: intercept all mice in Wintercept build HOT 1
- defoverrides is ignored in unmod and unshift HOT 2
- Directional Keys Not Working in Windows Task View HOT 6
- Bug: Home row mods advanced issue with block-unmapped-keys HOT 3
- Bug: unable to globally swap caps and esc HOT 2
- Feature request: modular per-platform config.adoc HOT 9
- Feature request: togglable `caps-word` HOT 2
- Bug: In WSL space is inserted after shift or control when running kanata in host HOT 1
- Bug: windows iconbar icon isn't removed when app is killed HOT 1
- Bug: Dead keys cause keyboard modifier state to get corrupt - witnessed on colemak HOT 7
- Feature request: support platform-specific IPC which has greater convenience than TCP
- Feature request: Auto Mouse Keys layer HOT 2
- Feature request: support BSD HOT 5
- Unable to send key input due to key having not been physically released yet. HOT 3
- Bug: Release 1.6.1 macos_x86_64 executable isn't what it says. HOT 6
- Feature request: Show keystroke or can let other app know the real key is stroked. HOT 2
- Feature request: Can we have a more flexible unmod? HOT 1
- See if windows shift workaround can be compiled out for winiov2 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from kanata.