New plugin: Qukeys (yet another SpaceCadet/DualUse-type plugin)

Excellent. Sorry about the bug being there in the first place.

I’m using a PR because I want to be able to provide the fix for other people to test out (and discuss) before merging it into the master codeline.

I’d just been banging on about using OneShot and Qukeys in this post Top 5 plugins or macros? and thought it not unreasonable to make a link to it from here, but also to share the details of my own successful Qukeys/OneShot use.

I configure the home row keys (both sides) to be Qukeys thus:

  QUKEYS(
    kaleidoscope::Qukey(0, 2, 1,  Key_LeftGui),
    kaleidoscope::Qukey(0, 2, 2,  Key_LeftAlt),
    kaleidoscope::Qukey(0, 2, 3,  OSM(LeftShift)),
    kaleidoscope::Qukey(0, 2, 4,  Key_LeftControl),
    kaleidoscope::Qukey(0, 2, 11, Key_LeftControl),
    kaleidoscope::Qukey(0, 2, 12, OSM(LeftShift)),
    kaleidoscope::Qukey(0, 2, 13, Key_LeftAlt),
    kaleidoscope::Qukey(0, 2, 14, Key_LeftGui)
  )

But you’ll see I also set the d and k keys (QWERTY) to be OneShot modifiers - LeftShift, to be precise.

The aim was a common one; fast typing but keeping movement from the home rows at a minimum. Prior to getting my Keyboardio I’d always used Sticky Keys set at OS level, and I thought this would be something that I’d always use, but by having all the modifiers on the home row, chording is no longer the strain it once was and I quickly realized that I could dispense with Sticky Keys (which, despite the huge benefits, also came with a fair few annoyances). The Shift key is different though just by virtue of the sheer frequency of its use. Typing slowly, it’s no problem to press and hold k (bound to the alternate Qukey of LeftShift), tap e, and then release k, in order to type an ‘E’, say, but this really slows you down and feels very ‘clunky’ when trying to type faster. So this is where OneShot comes back in in all its glory as a more configurable version of Sticky Keys.

Timings are important here: typing at normal speed you want all the keys to give only their primary keycodes. Holding any of the home row keys will give their alternate keycodes. But then you want something in between the tap and the hold to give you the OneShot modifier lurking underneath the Qukey. I’ll call this between-hold-and-tap duration the ‘long-tap’, because it should be ideally closer to a tap than a hold.

So, your mileage would definitely vary, but for me, this works very nicely:

Qukeys.setTimeout(150);
OneShot.time_out = 300;
OneShot.hold_time_out = 500;
OneShot.double_tap_sticky = false;

The default setting for Qukeys.setTimeout is 250 ms, so I’ve lowered that a little but without problem. The reason I lowered it is because I want the d and k keys to descend into their underlying OneShot nature as quickly as possible but without affecting the use of the other Qukey home row modifier keys should I tap another key before releasing one of these Qukeys (which could have non-amusing consequences).

The OneShot.time_out = 300; setting is very different from the default setting of 2500 ms, but this is absolutely what I want for normal typing. When one of these OneShot shift key modifiers is in operation I only want it to remain sticky for however long it takes me to go from releasing said OneShot/Qukey and pressing the next key, which would typically yield the desired capital letter or symbol. I expect for many this timeout could kick in even sooner.

The OneShot.hold_time_out = 500; setting is also different from the default 200 ms. I’m not entirely certain whether this matters when used in conjunction with a Qukey. I set it quite high, but I don’t doubt that if I’m key-chording my way outta somewhere with a Ctrl-Shift-q, I still end up outta wherever despite holding the Shift for longer than half a second. In any case, the main point would be that if I ever press the d or k key for anything longer than a tap I want a Shift whether it times out after 200 ms (after a long-tap), or times out immediately after release (for a ‘hold’).

I set OneShot.double_tap_sticky = false; as I imagine it would be tricky getting this to work appreciably well, but the truth is I’m not even brave enough to try!

Anyway, in summary for a OneShot/Qukey Shift modifier, what I’ve found to work harmoniously:

  • for ‘key down’ duration < 150 ms : you get the primary keycode
  • for ‘key down’ duration > 150 ms : you get the alternate keycode

Upon release of such a key:

  • after < 300 ms : the Shift modifier is ‘sticky’.
  • after > 300 ms : the Shift modifier times out and subsequent key-presses will be unmodified.
3 Likes

One thing to note: when the qukey times out (or its state collapses from a release event), that’s when the timeout for the OSM begins. So if you press D, you’ll have to hold it for ~450ms to get the OneShot modifier to time out.

1 Like

I am trying to figure out how to use qukeys, so I thought I’d toss in some of my initial pain points.

First: the documentation is pretty spare, and seems incorrect? It mentions KALEIDOSCOPE_INIT_PLUGINS, which does not seem to be defined, and the example code does not seem to include it.

Second: searching this forum doesn’t yield any other reference to layer-row-column counting. Is the thumb cluster row 4? If i wanted to qukey the first and last entries in that cluster (the ctrl keys in the default layout), would it be 0, 4, 0 and 0, 4, 7?

Third: do I have to do anything in the base keymap when using qukeys (besides setting the tap action there)? The demo has a bunch of extra stuff on the right side of the base layer, and i cannot tell if that’s needed; it doesn’t seem needed.

Finally, how do you just activate the plugin? I don’t want to bind a key to toggle. I think it’s activate(), but that’s from reading the source code.

My goal is to just bind two of the thumb cluster keys to enter on press and modifier on hold (either ctrl or shift, depending on which feels most natural).

A gist to my keyboardio layout. It’s pretty wordy, based on the default firmware setup. This builds and uploads, but the shift keys don’t act like shift keys ever, they’re just enter keys.

You are absolutely right that the documentation is lackluster, and I’m sorry about that. I’ll see if I can help you with your sketch first.

  1. If you’re using Kaleidoscope from git, it would be best to upgrade by switching from Kaleidoscope.use() to KALEIDOSCOPE_INIT_PLUGINS() (and possibly other changes. Alas, I’m not sufficiently expert in the specifics to provide much help with that, but @algernon probably can do so.)

  2. Plugins hook functions get called in the order in which they are declared in Kaleidoscop.use() or KALEIDOSCOPE_INIT_PLUGINS(). Qukeys works best when it appears first in that list, or near the top, anyway.

  3. The thumb keys are not, alas, in row 4. In fact, there is no row 4. The two sets of thumb keys are actually columns 7 & 8. On the left side, I believe they’re rows 0-3 (left to right), and on the right, I think they’re rows 3-0 (in both cases, row 3 is closest to you — someone please correct me if I’m wrong).

  4. The good news is that with the relatively straightforward configuration you want, you don’t need to worry about the obscure coordinate system used by full Qukey objects; the following entry in the keymap should work for a shift/enter key:

SFT_T(Enter)

That’s the old DualUse syntax, and defines a key that will be Key_LeftShift when held, Key_Enter when tapped. As long as you don’t need a separate Key_RightShift, this should work fine.

Last, if you could open issues against the Kaleidoscope-Qukeys git repository about specific shortcomings in the documentation, that would help us to get it up to snuff sooner.

Wow, yeah. SFT_T and CTL_T are all I really need right now- this way I can use some of the old keymap from my ergodox (I had shift and control on the leftmost column and a shift where the - is on a keyboardio). But all i have to do now is hold those keys down for a little bit and they behave the way my fingers want them to.

I’ll write up an issue, and maybe even pr the docs, once I figure out what is going on. Thanks for the assist!

1 Like