Giter VIP home page Giter VIP logo

kmonad's Introduction

KMonad

The Onion of Keyboard Management Tools, available on GNU/Linux, Windows, and MacOS!

FeaturesInstallationConfigurationTroubleshootingDisclaimer

Introduction

KMonad is an advanced tool that lets you infinitely customize and extend the functionalities of almost any keyboard. For a detailed list of features, see here.

If you want to get started with the latest, stable binary release, please check out the master branch, if you are interested in the latest additions and tweaks, switch on over to develop and compile your own binary.

Additionally, if you need any help or just want to say hi, you can join our Matrix space or jump into our IRC channel. There is also an unofficial Discord server, and a KMonad Subreddit.

Features

KMonad offers advanced customization features such as layers, multi-tap, tap-hold, and much more. These features are usually available at the hardware level on the QMK-firmware enabled keyboards. However, KMonad allows you to enjoy such features in virtually any keyboard by low-level system manipulations.

For a good introduction to KMonad, have a look at this YouTube video.

Key Customizations

KMonad lets you map any keyboard button to any keymap. Want to swap the useless Caps Lock key with the Escape key? Want to have your modifiers such as Shift and Control on your home row, without breaking your normal typing flow? Want a modifier that is combination of Alt + Ctrl + Super + Shift? You can do all of those and much more!

Layers

A layer is a set of keymaps assigned to your keyboard's buttons. You can have as many layers on top of your base layer as you want. For instance, you can have your regular QWERTY layout, a Colemak/Dvorak layout, a numbers and symbols layer, a function keys layer, a layer for mouse navigation and system controls --- all in a 60% keyboard. When a particular layer is active, any keypress is interpreted according to the layout defined in that layer. With proper configurations, you can jump to a specific layer or switch to one for the next keypress, or do various other complex manipulations.

Multi-Use and Multi-Tap Buttons

Multi-Use Buttons are one of the distinguishing features of KMonad. You can have a single button do different things based on whether it is pressed quickly in succession, or pressed once, or held. For example, you can configure the Caps Lock key to act as an Escape button when pressed once and released, a Ctrl modifier when held-down, and a button to jump to a layer when pressed twice quickly in succession. You can make the left and right Shift keys to act like left and right parentheses (like the Space Cadet Shift keys) when tapped once, and regular Shift keys when held down. The possibilities are infinite!

Command Buttons

With Command Buttons you can trigger shell commands with a tap of any button.

And More!

There are many more exciting features of KMonad that you can find in the configuration tutorial.

Installation

For more information on how to install KMonad, please refer to:

Configuration

For information on how to configure KMonad, please refer you to:

Want to add your own keyboard configuration to kmonad-contrib? Just fork the repository, create a new subdirectory using your GitHub username and submit a pull request!

Editor Support for the Configuration Language

Startup

Troubleshooting

For several commonly asked questions regarding various configuration issues, please see:

Disclaimer

The core maintainer is currently chronically ill with debilitating autoimmune symptoms. They come and go, but when they are there they very much get in the way of concentrated work. It is very much his intent to keep working on KMonad until it is very, very good. But please be aware that he might be gone for weeks on end, not out of a lack of interest, but out of a lack of capacity. You are always free to reach out to him by email.

kmonad's People

Contributors

andreyadrian avatar arialdomartini avatar david-janssen avatar eepykate avatar flexagoon avatar gelisam avatar jokesper avatar klavul avatar lapidot avatar lierdakil avatar manna-harbour avatar maxgyver83 avatar mtoohey31 avatar muhammedzakir avatar nharward avatar pataquets avatar pjones avatar precondition avatar salastro avatar slotthe avatar stevep99 avatar stites avatar terlar avatar thoelze1 avatar toymil avatar truenaho avatar txtyash avatar ultrahalf avatar vermoot avatar vosaica 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  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

kmonad's Issues

Add tracking output state

I didn't want to make a track input state-style function, because 'Button's should not be aware of what their trigger is, or of what the global trigger state it, they should simply go off when triggered. However, it actually does make sense to track output state, so I can add a primitive that returns a set of all the keycodes that are currently in 'pressed' state.

Add the ability to wait in a macro

Macros output so fast that certain programs won't keep up. I tried to insert a UTF-8 macro in emacs using:

@tst = (( C-x 8 ret 1 2 3 4 ret ))

Although this outputs the correct sequence, it happens so quickly that emacs doesn't register the last 'ret', probably because it got lost in Helm completion. This is an issue that could probably crop up in many places, and the simplest solution is to simply add the ability to wait.

This actually does require a redesign of the macro-system that I was already intending. I'll make a new issue for that and reference it here.

\\ maps to |, not \

Like the title says, escaped backslash in config evaluates to a pipe-symbol, and not a backslash.

Emitting Hyper_L

Xmodmap has support for the historic Hyper key (archwiki source):

$ xmodmap -pm

xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Meta_L (0xcd)
mod2        Num_Lock (0x94)
mod3      
mod4        Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  ISO_Level3_Shift (0x6c),  Mode_switch (0x85),  Mode_switch (0xcb)

Which seems to have keycode 0xcf. Sxhkd has support for catching Hyper as one of the modifiers.

However neither keycode nor symbol can be found in linux/input-event-codes.h.

More generally, maybe aliasing a keycode directly could serve as a workaround for similar cases.

KeyFn missing frm KeyCode.hs

I noticed that the Fn key is missing from KeyCode.hs. Is there a reason for this? Given that Kmonad really shines on laptops and some of the most popular linux laptops ship an Fn key by default, it seems to me like a surprising omission.

Leader key/layer momentary timer

Would it be possible to designate a key to switch to a layer for the next 500 (or shorter) milliseconds, allowing toggling a layer momentarily, without holding a key and without switching to it? It could be the equivalent of how the leader key works in qmk.

Haddock needs some love

There is missing haddock documentation and some haddock syntax errors, leading to stack haddock erroring out.

systemwide configuration using kmonad

This is a great project. Switched from xcape, xmodmap and
setxkbmap. Much easier and better. Thank you!

This issue could perhaps be guix specific, though would apply to other
users on other distros, just in a different way.

Ideally I want my keyboard setup to be available from grub level,
through to unlocking my luks encrypted disk and into tty2 and X level
etc.

Currently I'm not sure if that is possible or has been done.

Secondly, currently I do this on my Guix system:

With guix I do something like this:

(operating-system
 ...
 (keyboard-layout (keyboard-layout "dvorak"))
 (bootloader (bootloader-configuration
              (bootloader grub-efi-bootloader)
              (target "/boot/efi")
              (keyboard-layout keyboard-layout))) ;for grub
  ...
  (modify-services %desktop-services
  (udev-service-type
  config => (udev-configuration
  (inherit config)
  (rules (append (udev-configuration-rules config)
  (list %backlight-udev-rule android-udev-rules kmonad)))))
 ...

In my .xinitrc I then auto start kmonad:

kmonad ~/.config/kmonad/dell-l7280.kbd &
kmonad ~/.config/kmonad/ergodox.kbd &

Once I log into X all is well.

However, switching to tty2 console, my dvorak layout does not work as
dvorak has been applied twice. Once by guix (keyboard-layout
(keyboard-layout "dvorak")) and once by kmonad.

I could disable (keyboard-layout (keyboard-layout "dvorak")) in
guix. But then I can't type my luks decryption password using dvorak.

It would be nice to have system wide keyboard setup using kmonad from
as early as possible, that would solve this.

Is anyone doing this on any distro?

cc @ajgrf

Make defcfg more powerful

The defcfg block should provide a way to set any possible command-line flag argument. Values provided over the commandline should override the values from defcfg when provided

How to avoid "Duplicate encountered in SRC layer" when keyboard has duplicate keys (split spacebar)

How should I write a source layer for a keyboard with 2 space keys?

Here is an image of the layout:

fs2-blue-mac-oh

Here is my in-progress .kbd file, which causes Duplicate encountered in SRC layer:

INPUT = LINUX_DEVICE L64 /dev/input/event13

OUTPUT = UINPUT_SINK "Kinesis Freestyle2 Blue (Mac)"


SRC
  grv  1    2    3    4    5    6       7    8    9    0    -    =    bspc      home
  tab  q    w    e    r    t            y    u    i    o    p    [    ]    \    end
  caps a    s    d    f    g            h    j    k    l    ;    '    ent  pgup
  lsft z    x    c    v    b            n    m    ,    .    /    rsft up   pgdn
  lctl lalt lmet spc                              spc  rmet ralt left down rght


@lsp = TH 300 spc lctl
@rsp = TH 300 spc lsft
  
  
LAYER MAIN
  grv  1    2    3    4    5    6       7    8    9    0    -    =    bspc      home
  tab  q    w    e    r    t            y    u    i    o    p    [    ]    \    end
  caps a    s    d    f    g            h    j    k    l    ;    '    ent  pgup
  lsft z    x    c    v    b            n    m    ,    .    /    rsft up   pgdn
  lctl lalt lmet @lsp                             @rsp rmet ralt left down rght

When I use evtest to test the left space and right space, they both appear to be the same:

Testing ... (interrupt to exit)
Event: time 1594264935.513920, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028
Event: time 1594264935.513920, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
Event: time 1594264935.513920, -------------- SYN_REPORT ------------
Event: time 1594264936.817861, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7002c
Event: time 1594264936.817861, type 1 (EV_KEY), code 57 (KEY_SPACE), value 1
Event: time 1594264936.817861, -------------- SYN_REPORT ------------
 Event: time 1594264936.907872, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7002c
Event: time 1594264936.907872, type 1 (EV_KEY), code 57 (KEY_SPACE), value 0
Event: time 1594264936.907872, -------------- SYN_REPORT ------------
Event: time 1594264940.302462, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7002c
Event: time 1594264940.302462, type 1 (EV_KEY), code 57 (KEY_SPACE), value 1
Event: time 1594264940.302462, -------------- SYN_REPORT ------------
 Event: time 1594264940.392538, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7002c
Event: time 1594264940.392538, type 1 (EV_KEY), code 57 (KEY_SPACE), value 0
Event: time 1594264940.392538, -------------- SYN_REPORT ------------
Event: time 1594264942.303683, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0
Event: time 1594264942.303683, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 1
Event: time 1594264942.303683, -------------- SYN_REPORT ------------
Event: time 1594264942.393735, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006
Event: time 1594264942.393735, type 1 (EV_KEY), code 46 (KEY_C), value 1
Event: time 1594264942.393735, -------------- SYN_REPORT ------------

I'm hoping to have different mappings for left space and right space, but is that possible if both are the same key in evtest?

Removing a layer in a macro

Hello,

I want to support the following workflow:

  • press a trigger key to enter e.g. desktop switching mode
  • press another key to do the action I want (e.g. switch to desktop 1) and exit desktop switching mode

The first point is easy with a layer - I have @ds = LA-ds. But I'm stuck on the second point. @ds1 = (( M-w 1 )) works for the switching part, but adding @ds1 = (( M-w 1 LR-ds )) leads to a syntax error.

Is it possible to somehow remove a layer in a macro? Or do you have another suggestion on how to solve the issue?

Idea: Community Repo to share configs for the refactor

Would you be open to a separate, community repo (similar to QMK's keyboards/*/keymaps/* directories)? It would potentially make it easier for people to jump in and get started, plus it could help get some default SRC layers for various keyboard types. Again, this would be community driven, but could be helpful.

Support for arbitrary shifted keycodes

By default, shifted keycodes mask the corresponding non-shifted keycodes. Is it possible to define shifted keycodes that do not correspond to the non-shifted keycodes?

For example, the dvorak-programmer layout emits the QWERTY 6 keypress as a non-shifted =, and a shifted 9.

The obvious solution is to define the shift-keys as a layer-toggle to a separate layer, e.g. LAYER shift. However, this has the slight downside that key combinations that need shift keys, e.g. C-S-left and C-S-tab, no longer work, unless many aliases are defined.

Is there any other way to do this? Is there a plan to support aliasing arbitrary shifted keycodes with a new "shift" keyword (keywords like TH and TN)?

Thank you! And problem with MacBook Pro 2012 keyboard on Linux

The main thing I want to say is how much I like this project. Thank you for writing it!

The latest iteration doesn't seem to work on my 2012 MacBook Pro - when I run kmonad with the tutorial configuration file (with just the input source changed to match my keyboard), all of my keys stop producing any effects.

Print Screen, System Request codes

With the two keyboards I have to test, under Ubuntu 20.04, using showkey from the terminal, I don't actually get the Print button code from the Print Screen key—I get System Request. The OS translates this to Print (works in i3 key binding for example).

I tried putting print into the source and base layers of my kmonad config but it didn't work, that's how I realized this is happening. By replacing this with sysrq in both spots it works again. It also works by just replacing in the source, and having sysrq translate to print in kmonad.

I know that these two keys have a historical link but I don't have enough keyboards to test. If this key code is being sent in the same way across all keyboards (I suspect not), it might be worth aliasing the keycodes differently for the source layer. If it's not consistent, maybe a note about this behavior in the documentation would be worthwhile? Or maybe this issue is enough of a heads up :)

If anyone reading this has a print screen button to test with, please share your experience. Starting kmonad with -l debug will show relevant codes received. I've tried with a Microsoft Sculpt and a cheap Microsoft Digital Media Pro keyboard.

Key Code List

I looked around, but I couldn't find one. Is there a list of key codes?

in the documentation and examples I didn't see the name for Print Screen, Pause Break, volume up and down, and mute.

openFd Permission denied

Hi. I'm trying to get kmonad working on nixos. I read the discussion here. I've added the uinput kernel module and added myself to the input group.

When I attempt to run kmonad:

$ sleep 2 && kmonad .local/etc/kmonad.kbd
/dev/uinput: openFd: permission denied (Permission denied)
Encountered raw IO Exception attempting restart

/dev/uninput is owned by root:root. Should I set the group ownership to input?

Emitting multiple modifier keys

Like this:

@a1 = C-M-S-lalt

The usecase being, using this in combination with other keys, to trigger actions from the hotkey manager. This example uses 4 modifiers, but 3 or 2 exhibit same behavior: KeyPress and KeyRelease are all emitted together on @a1 keypress, so it's not possible to combine it with other keys.

Related question: what is the best strategy for sending unique key combinations for the hotkey manager to consume? F13-F24 doesn't seem to work on my machine (F13 seems to send the keycode for F21, and sxhkd is not catching either). Currently using super-key combos that I do not use, e.g. M-6, M-7; The drawback being that these are limited and have side-effects, such as Super being registered as pressed, or a Vimperator prompt closing prematurely when this is emitted.

Edit: disregard the Vimperator prompt bit, the reason behind this is that I've moved on from using XkbOptions for layout switching on grp:lctrl_rctrl_switch, to firing M-6 and M-7 on the same physical keys, triggering a switch manually using xkb-switch. The difference probably being that xorg.conf.d has a special way of handling keys that Vimperator is oblivious to.

Variable remapping based on order of Release events?

Hello and thanks for your work! I am trying to figure out if kmonad would allow me to bind a non-modifier character and a modifier to the same key, but with variable behavior based on the order of key releases. This behavior is similar that of TapNext, but with a slight difference. Here is my use case:

Suppose I want to bind escape and control to the key CAPS LOCK. Let's say that a Push event for CAPS LOCK has occurred, followed by a Push event for J. At this point, CAPS LOCK and J are currently depressed.

  • If the Release event for J happens next, then I want control to be applied, and then j to be posted. Then, whenever the Release event for CAPS LOCK happens, I want control to be unapplied. The rationale for this behavior is that because J was both pressed and released while CAPS LOCK was held, I was intending to use CAPS LOCK as control here.

  • If the Release event for CAPS LOCK happens next, then I want escape to be posted, immediately followed by j. Then, when the key up for J happens, nothing additional happens. The rationale for this behavior is that I intended to send escape followed by j, but I was typing so quickly that I started to press J before I released CAPS LOCK.

I read the documentation and I couldn't tell if this behavior is impossible with kmonad, or if it's possible with layers but I just don't understand kmonad yet. This line in the general concepts documentation makes me think it's not possible:

When we register a Release event, the stack is not consulted at all. Instead we keep track of exactly which Button was used to handle a push-event for the corresponding keycode, and then use that same Button to handle the release-event.

I have been trying to achieve this behavior with several keyboard managers now, but I haven't been able to implement it with existing tools. Any help or advice would be appreciated! Thanks.

Wait/delay in macros

Motivation: quick gui-affecting macros sometimes need a short pause between keys, or have all keys be emitted with a configurable delay.

// Thunderbird: next unread folder. Here, 50 is a custom delay:
@m7 = 50 (( S-tab down n ))

Workaround is to use a more suitable tool for the job, which is xdotool:

xdotool key --delay 50 shift+Tab Down n

Is this something that would ultimately be in scope for kmonad? Reasoning being that hooking up xdotool involves creating a custom script and passing a custom unoccupied key from kmonad to sxhkd to dispatch on, for what ultimately isn't much different from the other kmonad macros existing in the same layer :)

Emitting endless returns/enters when starting

Using this config for this Das keyboard

Downloaded the latest release, made it executable and starting like this:

sudo ./kmonad-0.3.0-linux kmonad-das.kbd

Kmonad seems to start up fine with Starting event loop but that line quickly scrolls away. An endless loop of returns/newlines are being emitted and not just in that particular terminal. The whole system is receiving the key, it locks up the trackpad, etc.

Any idea what's going on here?

Need a test on 'testing' branch from Mac User

Hey @thoelze1 (or other Mac user),

So I just merged your pull request, and everything looked fine to me, but in your description you mention that maybe some of your code was uselessly allocating and deallocing a string. I think I fixed that, my change can be found in the testing branch. Could you give it a go?

Cheers,

D

leave all layers

Hello,

Congrats on kmonad it's great. I am typing at normal speed while having space as a modifier, amazing really.

Two ideas, I thought it might be useful to:

  • remove all layers from the stack at once and return to default
  • add a configurable timeout to an added layer

That is in case you wanted to leave nested layers without pressing LR binds in each regression. Is that possible btw?

Thanks.

KMonad is now packaged for GNU Guix

I just thought you'd like to know that KMonad is now packaged for GNU Guix. For now it is stuck on version 0.2, but it will be updated soon when Guix moves to a newer Stackage LTS (kmonad has depended on GHC 8.6 since commit 83049b9, in case you didn't realize).

Users of the Guix package manager can install it by running guix install kmonad, and copying the udev rules into place with sudo cp $(guix build kmonad)/lib/udev/rules.d/70-kmonad.rules /lib/udev/rules.d/.

Users who run Guix System to manage their entire machine will instead want to install the udev rules by putting something like this into their system's config.scm:

(use-modules (gnu packages haskell-apps))

(operating-system
 ;; ...
 (services
  (modify-services %desktop-services
    (udev-service-type config =>
      (udev-configuration (inherit config)
       (rules (cons kmonad
                    (udev-configuration-rules config))))))))

Improve MacOS KeyIO api

Currently we are relying on kext extensions to get at the MacOS keyboard internals. These have been deprecated in the most recent versions of MacOS, so we should figure out something different for the future.

Any Mac-specialists want to take up this banner?

The concepts of macros and actions are muddled

We currently have an internal distinction between:

  • pushing/releasing/repeating a key
  • pushing/releasing a button

This originally came about because KMonad mirrored Linux's event system very closely. When adding windows support it turns out that they use events conceptually differently (they don't have repeat events, for example).

I think it's high time for a proper refactor of the way we define these actions to unify them under 1 type, since the distinctions are making certain things clumsier to code, and they feel artificial. Additionally, there are a number of practical fixes/additions I would like to make that seem clumsy given the current system, but after a refactor of events are conceptually simpler.

The biggest example of this is the distinction between input and output macros: macro-buttons contains key-sequences that emit, which are sequences of output-key events. The 'after' button models pushing 1 input button and then pushing another input button. Ideally we'd just unify these two concepts, because at the moment you can also use either method to produce identical results. If we unify actions this seems easier to do.

Run kmonad in check mode

Proposal: a flag to only check the file argument, without launching.

Why: I've tried to use vim-quickrun with kmonad as a poor man's lint / makeprg, but kmonad never exits.

Config error reporting

When the number of seconds is omitted from the definition of any of the variations of tap-hold, the error reporting is unclear. For example, with the following config:

...
(defalias
  q (tap-hold a lsft)
)
...

The following error is reported:

kmonad: Parse error at #:##:
  |
# |   q (tap-hold a lsft)
  |               ^
unexpected 'a'
expecting button

I would expect this to say "expecting int" or something along those lines. I think I've noticed some other issues with the error reporting but I just wanted to start a thread for this issue while I'm thinking of it.

Improve Windows KeyIO API

The low level Linux API to the operating system allows for a user to choose which keyboard should be grabbed by KMonad. This allows for different mappings on different devices, and does not automatically rob the OS of all raw input.

Due to limitations with the C-code and the Win32 API the current C-implementation for Windows is extremely naive, and needs to capture all raw input. The reasons for this are as follows:

Windows offers 2 different API's to keyboard events, using keyboard-hooks that install a callback and the RawInput API. The Keyboard-hook based API will allow you to intercept events and block them from further processing by windows, but does not distinguish between input sources. The RawInput API lets you register a particular type of raw input, and then distinguish between input sources, but is does not allow you to block processing of input events.

Therefore:

  • using only a keyboard hook will not let you distinguish between input sources (current implementation).
  • using RawInput will not let you block events (making it useless on its own).

Potential solution:
Combine the RawInput and keyboard hook API, using an approach similiar to one described here. However, this becomes exponentially more complicated in the following ways:

  • We'll need to set up a much more complicated c-module that registers inputs from both API's, coregisters them despite having no order guarantees, and deals elegantly with missing events happening sometimes. (according to that article).
  • This combined approach can't use a low-level hook, but needs a normal keyboard hook, which as a consequence means you can no longer keep your hook in a simple C-file, but need to create a .dll file for the keyboard hook so that it can be injected into windows namespaces (or something like that).
  • Not sure if/how, but this might also complicate the FFI from haskell and the compilation process.

Gotta love windows.

If anyone has some serious Win32 programming skills (or desire to have those skills) it would be great if they could help out with this. Of course, I'd also be very happy to hear any other potential solution.

Typing quickly with home row mods leads to out of order sequences

I'm playing around with the refactor branch, using the colemak layout from the example configuration, and the following home row mods on the pointer finger keys t and n:

(defalias
  tsh (tap-hold 200 t lsft)
  nsh (tap-hold 200 n lsft)
  )

This works great when typing slowly, but results in out-of-order of the tap-hold keys and whichever key follows when typing quickly. This seems to be the result of a key down of the following key coming before the key up of the tap-hold mod. The simplest example of the issue is typing to quickly. I get ot nearly every time, with the following output with debug-level messages:

--------------------------------------------------------------------------------
Received event: Press <f>
Running hooks
Registering hook: 5
Registering hook: 6

--------------------------------------------------------------------------------
Received event: Press <;>
Running hooks
Registering hook: 7
Registering hook: 8
Emitting: Press <o>
Registering hook: 9

--------------------------------------------------------------------------------
Received event: Release <f>
Running hooks
Emitting: Press <t>
Emitting: Release <t>
Registering hook: 10

--------------------------------------------------------------------------------
Received event: Release <;>
Running hooks
Emitting: Release <o>
Tried cancelling expired hook: 5
Tried cancelling expired hook: 7

--------------------------------------------------------------------------------

Is there a way to wait for a tap-hold release or the hold time being reached (whichever comes first) before emitting the next key codes?

Thanks for the useful package!

Multiple Quick TapHold Issue

I am currently having an issue while pressing multiple TapHold keys in quick succession. When I tap two TapHold keys one after the other as fast as I can, only the first one will register. If I tap one TapHold key and one regular key one after the other as fast as I can, both register.

Execute command on layer change

Sometimes it might be desirable to execute a shell command whenever the layer changes (e.g. if you wanted to change the input language of your keyboard on layer X). I don't think this is possible right now.

I would try hacking this in myself but I'm not sure how extensive the planned refactoring will be. I'd rather wait until it's (mostly) finished before trying to add new features (though I just realized that there is another branch for that and you haven't been doing all the development offline :o).

Improve logging

Logging is currently only performed with simple print statements. It would be great if we could have the ability to specify a log level, and use proper logging statements.

Has anybody had success with TapHold on the home row keys?

I have tried different kinds of time thresholds for binding a,s,d,f and j,k,l,; to ctrl, super, alt, meta but nothing has worked reasonably well.

I would like to know if somebody has a setting or workaround for using any of the main alphabet keys as taphold keys.

The problems I have faced

- when I type these taphold keys as normal keys in quick succession some weird things happen and it seems like all these modifier keys are in a held state even long after releasing them.
- I set up both `a` and `;` as shifts. Now typing `A` and `:` requires very precise timing on my end, otherwise it does not get registered.

Multiple modifiers with hotkey

Hi, I've read some of the other issues here and there seems to be a pattern. Everyone loves what you did! Including me, I'm really grateful for the wonderful piece of software you're working on!

For my issue, I can't seem to use multiple modifiers in one hotkey. For example C-S-down doesn't work.
Am I doing it wrong?

Here's my full config if you're interested.

(defcfg
    input (device-file "/dev/input/event11")
    output (uinput-sink
                "KMonad: DasKB"
                "sleep 1 && setxkbmap -option compose:ralt"))

(defalias
caps (tap-hold 200 esc lctl)
lay (layer-toggle layerSwitch))

(defalias
reset (layer-switch base)
discChan (layer-switch discordChannels)
channelUp A-up
channelDown A-down
discServ (layer-switch discordServers)
serverDown C-S-down
serverUp C-S-up
jumpChan #(C-k # (layer-switch base))
jumpVoice #(C-k ! (layer-switch base))
jumpServer #(C-k * (layer-switch base))
jumpDm #(C-k @ (layer-switch base)))

;; Source layer
(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    z   x   c   v   b   n   m   ,   .   /   rsft
lctl    lmet    lalt    spc     ralt    menu    rctl
     up
left down right)

;; Base layer
(deflayer base
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    z   x   c   v   b   n   m   ,   .   /   rsft
lctl    lmet    lalt    spc     @lay    menu    rctl
     up
left down right)

;; Layer switch layer
(deflayer layerSwitch
_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	@discChan	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_
	_
_   _   _)


;; Discord layer channels
(deflayer discordChannels
@reset	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_   @jumpServer	@jumpDm	_	_	@discServ	@channelDown	@channelUp	@reset	_   _
lsft	_	_	@jumpChan	@jumpVoice	_	_	_	_	_	_	_
_	_	_	_	_	_	_
	_
_   _   _)

;; Discord layer Servers
(deflayer discordServers
@reset	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	_	_	_	_	_	_	_
_	_	_	_	_	_	_	@serverDown	@serverUp @discChan	_   _
_	_	_	_	_	_	_	_	_	_	_	_
lsft	_	_	_	_	_	_
	_
_   _   _)

I'm putting in the time to learn Haskell but it's gonna take me a long time to get used to it.

Hack for openSUSE

Hi there, thanks for the great work!

I had trouble to make kmonad work on openSUSE Tumbleweed. It does work using sudo, but if I want to run kmonad as normal user on my system there is no such group uinput. There is a group input but simply adding it to my user does not solve the issue.

My current solution is:

  • create a group uinput and add my user to it
  • add my user to the group input
  • create a file /lib/udev/rules.d/99-kmonad.rules with the following content:
    KERNEL=="uinput", MODE="0660", GROUP="uinput", OPTIONS+="static_node=uinput"
  • reboot

I am no expert. I wonder if this is secure and if it could be simplified?

How to do sequences?

Hello, I read all the documentation and I've got everything else working but I couldn't get the "sequence buttons" working e.g:

@spc = >> (( spc )) LR-punctuation

  |
5 | @spc = >> (( spc )) LR-punctuation
  |         ^
unexpected '>'
expecting end of input or white space

I created example configs: https://pastebin.com/vKwvGqhy
https://pastebin.com/v9jKFhYM

I am using the default kmonad (I think the binary).

Just wondering if its my wrong understanding and/or using the wrong version, or kmonad going through changes.

Many thanks,

Edit: solved by refactor branch.

Regular keys + TapHold in quick succession repeats the last previous key

Hi, was recommended this project by a friend and I think it really looks promising. I am currently using 0.3.0. I see consistently key repeats when typing quickly.

With a binding like this:

@let = TH 200 ret lctl      // Return when tapped, control when held
@ret = TH 200 ret rctl      // Return when tapped, control when held

If I write gs, followed by holding the @ret or @let key I will see something like gsss up to gsssss. So somehow the holding of the key triggers as holding the previous key.

I see it very consistently. I have quite low "xkb repeat interval" set, so might influence this behavior as well, will try to configure it higher.

xkbRepeatDelay = 200;
xkbRepeatInterval = 33; # 30Hz

How to determine action for different key release within a button?

I've started learning Haskell so I could do something more useful in this project than just asking for things :) I'm beginning to get it, but I'm not sure how to capture a KeyEvent and determine the action from it. Or maybe I am thinking about this problem the wrong way.

What I'd like to do is have a tapNextRelease parameter to treat modifiers of the tap action as sticky if they were down at the press of this button. An example:

sc (tap-next-release s lctl)

If tapped or in a roll it emits s, but only on key release—that's not how a key normally works with shift for example, emitting on key press. s is only capitalized when shift is held until release, which feels quite different than the other keys. Rather than slowing down all typing that involves the shift key, what I'd like is to capture a release of shift during the press and apply it during the tap action. That's not too hard, but the complexity arises when using different keys that emit these modifiers. Continuing the example:

/sh (tap-hold-next 300 / rsft)

The KeyEvent for this key is KeySlash, not a shift. Is there a way to capture the translated KeyEvent from this? Here is the code I have so far

myTapNextRelease :: Button -> Button -> Button
myTapNextRelease t h = onPress $ do
  hold True
  go [] []
  where
    allmods = [KeyLeftCtrl,KeyLeftShift,
               KeyLeftAlt,KeyLeftMeta,
               KeyRightCtrl,KeyRightShift,
               KeyRightAlt,KeyRightMeta,
               KeyCompose, KeySlash, KeyCapsLock]
    -- What it should actually be:
    -- allmods = [KeyLeftCtrl,KeyLeftShift,
    --            KeyLeftAlt,KeyLeftMeta,
    --            KeyRightCtrl,KeyRightShift,
    --            KeyRightAlt,KeyRightMeta,
    --            KeyCompose]
    go :: MonadK m => [Keycode] -> [Keycode] ->  m ()
    go ks mods = hookF $ \e -> do
      p <- matchMy Release
      let isRel = isRelease e
      if
        -- If the next event is my own release: we act as if we were tapped
        | p e -> doTap mods
        -- If the next event is the release of some button that was held after me
        -- we act as if we were held
        | isRel && (e^.keycode `elem` ks) -> doHold e
        -- If the next event is the release of a modifier, store that modifier and wait again
        | isRel && (e^.keycode `elem` allmods) -> (go ks ((e^.keycode):mods)) *> pure NoCatch
        -- Else, if it is a press, store the keycode and wait again
        | not isRel                       -> go ((e^.keycode):ks) mods *> pure NoCatch
        -- Else, if it is a release of some button held before me, just ignore
        | otherwise                       -> go ks mods *> pure NoCatch

    -- Behave like a tap: tap the button `t`, mod as needed, release processing
    doTap :: MonadK m => [Keycode] -> m Catch
    doTap [] = tap t *> hold False *> pure Catch
    doTap mods =
      case (head mods) of
        KeySlash    -> tap (modded KeyRightShift t) *> hold False *> pure Catch
        KeyCapsLock -> tap (modded KeyLeftCtrl t) *> hold False *> pure Catch
        _           -> tap (modded (head mods) t) *> hold False *> pure Catch

    -- Behave like a hold is not simple: first we release the processing hold,
    -- then we catch the release of ButtonX that triggered this action, and then
    -- we rethrow this release.
    doHold :: MonadK m => KeyEvent -> m Catch
    doHold e = press h *> hold False *> inject e *> pure Catch

(note that this requires importing Data.List and adding myTapNextRelease to Joiner.hs, Parser.hs and Types.hs)

For now to keep things easy for me, I'm only applying one released modifier (for my usage it's sufficient but it should do some sort of fold applying all mods from the list), hard-coding in the slash mod as well as my capslock-as-ctrl translation, and creating a new type of button (rather than an argument for the existing button). That stuff I can certainly change later, and as it stands this all works fine for me, but it's clearly in no shape to contribute if special mods need to be hard-coded in. Is it even possible to, in this function, figure out that the release of keySlash would emit right shift?

Layer-toggling to non-existent layer should crash

Currently, it is possible to create a layer toggle button that switches to a non-existent layer. It is even possible to use this button once. Trying to access a key in the non-existent layer crashes KMonad, trying to switch to that layer again also crashes KMonad.

KMonad should simply refuse to start-up if the configuration contains a layer-switching button that points to a non-existent layer.

Modifiers behaving differently than OS in kmonad

First of all, thanks again for making this super cool project, it is very impressive and useful 😃.

Hopefully I can explain this issue properly. I am using the refactor branch now.

With kmonad disabled, and the OS (linux) handling the keyboard, if I press a modifier and key in the following order, I get the modified key. For example:

  • SHIFT is pressed
  • j is pressed
  • SHIFT is released
  • j is released

In this example, my OS will emit J. However, kmonad emits j.

This has caused me to make a lot of typos, I write c++ code and all my double colons were being typed like :; 😛. This applies to all keys (special behaviour assigned to them or not), and all modifiers (like CTRL, etc). My customary action of CTRL-S by rolling my hand from CTRL to S does not work anymore, I now have to be deliberate to keep CTRL held after I release S.

I feel like this is a product of another difference from the OS, where a modded key is emitted on press instead of on release like with kmonad.

Anyways, I hope this made sense, and that a fix is doable. Thanks!

Tap-Hold on ret not working with met

Description

If you rebind ret to use the Tap-Hold feature, the key works in very unexpected ways when pressing met (= [l,r]met). When using TH 2000 ret rctl (I chose a long time here to better observe the bug), ret seems to be triggered after the time has passed, while with TH 2000 ret \, ret is completely dead and \ works as expected after 2000ms. This behaviour seems to only occur when holding met, all other keys (in the combinations I've tried them in) seem to work just fine. It also doesn't matter if met is pressed directly or if it's in another Tap-Hold.

To Reproduce

  1. Bind something to met + ret (i.e. spawning a terminal)
  2. Use the Tap-Hold feature with ret (i.e. @rcp = TH 2000 ret rctl)
  3. Run kmonad and press met + ret
  4. Nothing will happen
  5. Hold down met and ret, depending on your choice of keys (see above) a terminal will spawn.

Files

I used the following file to test this:

INPUT = LINUX_DEVICE L64 /dev/input/event0
OUTPUT = UINPUT_SINK

@rcp = TH 2000 ret rctl
@tmp = TH 100  tab rmet

SRC
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  home end  ins  del
  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
  lctl      lmet lalt           spc            ralt rctl pgup up   pgdn
                                                         left down rght
LAYER bug
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  home end  ins  del
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc
  @tmp q    w    e    r    t    y    u    i    o    p    [    ]    @rcp
  caps a    s    d    f    g    h    j    k    l    ;    '    \
  lsft 102d z    x    c    v    b    n    m    ,    .    /    rsft
  lctl      lmet lalt           spc            ralt rctl pgup up   pgdn
                                                         left down rght

Create tap-hold-release button

So, referencing the beginning of #38 and the end of #42, it seems there is continued interest in the following style of button.

A tap-hold style button combinator that decides if it enters 'held' or 'tapped' mode based on the next release. If the first release it detects is itself, then we act as a tap button. However, if the next release we detect is of another key, then we act as held (with rollback of any events that might have occurred).

This as opposed to:

  • a tap-next: which decides on if the next event is the 'release of itself' or not
  • a tap-hold: which decides on a delay (with rollback)
  • a tap-hold-next: which is a mixture of the above two (further documented in #42)

@thoelze1 has expressed interest in trying his hand at this. I think I have an idea of how to do this but I'll let you give it a shot. As usual I am available for questions.

Just mentioning @obar as well, for notification reasons.

Trying to keep the issues organized :-)

EDIT: clarification

Add possibility to hook output events

As explained in greater detail in #58, we currently only provide hooks for input events, which makes certain decision impossible. If we add the option to hook output events as well, this opens up more design options.

Tap-hold behavior seems off in refactor branch

Alright, I switched to the refactor branch and tried it out. The fallthrough seems to work great! Thanks a lot for doing this.

However, I noticed a problem that I'm not sure comes from refactor or just this change, which is preventing me from switching to refactor.

In the old docs, it says:

The tap-hold pauses all event processing until it decides what kind of button it is, and then emits either the tap of its tap-button (when tapping) or the press of its hold button (when holding), with the release coming when the tap-hold is released again.

However, this does not seem to be the case anymore. If I press (and hold) a button with tap-hold, and then type characters (which are supposed to now be from a different layer) within the tap-hold delay, the characters from the base layer get emitted immediately.

Here is my layout for reference: https://github.com/theol0403/kmonad-layout/blob/master/refactor.kbd

Originally posted by @theol0403 in https://github.com/david-janssen/kmonad/issues/41#issuecomment-662739621

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.