forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix the layer-dependent modifiers handling
Closes qmk#181.
- Loading branch information
Showing
1 changed file
with
21 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the benefit-cost ratio of this change is high enough to warrant it. Here are some alternative solutions to your problems.
You can simply make any of your current modifiers that are not transparent across all your layers into weak ones so that they are automatically "released" whenever you switch layers by assigning a variant of the macro below to each of them.
Also, you can solve your problem with changing your default layer by assigning variants of the macro below to your current
DF(/*layer*/)
keys.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just feel like your patch is a little overkill, especially in the amount of additional memory it consumes.
If you want to cut down on syntax, you can define this function in your keymap file.
Then, you can give each modifier a much shorter definition like this one.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, my solution only would have worked if each of your modifiers was only visible on one layer. If you want any modifiers to be on more than one layer, you want to define them like this.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can quickly become very unmaintainable it seems. And you have to actively think about this issue when creating the keymap. I see that it might be the solution if you only need one or two such keys but I'd still rather have my patch as an option (off by default).
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just feel like my fix would take up a lot less memory than yours would. I updated it with a switch statement; see if you like it better now.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You still need to track each such situation and hand-craft your macros for each such key. A maintenance hell. I think both solutions have their merits depending on the use case. Since I have some unused RAM, I prefer mine but I understand your point.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have an idea. Instead of storing the action code for each key when it is pressed, why not just store the highest layer that was active? That way, only five bits (to store the values 0–31) need to be allocated for each key rather than the previous 16.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was one of my ideas for future improvement. I would need to move (or copy but moving would be preferable) some logic from
layer_switch_get_action
so that I can retrieve the layer number easily.Using exactly 5 bits would be tricky (aligning and such) and IMHO not worth it but a single byte is not that much worse.
I'll try to implement it in a few days.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a fairly simple way to ensure that not even three bits are wasted for each key. I might have time to implement it in a few weeks.
I imagine that
biton32(default_layer_state | layer_state)
will return the correct layer number.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is it? Bit fields with
__attribute__((packed))
or something like that? Now I'm curious.That was my first thought too but it does not take
KC_TRNS
into account.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, it's an array:
uint8_t array[5][(MATRIX_ROWS * MATRIX_COLS) / 8]
. Imagine a keyboard has eight columns and one row. The array would beuint8_t array[5][1]
. Say that a key is pressed and we need to store the layer from which the action code was read.(key.row * key.col) / 8
gives the correct row of the array to enter,[0]
. Then, we need to load each bit of the layer number into separate bytes in that row. In each one, we need to grab the corresponding bit of the layer number, shift it left(key.row * key.col) % 8
, and load it in. Does that make sense to you? If not, I can write the code that stores and retrieves the layer numbers.I realize that too. Perhaps we need to makeYeah, it might be easier just to move everything in this function tolayer_switch_get_action
return it's loop control variable in addition to the action code?action.c
so that all the data that it uses is more accessible to the other code in that file.Edit: Nobody try to make code based on this. I found some flaws in the logic that I will fix.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it should work (as long as the number of keys is divisible by 8) though I'm beginning to get worried about the performance. Though it probably won't have any noticeable impact anyway.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't matter whether the number of keys is divisible by eight. If it's not, there will just be some empty space at the left of each byte of the bottommost row of the array.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't we need to add 1 for that to work like that? It's a minor problem either way.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean?
If you really want to boost the performance of the firmware, there are a ton of ways in which it could be optimized. For example, I believe most of the code in
keymap_common.c
is just adding an extra layer of abstraction for no reason as the code inaction.c
has the ability to interpret action codes directly.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. I'm probably worrying for no reason.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan to optimize
keymap_common.c
when I have time.What were you saying about adding one?
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant the division by 8, so that we round up and not down.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are referring to the declaration of the array, correct? It seems that
[(MATRIX_ROWS * MATRIX_COLS) / 8]
does need to be changed to[((MATRIX_ROWS * MATRIX_COLS) / 8) | 1]
in order to accommodate keyboards with less than 8 keys.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now I'm no longer sure what I referred to. Too many potential off-by-ones and not enough sleep. ;)
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be good to drop support for layers 16–31 entirely from QMK. In addition to making this feature much easier to implement, it would also allow many rarely-used action codes to be repurposed. I am developing a lot of features, but there just aren't enough action codes to go around. Alternatively, we might just expand the action codes to 32 bits.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also deprecate
KC_TRNS
. There won't be much use for it if this PR gets merged.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about halving the layer count. That's not much if you consider some special purpose layers (for example I have some layers for macro recording). But maybe it would be enough in practice, hard to tell...
It would be still useful for layers modifying only the selected keys, regardless of the layer below. Additionally, I still consider this change optional.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hadn't thought of those things. I think storing the value of the loop control variable in
layer_switch_get_action
when the function terminates is the way to go.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read your discussion with @ezuk. When do you want to do the optimization? I think that the memory usage can be cut down enough that this feature can be enabled by default.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just pushed the first half. Now it's 1 byte per key.
I don't think enabling it by default would be a good idea either way. It does change the layer semantics and it may interfere with someone's setup. I know I needed to adjust one or two things in mine.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, enabling this feature would allow the rest of the code to be greatly simplified. For example,
clear_keyboard_but_mods
wouldn't have to be called every time the layer changes. Also, I have some features that will depend on this feature.c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to do your magic with 5 bits?
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! I'll send you a PR in a few days.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @vifon - backwards compatibility is crucial, let's keep this an optional feature.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vifon @ezuk Exactly what functionality is lost when this feature is enabled?
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no functionality lost here. The functionality is changed and it will surely break some more complex layouts in a confusing way if it's made a default. Enabling it in some major update would be a good idea though.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I thought. It won't break most common keymaps, correct? I'm quite confident that the programmers who have constructed more complex keymaps will eventually be able to figure things out.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some definitions of "most" and "common".
Surely they will be able to figure things out but I'd hate to debug my config only because I merged to upstream.
c248088
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think some proper documentation should keep frustration to a minimum. I just think that now that this feature can be made to use only ~5 bits per key, its benefit-cost ratio is a little too high for it not to be enabled by default.