Unexpected characters using Qukeys

I’m getting some wierd behavior using the (Qukeys plugin. I have it set up so that a tap on my thumb keys emits a [{()}] character. (I’m getting the odd behavior where if i type a chorded character too quickly (like a capital letter or keyboard command) I get both the punctuation and the chorded character ((I’ve left the behavior in this post to show what (I mean.)

If I slow down my typing for these chorded characters, it works correctly. (It seems like it mostly occurs if I release the modifier key before release the character, I get both in the output. I don’t have my Qukeys configuration handy, but I can add that here tonight if its helpful. (I believe my timeout is set to 200.

Am I expecting something unreasonable from the plugin? I’m trying to replicate the space cadet plugin behavior where a tap gives the punctuation but I can still hold the key down and get the modifier.

If I remember correctly, there were a few issues fixed in Kaleidoscope reasonably recently, that affected Qukeys too. Are you running the latest firmware from git, or an older version?

I updated just on Friday, 3/29. I started from scratch (following the steps at https://github.com/keyboardio/Model01-Firmware/blob/master/README.md) since I couldn’t figure out right away how to migrate my existing firmware to the new-ish plugin architecture. Turns out all I was missing was the ::plugin:: namespace, but I had to rebuild my local github repos to make sure I wasn’t missing anything else.

You definitely shouldn’t be seeing that behaviour. I’ll look into it today. If you can share your sketch, that would help. I also recommend reporting the issue on GitHub, if you’ve got an account there.

Did you update to Kaleidoscope-Bundle-Keyboardio’s master branch, or to Kaleidoscope’s master branch? There are some big changes in the latter than have not been updated in the former yet.

That said, I have so far been unsuccessful at reproducing this bug in either case. I’m probably going to need more information in order to sort this one out.

I’m speculating that this is being caused by interaction with another plugin, possibly due to suboptimal plugin hook ordering.

Thanks. I can reproduce the problem now, and I know what’s going on (but not yet all the details). It’s not that Qukeys is sending both the modifier and the parenthesis character – the problem is rollover from a mod-flagged key (LSHIFT(Key_0)) to a normal key (Key_Q). So, Qukeys is doing what it ought to, but Kaleidoscope isn’t suppressing the shift modifier flag when the Q is pressed. This also happens when rolling over from one of the curly-brace keys on the FUNCTION layer to any other key.

I thought we had fixed this problem several months ago, but perhaps recent changes have brought it back. :confused:

One recommendation, regarding Qukeys – it’s best to put it first in KALEIDOSCOPE_INIT_PLUGINS() (though that is not the source of the problem you were seeing.

This won’t fix the bug, but if you’re in the habit of (nearly) simultaneously releasing the modifier key and the modified key, you should probably set the Qukeys release delay to some non-zero value, like so:


That specifies a 20ms “grace period” window after a Qukey is released. If a subsequently-pressed key is released within that window, Qukeys will interpret that as the user intending to get the alternate (i.e. modifier) keycode. The danger is that you might get the alternate keycode when you intended to get the primary one when typing fast, so I wouldn’t recommend setting it to anything higher than ~25ms (and even that is probably pushing it).

1 Like

I made the recommended changes just for good hygiene’s sake, and as you said the issue persists. One thing I’m noticing that I can’t explain is when I’m in the MACOS layer and hit Cmd+A (where Cmd is a Qukey mapped to {), I’ll sometimes get “{A” when it doesn’t select all. I don’t quite understand why the A is capitalized, since I’m not involving a shift key.

When you release the qukey first, it becomes {, which is generated by shift + [. While that key is still in effect, including the shift, the A keycode is sent, so the host produces a capital letter A. The fact that you were getting capital letters with the (/shift qukey was coincidental — the shift came from the (, not the qukey’s alternate value.

I’m having a hard time figuring out a way to fix the bug that you’ve uncovered (short of a wholesale rewrite of Kaleidoscope…), but assuming I can, what Qukeys would be producing in these cases is still not what you intend. Rather than {A, you would get {a; you would not be getting cmd + A, because Qukeys determines the value of the key based on the order in which the keys are released.

You can try bigger values for Qukeys.setReleaseDelay() — the maximum is 255ms — but you might find that you then get unintended alternate keycodes (i.e. modifiers), which is generally more dangerous than unintended primary keycodes. This is a fundamental limit of this type of dual-purpose key; in order to produce reliable output, it needs clear inputs. Sadly, for people who regularly roll over from modifiers, rather than holding them until after the modified key is released, Qukeys may not be able to give them the functionality they want.

@pian0 – I’ve submitted a PR that should fix the bug (with the caveat that it will most likely not fix the problem that you’re having):

[Edit: That PR has now been merged into the master branch of Kaleidoscope.]

I’m trying to get my environment set up to build with the fix, but I’m a little confused with which repos do what. After not seeing any changes in the remote repository I already had, I cloned the Kaleidoscope-Bundle-Keyboardio and Kaleidoscope bundles and symlinked them into my Arduino/hardware/keyboardio directory. If I do make flash from inside my Model01-Firmware folder, will those get picked up?

You should just clone the Kaleidoscope-Bundle-Keyboardio repository (recursively), and set it up so that Arduino can find it. One of that repository’s submodules is Kaleidoscope (in avr/libraries/Kaleidoscope). Within that directory, a git checkout master will bring it up to date.

1 Like

I got the latest and the bug where the shift modifier would carry over is fixed, but as you said, rolling over modifiers still produces undesirable results. I think I only switched to Qukeys in the past because I thought SpaceCadet was dead, but I think I got confused by its repo being archived and I hadn’t figured out how to navigate the merged repo. I found the new SpaceCadet home though and I’m back in business! Based on the Qukeys description, it sounds like it’s designed to prioritize the tap where SpaceCadet prioritizes holding the key.

Thank you very much for your help!

You are exactly correct about the difference between SpaceCadet and Qukeys. SpaceCadet is for adding a secondary function to modifier keys, and Qukeys is for adding a secondary function to other keys (e.g. home row keys). Qukeys can be used where you would use SpaceCadet, but depending on one’s typing habits, it might be unsuitable. (SpaceCadet, on the other hand, would be a total disaster on the home row for touch-typists.)

I think someone asked a long time ago if the release delay could be configured with different values based on the key. I didn’t think that would really be worthwhile, but now I can see a clear use for it — keys that are meant to serve primarily as modifiers should have a very long release delay, or even better, I could treat the maximum value as special, and have qukeys immediately enter their alternate state when rolling over to another key. Maybe even better, the release delay could get longer the longer a qukey is held…

This conversation has given me some interesting ideas — thanks!

1 Like

I run into the rollover problem with Qukeys pretty constantly. I use the thumb clusters for SpaceCadet-like behavior. I can’t use SpaceCadet itself, because it doesn’t allow me to use the modifiers and the tap behavior in a single chord (e.g., I have “Ctrl-]” set to my tmux prefix key, which requires holding left-control and tapping right-control at the same time).

The behavior is consistent: I always get the tapped version of the key, followed by the modified version of the subsequent character.



    (Key_Escape,      Key_1,         Key_2,       Key_3,      Key_4, Key_5, Key_LEDEffectNext,
     Key_Backtick,    Key_Quote,     Key_Comma,   Key_Period, Key_P, Key_Y, Key_Tab,
     Key_PageUp,      Key_A,         Key_O,       Key_E,      Key_U, Key_I,
     Key_PageDown,    Key_Semicolon, Key_Q,       Key_J,      Key_K, Key_X, Key_LeftGui,
     Key_LeftBracket, Key_Backspace, LSHIFT(Key_LeftBracket), LSHIFT(Key_9),

     LockLayer(EMOTES), Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
     Key_Enter,         Key_F, Key_G, Key_C, Key_R, Key_L, Key_Slash,
                        Key_D, Key_H, Key_T, Key_N, Key_S, Key_Minus,
     SYSTER,            Key_B, Key_M, Key_W, Key_V, Key_Z, Key_Equals,
     LSHIFT(Key_0), LSHIFT(Key_RightBracket), Key_Spacebar, Key_RightBracket,

Qukeys setup:

  QUKEYS(kaleidoscope::plugin::Qukey(0, 3, 7, Key_LeftShift),
         kaleidoscope::plugin::Qukey(0, 3, 8, Key_RightShift),
         kaleidoscope::plugin::Qukey(0, 0, 7, Key_LeftControl),
         kaleidoscope::plugin::Qukey(0, 0, 8, Key_RightControl),
         kaleidoscope::plugin::Qukey(0, 2, 7, Key_LeftAlt),
         kaleidoscope::plugin::Qukey(0, 2, 8, Key_RightAlt),
         kaleidoscope::plugin::Qukey(0, 2, 9, Key_RightGui));

Given the above, it is frequently the case that when I type a capital letter I, I’ll get the key sequence “)I”. IOW, the tapped right shift, plus the shifted letter I.

It seems like the easiest course of events would be that, for certain keys, if a modifier is being held and any key is pressed down while that key is held, Qukeys will always act like the key is held rather than tapped. I can see this being a problem for people who use Qukeys on the home row, and primarily roll over when typing quickly, but I’d rather not have to deal with heuristic timings which you seem to be working towards in your other recent post; I know how I want these keys to act, so I’d rather just set a flag on the Qukey definition that says “rollover is/isn’t wanted here”.

I’ve got an idea for that in the works, too. If you’re interested, read the section titled “A related problem” in my latest post in that topic.

Sigh. Even though I read that post at least three times, apparently my brain didn’t register that section properly. That does sound exactly like what I want.