/macro test.ino
// Requires the Encoder library
#include <Encoder.h>
#include <Keyboard.h>

// Keyboard module pins - rows 1 and 2, columns 1 and 2
#define R1 2
#define R2 3
#define C1 4
#define C2 5
// Encoder pins - A & B are the encoder itself, D is the active-low pushbutton
#define A 9
#define B 8
#define D 7
// 7-segment pins - DO is data out, SH is shift, LAT is latch
#define DO 14
#define SH 15
#define LAT 16

uint16_t c;
Encoder enc(B, A);

void encoder_setup() {
  // All inputs have external pull-ups on the module, so no pull-up configuration is required here
  pinMode(A, INPUT);
  pinMode(B, INPUT);
  pinMode(D, INPUT);
}

void encoder_update() {
  if (digitalRead(D) == LOW) {
    enc.write(0);
  }
  c = enc.read() >> 1;
}

// bit order is the same as segment order, msb -> lsb
const uint8_t charmap[] = {
  //ABCDEFG.
  0b11111100, // 0
  0b01100000, // 1
  0b11011010, // 2
  0b11110010, // 3
  0b01100110, // 4
  0b10110110, // 5
  0b10111110, // 6
  0b11100000, // 7
  0b11111110, // 8
  0b11110110, // 9
  0b11101110, // A
  0b00111110, // b
  0b10011100, // C
  0b01111010, // d
  0b10011110, // E
  0b10001110, // F
};

void toggle(int pin) {
  digitalWrite(pin, HIGH);
  digitalWrite(pin, LOW);
}

void shift_byte(uint8_t b) {
  for (char i = 0; i < 8; i++) {
    digitalWrite(DO, (b >> i) & 1);
    toggle(SH);
  }
}

void ss_setup() {
  pinMode(DO, OUTPUT);
  pinMode(SH, OUTPUT);
  pinMode(LAT, OUTPUT);
  shift_byte(0x00);
  shift_byte(0x00);
  toggle(LAT);
}

void ss_update() {
  uint8_t d = (c & 0xFF); //(c >> 8) & 0xFF;
  shift_byte(charmap[d & 0xF]);
  shift_byte(charmap[(d & 0xF0) >> 4]);
  toggle(LAT);
}

uint8_t keystate;

void key_setup() {
  keystate = 0;
  pinMode(R1, INPUT);
  digitalWrite(R1, LOW);
  pinMode(R2, INPUT);
  digitalWrite(R2, LOW);
  // The matrix on the pad module does _not_ have external pull-ups
  pinMode(C1, INPUT_PULLUP);
  pinMode(C2, INPUT_PULLUP);
  Keyboard.begin();
}

char which_key(uint8_t *n) {
  char c = 0;

  if (*n & 1) {
    c = 'a';
    *n &= ~(uint8_t)1;
  } else if (*n & 2) {
    c = 'b';
    *n &= ~(uint8_t)2;
  } else if (*n & 4) {
    c = 'm';
    *n &= ~(uint8_t)4;
  } else if (*n & 8) {
    c = ' ';
    *n &= ~(uint8_t)8;
  } else {
    *n = 0;
  }
  return c;
}

void key_update() {
  uint8_t new_keystate = 0;
  pinMode(R1, OUTPUT);
  new_keystate = (digitalRead(C2) << 1) | digitalRead(C1);
  pinMode(R1, INPUT);
  pinMode(R2, OUTPUT);
  new_keystate |= (digitalRead(C2) << 3) | (digitalRead(C1) << 2);
  pinMode(R2, INPUT);
  
  uint8_t pressed = ~new_keystate & keystate;
  uint8_t released = new_keystate & ~keystate;
  if (pressed) {
    while (char k = which_key(&pressed)) {
      Keyboard.press(k);
    }
  } else if (released) {
    while (char k = which_key(&released)) {
      Keyboard.release(k);
    }
  }
  keystate = new_keystate;
}

void setup() {
  c = 0;
  key_setup();
  ss_setup();
  Serial.begin(115200);
}

void loop() {
  key_update();
  encoder_update();
  ss_update();
  delay(1);
}