Qukeys enhancements

(Michael Richters) #1

I’ve done some work recently on Qukeys, most significantly, making it understand the same markup as DualUse for both modifiers and layers, so it can be used as a drop-in DualUse replacement.

I’ve got two other enhancements in mind, and I’m wondering how much interest there might be.

First, I’ve had one report of unexpected behaviour when releasing two keys simultaneously, where a qukey was meant to be used as a modifier. This resulted in a race condition — if the qukey release was detected first, it would send its primary (i.e. printable) keycode, but if the other was detected first, it would send its alternate (i.e. modifier) keycode. To solve this, I came up with the idea to have a configurable grace period, set to some very low value (e.g. 20ms), so if the qukey release is detected just before a subsequent release, it will still become a modifier. This should improve reliability for people who tend to release modifiers and modified keys simultaneously, but if the grace period is too long, it could produce unintended modifiers due to rollover for people who type very fast.

Second, I’ve heard that QMK “Mod-tap” keys (their version of DualUse) allow repeating the printable keycode by double-tapping and holding the key. I have an idea of how to do the same thing with Qukeys, enabling primary-keycode repeat and — on macOS Cocoa input apps — access to international characters via key-holding. The trick is to not mess up intended repeat characters while typing (double-tapping without holding), and — in the macOS case, at least — not inputting extra characters by suppressing the initial key release.

Last, it has occurred to me that Qukeys could optionally treat layer-changing keys as automatic qukeys. Any LockLayer(n) key would lock the layer when tapped, but act as ShiftToLayer(n) when held. ShiftToLayer(n) keys could also be treated the same way. This one can be done with a normal qukey definition, but not right in the keymap, so it’s not as convenient.

I’m very interested in hearing from anyone who’s interested in any of these features, or, for that matter, other features that people would like.

(Tyler Smith) #2

I would like to be able to repeat the printable keycode, if that is possible!

I think the third option might be interesting too, but I’m not sure I completely understand what you mean?

(Michael Richters) #3

My idea for “automatic layer-shift qukeys” would work like this:

Any key in the keymap defined as LockLayer(N) would work normally when tapped, but if it was held, it would become ShiftToLayer(N) until it was released. This would be somewhat similar to a OneShot layer key.

If I add this feature, it will be toggle-able.

(Florent Nicoulaud) #4

I would be interested in the feature from QMK, I already use it on my Ergodox and it’s quite useful.

The first behaviour you’re describing sounds like I might be having this issue, so I could test it and give feedback if needed.

(Michael Richters) #5

There is a PR for the simultaneous-release grace period problem. It has been tested by one person so far (see #24, but I’d be happy to get more feedback on it. I will probably merge it in to the master branch soon, but right now that PR branch doesn’t have the changes that enable the use of DualUse key definitions in the keymap as Qukeys.

(Michael Richters) #6

I plan to implement it sometime, but I’m not sure when. Are you currently feeling a need for it? If people really want this feature now, I’ll be more motivated to implement it sooner.

(Florent Nicoulaud) #7

This is my Enter key, so it’s not super needed, but sometimes I could like that :slight_smile:

(Florent Nicoulaud) #8

I’m going to test the PR and let you know.

(Florent Nicoulaud) #9

I’ve been testing PR 24 for quite some time now but it’s still not satisfactory.
I will try the new PR 35 so that I can find the correct grace period for my use.
I’ll give you some feedback when I have tested it.

(Florent Nicoulaud) #10

@merlin Do you have any idea what is the default grace period for ‘normal’ keys ? So that I could configure Qukeys to have the same period. This way, my qukeys will behave the same way normal keys do.

Thank you.

(Michael Richters) #11

There’s no need for a “grace period” for normal keys, because they start sending their keycodes as soon as the keyswitch activates. A qukey doesn’t send its keycode until either it or a subsequently-pressed key is released — which is fundamental to how they work.

For normal keys, as long as the modifier is pressed first, the order of key release doesn’t matter, because the OS suppresses repeats for ~½ second. When you type shift+s, but release shift slightly before s, this means you only get S, not Ss.

You can increase the qukeys grace period to allow for sloppiness in release order, but if you make it too big (100ms, perhaps), and you type fast, you may end up getting the opposite problem: unintended modifiers. There is fundamentally no way to guarantee that you’ll always get what you want from a qukey if you both type very fast and release modifiers before the keys you intend to modify.

(Florent Nicoulaud) #12

Thank you for the very cool explanation :slight_smile:
I guess you pointed right at my flaw, I must have the bad habit of releasing my modifier key before the modified key, that’s why I’m having difficulties with my modifiers on qukeys…

(Michael Richters) #13

Whether or not that’s a bad habit is a matter of opinion. After all, it works perfectly well on any “normal” keyboard.

If you sometimes get primary (printable) keycodes when you intend alternate (modifier) keys, you can increase the grace period timeout. If you sometimes get alternate keycodes when you intend primary keycodes, you can decrease that timeout. If, without changing the timeout value, you sometimes get both kinds of unintended keycodes, your only recourse is to change your habits, unfortunately.

It would be great if the keyboard firmware could read our minds to know what we intend, but if it could do that, we wouldn’t need the keys. :wink:

(Michael Richters) #14

There is actually one more thing that I can do that might help. I have had a request to allow per-key grace period configuration, which I have a plan to implement. So if a global grace period doesn’t work because you get both types of errors, but only one type of error on any given key, I do have a solution, but it hasn’t been implemented yet.

(Jordihs) #15

Hi Michael. I have a question about Qukeys: Can you trigger a macro, or a specific unicode input with the plugin?
I will be using a spanish keyboard layout in the OS and I’d like to trigger characters such as { } [ ] á é.
The accented vowels in this layout require pressing the ´ and then the desired key. Other symbols are triggered by holding right alt + some key.
Reading the docs, seems you can only specify a single keycode. So in principle this is not feasible with the plugin as-is. Or can you do this, for example?

kaleidoscope::Qukey(0, 2, 1, M(MACRO_ACCENT_A))

Otherwise, I am thinking of a workaround but I have no idea about its feasibility. Suppose I created my own keycode with an otherwise unused value:
#define Key_a_tilde 0xfe

And then I map that in qukeys:
kaleidoscope::Qukey(0, 2, 1, Key_a_tilde)

And then somehow I create a listener (still a noob here!) that captures my fake keycode and triggers a unicode character with no need to use a macro.

Does any approach work? Any alternative ideas?
Thanks for reading!

(Michael Richters) #16

Yes, you should be able to define both the primary and alternate keycodes as any keycode whatsoever, including macros, if you use the full Qukeys definition (like your example). With DualUse definitions in the keymap, you’re much more limited.

(Jordihs) #17

Thanks a lot. I’m assuming that you meant that this would work, right?

(Michael Richters) #18

Yes, that’s what I meant. Typing those alternate characters might feel a bit unnatural that way, though, because you’ll have to hold the key down long enough to trigger the timeout. You might want to push the timeout to a smaller value to make it more convenient, depending on how quickly you normally tap keys while typing. 100 ms might be too short, but it might work.

(Jordihs) #19

Thanks for the insights. I still don’t have the keyboardio but programming and tuning will likely be a lot of trial and error. Good tip about timeouts though. It must hit the sweet spot where it pays off compared to the two separate keypresses that it normally entails to type a vowel with a tilde.

(Jordihs) #20

Hi @merlin, I am having a compile issue with Qukeys. I am quite certain that I am up to date since I just got started today with programming, so I have pulled everything today from git. I am a coder but have no knowledge of C++.
The only thing I changed from the user guide is that I put the code at Arduino\hardware\keyboardio\avr\libraries, and with the include and the call to use &Qukeys it all compiles normally. However, I do have an issue whenever I include definitions. I tried relocating to different points in the source file, but every time I get the same error:

Qukeys.h:135:31: error: expected unqualified-id before ‘{’ token
#define QUKEYS(qukey_defs…) { \

Model01-Firmware.ino:237:1: note: in expansion of macro ‘QUKEYS’

I have tried removing my own definitions and copy pasted the example in the readme.md from your project, but it happens just the same. Do you have any advice on how to resolve this?

Here is my ino file, in case you want to take a look:
Model01-Firmware.ino (17.5 KB)

Note: I am working with the Arduino IDE on windows 10.

Thanks in advance!