Macro triggering a OneShot

Thought it might be worth having a separate thread for this particular topic, since it’s been brought up more than once (Combining macros with modifiers and Thumb key choices) and though people think it should be able to be made to work, I haven’t been able to make or find a working example.

Also because it would be so damn useful as a macro if you can learn to use it, doing three very frequently combined keypresses and avoiding errors where you hold shift for too long and capitalise too many letters.

So the idea is to have a key that avoids having to press spacebar and shift at the end of a sentence or paragraph, so a macro which types [whatever punctuation you are using], spacebar and then adds a oneshot shift at the end - the last bit obviously being the hard part. Wish I could get this working myself, but there is obviously a lot to learn beyond the readmes of the macros and I don’t really know where to find out more.

macro_t macroPunctuationSpaceOneShot(Key punctuation) {
  handleKeyswitchEvent(punctuation, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();
  handleKeyswitchEvent(punctuation, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();

  handleKeyswitchEvent(Key_Space, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();
  handleKeyswitchEvent(Key_Space, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();

  handleKeyswitchEvent(OSM(Key_LeftShift), UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
  handleKeyswitchEvent(OSM(Key_LeftShift), UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);

  return MACRO_NONE;
}

Something like this may work, but I haven’t tested. Call this from macroActions like this:

case M_PERIODSPCOSS:
  if (keyToggledOn(keyState)) {
    return macroPunctuationSpaceOneShot(Key_Period);
  }
  return MACRO_NONE;

Hope this helps!

1 Like

Thanks @algernon

I’m guessing by the first line and the “return macroPunctuationSpaceOneShot(Key_Period);” that your idea is setting the macro to run whenever the key for that punctuation is used? I would instead want a dedicated key for M(MACRO_PUNCTUATION) somewhere in the keymap so that it triggers the macro, and on another layer in the same spot, there would be the key_punctuation mapped so that it could be used whenever I wanted the character without the macro.

In any case, I would have thought it would be easier to do a macro like that without binding it to whichever punctuation key you’re using, especially ? and ! which don’t have a key_punctuation?

In any case, I know where I’d put the part calling from macroAction, but I’m not really sure where I would put the text in your first quote up.

Aha! I think I understand what you want: press the macro key, then the punctuation key, and end up with the punctuation, space, and one-shot shift? This way you could just press the punctuation key without the macro key to get its normal behaviour.

In that case, the Leader plugin can help. You set up the “macro” key as the leader, and configure it so that LEAD ., LEAD !, LEAD ?, etc, all do the necessary dance (somewhat similar to the function I posted before). If I understood your desire correctly this time, let me know, and I’ll cook up some code to accomplish it =)

Anywhere before macroAction. You can even rename the function to something else, there’s nothing special about it.

I still just want one key for each punctuation macro to do the entire macro.

I may be completely off about what your earlier code would do, so just bear that in mind when you read this:

I am getting the impression that your code is intended to tell keyboardio “hey keyboardio, when Llamalland presses the key mapped as Key_punctuation, what he really wants is MACRO_PUNCTUATION, so can you play that instead?”. But what I want is to just put in the keymap M(MACRO_PUNCTUATION), one for each punctuation mark (and another for paragraphs, but that’s beside the point), have them directly call the macros.

That way, I can have the original key_Punctuations mapped to the corresponding spots on another layer (probably something resembling the default function layer), so that I can use those symbols without the macro when I access that layer.

Okay. Then my original code is what you want, it makes exactly this scenario possible. Write M(M_PERIODSPCOSS) in your keymap for the period-variant, others for any other punctuation. You can extend the switch statement in macroActions to include them too (using abbreviated macro names now, because I don’t want to type them all out):

case M_SPEC_PERIOD:
  if (keyToggledOn(keyState)) {
    return macroPunctuationSpaceOneShot(Key_Period);
  }
  return MACRO_NONE;
case M_SPEC_QMARK:
  if (keyToggledOn(keyState)) {
    return macroPunctuationSpaceOneShot(LSHIFT(Key_Slash));
  }
  return MACRO_NONE;
1 Like

(apologies for the lack of explanations and just dumping code - I’m at work and don’t have the time to explain what the code does.)

1 Like

No worries at all, thanks for helping as much as you are while at work!

So I added this just before macroAction:

macro_t fullStopMacro(Key Period) {
handleKeyswitchEvent(Key_Period, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();
handleKeyswitchEvent(Key_Period, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();

handleKeyswitchEvent(Key_Spacebar, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();
handleKeyswitchEvent(Key_Spacebar, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();

handleKeyswitchEvent(OSM(Key_LeftShift), UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
handleKeyswitchEvent(OSM(Key_LeftShift), UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);

return MACRO_NONE;
}

and I put this in macroAction:

case MACRO_FULLSTOP:
if(keyToggledOn(keyState)){
return fullStopMacro(Key_Period);
}
return MACRO_NONE;

And as is, it errors with

invalid conversion from ‘macro_t {aka unsigned char}’ to ‘const macro_t* {aka const unsigned char*}’ [-fpermissive]

And when I fix what I assume was a typo earlier in the first line and change (Key Period) to (Key_Period), instead I get

cannot convert ‘Key’ to ‘macro_t {aka unsigned char}’ in initialization

As algernon seems to be busy…

That won’t work. You need to replace

macro_t fullStopMacro(Key Period) {

with

macro_t fullStopMacro(Key punctuation) {

as algernon wrote in his original macro function. Else the argument Period of fullStopMacro is unused.

Also

handleKeyswitchEvent(Key_Period, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();
handleKeyswitchEvent(Key_Period, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
kaleidoscope::hid::sendKeyboardReport();

must then be replaced with

handleKeyswitchEvent(punctuation, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();
  handleKeyswitchEvent(punctuation, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED);
  kaleidoscope::hid::sendKeyboardReport();

Unfortunately, I cannot help you with this without seeing your overall code.

My bad, the function should read const macro_t *fullStopMacro(Key punctuation). As in,const macro_t * instead of just macro_t.

That helps, but now I just get a nondescript message saying that it couldn’t compile. Will have another crack in the morning, and if that doesn’t help, go blank slate and just add oneshot and see if it works. Thanks again!

Perhaps its size is too big… if you are using the command-line, try make VERBOSE=1.

I don’t know how to use the command line, but I do have verbose feedback turned on via file-preferences. It gives me all the usual stuff about libraries that I’d see in a successful compile, then this:

exit status 1
Error compiling for board Keyboardio Model 01.

Can you upload your sketch somewhere (GitHub, maybe)? I’d take a look.

Will do when I get home from work, thanks!

That’s my current sketch with what I’ve tried so far for the macro - it works fine when the new bits are commented out and the replacement bits are uncommented back in. It contains Qukeys which I understand has some issues currently working with OneShot, so I transplanted what I used for the macro into the default keyboardio firmware to isolate it. Same issues:

Aha!

My bad: OSM() adds a Key_ prefix, so in the new function, you need to write OSM(LeftShift) instead of OSM(Key_LeftShift). With this change, the sketch compiles for me. (Haven’t tested if it works, but it compiles, that’s halfway there at least!)

1 Like

Oops, I actually knew that myself! Compiles here too now, but there’s no OSM functionality yet on testing.

Hrm… try OneShot.inject(OSM(LeftShift), IS_PRESSED); OneShot.inject(OSM(LeftShift), WAS_PRESSED); then, instead of the handleKeyswitchEvent lines that deal with oneshot…

Same result unfortunately.