src/MultiReport/Keyboard.cpp
int Keyboard_::sendReport() {
  // If the new HID report differs from the previous one both in active modifier
  // keycodes and non-modifier keycodes, we will need to send at least one extra
  // report. First, we compare the modifiers bytes of the two reports.
  const uint8_t old_modifiers = last_report_.modifiers;
  const uint8_t new_modifiers = report_.modifiers;

  const uint8_t changed_modifiers = old_modifiers ^ new_modifiers;

  if (changed_modifiers != 0) {
    // There was at least one modifier change (toggled on or off), remove any
    // non-modifiers from the stored previous report that toggled off in the new
    // report, and send it to the host.
    bool non_modifiers_toggled_off = false;
    for (uint8_t i = 0; i < KEY_BYTES; ++i) {
      byte released_keycodes = last_report_.keys[i] & ~(report_.keys[i]);
      if (released_keycodes != 0) {
        last_report_.keys[i] &= ~released_keycodes;
        non_modifiers_toggled_off = true;
      }
    }
    if (non_modifiers_toggled_off) {
      sendReportUnchecked();
    }
    // Next, update the modifiers byte of the stored previous report, and send
    // it.
    last_report_.modifiers = new_modifiers;
    sendReportUnchecked();
  }

  // Finally, copy the new report to the previous one, and send it.
  if (memcmp(last_report_.keys, report_.keys, sizeof(report_.keys)) != 0) {
    memcpy(last_report_.keys, report_.keys, sizeof(report_.keys));
    return sendReportUnchecked();
  }
  // A note on return values: Kaleidoscope doesn't actually check the return
  // value of `sendReport()`, so this function could be changed to return
  // void. It would be nice if we could do something to recover from an error
  // here, but it's not at all clear what that should be. Also note that if the
  // extra reports above return an error, there's not much we can do to try to
  // recover. We could try to send the report again, but that would be likely to
  // fail as well.
  return -1;
}
// Sending the current HID report to the host:
//
// Depending on the differences between the current and previous HID reports, we
// might need to send one or two extra reports to guarantee that the host will
// process the changes in the correct order. There are two important scenarios
// to consider:
//
// 1. If a non-modifier keycode toggles off in the same report as a modifier
// changes, the host might process the modifier change first. For example, if
// both `shift` and `4` toggle off in the same report (most likely from a
// `LSHIFT(Key_4)` key being released), and that key has been held long enough
// to trigger character repeat, we could end up with a plain `4` in the output
// at the end of the repeat: `$$$$4` instead of `$$$$$`.
//
// 2. If a non-modifier keycode toggles on in the same report as a modifier
// changes, the host might process the non-modifer first. For example, pressing
// and holding an `LSHIFT(Key_4)` key might result in `4$$$` rather than `$$$$`.
//
// Therefore, each call to `sendReport()` must send (up to) three reports to the
// host to guarantee the correct order of processing:
//
// 1. A report with toggled-off non-modifiers removed.
// 2. A report with changes to modifiers.
// 3. A report with toggled-on non-modifiers added.
Sending the current HID report to the host:
Depending on the differences between the current and previous HID reports, we
might need to send one or two extra reports to guarantee that the host will
process the changes in the correct order. There are two important scenarios
to consider.

1. If a non-modifier keycode toggles off in the same report as a modifier
changes, the host might process the modifier change first.

2. If a non-modifier keycode toggles on in the same report as a modifier
changes, the host might process the non-modifer first.

Therefore, each call to `sendReport()` must send (up to) three reports to the
host to guarantee the correct order of processing.

1. A report with toggled-off non-modifiers removed.
2. A report with changes to modifiers.
3. A report with toggled-on non-modifiers added.
Sending the current HID report to the host : Depending on the differences between the current and previous HID reports we might need to send one or two extra reports to guarantee that the host will process the changes in the correct order . There are two important scenarios to consider . 1 . If a non - modifier keycode toggles off in the same report as a modifier changes the host might process the modifier change first . 2 . If a non - modifier keycode toggles on in the same report as a modifier changes the host might process the non - modifer first . Therefore each call to ` sendReport () ` must send ( up to ) three reports to the host to guarantee the correct order of processing . 1 . A report with toggled - off non - modifiers removed . 2 . A report with changes to modifiers . 3 . A report with toggled - on non - modifiers added .
int Keyboard_::sendReport() {
  const uint8_t old_modifiers = last_report_.modifiers;
  const uint8_t new_modifiers = report_.modifiers;
  const uint8_t changed_modifiers = old_modifiers ^ new_modifiers;
  if (changed_modifiers != 0) {
    bool non_modifiers_toggled_off = false;
    for (uint8_t i = 0; i < KEY_BYTES; ++i) {
      byte released_keycodes = last_report_.keys[i] & ~(report_.keys[i]);
      if (released_keycodes != 0) {
        last_report_.keys[i] &= ~released_keycodes;
        non_modifiers_toggled_off = true;
      }
    }
    if (non_modifiers_toggled_off) {
      sendReportUnchecked();
    }
    last_report_.modifiers = new_modifiers;
    sendReportUnchecked();
  }
  if (memcmp(last_report_.keys, report_.keys, sizeof(report_.keys)) != 0) {
    memcpy(last_report_.keys, report_.keys, sizeof(report_.keys));
    return sendReportUnchecked();
  }
  return -1;
}
int Keyboard_ :: sendReport ( ) { const uint8_t old_modifiers = last_report_ . modifiers ; const uint8_t new_modifiers = report_ . modifiers ; const uint8_t changed_modifiers = old_modifiers ^ new_modifiers ; if ( changed_modifiers != 0 ) { bool non_modifiers_toggled_off = false ; for ( uint8_t i = 0 ; i < KEY_BYTES ; ++ i ) { byte released_keycodes = last_report_ . keys [ i ] & ~ ( report_ . keys [ i ] ) ; if ( released_keycodes != 0 ) { last_report_ . keys [ i ] &= ~ released_keycodes ; non_modifiers_toggled_off = true ; } } if ( non_modifiers_toggled_off ) { sendReportUnchecked ( ) ; } last_report_ . modifiers = new_modifiers ; sendReportUnchecked ( ) ; } if ( memcmp ( last_report_ . keys , report_ . keys , sizeof ( report_ . keys ) ) != 0 ) { memcpy ( last_report_ . keys , report_ . keys , sizeof ( report_ . keys ) ) ; return sendReportUnchecked ( ) ; } return -1 ; }
Sending the current HID report to the host:
Depending on the differences between the current and previous HID reports, we
might need to send one or two extra reports to guarantee that the host will
process the changes in the correct order.
Sending the current HID report to the host : Depending on the differences between the current and previous HID reports we might need to send one or two extra reports to guarantee that the host will process the changes in the correct order .
// If the new HID report differs from the previous one both in active modifier // keycodes and non-modifier keycodes, we will need to send at least one extra // report. First, we compare the modifiers bytes of the two reports. // There was at least one modifier change (toggled on or off), remove any // non-modifiers from the stored previous report that toggled off in the new // report, and send it to the host. // Next, update the modifiers byte of the stored previous report, and send // it. // Finally, copy the new report to the previous one, and send it. // A note on return values: Kaleidoscope doesn't actually check the return // value of `sendReport()`, so this function could be changed to return // void. It would be nice if we could do something to recover from an error // here, but it's not at all clear what that should be. Also note that if the // extra reports above return an error, there's not much we can do to try to // recover. We could try to send the report again, but that would be likely to // fail as well.