Latin1 input macro

I am working on a macro – that can maybe evolve into a plugin – that can enter latin1 characters on windows. I have trouble with the unicode plugin. So I wanted to try this simpler approach.

On windows:
Hold down the left alt.
Press keypad 0
Press keypad 2
Press keypad 4
Press keypad 8
Release left alt
I get the “ø” character from the latin1 codepage.

This macro goes all the way back to my youth on DOS, where I knew the codepage by heart, so I could type many of the special characters, like german sz and all the table drawing characters.

Anyways. I am a Java guy. And I havn’t done any c++ in 20 years, so I make newbie mistakes.

I made one generic macro - that just goes crazy and gets the menu bar to blink in notepad.
I also made a hardcoded macro - to test my approach. That works, but in doesn’t just print one ø, it keeps printing until I unplug the keyboard.

I pushed my attempts to my github account.

Questions:

  1. Why does the oe() macro not stop printing øøøøøøøøøø?
  2. Can you see one or more problems with the generic latin1 macro? (input 248 for ø).

Code is inspired by the unicode plugin:

1 Like

Just found this thread. That seems to hold the solution to my infinite ø problem :wink:
I’ll just try that out. But I’d still like to feedback on the generic latin1 macro.

1 Like

So I actually got it to work. Thank you all for rubber ducking :slight_smile:

5 Likes

I am hoping that someone reads this, since I am all alone in this thread.

But it turns out that my latin1 macro only almost works.

It works in notepad, but in Outlook and IntelliJ IDEA it doesn’t work.

The strange thing is that doing the sequence hold left alt + numeric 0248 + release, works in all the programs.

I tried putting a delay(100) between everything. But it doesn’t make a difference.

Can any of you see something wrong about my macro?

 const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
  switch (macroIndex) {
    case L_AE:
      win_latin1_shift(230, 198, keyState);
      break;
    case L_OE:
      win_latin1_shift(248, 216, keyState);
      break;
    case L_AA:
      win_latin1_shift(229, 197, keyState);
      break;
   }
   return MACRO_NONE;
}

static void win_latin1_shift(int lower, int upper, uint8_t keyState) {
  bool shifted = kaleidoscope::hid::wasModifierKeyActive(Key_LeftShift)
  || kaleidoscope::hid::wasModifierKeyActive(Key_RightShift);

  win_latin1(shifted ? upper : lower, keyState);
}

static void win_latin1(int keycode, uint8_t keyState) {
  if (!keyToggledOn(keyState)) {
    return;
  }
  int digits[4];
  digits[0] = 0; // (keycode > 999) ? keycode / 1000 % 10 : 0;
  digits[1] = (keycode > 99) ? keycode / 100 % 10 : 0;
  digits[2] = (keycode > 9) ? keycode / 10 % 10 : 0;
  digits[3] = keycode % 10;
  kaleidoscope::hid::pressRawKey(Key_LeftAlt);
  delay(100);
  kaleidoscope::hid::sendKeyboardReport();
  delay(100);
  for (int i=0; i < 4; i++) {
    Key key = keypad(digits[i]);
    kaleidoscope::hid::pressRawKey(key);
    delay(100);
    kaleidoscope::hid::sendKeyboardReport();
    delay(100);
    kaleidoscope::hid::releaseRawKey(key);
    delay(100);
    kaleidoscope::hid::sendKeyboardReport();    
    delay(100);
  }
  kaleidoscope::hid::releaseRawKey(Key_LeftAlt);
  delay(100);
  kaleidoscope::hid::sendKeyboardReport();  
}
2 Likes

Have you tried it using pressKey(Key_LeftAlt) instead of pressRawKey(Key_LeftAlt)? Maybe sending the extra report would help.

2 Likes

Thank you! That did the trick.
I only had to make the change for the alt key. I left the raw for the numbers.

What is the difference between pressKey and pressRawKey? And what do you mean about the extra key report?

pressKey() causes an extra HID report to be sent after a modifier is pressed, whereas pressRawKey() just adds it to the report. Some operating systems (or programs?) seem to fail to apply the modifier to keycodes that become active in the same report as the modifier (probably applying the modifier after registering the rest of the keycodes in the report). The delay didn’t help because no reports were being sent to the host in the interim.

4 Likes

So do I need the sendKeyboardReport() if I use pressKey?

It worked for a minute there last night. But when I got to work this morning it didn’t work anymore :confused:

But manually doing the combo always seems to work, so the problem must be in my macro.

So I am going to need a little more help on how to best express alt 0248 as a macro.
This is my current version:

static void win_latin1(int keycode, uint8_t keyState) {
  if (!keyToggledOn(keyState)) {
    return;
  }
  int digits[4];
  digits[0] = 0; // (keycode > 999) ? keycode / 1000 % 10 : 0;
  digits[1] = (keycode > 99) ? keycode / 100 % 10 : 0;
  digits[2] = (keycode > 9) ? keycode / 10 % 10 : 0;
  digits[3] = keycode % 10;
  kaleidoscope::hid::pressKey(Key_LeftAlt);
  delay(1);
  kaleidoscope::hid::sendKeyboardReport();
  delay(1);
  for (int i=0; i < 4; i++) {
    Key key = keypad(digits[i]);
    kaleidoscope::hid::pressKey(key);
    delay(1);
    kaleidoscope::hid::sendKeyboardReport();
    delay(1);
    kaleidoscope::hid::releaseKey(key);
    delay(1);
    kaleidoscope::hid::sendKeyboardReport();    
    delay(1);
  }
  delay(1);
  kaleidoscope::hid::releaseKey(Key_LeftAlt);
  delay(1);
  kaleidoscope::hid::sendKeyboardReport();  
}

Thanks!

I see you changed the delay to just 1 ms. Maybe that’s too short?

I would try changing the delay to 10 or 100, but you probably don’t need any delay between pressKey() and sendKeyboardReport() calls. If that doesn’t work, you could try to make it even more like actual keypresses by sending several reports:

  kaleidoscope::hid::pressKey(Key_LeftAlt);
  kaleidoscope::hid::sendKeyboardReport();
  delay(10);
  for (int i=0; i < 4; i++) {
    Key key = keypad(digits[i]);
    kaleidoscope::hid::pressKey(key);
    for (int j=0; j < 5; j++) {
      kaleidoscope::hid::sendKeyboardReport();
      delay(10);
    }
    kaleidoscope::hid::releaseKey(key);
    for (int j=0; j < 5; j++) {
      kaleidoscope::hid::sendKeyboardReport();    
      delay(10);
    }
  }
  kaleidoscope::hid::releaseKey(Key_LeftAlt);
  kaleidoscope::hid::sendKeyboardReport();

I have no idea if that will help. I’d try this out myself, but I don’t have the necessary equipment.

I already tried 10 and 100 ms delays. That didn’t work - just made it slow and shaky. If I type fast it would mess up the ascii codes and different characters will show up!

But I’ll try the keyboard reports and see how that works.

So a keyboard report is what is sent when you hold down a key? I wonder how many is sent pr. second on a normal keyboard?

Why send keyboard reports after releaseKey(key)?

Sorry. Your code gives the same result.
I have this feeling, that this should be easy - if only I knew how a keyboard actually works…

You’re right, that shouldn’t be necessary. I’m afraid I’m out of ideas on this one.

Well - thank you for taking the time :slight_smile:

sendKeyboardReport calls Keyboard.sendReport(), which should have an explicit guard that swallows repeated calls without any changes to the report.

Right. I forgot about that check. Do most USB keyboards send HID reports on every scan cycle, even if there’s no change?

No. They do not. It results in too chatty a usb bus

So @Jesse do you have any suggestions on how to emulate the key sequence more accurately than merlin og my suggestions?
Or do you have other suggestions as to why the sequence works when entered manually, but fails as a macro?

I’m happy to check it when I have my USB sniffer out, though I don’t know for sure.

I do wonder if you can find anything in https://github.com/keyboardio/Kaleidoscope-Unicode/blob/master/src/Kaleidoscope/Unicode.cpp to try.