Trying to understand key flags and onKeyswitchEvent()

(tiltowaitt) #1

In onKeyswitchEvent(), how does the mapped Key's .flags variable work in the following situations?

  1. Key toggled down, no modifiers
  2. Key toggled down, shift already active
  3. Shift key toggled down

It seems to me that in cases 2 & 3, if(mapped_key.flags & SHIFT_HELD) should return true, but that doesn’t seem to be the case—at least, not reliably so.

(Gergely Nagy) #2

SHIFT_HELD is only put in flags if the key in question is LSHIFT(Key_Something). Otherwise Shift is just a regular key held together with the rest. Well, mostly… we do send modifiers in a separate part of the report, but if shift is held, that does not appear in other keys’ .flags.

.flags is there to differentiate between normal keys and special keys that are only meaningful to the keyboard, such as the modifier-augmented ones, mouse keys, macros, layer keys, and so on.

(tiltowaitt) #3

I see. If I want to know if any modifier is being held, what would be the best/simplest way to do so? Currently, I’m just using wasModifierKeyActive() a bunch of times, which seems inefficient.

(Gergely Nagy) #4

While not a particularly nice or recommended API, you can look at Keyboard.lastKeyReport.modifiers. If it is non-zero, then the previous report cycle had modifiers. You can also look at Keyboard.keyReport.modifiers for the current report, but depending on where the scanner is in the scanning process, this might not be entirely up-to-date.

Can you file a bug on Kaleidoscope, requesting a proper API to discover all held modifiers?

(tiltowaitt) #5

Can do. If it’s just going to follow the pattern of the existing wasModifierKeyActive() function, I can also submit a PR (sometime this evening).

EDIT: Also, how stable is the order of the bitmap in Keyboard.lastKeyReport.modifiers? I ask, because I also need to find out if any modifiers other than shift are active. I can easily do this in a single line of code by applying a mask:

return Keyboard.lastKeyReport.modifiers & B11011101;  // Running off of memory; not at my computer right now

It’s kind of an icky way of doing it, but it’s certainly fast. If the positions in the bit field are likely to change, however, I won’t do it.

(Gergely Nagy) #6

I didn’t think about how it’d look, the wasModifierKeyActive() pattern seems good, and a PR would be lovely. Thanks in advance!

(tiltowaitt) #7

Cool; will do. Also, I just edited my previous post. Can you let me know if I’m doing something crazy? (This isn’t for the PR, but it’s related.)

(Gergely Nagy) #8

You can use something like this instead to make this easier:

const uint8_t modifierIndex = key.raw - Key_LeftControl.raw;
return Keyboard.lastKeyReport.modifiers & (1 << modifierIndex);

The order of modifiers is set in stone, from bit 0 to 8, it is Left Control, Left Shift, Left Alt, Left Gui, Right Control, Right Shift, Right Alt, Right Gui.

It might make sense to introduce a helper, that would build us a mask. Say, kaleidoscope::hid::modifierBitMask(Key_LeftControl, Key_LeftShift) would return (1 << 0) | (1 << 1). This is doable with a little bit of templating, but a PR without this is just as good. The intended use is:

// assuming we're in the kaleidoscope::hid namespace
// return true-ish if Ctrl+Shift was held
return lastActiveModifiers() & modifierBitMask(Key_LeftControl, Key_LeftShift);

Another option is to have #defines for the various modifiers, stuff one could OR together, but I failed to come up with a good name for those, so went with the helper instead.

(tiltowaitt) #10

Issue and related PRs are here. First time ever opening a PR, so hopefully I did everything okay.