I didn’t find the time yesterday to elaborate on my idea for the possible improvement(s) to Qukeys that constitute the raison d’etre of this project, so I’ll try now.
The Qukeys rollover problem
When I first wrote Qukeys, I assumed that people ~always hold modifiers for the full duration of the modified keypress (as I do). In other words, to send ctrl
+ S
, I would press ctrl, press S, release S, then release ctrl. This is how Qukeys determines which state a qukey ends up in – by delaying both keypress events until one of them is released.
I then learned that my assumption was faulty, and there are plenty of people who frequently roll over from modifiers to other keys (i.e. press ctrl, press S, release ctrl, release S). Some people tend to release the two keys simultaneously, which results in a race condition. My solution was to introduce a configuration parameter, allowing the users to select a “grace period” for qukey release, so that if the S in the above example was released just a few milliseconds after the modifier, it would be treated as if it was released first.
That grace period idea helped, but it also made it possible for very fast typists to get unintended modifiers if they set up home-row qukeys. Typos from unintended letter keys can be frustrating, but unintended modifier keys have a much greater potential for destruction, so I always caution people to keep the release delay parameter set fairly low, and some users haven’t been able to find a setting that works well enough.
A new solution (or two)
It occurred to me after a recent discussion that I was not using all of the input data available, and that I might be able to do better. In a rollover situation, there are four points in time that can be measured:
- qukey press time
- other press time
- qukey release time
- other release time
…but I was only using two of them (the two releases) to decide whether the qukey should take on its primary or alternate Key
value. In general, my goal with this research project is to get a data set showing how people use modifiers in combination with other keys – particularly when they roll over, and try to find the best algorithm to use all the available information to produce the intended output.
Specifically, I have one idea that I want to test, using just three of the timestamps above. This idea is to compare the duration of the overlap (between points 2 & 3, when both keys are held) to be at least x percent of the total duration of the second key press (between points 2 & 4). This would make the effective release delay dynamic, so it would be longer or shorter depending on how long the two keys overlap. I’m hoping that this will produce better results than the fixed-length release delay, and as a side benefit, it’s actually simpler in the code.
Of course, that only uses three of the timestamps available, and it’s possible that, for people who regularly roll over from modifiers (rather than those that release the two keys ~simultaneously), it might not provide a clear distinction between typing overlap and modifier use. In that case, there might still be a pattern that can be used based on the relative timing of the two key presses, or the duration that the first one is held, as well. And for people who really do roll over when using modifiers in the same way they do when typing normally, there still might be one possible distinguishing factor I could find by looking at the key press(es) preceding the modifier – I’m guessing that it’s more likely to have a gap before pressing a modifier key than a printable character key, though that would probably be somewhat less true of qukeys on the home row, especially ones with an alternate Key
of shift
.
A related problem
I’ve got one other Qukeys improvement in the works, which is related. A few times, people have reported rollover-related errors when using qukeys for what would normally be modifier keys (e.g. the thumb keys on the Model01). In these cases, I have usually recommended SpaceCadet instead, because it is intended for the purpose (using what is normally a modifier as a printable character if it is tapped alone), whereas Qukeys is the reverse (using printable character keys as modifiers if chorded). However, as a result of the release delay conversation, it occurred to me that a very small change would allow Qukeys to do both.
The idea is that if a qukey’s primary Key
value is a modifier (including layer shift keys), it will be treated like a SpaceCadet key instead. It will always produce that modifier, unless it is tapped on its own. In other words, if there’s any rollover from a shift
/ X
qukey, it will be shift
, but for a X
/ shift
qukey, its value will depend on release order and timing.
This might be useful because Qukeys offers more flexibility than SpaceCadet in defining which keys are affected. With SpaceCadet, if Key_LeftShift
produces (
on tap, every Key_LeftShift
will do so, regardless of where it is in the keymap. Qukeys specifies the exact coordinates of its keys, so you could have two different Key_LeftShift
keys (probably on different layers), one of which has an alternate key value, and one that doesn’t.
One last note: If I can get a variety of contributors, I might even be able to produce a script that can be run on a future version of the data file produced by RolloverLogger that would recommend certain settings for the users to minimize Qukeys errors.
Again, I will be very grateful to anyone who helps me out by contributing some typing data so I will be able to make some better choices in the design of Qukeys. Even if you’re not a Qukeys user, it could still be very helpful to get typing rollover data.