Generate different character on long press

Hi,

I would like to configure some keys to produce a different character when held for a certain amount of time than when pressing and releasing it normally.

Basically what AutoShift does, but I don’t want to produce a shifted, but a totally different character.

Is there a plugin that can achieve this?

Yes and no. You could use Qukeys to achieve this effect, but it’s not an intended use case. It wouldn’t be too difficult to make a custom plugin based on AutoShift that does what you want, though.

That sounds nice, but I have roughly 0 experience with C++, keyboard firmware and embedded devices. So, it will probably be hard for me.

Can you help me, what I must do and how?

Without taking a look at the AutoShift plugin, I expect that some struct (or other data structure) must be provided to configure which key should result in what other key(s). But I have no idea how to do this in C++ (and especially for an embedded device) and what the pitfalls are.

You can’t do it with Chrysalis, but if you compile your own firmware, you can follow the example Qukeys sketch, and instead of defining the alternate key as a modifier, use the Key value you want it to produce when “long pressed”.

Yes, I think I understood this. But as you said using Qukeys for that purpose was not intended and may have undesired behaviour. Also I am actually using Qukeys already and I am afraid the two different use cases could interfere with each other.

Therefore I thought about modifying the AutoShift plugin for that purpose. But I am totally lost there. I looked into other plugins how they provide such configurability, but they all do it in a different way (which is not nice even from a user-only perspective).

Qukeys:

QUKEYS(
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 1), Key_LeftGui),      // A/cmd
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 2), Key_LeftAlt),      // S/alt
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 3), Key_LeftControl),  // D/ctrl
    kaleidoscope::plugin::Qukey(0, KeyAddr(2, 4), Key_LeftShift),    // F/shift
    kaleidoscope::plugin::Qukey(0, KeyAddr(3, 6), ShiftToLayer(1))   // Q/layer-shift (on `fn`)
  )

CharShift:

CS_KEYS(
    kaleidoscope::plugin::CharShift::KeyPair(Key_Comma, Key_Semicolon),               // CS(0)
    kaleidoscope::plugin::CharShift::KeyPair(Key_Period, LSHIFT(Key_Semicolon)),      // CS(1)
    kaleidoscope::plugin::CharShift::KeyPair(LSHIFT(Key_Comma), LSHIFT(Key_Period)),  // CS(2)
  );

Chord:

  CHORDS(
    CHORD(Key_J, Key_K), Key_Escape,
    CHORD(Key_D, Key_F), Key_LeftShift,
    CHORD(Key_S, Key_D), TOPSY(Semicolon),
    CHORD(Key_S, Key_D, Key_F), Key_Spacebar,
  )

ShapeShifter:

 static const kaleidoscope::plugin::ShapeShifter::dictionary_t shape_shift_dictionary[] PROGMEM = {
  {Key_1, Key_2},
  {Key_2, Key_1},
  {Key_NoKey, Key_NoKey},
};

[…]

ShapeShifter.dictionary = shape_shift_dictionary;

And looking at the actual implementation the differences are even bigger. For someone who is not used to C++ and embedded programming I don’t know which variant to choose (and what the actual differences are and how they work).

Qukeys and CharShift were both written by me, and they’re different because Qukeys began as a third-party plugin, and I didn’t want to deal with conflicts with other third-party plugins using the same range of Key values. That’s why it’s different from CharShift, which was written and submitted as a core Kaleidoscope plugin, with its own official range in Kaleidoscope-Ranges.h. I have plans to eventually update Qukeys so that its values can be defined like CharShift’s, but I want to coordinate that change with changes to Chrysalis such that both plugins can be configured without compiling new firmware, including redefinition of full Qukeys and CharShift keypairs in EEPROM.

ShapeShifter is the oldest, and was written by @algernon. Rather than affecting only a specific entry in the keymap, it acts on any key with a specified value. This makes its dictionary simpler, but less flexible for the user.

Chord is a new plugin, written by a new plugin author, and I haven’t had time free to look at the code for it yet, so I can’t comment on the merits of the way in which its data structures are defined, except that the last example suggests that it doesn’t use a fixed-sized object, which probably means that it uses a special Key value as a separator, which means that it’s safer to define using a preprocessor macro (CHORD) to ensure that it doesn’t start reading past the end of the data structure.

I now managed to adapt the AutoShift plugin by cargo-culting the existing plugins.
As it seems to be actually useful for others, I also opened a pull request for it.