Open MaxGyver83 opened 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.
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?
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?
Hey @MaxGyver,
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?
What does evtest
say on a hardwired German keyboard when you press shift
and then 3? What does it say for ö?
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.
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.
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 :-)).
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)!
What does evtest say on a hardwired German keyboard when you press shift and then 3? What does it say for ö?
setxkbmap us
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 ------------
setxkbmap de
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
).
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
?
@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?
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! :-)
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)
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.
Something like QMK's keymap extras aliases can help to reduce localization confusion
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).
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!?
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.
Perfect!
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.
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 ¯_(ツ)_/¯
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.
@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 :-).
I wouldn't autodetect it, I'd just make it an extra configuration option, where you could put something like
localization de
in thedefcfg
. 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)?
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 "ä".
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 thea
key has a second function (tap-hold-next-release
or similar), I have to dopS pa ra rS
(releasea
beforeshift
). This doesn't surprise me becausea
won't be ana
until I release it (when I usetap-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.
@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:
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?
@vherrmann We talked about this here. David said he wants to support it.
@MaxGyver83 I got confused with the both issues D: @jchtt
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.
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
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.
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 `)
)
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?
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.
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 stacki 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 defaultdo you think it makes sense to explore this, or not so much?
I think this would be a great solution...
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
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: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 withshift+RightArrow
anymore (not vim). Orshift
+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.
Ideas
1. No custom shift layer: Define combinations like
S-2
indefsrc
I thought I was clever and tried to do this:
But that's not allowed.
2. Define a custom shift layer and map both that layer and
shift
to the shift keyThe good: This works for keys outside of
defsrc
(likeshift+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 fortap-hold-next-release
onlyI 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 bysetxkbmap
.)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!?