kmonad / kmonad

An advanced keyboard manager
MIT License
4.13k stars 325 forks source link

The shift key dilemma #111

Open MaxGyver83 opened 4 years ago

MaxGyver83 commented 4 years ago

KMonad is the perfect tool for defining a custom keyboard layout that uses some extra features.

There are still some open issues for Windows (and MacOS) but in Linux everything works. There is just one pain point left. I mentioned it in #77 but this was also about Unicode support, that's why I want to elaborate on what I call the "shift key dilemma". It's about to define or not to define a "shift layer".

Option 1: No explicit shift layer

When I reorder the letters in my KMonad configuration, I don't have to care about capitalization. I'm using the option fallthrough true. So every letter gets capitalized ("shifted") automatically when I press it together with a shift key.

But there is more than letters: When I press shift plus a number key, I get whatever a US american expects to get. Like shift+2 = @. The shift layer of numbers depends on the keyboard layout set in Linux (or Windows or MacOS). For example:

    1234567890-=;',./
---------------------
US  !@#$%^&*()_+:"<>?
UK  !"£$%^&*()_+:@<>?
DE  !"§$%&/()=?`ÖÄ;:_
Neo °§ℓ»«$€„“”—̧ DY•–J

So many keys emit the wrong symbol (for me not being used to a US keyboard layout).

Option 2: A custom shift layer

The obvious fix for this is to define a "layer 2" and map it to the shift keys. Then I can define the special characters I want for all number keys. But this has a bad side effect: Every key that is not part of defsrc doesn't get "shifted" anymore. That means you can't select the next letter with shift+RightArrow anymore (not vim). Or shift + Home/End/PageUp/Tab/Backspace/F1/Pause don't work anymore.

This means you have to remap every single key you can find on a keyboard. That's doable but not very elegant.

(defsrc           lsft a 2 tab   home   F1)
(deflayer base    @l2  a 2 tab   home   F1)
(deflayer shifted XX   A " S-tab S-home S-F1)
(defalias l2 (layer-toggle shifted))

Ideas

1. No custom shift layer: Define combinations like S-2 in defsrc

I thought I was clever and tried to do this:

(defsrc        1 2 S-1 S-2)
(deflayer base 1 2 !   "  )

But that's not allowed.

2. Define a custom shift layer and map both that layer and shift to the shift key

(defsrc           lsft  a 7)
(deflayer base    @l2sh a 7)
(deflayer shifted XX    A /)
(defalias l2sh (around lsft (layer-toggle shifted) ))

The good: This works for keys outside of defsrc (like shift+home).

The bad: KMonad (or the OS) applies an additional shift to the shifted key. For example in a german layout shift+7 = /. But if you define a / in your second layer, this becomes a ? (because that's the result of shifting the / key in a US layout).

3. Leave layer handling to setxkbmap/xkbcomp and use KMonad for tap-hold-next-release only

I tried that but this causes other problems. (Like / refers to the key next to the right shift key, no matter what it's mapped to by setxkbmap.)

Other ideas?

This issue is rather about comfort or tidiness when creating a KMonad configuration, not about a bug. No need to change KMonad's code for it. But maybe there is a creative way of automatically handling the shift for all keys not mentioned in defsrc on the configuration side!?

ghost commented 4 years ago

I've been thinking about this too but concluded that the only solution would be to make KMonad more complicated (which, like you, I wouldn't like). I hope I'm wrong.

This is probably more of a big deal for people who use full keyboards. I use a small keyboard on which almost everything in the base layer is an alphabetic character anyway and so this issue almost doesn't bite me.

And there's the same issue with the control key too, of course.

precondition commented 4 years ago

The buttons in the configuration file do not actually correspond to actual symbols, do they? It's just aliases for the scan codes which just so happen to be based on US QWERTY. My KMonad file might show q and 2 but when I press those, I get respectively a and é. So managing shift pairs is just up to your xkb layout on the OS. Same goes for the shifted buttons of KMonad, M gives me ? with the Belgian layout enabled.

Am I misunderstanding the issue?

ghost commented 4 years ago

Maybe the issue is better stated like this: we might like to have shifted keys that are different from what the OS wants them to be. We can already have that, but only by redefining all the keys we use, in a new layer, even if it's only the shifted punctuation keys we want to change. Not a big problem IMO but does that help to explain the thought?

david-janssen commented 4 years ago

Hey @MaxGyver,

Diagnosis

I actually have a lot of thought about this, but the problem still isn't 100% clear for me (only about 80% :-)). Could you answer the following questions?

  1. What does evtest say on a hardwired German keyboard when you press shift and then 3? What does it say for ö?

  2. What does kmonad ... --log-level debug say about those same inputs?

My thinking is this: the problem can be happening at multiple locations, and if we want to be as 'out-of-the-box' as possible, we are going to have to invent a good way of dealing with mapping between localizations.

The above test is to see exactly how your keyboard encodes its events, i.e., if the keyboard sends a 16 for a on an English keyboard, but a 16 for ö in German, then we're going to need more than a 'shifting-layer', because the problem is already happening in how we interpret our inputs.

The reason I am suspecting this is because if you do a 'shift+2' with fallthrough, it should just be a 'shift+2', we don't ever actually remap any fallthrough events, so it should basically be a no-op, which leads me to believe that the problem occurs 'before' KMonad.

Addressing specific bits

Every key that is not part of defsrc doesn't get "shifted" anymore.

That is a very good point that I hadn't considered. That is simply unacceptable, so we will have to find some solution.

No custom shift layer: Define combinations like S-2 in defsrc

This I would really rather avoid. 1-key -> 1-button. The moment we start losing isolation and can no longer think of this as a 1-on-1 correspondence, the whole thing gets loads more semantically complex. I am confident, however, that we can solve the core issue without resorting to this.

Define a custom shift layer and map both that layer and shift to the shift key

Yeah, that also really seems suboptimal. We must be better :-)

Leave layer handling to setxkbmap/xkbcomp and use KMonad for tap-hold-next-release only

This too would be sad.

Localization based input-parser

If it turns out that your German keyboard is basically just a US keyboard, but with 'different ink on the buttons', then we will have to remap the input events ourselves, because we can't deduce what's going on from the input stream itself.

Basically, I think this means that we have to have a different set of keycode parsers and button-shortcuts for different localizations. That is to say: if you tell us that you are using a German localization, then 'ö' should actually evaluate to a keycode (because you have an actual key with that ink on it). And the little paragraph sign should evaluate to (around lsft 3) because that is how we can generate it on your screen.

This would change nothing about the internals of KMonad, only about how the configuration file gets interpreted.

In addition to that I have some ideas about improving on the configuration language in general, (like multiple named source layers, OS-dependent execution, and mini-layers, but to travel a 1000 miles you first have to take 1 step :-)).

MaxGyver83 commented 4 years ago

Maybe the issue is better stated like this: we might like to have shifted keys that are different from what the OS wants them to be. We can already have that, but only by redefining all the keys we use, in a new layer, even if it's only the shifted punctuation keys we want to change. Not a big problem IMO but does that help to explain the thought?

@eighal : Exactly! BUT I just found another problem: If we define a custom shift layer and map it to the shift key, we can't select text with the mouse with shift held down (like you do in a terminal window)!

MaxGyver83 commented 4 years ago

What does evtest say on a hardwired German keyboard when you press shift and then 3? What does it say for ö?

With setxkbmap us

Shift-3

Event: time 1601580726.232249, type 4 (EV_MSC), code 4 (MSC_SCAN), value 2a
Event: time 1601580726.232249, type 1 (EV_KEY), code 42 (KEY_LEFTSHIFT), value 1
Event: time 1601580726.232249, -------------- SYN_REPORT ------------
Event: time 1601580726.440172, type 4 (EV_MSC), code 4 (MSC_SCAN), value 04
Event: time 1601580726.440172, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1601580726.440172, -------------- SYN_REPORT ------------
#Event: time 1601580726.590488, type 4 (EV_MSC), code 4 (MSC_SCAN), value 04
Event: time 1601580726.590488, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1601580726.590488, -------------- SYN_REPORT ------------
Event: time 1601580726.649259, type 4 (EV_MSC), code 4 (MSC_SCAN), value 2a
Event: time 1601580726.649259, type 1 (EV_KEY), code 42 (KEY_LEFTSHIFT), value 0
Event: time 1601580726.649259, -------------- SYN_REPORT ------------

ö

Event: time 1601580297.980874, type 4 (EV_MSC), code 4 (MSC_SCAN), value 27
Event: time 1601580297.980874, type 1 (EV_KEY), code 39 (KEY_SEMICOLON), value 1
Event: time 1601580297.980874, -------------- SYN_REPORT ------------
;Event: time 1601580298.130629, type 4 (EV_MSC), code 4 (MSC_SCAN), value 27
Event: time 1601580298.130629, type 1 (EV_KEY), code 39 (KEY_SEMICOLON), value 0
Event: time 1601580298.130629, -------------- SYN_REPORT ------------

With setxkbmap de

Shift-3

Event: time 1601580805.475988, type 4 (EV_MSC), code 4 (MSC_SCAN), value 2a
Event: time 1601580805.475988, type 1 (EV_KEY), code 42 (KEY_LEFTSHIFT), value 1
Event: time 1601580805.475988, -------------- SYN_REPORT ------------
Event: time 1601580805.684549, type 4 (EV_MSC), code 4 (MSC_SCAN), value 04
Event: time 1601580805.684549, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1601580805.684549, -------------- SYN_REPORT ------------
§Event: time 1601580805.807392, type 4 (EV_MSC), code 4 (MSC_SCAN), value 04
Event: time 1601580805.807392, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1601580805.807392, -------------- SYN_REPORT ------------
Event: time 1601580805.839474, type 4 (EV_MSC), code 4 (MSC_SCAN), value 2a
Event: time 1601580805.839474, type 1 (EV_KEY), code 42 (KEY_LEFTSHIFT), value 0
Event: time 1601580805.839474, -------------- SYN_REPORT ------------

ö

Event: time 1601580807.300526, type 4 (EV_MSC), code 4 (MSC_SCAN), value 27
Event: time 1601580807.300526, type 1 (EV_KEY), code 39 (KEY_SEMICOLON), value 1
Event: time 1601580807.300526, -------------- SYN_REPORT ------------
öEvent: time 1601580807.412911, type 4 (EV_MSC), code 4 (MSC_SCAN), value 27
Event: time 1601580807.412911, type 1 (EV_KEY), code 39 (KEY_SEMICOLON), value 0
Event: time 1601580807.412911, -------------- SYN_REPORT ------------

Well, setxkbmap seems to make no difference.

If it turns out that your German keyboard is basically just a US keyboard, but with 'different ink on the buttons'

Yes, I think it's like that (except that a German keyboard has an additional key 102d).

MaxGyver83 commented 4 years ago

What does kmonad ... --log-level debug say about those same inputs?

 ▶ pkill kmonad && kmonad ~/.config/kmonad/vou4.kbd --log-level debug
Opening KeySink
Registering Uinput device
Running UinputSink command: "/bin/sleep 1 && /bin/setxkbmap us -option compose:ralt"
Opening KeySource
Initiating ioctl grab
Launching process: emitter_proc

--------------------------------------------------------------------------------
Received event: Press <sft>
Running hooks
Pushed layer to stack: level2
 1. level2
Base-layer: level1

Registering untimed hook: 1

--------------------------------------------------------------------------------
Received event: Press <3>
Running hooks
Registering untimed hook: 2
Emitting: Press <ralt>
Emitting: Release <ralt>
Emitting: Press <s>
Emitting: Release <s>
Registering untimed hook: 3
Emitting: Press <o>
Registering untimed hook: 4
§
--------------------------------------------------------------------------------
Received event: Release <3>
Running hooks
Registering untimed hook: 5
Emitting: Release <o>

--------------------------------------------------------------------------------
Received event: Release <sft>
Running hooks
Popped layer from stack: level2
Base-layer: level1

--------------------------------------------------------------------------------
Received event: Press <;>
Running hooks
Block level set to: 1
Registering untimed hook: 7
Registering 500ms hook: 6

--------------------------------------------------------------------------------
Received event: Release <;>
Running hooks
Emitting: Press <s>
Unblocking input stream, no stored events
Emitting: Release <s>
sTried cancelling expired hook: 6

Should I use an "empty" configuration for this test? And should I set setxkbmap de?

MaxGyver83 commented 4 years ago

@precondition :

The buttons in the configuration file do not actually correspond to actual symbols, do they? It's just aliases for the scan codes which just so happen to be based on US QWERTY.

Yes.

My KMonad file might show q and 2 but when I press those, I get respectively a and é. So managing shift pairs is just up to your xkb layout on the OS. Same goes for the shifted buttons of KMonad, M gives me ? with the Belgian layout enabled.

Do you use KMonad with a belgian layout? This might work if you don't touch the number keys in your config but if you want to redefine some non-letter characters it will be complicated. Could you share your configuration?

MaxGyver83 commented 4 years ago

Basically, I think this means that we have to have a different set of keycode parsers and button-shortcuts for different localizations. That is to say: if you tell us that you are using a German localization, then 'ö' should actually evaluate to a keycode (because you have an actual key with that ink on it). And the little paragraph sign should evaluate to (around lsft 3) because that is how we can generate it on your screen.

But then I have to use setxkbmap de, don't I? And KMonad will then internally map / to S-7 (instead of the US / key)?

but to travel a 1000 miles you first have to take 1 step :-)).

So true! :-)

thoelze1 commented 4 years ago

If we define a custom shift layer and map it to the shift key, we can't select text with the mouse with shift held down (like you do in a terminal window)!

But luckily this does have an easy fix: use something like

(around (layer-toggle shift-layer) shft)
david-janssen commented 4 years ago

But then I have to use setxkbmap de, don't I? And KMonad will then internally map / to S-7 (instead of the US / key)?

Yep. There is no way for us to change the way that the OS interprets S-7, we can only emit pS p7 r7 rS. So we can make our parsers line up with the localization expectations, but we cannot change how the computer will interpret these strings of events. (That's for xkb, or Windows, some other operating system component to decide).

EDIT added: Also, given the confirmation from evtest and kmonad that a German keyboard is only 'different ink on the buttons', I think the solution really lies in localization-dependent parsers (because a parser, in the end, is just 'ink on a kmonad button' anyways). That will solve most of these issues. Then, a second feature that will really go a long way is better support for special-characters, for those edge cases.

precondition commented 4 years ago

Something like QMK's keymap extras aliases can help to reduce localization confusion

MaxGyver83 commented 4 years ago

But luckily this does have an easy fix: use something like

(around (layer-toggle shift-layer) shft)

Yes, this makes the mouse happy :-) But this additional shift will also be applied to shift-layer (see Idea 2 in my original post).

MaxGyver83 commented 4 years ago

Something like QMK's keymap extras aliases can help to reduce localization confusion

I also thought about that.

I think the solution really lies in localization-dependent parsers

This sounds like recognizing the keyboard language automatically instead of using language dependent aliases!?

david-janssen commented 4 years ago

This sounds like recognizing the keyboard language automatically instead of using language dependent aliases!?

I wouldn't autodetect it, I'd just make it an extra configuration option, where you could put something like localization de in the defcfg. Then we adjust the parsers so that they line up with german keyboard layouts.

MaxGyver83 commented 4 years ago

Perfect!

MaxGyver83 commented 4 years ago

There is one more aspect, I haven't noticed before. When I use a custom layer 2, shift (toggling level 2) works as expected with regard to the press and release order: pS pa gives me capital A (no matter which key I release first). When I use plain shift and the a key has a second function (tap-hold-next-release or similar), I have to do pS pa ra rS (release a before shift). This doesn't surprise me because a won't be an a until I release it (when I use tap-hold-next-release). But it causes a lot of typos. I suppose that most people are used to release first shift, then a, because the right hand already moves to the next letter while a is still being pressed down (assuming you use the right shift for typing shift+a).

What I want to say: Maybe it's not a bug/problem having two types of shift keys but a feature. I'm going to use a layer-toggle level2 key (with no tap-hold-next-release keys in layer 2) for typing text and a separate plain shift key for key combinations like ctrl+shift+t.

@david-janssen : Please consider that this behavior can be a "feature" when you further improve KMonad. There might be even better solutions than mapping two types of shift keys. For example: If a chord starts with shift+letter, don't wait for releasing the letter key. If somebody wants to type shift+ctrl+letter (and ctrl is a tap-hold-next-release on another letter), they have to press ctrl first, then shift, then a letter. But maybe this would overcomplicate things.

precondition commented 4 years ago

When I use plain shift and the a key has a second function (tap-hold-next-release or similar), I have to do pS pa ra rS (release a before shift). This doesn't surprise me because a won't be an a until I release it (when I use tap-hold-next-release). But it causes a lot of typos.

You get used to it, especially if your shift key is also a modtap.

What I want to say: Maybe it's not a bug/problem having two types of shift keys but a feature. I'm going to use a layer-toggle level2 key (with no tap-hold-next-release keys in layer 2) for typing text and a separate plain shift key for key combinations like ctrl+shift+t.

If you really don't want to adapt your typing style, you can look into using caps lock for capital letters instead or a one-shot shift key (tap, i.e. press and release, the one shot shift key and the next letter you type will get shifted) although I don't know whether KMonad has that feature yet or not.

For example: If a chord starts with shift+letter, don't wait for releasing the letter key. If somebody wants to type shift+ctrl+letter (and ctrl is a tap-hold-next-release on another letter), they have to press ctrl first, then shift, then a letter. But maybe this would overcomplicate things.

I'm not sure that this is a good idea. When I want to do Ctrl+Shift, I just press and hold down the two modtap keys simultaneously. Chords that require ordered presses aren't the greatest. On my QMK keyboard, for example, I have set a layer tap key that switches on a layer with accent keys but there isn't a shift key on that layer, so if I want a capital accented letter, I first need to press and hold shift and then press and hold my layer tap. Exactly how you suggest to do for Ctrl and Shift and I must say that it's annoying. The human ability to adapt to circumstances should never be underestimated though ¯_(ツ)_/¯

MaxGyver83 commented 4 years ago

You get used to it, especially if your shift key is also a modtap.

No doubt. Shouldn't take too long.

... or a one-shot shift key (tap, i.e. press and release, the one shot shift key and the next letter you type will get shifted) although I don't know whether KMonad has that feature yet or not.

Yes, it has. For now, I have the shift keys configured being a one-shot shift (level2) when tapped and normal shift (also level2) when held down:

(defalias l2 (tap-hold-next-release 500 (layer-next level2) (layer-toggle level2)))

I don't know if I rather get used to using the classical shift keys as one-shot shift keys or if I use the tap-hold-next-release shift function on the A and the ; keys. The former can be used more smoothly, for the latter I can keep my pinkies in the home row.

I'm not sure that this is a good idea. When I want to do Ctrl+Shift, I just press and hold down the two modtap keys simultaneously. Chords that require ordered presses aren't the greatest. On my QMK keyboard, for example, I have set a layer tap key that switches on a layer with accent keys but there isn't a shift key on that layer, so if I want a capital accented letter, I first need to press and hold shift and then press and hold my layer tap. Exactly how you suggest to do for Ctrl and Shift and I must say that it's annoying. The human ability to adapt to circumstances should never be underestimated though ¯(ツ)

You are right. Probably it's a bad idea. Maybe there is a better solution.

david-janssen commented 4 years ago

@MaxGyver83 Sorry for the late reply, things have been hectic :-).

In regards to the feature you describe, I was already thinking of something along those lines. Basically a button that is aware of the output-state of the keyboard when pressed, so it can know, for example, that we are currently holding shift, and the ability to change its behavior based on that output state and whatever happens during its activation. That required a redesign of some core structure that I think I managed to complete, but now I still have to use that architecture to define this family of buttons.

It's one of those 'thinky' fun-time features I get too add when I've gotten through the slog of cross-platform support and documentation writing and such :-).

MaxGyver83 commented 4 years ago

I wouldn't autodetect it, I'd just make it an extra configuration option, where you could put something like localization de in the defcfg. Then we adjust the parsers so that they line up with german keyboard layouts.

@david-janssen : I just noticed that I can't type ä (or ö, ü) in keybr.com typing lessons when I use KMonad. Probably they expect the ä (=') key being sent. They don't understand composed characters. I'll have to switch to setxkbmap before starting a lesson until you support a German localization.

Do you still find some time for improving KMonad? I hope you are done with your relocation. Actually, have you just moved to Colombia or have you returned recently (if I may ask)?

precondition commented 4 years ago

I'll have to switch to setxkbmap before starting a lesson until you support a German localization.

@MaxGyver83 technically, there is no need to set up anything to support regional keyboard layouts. Pressing on the ; button with the german layout enabled in the keyboard/language/region settings of your OS will produce "ö" despite what the .kbd file says. The button names are just aliases for scancodes. KMonad does not send keysyms directly. If mismatched legends on keys isn't a problem for you then nothing holds you back.

I just noticed that I can't type ä (or ö, ü) in keybr.com typing lessons when I use KMonad. Probably they expect the ä (=') key being sent. They don't understand composed characters.

The issue is that most typing practice websites are not looking at the input field change, but the raw keypress events. So that's not really a KMonad problem per se. If you want to avoid that issue, either use dead keys or a layout with the desired symbol as an available keysym.

PS: I've tried to create a custom text containing accented letters on keybr.com to test compose sequences, dead keys and direct keysyms but it automatically removes them so I don't know how you managed to make keybr.com show characters such as "ä".

jchtt commented 4 years ago

Hi everyone, and thanks for developing such a great piece of software! Like @MaxGyver83, I would love to eventually use kmonad to implement my own version of a custom keyboard layout. Most important to me, however, is the tap-hold-next-release (or tap-next-release) functionality. In fact, a while back I wrote Dualkeys to give me this specific functionality in Linux, based on the same principle of filtering evdev events that kmonad uses. Compared to kmonad, it has a more limited scope (no layers, for example), is a bit more buggy, and it is slower because it is written in python, so I would love to just switch over to kmonad instead of maintaining my own software for this purpose. But writing Dualkeys made me think about some of the issues discussed in this thread, and I thought I might give you some suggestions of how they could potentially be resolved.

To consider an example, let's say we had

(defsrc a)
(deflayer default @act)
(defalias
  act (tap-next-release b lctl)
)

in our kmonad config.

1) Concerning @MaxGyver83's problem with shift:

When I use plain shift and the a key has a second function (tap-hold-next-release or similar), I have to do pS pa ra rS (release a before shift). This doesn't surprise me because a won't be an a until I release it (when I use tap-hold-next-release). But it causes a lot of typos.

While one might get used to it, I don't think this is how it should work. What happens when you input pS pa rS ra is that since the shift key is already "resolved", that is, kmonad knows what it should be, the rS event is sent out immediately, even though the a key has not been resolved to either its tap or its hold key yet. Effectively, this means that the order of key events in the output is different from the input, which I feel is almost never what you would want or expect. When kmonad is waiting to resolve the a key, say if t is just a regular key and I type pa pt, nothing is being sent out yet and key event output is on hold. I think it should be the same for events such as pS pa rS ra, that is, rS should only be sent out once the role of the a key has been resolved, and the output signal in this case should be (given the above config) pS pb rS rb.

I am not familiar with the kmonad internals but I suspect this should not be too hard to do, especially as an option, since kmonad already knows how to pause outputting key events if a key has not been resolved yet.

2) Regarding the original shift issue, while I agree that redefining every possible key is not the most elegant way to solve it, it definitely makes sense given kmonad's current logic and this approach almost allows creating a fully custom keyboard layout. It's almost because of @MaxGyver83's complaint:

BUT I just found another problem: If we define a custom shift layer and map it to the shift key, we can't select text with the mouse with shift held down (like you do in a terminal window)!

I addressed something similar in Dualkeys, but it's admittedly pretty ugly and does not quite align with the way kmonad works right now. Dualkeys listens to all input devices, including mice. If one wanted to filter all mouse signals as well, one could simply extend the redefinition of keys to all mouse keys, for example defining mouseleft -> S-mouseleft, mouseright -> S-mouseright in the shift layer. Since I did not want to capture/filter mouse events, I did something slightly different that only makes sense for modifier keys. When a tap-next-release key is pressed, it immediately emits the associated hold key, and if it is later resolved to a tap key, this modifier is lifted up again. For example, pa ra would translate into plctl rlctl pb rb. That means it is enough to listen to mouse events without capturing them, and resolve a tap-next-release key from those as well (ideally already on a down event/click, since the "twisted finger" phenomenon is unlikely to occur with a mouse). For example, pa pmouseleft would translate into plctl pmouseleft.

Note that this approach means one needs to do bookkeeping on "how often" a specific scancode is being pushed down at any given time and only send out the release signal if that number goes down to zero. In the example above, if I pressed plctl pa pmouseleft ra rlctl, I would expect plctl pmouseleft rlctl.

For point 2, I don't really think this is the way it should be implemented in kmonad. If it's fast enough to filter mouse events, that could be a clean way of doing it, though. On the other hand, for point 1, I think maintaining the event order would make a lot of sense.

MaxGyver83 commented 4 years ago

@precondition :

PS: I've tried to create a custom text containing accented letters on keybr.com to test compose sequences, dead keys and direct keysyms but it automatically removes them so I don't know how you managed to make keybr.com show characters such as "ä".

I haven't used any custom text. I just have set the language to German and the layout to Germany. Then the random words contain ä, ö, ü and ß.

@MaxGyver83 technically, there is no need to set up anything to support regional keyboard layouts. Pressing on the ; button with the german layout enabled in the keyboard/language/region settings of your OS will produce "ö" despite what the .kbd file says. The button names are just aliases for scancodes. KMonad does not send keysyms directly. If mismatched legends on keys isn't a problem for you then nothing holds you back.

Sure. It works on keybr.com when I put setxkbmap de in my KMonad config and then use y when I mean z, ; when I mean ö, [ when I mean ü, S-[ when I mean Ü and so on:

(defcfg
  ;; For Linux
  input  (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd")
  output (uinput-sink "KMonad output"
    "/bin/sleep 1 && /bin/setxkbmap de -option compose:ralt")

  fallthrough true
)

(defsrc
  grv       1    2    3    4    5    6    7    8    9    0    -    =
  tab       q    w    e    r    t    y    u    i    o    p    [    ]
  caps      a    s    d    f    g    h    j    k    l    ;    '    \
  lsft 102d z    x    c    v    b    n    m    ,    .    /    rsft
)

(deflayer level1
  grv       1    2    3    4    5    6    7    8    9    0    -    =
  tab       v    .    o    u    '    q    g    l    h    f    j    ´
  @22       c    a    e    i    z    b    t    r    n    s    @22  -
  lsft @s2  y    x    ,    [    ;    p    d    w    m    k    rsft
)

But then it will be a brainf!@# getting level 3 with all the special characters right. :wink:

vherrmann commented 4 years ago

Hi everyone, just like @MaxGyver83 I use a successor of the neo layout and would love to use kmonad to have the tap-hold-next-release functionality. I have a few suggestions, that might be really stupid or you might have already discussed them (At the moment i don't have the time to read the whole backlog): Couldn't it be possible to extend the keycodes, so that they support unicode? If QMK has Unicode support on Linux, what is the reason kmonad does not? (https://beta.docs.qmk.fm/using-qmk/software-features/feature_unicode) Would it be possible to support Unicode on Systems with Ibus?

MaxGyver83 commented 4 years ago

@vherrmann We talked about this here. David said he wants to support it.

vherrmann commented 4 years ago

@MaxGyver83 I got confused with the both issues D: @jchtt

  1. Another way to resolve problem 2 would probably be to apply the current modifier to all keycodes that fallthrough kmonad and to add an option to the kmonad configuration file, so that you can define multiple input devices.

  2. On linux a second solution could be to replace the used xkb map by an minimal layout, that hasn't got a shiftlayer, so that (around (layer-toggle shift-layer) shft) probably works.

Nah the 2nd suggestion doesn't work

bryce-carson commented 2 years ago

If we define a custom shift layer and map it to the shift key, we can't select text with the mouse with shift held down (like you do in a terminal window)!

But luckily this does have an easy fix: use something like

(around (layer-toggle shift-layer) shft)

That helped! Thanks! Pictured is my configuration now. carbon

twopwood commented 2 years ago

I just started using KMonad but so far it has been the best software remapper I have used and even has some advantages over TMK/QMK. I've been trying to set up a Programmer Dvorak layout and I was having some of the same issues that others on this thread mentioned. I cobbled together something that meets my needs so far. Basically it is Programmer Dvorak that remaps the layout back to qwerty when certain modifier keys are pressed (so my muscle memory for Ctrl-C, etc. works). Anyway this layout has solved the shift issues for me so maybe it will be useful to others. Let me know there are any ways to improve or simplify this since I'm still probably making some rookie mistakes. Thanks.

(defsrc
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12        ssrq slck pause
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  ins  home pgup  nlck kp/  kp*  kp-
  tab  q    w    e    r    t    y    u    i    o    p    [    ]    \     del  end  pgdn  kp7  kp8  kp9  kp+
  caps a    s    d    f    g    h    j    k    l    ;    '    ret                        kp4  kp5  kp6
  lsft z    x    c    v    b    n    m    ,    .    /    rsft                 up         kp1  kp2  kp3  kprt
  lctl lmet lalt           spc            ralt rmet cmp  rctl            left down rght  kp0  kp.
)

(deflayer pdvk
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12        ssrq slck pause
  $    &    [    {    }    \(   =    *    \)   +    ]    !    #    bspc  ins  home pgup  nlck kp/  kp*  kp-
  tab  ;    ,    .    p    y    f    g    c    r    l    /    @    \     del  end  pgdn  kp7  kp8  kp9  kp+
  caps a    o    e    u    i    d    h    t    n    s    -    ret                        kp4  kp5  kp6
  @lsl '    q    j    k    x    b    m    w    v    z    @rsl                 up         kp1  kp2  kp3  kprt
  @lcl @lml @lal           spc            ralt @rml cmp  @rcl            left down rght  kp0  kp.
)

(deflayer pdvk-lsft
  _    _    _    _    _    _    _    _    _    _    _    _    _          _    _    _
  ~    %    @ls7 @ls5 @ls3 @ls1 @ls9 @ls0 @ls2 @ls4 @ls6 @ls8 @ls` _     _    _    _     _    _    _    _
  _    :    <    >    P    Y    F    G    C    R    L    ?    ^    |     _    _    _     _    _    _    _
  _    A    O    E    U    I    D    H    T    N    S    \_   _                          _    _    _
  _    "    Q    J    K    X    B    M    W    V    Z    _                    _          _    _    _    _
  _    _    _              _              _    _    _    _               _    _    _     _    _
)

(deflayer pdvk-rsft
  _    _    _    _    _    _    _    _    _    _    _    _    _          _    _    _
  ~    %    @rs7 @rs5 @rs3 @rs1 @rs9 @rs0 @rs2 @rs4 @rs6 @rs8 @rs` _     _    _    _     _    _    _    _
  _    :    <    >    P    Y    F    G    C    R    L    ?    ^    |     _    _    _     _    _    _    _
  _    A    O    E    U    I    D    H    T    N    S    \_   _                          _    _    _
  _    "    Q    J    K    X    B    M    W    V    Z    _                    _          _    _    _    _
  _    _    _              _              _    _    _    _               _    _    _     _    _
)

(deflayer qwerty
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12        ssrq slck pause
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  ins  home pgup  nlck kp/  kp*  kp-
  tab  q    w    e    r    t    y    u    i    o    p    [    ]    \     del  end  pgdn  kp7  kp8  kp9  kp+
  caps a    s    d    f    g    h    j    k    l    ;    '    ret                        kp4  kp5  kp6
  lsft z    x    c    v    b    n    m    ,    .    /    rsft                 up         kp1  kp2  kp3  kprt
  lctl lmet lalt           spc            ralt rmet cmp  rctl            left down rght  kp0  kp.
)

;; Layers
(defalias
  qwe (layer-switch qwerty)
  dvk (layer-switch pdvk)
  lsl (around (layer-toggle pdvk-lsft) lsft)
  rsl (around (layer-toggle pdvk-rsft) rsft)
)

;; Modifier keys
(defalias
  lcl (around (layer-toggle qwerty) lctl)
  rcl (around (layer-toggle qwerty) rctl)
  lml (around (layer-toggle qwerty) lmet)
  rml (around (layer-toggle qwerty) rmet)
  lal (around (layer-toggle qwerty) lalt)
)

;; Shifted Dvorak keys
(defalias
  ls0 #(lsft 0)
  rs0 #(rsft 0)
  ls1 #(lsft 1)
  rs1 #(rsft 1)
  ls2 #(lsft 2)
  rs2 #(rsft 2)
  ls3 #(lsft 3)
  rs3 #(rsft 3)
  ls4 #(lsft 4)
  rs4 #(rsft 4)
  ls5 #(lsft 5)
  rs5 #(rsft 5)
  ls6 #(lsft 6)
  rs6 #(rsft 6)
  ls7 #(lsft 7)
  rs7 #(rsft 7)
  ls8 #(lsft 8)
  rs8 #(rsft 8)
  ls9 #(lsft 9)
  rs9 #(rsft 9)
  ls` #(lsft `)
  rs` #(rsft `)
)
ghost-of-freedom commented 1 year ago

i'm not sure if this is still open for suggestions, but how feasible would a construct like without-modifiers be? i imagine it could work by pushing all active modifiers to a stack, disabling them (not sure if that's possible and how, programatically send keyup perhaps?), pressing whatever is specified in the construct, and applying the modifiers back from the stack

i don't know a lick of haskell though, so i can't tell how feasible this is, and if it would require a lot of work. i believe this would allow the use of (around (layer-toggle layer) shft) with the key held down without a character from that layer being shifted, as long as it's properly aliased, like this:

(defalias lsh (around (layer-toggle shift) shft))
(defalias ob (without-modifiers [))
(defalias cb (without-modifiers ]))

(defsrc lsft a [ ])

(deflayer default
  @lsh _ _ _)

(deflayer shift
  _ A @ob @cb)

expectation is that when left shift is held, [ is inserted (instead of {). perhaps it would be good to allow to optionally specify what modifiers to disable unconditionally, and disable the active ones by default

do you think it makes sense to explore this, or not so much?

nahuel commented 1 year ago

Another drawback of using "Option 2: A custom shift layer" is that when you press shift, the layer is toggled but no shift-pressed event is sent. So, you can have a perfect shift layer defined with all the keys shifted, but if you try to use shift + mouse combinations, they will not work. For example, using a shift layer you cannot use shift+left click to select multiple mail rows on the gmail pane.

hl037 commented 2 months ago

i'm not sure if this is still open for suggestions, but how feasible would a construct like without-modifiers be? i imagine it could work by pushing all active modifiers to a stack, disabling them (not sure if that's possible and how, programatically send keyup perhaps?), pressing whatever is specified in the construct, and applying the modifiers back from the stack

i don't know a lick of haskell though, so i can't tell how feasible this is, and if it would require a lot of work. i believe this would allow the use of (around (layer-toggle layer) shft) with the key held down without a character from that layer being shifted, as long as it's properly aliased, like this:

(defalias lsh (around (layer-toggle shift) shft))
(defalias ob (without-modifiers [))
(defalias cb (without-modifiers ]))

(defsrc lsft a [ ])

(deflayer default
  @lsh _ _ _)

(deflayer shift
  _ A @ob @cb)

expectation is that when left shift is held, [ is inserted (instead of {). perhaps it would be good to allow to optionally specify what modifiers to disable unconditionally, and disable the active ones by default

do you think it makes sense to explore this, or not so much?

I think this would be a great solution...

jokesper commented 2 months ago

This can somewhat be emulated / achieved by using around-only to combine shift with the layer-toggle. The only drawback is some extra key events when pressing shifted keys there as around-only would release shift and the shifted key would be pressed