Code Monkey home page Code Monkey logo

ktrl's People

Contributors

acidnik avatar andrewsmithdev avatar brockelmore avatar evanrichter avatar goffrie avatar itaygarin avatar sudo-ben avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ktrl's Issues

Make TapHold independent of any timeout?

I'm just poking around the edges of ktrl at the moment (nice work!) and I have a question/suggestion:

It seems to me that the dual function of a tap/hold key need not be dependent on the length of time the key is held down.

Example use case:

  • consider the "CapsEscCtrl" setup, where "CapsLock is Escape when tapped, but Ctrl when pressed in combination with another key"
  • Sometimes I press CapsLock with the intent to follow up with a key combination (i.e. use it as Ctrl) but then hesitate if I've forgotten the correct completion for the combo. I don't want my "unintentional hesitations" to determine the key state for CapsEscCtrl.

One or two of the other keyboard event mappers I've seen (notably interception) works by waiting to see if a second key is pressed before the first is released. Here's how it might work:

  1. If the user presses CapsLock (KEYDOWN), then releases CapsLock (KEYUP) with no intervening KEYDOWN events, then this is a "tap", therefore it should simulate Escape (KEYDOWN/SYN/KEYUP).
  2. If the user presses CapsLock (KEYDOWN), then presses another key (e.g. KEYDOWN "C") before the CapsLock KEYUP event, then this is a "hold", therefore it should simulate Ctrl+C (Ctrl KEYDOWN/SYN/"C" KEYDOWN/SYN/"C" KEYUP/Ctrl KEYUP).

This way, the user need not think about whether they've reached a certain time threshold. Is this reasonable? Has it already been covered by ktrl but I didn't notice?

No Sound Effect variant

I'm getting the error:

Failed to parse the config file: Error { code: Message("unknown variant `Sound`, expected one of `NoOp`, `Key`, `KeySticky`, `KeySeq`, `Meh`, `Hyper`, `ActivateProfile`, `DeactivateProfile`, `DeactivateAllProfiles`, `TurnOnLayer`, `TurnOffLayer`, `ToggleLayer`, `TurnOnLayerAlias`, `TurnOffLayerAlias`, `ToggleLayerAlias`, `MomentaryLayer`, `Multi`")

Not sure why Sound is not a variant.

I installed ktrl using cargo and am on version 0.1.7

tap_dance 无限重复

系统:Debian 12
ktrl 版本: 最新

问题描述:把 dance 的周期设置为 250 毫秒时,dance 的内容会无限重复,造成系统按键出现问题。

问题复现步骤:
将 dance 的时间设定为:

tap_dance_wait_time: 250,

将按键设定为:

KEY_CAPSLOCK:  TapDance(2, Key(KEY_LEFTCTRL), KeySeq([KEY_LEFTALT, KEY_LEFTSHIFT, KEY_LEFTMETA, KEY_L])),

做好上述设定后,正常启动 ktrl ,当快速连按两次 CAPSLOCK 键时,会有 KEY_LEFTALT, KEY_LEFTSHIFT, KEY_LEFTMETA, KEY_L 的组合按键操作一直被触发,导至系统无法正常使用。

注:在当前系统下设定了 KEY_LEFTALT, KEY_LEFTSHIFT, KEY_LEFTMETA, KEY_L 该组快捷键执行一个 shell 脚本,当快速连按两次 CAPSLOCK 键时,脚本会一直被触发,无限重复执行。

问题复现程度:必现

临时解决办法:将 dance 周期设定为300毫秒,tap_dance_wait_time: 300,

Follow XDG Base Directory Specification

Can you change the defaults to follow the XDG Base Directory Specification?

Full spec is here but the main changes would just be to change the assumption that configs and assets live in /opt/ktrl to the specified dirs.

It would only involve the following changes:

  • assume config is found in $XDG_CONFIG_HOME/ktrl/cfg.ron if the variable is set and $HOME/.config/ktrl/cfg.ron otherwise
  • assume assets found at $XDG_DATA_HOME/ktrl/assets if the variable is set and $HOME/.local/share/ktrl/assets otherwise
  • default to logging in $XDG_CACHE_HOME/ktrl/log.txt if the variable is set and $HOME/.cache/ktrl/log.txt otherwise

Cross platform would be cool

currently we need to configure karibener for mac and autohot keys for windows as well as ktrl. When we use a laptop we are stuck with the keyboard we have (otherwise QMK or similar makes sense).

Is there some interest in cross platform support?

Compose key output doesn't seem to work on Xorg

Hi,

Here is my config file:

(
    tap_hold_wait_time: 300,
    tap_dance_wait_time: 1000,

    layer_aliases: {
        "base": 0,
    },

    layer_profiles: {
    },

    layers: [

        {
            KEY_RIGHTALT: Tap(Key(KEY_COMPOSE)),
        },
    ],
)

With the aim of duplicating the functionality of this setxkbmap command but with Alt Gr instead of the menu key (as my laptop doesn't have a dedicated menu key):

setxkbmap -option compose:menu ;

However the compose output doesn't seem to work. If I change it to another key (like KEY_U for example) it works fine, but the compose key isn't working as desired (to allow one to enter accented characters, etc.).

Do you have any ideas? Or how to debug what key action gets produced?

Incidentally is there a way to enable even more verbose debugging/logging to see each relevant key press from the device, etc.? As for a while it was tricky to work out that I had the right device and keys were being read correctly.

This seems like a great tool, it'd be great to simplify and unify a lot of the disparate (and often poorly documented) tooling for this in Linux at the moment - see this Ubuntu question for example!.

Add a doc page for IPC usage

This should be a markdown file under a new doc/ directory.

It'll explain -

  • How to compile with the "ipc" feature flag
  • How to use ktrl's exe as an ipc client (--msg)
  • How to use the python client

TapHold modifiers used before hold time should queue key actions

It looks like there is a key queue being built up, but I think it should wait for either the hold time of the tap to be completed, or for key release on the TapHold key, whichever comes first.

With a minimal config; only one layer and these effects:

    KEY_F:  TapHold(Key(KEY_F), Key(KEY_LEFTSHIFT)),
    KEY_J:  TapHold(Key(KEY_J), Key(KEY_RIGHTSHIFT)),

Actual behavior

j pressed   "jg" emitted                          j released
v              v                                     v
---------------------------------------------------------> time
               ^            ^            ^
           g pressed     g released   hold time reached

Expected behavior

j pressed                           "S-g" emitted   j released
v                                        v           v
---------------------------------------------------------> time
               ^            ^            ^
           g pressed     g released   hold time reached


"S-g" = shift+g

OR

j pressed                 "jg" emitted
v                            v
---------------------------------------------------------> time
      ^          ^           ^           ^
  g pressed   g released   j released  hold time (not reached)

Don't crash on sound effect errors

Sound effects are a bit brittle at this point. It'd be better to just output a warning instead of crashing the entire process with unwrap/expect

TapHold doesn't work as expected with other TapHold keys

This is a great program! Thank you for creating and sharing it.

Here is the little bug I ran into with tap-hold for home row modifiers. With a minimal config; only one layer and these effects:

    KEY_CAPSLOCK: Tap(Key(KEY_LEFTCTRL)),
    KEY_F:  TapHold(Key(KEY_F), Key(KEY_LEFTSHIFT)),
    KEY_J:  TapHold(Key(KEY_J), Key(KEY_RIGHTSHIFT)),

The bug: Holding j and tapping f e e results in fee, which one would expect to be capitalized.

Not the bug: This above only happens when the first tapped key is another TapHold hey—holding j and tapping e f f o r t results in EFFORT as expected.

Also not the bug: The normal tap effect also works fine with TapHold, eg holding capslock and tapping f sends ctrl+f as expected, holding capslock and holding j then tapping e sends ctrl+shift+e as expected.

Back to the bug: Holding capslock and holding j then tapping f sends ctrl+f with no shift.

Put sound effects behind a feature flags

As some users pointed out, it'd be nice if there was a way to disable sound effects.
Currently, these effects depend on libalsa. We can make this dependency optional

`TapModi` makes the key stick

With this script

            KEY_C: TapModi(KEY_LEFTCTRL, Key(KEY_C), Key(KEY_I)),

The following sequence works fine:
LEFTCTRL down -> KEY_C down -> KEY_C up -> LEFTCTRL up

But if I lift LEFTCTRL before KEY_C, KEY_I will stick and start emitting on repeat:
LEFTCTRL down -> KEY_C down -> LEFTCTRL up -> KEY_C up
Result: ccccccccccccccccccccc... (the character under KEY_I) is printed until I press some other button.


There also sometimes happens another bug where (probably) my Win key sticks and I become unable to type any text but I couldn't track down what exactly causes it.

Add IPC port discovery with a "state file"

As suggested by @brockelmore,
maintaining a state file with the current bound port will allow clients
to resolve the port without needing to ask the user for it.

One ktrl supports multi-devices, we'd want to map device => port.

ktrl doesn't work on Gnome

I'm using ktrl installed from crates.io and trying to test it using example configuration based on steps from README, but it doesn't work. When i press any key from my keyboard, it doesn't appear in my monitor. It's like the keyboard just unplugged until i stopped the systemd service and then it worked again. This is my setup

OS: Arch Linux x86_64
Kernel: 5.10.19-1-lts
DE: GNOME 3.38.3 (Wayland)
WM: Mutter

It doesn't output any error in program log. But here some error related to ktrl from journalctl:

kernel: input: ktrl as /devices/virtual/input/input41
systemd-logind[1554]: Watching system buttons on /dev/input/event18 (ktrl)
gnome-shell[2630]: Could not open device /dev/input/event18: GDBus.Error:System.Error.ENODEV: No such device

Improve `TapHold`'s reset time

This was suggested by diogoxpinto over on reddit -

This is fantastic! I tried it for a short while and already added it to my startup script ^^

The only downside I noticed is that `TapHold` seems to take a while to "go back" to Tap mode. The holding itself works fine after tweaking it to my liking, but then I stop holding it, and tap it, and the "hold" effect is still on. I have to tap it a few times to get it working. (Presumably, whatever delay there is just runs out while I do this)

Great project, thanks for sharing it!

Named layers

It would be great to be able to name layers so if #13 gets integrated, you could activate via name. Also just helps for complex configs

Expose perform commands via cli

It would be great to be able to activate a particular layer via a script. I.e. I use bspwm, and when I change focus between windows, I would like to be able to update what layer is active (effectively, this turns layers into user-definable mappings for applications). This could be done via sending a command by having ktrl see if there is a running instance for the device and executing basically any of the perform commands.

I.e. in firefox, I can't redefine keyboard shortcuts (*easily, i.e. without compiling firefox myself essentially). Its dumb.

So I would like to have a firefox layer that maps the keyboard shortcuts I want to use to the unchangeable firefox ones, same with other apps I use.

Bluetooth keyboard support

It would be great to have bluetooth keyboard support. On arch + Xorg, at least, this is what the wiki says:

Xorg
Device should be added as `/dev/input/event*` and your Xorg should add it automatically if you did not disable such feature. 

And the corresponding events:

/dev/input/event0   /dev/input/event11  /dev/input/event14  /dev/input/event17  /dev/input/event2   /dev/input/event22  /dev/input/event25  /dev/input/event4  /dev/input/event7
/dev/input/event1   /dev/input/event12  /dev/input/event15  /dev/input/event18  /dev/input/event20  /dev/input/event23  /dev/input/event26  /dev/input/event5  /dev/input/event8
/dev/input/event10  /dev/input/event13  /dev/input/event16  /dev/input/event19  /dev/input/event21  /dev/input/event24  /dev/input/event3   /dev/input/event6  /dev/input/event9

If you know a workaround, would love to know!

Issue with ktrl service while running SELinux

I created a service based on ktrl.service found in the project's etc directory.

/etc/systemd/system/ktrl.service

[Unit]
Description=ktrl

[Service]
User=ktrl
Environment=HOME=/opt/ktrl
ExecStart=/home/andrew/.cargo/bin/ktrl -d /dev/input/event3
  
[Install]
WantedBy=multi-user.target

However, when I try to run the service I get the following error from systemctl status ktrl.service

     Loaded: loaded (/etc/systemd/system/ktrl.service; enabled; vendor preset: disabled)
     Active: failed (Result: exit-code) since Sat 2020-06-27 10:35:08 EDT; 5s ago
    Process: 23335 ExecStart=/home/andrew/.cargo/bin/ktrl -d /dev/input/event3 (code=exited, status=203/EXEC)
   Main PID: 23335 (code=exited, status=203/EXEC)
        CPU: 5ms

Jun 27 10:35:08 localhost.localdomain systemd[1]: Started ktrl.
Jun 27 10:35:08 localhost.localdomain systemd[23335]: ktrl.service: Failed to execute command: Permission denied
Jun 27 10:35:08 localhost.localdomain systemd[23335]: ktrl.service: Failed at step EXEC spawning /home/andrew/.cargo/bin/ktrl: Permission denied
Jun 27 10:35:08 localhost.localdomain systemd[1]: ktrl.service: Main process exited, code=exited, status=203/EXEC
Jun 27 10:35:08 localhost.localdomain systemd[1]: ktrl.service: Failed with result 'exit-code'.

I was able to track the issue down to SELinux. While SELinux is enforced the service does not work, however, while SELinux is disabled the service runs without issue. This is due to the bin being located in the user's home directory.

It would be better to have the bin located in /usr/local/bin/ktrl then you could update the ktrl.service file to be

[Unit]
Description=ktrl

[Service]
User=ktrl
Environment=/opt/ktrl
ExecStart=/usr/local/bin/ktrl -d /dev/input/event3
  
[Install]
WantedBy=multi-user.target

That way there would be no issues with SELinux.

If MomentaryLayer enables 2nd layer - its not disables 1on release button

Looks like MomentaryLayer not working properly, or I'm missing how it suppose to work. Consider such config:

// ktrl Example Configuration File
// -------------------------------
//
// ktrl config files use `ron` (Rust Object Notation) to serialize
// the text into the internal `cfg::Cfg` struct.
//
// - The full KEY_... listing can be found inside the `keys::KeyCode` enum
// - Layer entries are mapping between a source `KeyCode` into an `Action` (more on that below)
//
(
    // ktrl will register a TapHold as an hold after 300ms
    tap_hold_wait_time: 300,

    // ktrl will register a TapDance if all taps occur within a 1000ms period (1s)
    tap_dance_wait_time: 1000,

    layer_aliases: {
        "base": 0,
        "left_control": 1,
        "right_control": 2,
        "left_alt": 3,
        "right_alt": 4,
    },

    layer_profiles: {
        "left_control": Profile(
            indices: [],
            aliases: ["left_control"],
        ),
        "right_control": Profile(
            indices: [],
            aliases: ["right_control"],
        ),
        "left_alt": Profile(
            indices: [],
            aliases: ["left_alt"],
        ),
        "right_alt": Profile(
            indices: [],
            aliases: ["right_alt"],
        ),
    },

    layers: [
        {
            KEY_CAPSLOCK: TapHold(Key(KEY_LEFTCTRL), MomentaryLayer(1)),
            KEY_APOSTROPHE: TapHold(Key(KEY_RIGHTCTRL), MomentaryLayer(2)),
            
            KEY_TAB: TapHold(Key(KEY_LEFTALT), ToggleLayerAlias("left_alt")),
            KEY_LEFTBRACE: TapHold(Key(KEY_RIGHTALT), ToggleLayerAlias("right_alt")),

            KEY_SPACE: TapHold(Key(KEY_SPACE), Key(KEY_LEFTSHIFT)),

            KEY_Q: Tap(Key(KEY_Q)),
            KEY_W: Tap(Key(KEY_W)),
            KEY_E: Tap(Key(KEY_F)),
            KEY_R: Tap(Key(KEY_P)),
            KEY_T: Tap(Key(KEY_G)),
            KEY_Y: Tap(Key(KEY_J)),
            KEY_U: Tap(Key(KEY_L)),
            KEY_I: Tap(Key(KEY_U)),
            KEY_O: Tap(Key(KEY_Y)),
            KEY_P: Tap(Key(KEY_B)),

            KEY_A: Tap(Key(KEY_A)),
            KEY_S: Tap(Key(KEY_R)),
            KEY_D: Tap(Key(KEY_S)),
            KEY_F: Tap(Key(KEY_T)),
            KEY_G: Tap(Key(KEY_D)),
            KEY_H: Tap(Key(KEY_H)),
            KEY_J: Tap(Key(KEY_N)),
            KEY_K: Tap(Key(KEY_E)),
            KEY_L: Tap(Key(KEY_I)),
            KEY_SEMICOLON: Tap(Key(KEY_O)),

            KEY_B: Tap(Key(KEY_SPACE)),
            KEY_N: Tap(Key(KEY_K)),
        },
        // left_control
        {
            KEY_A: Tap(Key(KEY_COMMA)),
            KEY_S: Tap(Key(KEY_DOT)),
            KEY_D: Tap(Key(KEY_MINUS)),
            KEY_F: Tap(Key(KEY_KPPLUS)),
        },
        // right_control
        {
            KEY_A: Tap(Key(KEY_COMMA)),
            KEY_S: Tap(Key(KEY_DOT)),
            KEY_D: Tap(Key(KEY_MINUS)),
            KEY_F: Tap(Key(KEY_O)),
        },
    ],
)

As you can see I have 4 layers but describing only two - left_control enabled by holding CapsLock and right_control enabled by holding ' - APOSTROPHE. The strange thing is that when I press CapsLock + a/s/d/f- it inputs correct remapping and then when I release - it goes back to Layer 0. Strange thing happens when I'm trying ' + a/s/d/f. If I press it - it work perfectly inputting remapping, but when I release - it moves not to Layer 0 but to Layer 1, and then even if I'm not holding neither CapsLock nor ' - it still for some reason inserts Layer 1 remappings.

Is it supposed to work this way, and is there a way to just make setup such as:

"Till I hold one button - I get such layer remapping, if I hold another button - I get another layer remapping, and when I release any of such layer-until-holded buttons - it falls back to layer 0" ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.