jtroo / kanata Goto Github PK
View Code? Open in Web Editor NEWImprove keyboard comfort and usability with advanced customization
License: GNU Lesser General Public License v3.0
Improve keyboard comfort and usability with advanced customization
License: GNU Lesser General Public License v3.0
For Linux, can use https://github.com/k0kubun/xremap for inspiration.
For Windows: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow
I am really impressed with kanata. It replaced my xcape and kind of my use of kmonad. Tap-hold works well.
I was struggling to get a notification when changing layers , I got this workaround
nnlck ( multi (layer-switch numpad) (macro C-A-S-a))
the chord is binded to a shell notification that numpad is active. So far so good
The only thing that i miss from kmonad is switching out of virtualbox. In kmonad I could do it with a shell command to show the desktop.
kkk (multi-tap 300 (cmd-button "wmctrl -k on") (cmd-button "wmctrl -k off") )
For kanata, using a macro with chording I could not do it since virtualbox took over my keyboard and mouse
I am trying to add a functionality of creating a symlink in /dev/input/by-id/
for the newly created device /dev/input/eventxx
.
Creating a symlink works if #45 is applied. However, kanata doesn't gracefully exit, which makes cleaning up the symlink rather hard if not impossible.
I would like to discuss about graceful exit.
I haven't found a way to consistently reproduce this, but I have noticed it a few times. It also doesn't seem to happen when kanata has been running for a while, so it may be related to startup (#4).
Tracking issue for upgrading the evdev
crate when this is merged and published:
emberian/evdev#70
Some discussion in #57.
I have the truly ergonomic keyboard which can mapping the keys to F16, ... , F23 to remap.
https://trulyergonomic.com/ergonomic-keyboards/knowledge-base/
When I added 'f22' in the kbd file, kanata makes error like
thread 'kanata' panicked at 'Could not parse cfg: Unknown key in defsrc: "f22"', src\main.rs:85:51
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Any { .. }', src\main.rs:94:20
please add more function keys to find proper OS keys at mod.rs
Thank you for your great program.
Hi, when I package kanata for NixOS, a reviewer notice a license issue: what is the license? LGPL-3.0-only or LGPL-3.0-or-later?
Please refer to https://www.gnu.org/licenses/identify-licenses-clearly.html for more info.
A macro is different from the current multi
action in the configuration because multi
keeps all of the keys pressed for the entire duration. This makes some string sequences impossible to type with multi
, e.g. http://localhost
because :
requires shift to type and then shift will be held for the entire duration.
I've tried to find what the Windows OS numeric code for this is, but I haven't been able to find any info about it. This has been added to Linux in #63.
Or maybe there's nothing that needs to be done to handle this correctly? I have no idea either way.
This is pretty easily noticed when typing rapidly.
kmonad's configuration is quite pleasant to use. It doesn't have to be exactly like this, but something close/similar would be great.
Would need to look into how to run as a Windows service. The orginal ktrl project has instructions for running as a Linux service.
I see C ,S, A as modifier prefix . Is there a prefix for lmet ?
I personally like using kanata without system tray but system tray comes in handy to know if kanata is running or not and on which keyboard(or configuration).
It can be used at a later stage to control multiple keyboards on and of, or improvement in gui configurations.
I was able to build kanata on regular x86_64 PC without any issues, but it fails to build on Pinebook Pro under Manjaro ARM. Error is
Compiling kanata v1.0.1 (/home/fenuks/Projects/keyboard/kanata)
error[E0308]: mismatched types
--> src/oskbd/linux.rs:91:29
|
91 | uidev.name[0] = 'k' as i8;
| ------------- ^^^^^^^^^ expected `u8`, found `i8`
| |
| expected due to the type of this binding
error[E0308]: mismatched types
--> src/oskbd/linux.rs:92:29
|
92 | uidev.name[1] = 't' as i8;
| ------------- ^^^^^^^^^ expected `u8`, found `i8`
| |
| expected due to the type of this binding
error[E0308]: mismatched types
--> src/oskbd/linux.rs:93:29
|
93 | uidev.name[2] = 'r' as i8;
| ------------- ^^^^^^^^^ expected `u8`, found `i8`
| |
| expected due to the type of this binding
error[E0308]: mismatched types
--> src/oskbd/linux.rs:94:29
|
94 | uidev.name[3] = 'l' as i8;
| ------------- ^^^^^^^^^ expected `u8`, found `i8`
| |
| expected due to the type of this binding
For more information about this error, try `rustc --explain E0308`.
error: could not compile `kanata` due to 4 previous errors
Changing these casts to u8 fixes compilation error, so it seems it's portability problem, and c_char on my CPU is u8, as seen in libc sources:
//! AArch64-specific definitions for 64-bit linux-like values
pub type c_char = u8;
I'm not that familiar with rust, but perhaps code should be changed to something to this in order to fix problem for various strange machines:
diff --git i/src/oskbd/linux.rs w/src/oskbd/linux.rs
index a7de646..b3424ae 100644
--- i/src/oskbd/linux.rs
+++ w/src/oskbd/linux.rs
@@ -14,6 +14,7 @@
use crate::custom_action::*;
use crate::keys::*;
use libc::input_event as raw_event;
+use libc::c_char;
// file i/o
use io::Write;
@@ -88,10 +89,10 @@ pub fn new() -> Result<Self, io::Error> {
}
let mut uidev: uinput_user_dev = mem::zeroed();
- uidev.name[0] = 'k' as i8;
- uidev.name[1] = 't' as i8;
- uidev.name[2] = 'r' as i8;
- uidev.name[3] = 'l' as i8;
+ uidev.name[0] = 'k' as c_char;
+ uidev.name[1] = 't' as c_char;
+ uidev.name[2] = 'r' as c_char;
+ uidev.name[3] = 'l' as c_char;
uidev.id.bustype = 0x3; // BUS_USB
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
Unicode support should be possible in Linux applications with the existing functionality. Holding Ctrl+Shift+u then typing the unicode number will input the unicode character.
E.g. this sad smiley โน is U+2639, so the alias below works correctly to input the sad smiley.
(defalias sad (multi lctl lsft u 2 6 3 9))
However, Windows does not have any such convenient and well-designed feature. It looks like kbremap has unicode support for Windows though, so it's definitely possible.
This seems to happen during startup. I haven't seen it happen after the program has been running for a while.
It seems that multi cannot process more than 2 cmd.
For example:
pp (multi q (cmd notify-send "hello") t (cmd notify-send "hi"))
will print qt and display hello without notifying the hi
the same if I put it like this
pp (multi (cmd notify-send "hello") (cmd notify-send "hi")) will process only the first cmd.
Is it doable for including more mouse support as in default x11.
1 = left button
2 = middle button (pressing the scroll wheel)
3 = right button
4 = turn scroll wheel up
5 = turn scroll wheel down
6 = push scroll wheel left
7 = push scroll wheel right
8 = 4th button (aka browser backward button)
9 = 5th button (aka browser forward button)
For reference for NixOS packaging (of particular interest might be the hardening options with cmd
enabled):
NixOS/nixpkgs#182756
I was trying to fully utilize tap-hold by inserting another tap-hold inside it with no luck
pp (tap-hold 200 200 a (tap-hold 200 2000 b c))
no matter how I hold key, could not get b. it either prints a or c
It seems kanata doesn't support Wayland. I've tested Plasma and Gnome on Wayland. Debug output shows kanata gets key presses, but doesn't return keycodes to the system.
08:19:23 [DEBUG] (2) kanata::kanata: press A
08:19:23 [DEBUG] (2) kanata::oskbd::linux: input ev: InputEvent { time: TimeVal { tv_sec: 0, tv_usec: 0 }, event_type: EV_KEY, event_code: EV_KEY(KEY_A), value: 1 }
08:19:23 [DEBUG] (2) kanata::kanata: release A
08:19:23 [DEBUG] (2) kanata::oskbd::linux: input ev: InputEvent { time: TimeVal { tv_sec: 0, tv_usec: 0 }, event_type: EV_KEY, event_code: EV_KEY(KEY_A), value: 0 }
Kanata under X11 works correctly. Probably it's not important, as I suspect there is no support at all, but I'm using
kwayland 5.94.0-2
kwayland-server 5.24.5-1
wayland 1.20.0-2
ItayGarin/ktrl#32 might be related to this issue.
I've had this discussion before in this thread: kmonad/kmonad#560 (comment)
Basically, the main points are:
toggle
doesn't imply a momentary switchtoggle
's usage in here contradicts its usage in a lot of applications and gameslayer-switch
and layer-toggle
, the average user might be initially confused and have to look for the config reference again.With kmonad, we eventually settled with adding momentary-layer
as an alias, but I still think renaming it layer-hold
is the more succinct solution because
layer
prefix patternhold
is much simpler and more precise for the average userThe author seems to want to reserve hold
for patterns like tap-hold
, but I believe the average user would easily differentiate between tap-hold
and layer-hold
because of the different namespaces/contexts.
I use two of these 6x4 keypad as a split keyboard. As they are two independent keyboards, normally I can't setup layers which works across the "halves" (a key in one keypad which activates a layer in the other one). To solve this I currently use evsieve to fake one device out of these two. This way:
# evsieve --input /dev/input/by-id/usb-BlackC_Sayobot.cn_L-event-kbd grab --input /dev/input/by-id/usb-BlackC_Sayobot.cn_R-event-kbd grab --output create-link=/dev/input/by-id/sayo
It would be nice if kanata could use multiple devices this way out of the box.
For reference: https://github.com/TeXitoi/keyberon/blob/master/src/action.rs
The current tap-hold behaviour is default, because that's the one that I prefer.
As mentioned in #20, there are missing named keys that kmonad currently parses and kanata does not, namely most keys in the kmonad enum.
Looks like someone has a similar project in Windows:
https://github.com/timokroeger/kbremap
This should be more easily cross platform than replicating the whole mouse.
Here's my use case: I have a trackball that is great for scrolling and movement but I don't like it much for clicking. So instead, when paired with my QMK board, I click with my left hand using the keyboard and navigate+scroll with my right hand using the trackball.
Use case:
Let's say I want lalt as a multi-use key that acts as lalt as well as layer-toggle at the same time. Some desired actions in the new layer want lalt to be held down the whole time (1) since repeated press-release of alt results in the wrong behaviour. Other actions (2) actually don't want alt to be pressed at all.
To achieve (1), one could use (multi lalt (layer-toggle other-layer))
. To achieve (2), a theoretical action (multi (release lalt) <un-alted key>)
could work.
I'd like a functionality where you can emit a tap on-release only. The expression could be named on-release
.
You can get a similar functionality in kmonad with tap-macro-release
by ignoring the all the arguments except the last. (Note: To fully copy tap-macro-release
, you'd probably just have to combine on-release
with multi
and macro
)
I've found the on-release
functionality useful for complex layer switching where I would keep/change a layer depending on which key I release last.
I've also found it useful for clearing modifiers (especially since kmonad has a press-only
button that allows to keep mods activated).
There's a Windows-only key remapping project that should solve the problem of kanata not working with specific applications or in administrator privileged applications.
https://github.com/cajhin/capsicain
http://www.oblita.com/interception
Might look into it as an option for Windows input/output.
Transparent keys (i.e. using underscore _
) on the first layer should not be remapped at all, sending whatever key is defined in the defsrc
declaration. This is how kmonad behaves.
Although input is registered and visible from debug logs, no key is output at all leaving these keys dead.
Use the following config:
(defcfg)
(defsrc a f)
(deflayer one (layer-toggle two) _)
(deflayer two a z)
Tapping f
sends no key. Holding a
and then tapping f
sends z
as expected. Logs for this sequence:
$ ./target/debug/kanata.exe --cfg repro.kbd --debug
06:27:50 [INFO] Kanata: config parsed
06:27:50 [INFO] Kanata: entering the processing loop
06:27:50 [INFO] Init: catching only releases and sending immediately
06:27:51 [INFO] Starting kanata proper
06:27:59 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_F, value: Press }
06:27:59 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_F, value: Release }
06:28:01 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_A, value: Press }
06:28:01 [INFO] Entered layer:
(deflayer two a z)
06:28:01 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_F, value: Press }
06:28:01 [DEBUG] (3) kanata::kanata: press Z
06:28:01 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_F, value: Release }
06:28:01 [DEBUG] (3) kanata::kanata: release Z
06:28:02 [DEBUG] (2) kanata::kanata: event loop: KeyEvent { code: KEY_A, value: Release }
06:28:02 [INFO] Entered layer:
(deflayer one (layer-toggle two) _)
I'm on Windows 10, compiling myself using the most recent main
branch.
These installation steps in kmonad may provide some insight as to what's required.
I don't own any MacOS devices and don't plan to, so I will not be implementing this.
PRs are welcome however!
I have a vague idea in my head of being able to programmatically change layers when the focused application changes.
As I mentioned on Reddit, komorebi
has an event stream that can be subscribed to and acted upon; the idea I have looks like writing a daemon to respond to FocusChange
events from komorebi
by triggering LayerChange
events in kanata
.
The concrete use case I have for this right now is automatically changing to my ff
layer for Vim-like navigation in Firefox whenever it takes focus and switching back to my base layer whenever any other application takes focus. I'm sure as I add more and more application-specific layers this sort of functionality would become exponentially more useful and ergonomic for long sessions at the computer.
This feature seems like it could naturally fit into the work that is being done in #44, which the server responding to client messages to trigger layer changes (and maybe other actions in the future?).
Let me know what you think!
Hello and thank you for working on this.
I have an issue using kanata with windows. If my config (defsrc and deflayer) includes lctl it will send a lctl keypress when I press ralt. Here is the debug log:
10:08:27 [INFO] NOTE: kanata was compiled to never allow cmd
10:08:27 [INFO] Kanata: config parsed
10:08:27 [INFO] Sleeping for 2s. Please release all keys and don't press additional ones.
10:08:27 [INFO] Kanata: entering the processing loop
10:08:27 [INFO] Init: catching only releases and sending immediately
10:08:37 [INFO] Starting kanata proper
10:08:40 [DEBUG] (1) kanata::kanata: event loop: KeyEvent { code: KEY_LEFTCTRL, value: Press }
10:08:40 [DEBUG] (1) kanata::kanata: event loop: KeyEvent { code: KEY_RIGHTALT, value: Press }
10:08:40 [DEBUG] (2) kanata::kanata: press LCtrl
10:08:40 [DEBUG] (2) kanata::kanata: press RAlt
10:08:40 [DEBUG] (1) kanata::kanata: event loop: KeyEvent { code: KEY_RIGHTALT, value: Release }
10:08:40 [DEBUG] (2) kanata::kanata: release RAlt
10:08:54 [DEBUG] (1) kanata::kanata: event loop: KeyEvent { code: KEY_LEFTCTRL, value: Press }
10:08:54 [DEBUG] (2) kanata::kanata: repeat LCtrl
10:08:54 [DEBUG] (1) kanata::kanata: event loop: KeyEvent { code: KEY_LEFTCTRL, value: Release }
10:08:54 [DEBUG] (2) kanata::kanata: release LCtrl
What I am doing here is:
Here is my config:
(defcfg
;; Windows does not need any input / output config
)
(defalias
met_a (tap-hold 200 200 a lmet)
alt_s (tap-hold 200 200 s lalt)
ctl_d (tap-hold 200 200 d lctl)
sft_f (tap-hold 200 200 f lsft)
sft_j (tap-hold 200 200 j rsft)
ctl_k (tap-hold 200 200 k rctl)
alt_l (tap-hold 200 200 l ralt)
met_; (tap-hold 200 200 ; lmet)
)
(defsrc
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \
caps a s d f g h j k l ; ' ret
lsft z x c v b n m , . / rsft
lctl lmet lalt spc ralt rmet rctl
)
(deflayer homerowmods
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \
caps @met_a @alt_s @ctl_d @sft_f g h @sft_j @ctl_k @alt_l @met_; ' ret
lsft z x c v b n m , . / rsft
lctl lmet lalt spc ralt rmet rctl
)
To get around this issue I can simply remove lctl
from my config and everything will work as intended.
Not sure if it matters, but I am using norwegian keyboard layout with Alt Gr as right alt key.
I have Pinebook Pro with ISO keyboard, and it seems that kanata cannot handle 102d key. With this simple config
(defcfg
linux-dev /dev/input/by-id/usb-HAILUCK_CO._LTD_USB_KEYBOARD-event-kbd
)
(defsrc
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] ret
caps a s d f g h j k l ; ' \
lsft 102d z x c v b n m , . / rsft up
lctl lmet lalt spc ralt rctl left down rght
)
(deflayer qwerty
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] ret
caps a s d f g h j k l ; ' \
lsft 102d z x c v b n m , . / rsft up
lctl lmet lalt spc ralt rctl left down rght
)
all keys work, except for nubs.
kanata prints
19:51:53 [DEBUG] (2) kanata::oskbd::linux: input ev: InputEvent { time: TimeVal { tv_sec: 0, tv_usec: 0 }, event_type: EV_KEY, event_code: EV_KEY(KEY_UNKNOWN), value: 0 }
xev (with kanata disabled):
KeyPress event, serial 39, synthetic NO, window 0x1200001,
root 0x226, subw 0x0, time 6757247, (-249,402), root:(622,847),
state 0x0, keycode 94 (keysym 0x3c, less), same_screen YES,
XLookupString gives 1 bytes: (3c) "<"
XmbLookupString gives 1 bytes: (3c) "<"
XFilterEvent returns: False
I've added some prints, and in linux.rs
impl From<KeyCode> for OsCode {
fn from(item: KeyCode) -> Self {
receives KeyCode::No
, and from(item: OsCode) -> KeyCode
receives OsCode::KEY_UNKNOWN
.
Problem is present under both X11 and Wayland.
Could be any of (or all of) the following:
https://github.com/qmk/qmk_firmware/blob/master/docs/one_shot_keys.md
Would need to be added to the keyberon library since this needs to manipulate its state machine.
Kanata: config parsed
should be before Created device "/dev/input/event7"
12:57:40 [INFO] Created device "/dev/input/event7"
12:57:40 [INFO] Created symlink "/run/kanata-mykbd/mykbd" -> "/dev/input/event7"
12:57:40 [INFO] Kanata: config parsed
12:57:40 [INFO] Sleeping for 2s. Please release all keys and don't press additional ones.
12:57:42 [INFO] Kanata: entering the processing loop
12:57:42 [INFO] Kanata: entering the event loop
12:57:42 [INFO] Init: catching only releases and sending immediately
12:57:42 [INFO] Starting kanata proper
I assume that the keycode supported by kmonad https://github.com/kmonad/kmonad/blob/master/src/KMonad/Keyboard/Keycode.hs is compatible with kanata as well?
Is it all under the KeyCode name space in windows.rs and are they case sensitive?
I have an AMD Ryzen 9 3900X 12-core processor, and when left running unchecked, kanata
's CPU usage sits at 30%+.
If I use Task Manager to restrict which processors kanata.exe
can utilise, the CPU drops down to a negligible 0.x% without any noticeable performance impact (including with the TCP server emitting outgoing and processing incoming messages).
I think it would be a good idea to allow the number of processors that kanata utilises to be configurable either via a command line flag or through the configuration file.
I have used lmet as layer toggle. It did not recognize anymore lmet+rightclick from my window manager.
I tried adding mlft,mmid,mrght to defrc . It didn't work
Have a key action for hot reloading the configuration. A ~1-second convenience compared to closing and restarting the application.
Hi
Just to clarify ... when is this active on Linux?
I have my own custom layout, but it's currently only configured in KDE, so to log in I need to know where the Qwerty keys are. Avoiding that would be good.
Thanks, Ian
evdev device should call these functions to release resources before closing the device fd. They are wrapped by evdev-rs
in the Drop trait.
Currently, the only way to terminate kanata is to kill it by a signal, e.g. SIGINT and SIGTERM.
Rust doesn't unwind and call drop()
by default when receive SIGINT and SIGTERM, which causes those devices fail to release resources properly.
Relates to #46 , but I think this should be a separate issue and I cannot re-open that issue.
When starting the program, newlines get repeatedly and rapidly sent into the active application until a new key is pressed. This is currently worked around by sending spaces for 1s on program start, but this is pretty ugly. Need to see if there's a better solution.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.