/* Teensy 3.2 Board as a USB adapter for Sinclair ZX Spectrum keyboard

*/

#include <Bounce.h>

// Set the Teensy pins that your keyboard wires are plugged into.

const int data1 = 4;
const int data2 = 3;
const int data3 = 2;
const int data4 = 1;
const int data5 = 0;
const int colA = 19;
const int colB = 18;
const int colC = 17;
const int colD = 16;
const int colE = 15;
const int colF = 14;
const int colG = 13;
const int colH = 12;

// Create Bounce objects for each input row pin. The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.

Bounce row1 = Bounce(data1, 100);  
Bounce row2 = Bounce(data2, 100);
Bounce row3 = Bounce(data3, 100);  
Bounce row4 = Bounce(data4, 100);
Bounce row5 = Bounce(data5, 100);  

boolean cShift = false;
boolean sShift = false;

void setup() {

  Serial.begin(9600);
  
  // Sets which pins are inputs and which are outputs.
  // Inputs use the pullup resistor, so they read HIGH normally.
  // An output is set LOW and a key is pressed, the intersecting
  // input will be shorted to ground and digitalRead() will
  // see it as LOW. The fallingEdge() function is true when the key
  // is pressed. The risingEdge() function is true when the key is
  // released.
  
  pinMode(data1, INPUT); 
  pinMode(data2, INPUT); 
  pinMode(data3, INPUT); 
  pinMode(data4, INPUT); 
  pinMode(data5, INPUT); 
  pinMode(colA, OUTPUT); 
  pinMode(colB, OUTPUT); 
  pinMode(colC, OUTPUT); 
  pinMode(colD, OUTPUT); 
  pinMode(colE, OUTPUT); 
  pinMode(colF, OUTPUT); 
  pinMode(colG, OUTPUT); 
  pinMode(colH, OUTPUT); 
}

void loop() {

  checkModifiers();

  // Set the column to LOW, then check each input
  // row to see if a key has been pressed

  // --------------------- Check Column A ------------------------

  digitalWrite(colA, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("!");
      } else if (cShift == true) {
        Keyboard.print("1");
      } else {
        Keyboard.print("1");
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("@");
      } else if (cShift == true) {
        Keyboard.print("2");
      } else {
        Keyboard.print("2");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("#");
      } else if (cShift == true) {
        Keyboard.print("3");
      } else {
        Keyboard.print("3");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("$");
      } else if (cShift == true) {
        Keyboard.print("4");
      } else {
        Keyboard.print("4");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("%");
      } else if (cShift == true) {
        Keyboard.press(KEY_LEFT);
        Keyboard.release(KEY_LEFT);
      } else {
        Keyboard.print("5");
      }
    }
  }

  digitalWrite(colA, HIGH);                     // Set this row back to HIGH

  // --------------------- Check Column B ------------------------

  digitalWrite(colB, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("<=");
      } else if (cShift == true) {
        Keyboard.print("Q");
      } else {
        Keyboard.print("q");
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("<>");
      } else if (cShift == true) {
        Keyboard.print("W");
      } else {
        Keyboard.print("w");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(">=");
      } else if (cShift == true) {
        Keyboard.print("E");
      } else {
        Keyboard.print("e");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("<");
      } else if (cShift == true) {
        Keyboard.print("R");
      } else {
        Keyboard.print("r");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(">");
      } else if (cShift == true) {
        Keyboard.print("T");
      } else {
        Keyboard.print("t");
      }
    }
  }

  digitalWrite(colB, HIGH);                     // Set this row back to HIGH

  // --------------------- Check Column C ------------------------

  digitalWrite(colC, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("~");
      } else if (cShift == true) {
        Keyboard.print("A");
      } else {
        Keyboard.print("a");
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("|");
      } else if (cShift == true) {
        Keyboard.print("S");
      } else {
        Keyboard.print("s");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.press(KEY_BACKSLASH);
        Keyboard.release(KEY_BACKSLASH);
      } else if (cShift == true) {
        Keyboard.print("D");
      } else {
        Keyboard.print("d");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("{");
      } else if (cShift == true) {
        Keyboard.print("F");
      } else {
        Keyboard.print("f");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("}");
      } else if (cShift == true) {
        Keyboard.print("G");
      } else {
        Keyboard.print("g");
      }
    }
  }

  digitalWrite(colC, HIGH);                     // Set this row back to HIGH


  // --------------------- Check Column D ------------------------

  digitalWrite(colD, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("_");
      } else if (cShift == true) {
        Keyboard.press(KEY_BACKSPACE);
        Keyboard.release(KEY_BACKSPACE);
      } else {
        Keyboard.print("0");
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(")");
      } else if (cShift == true) {
        Keyboard.print("9");
      } else {
        Keyboard.print("9");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("(");
      } else if (cShift == true) {
        Keyboard.press(KEY_RIGHT);
        Keyboard.release(KEY_RIGHT);
      } else {
        Keyboard.print("8");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("'");
      } else if (cShift == true) {
        Keyboard.press(KEY_UP);
        Keyboard.release(KEY_UP);
      } else {
        Keyboard.print("7");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("&");
      } else if (cShift == true) {
        Keyboard.press(KEY_DOWN);
        Keyboard.release(KEY_DOWN);
      } else {
        Keyboard.print("6");
      }
    }
  }

  digitalWrite(colD, HIGH);                     // Set this row back to HIGH


  // --------------------- Check Column E ------------------------

  digitalWrite(colE, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.press(KEY_QUOTE);
        Keyboard.release(KEY_QUOTE);
      } else if (cShift == true) {
        Keyboard.print("P");
      } else {
        Keyboard.print("p");
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(";");
      } else if (cShift == true) {
        Keyboard.print("O");
      } else {
        Keyboard.print("o");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("AT");
      } else if (cShift == true) {
        Keyboard.print("I");
      } else {
        Keyboard.print("i");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("]");
      } else if (cShift == true) {
        Keyboard.print("U");
      } else {
        Keyboard.print("u");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("[");
      } else if (cShift == true) {
        Keyboard.print("Y");
      } else {
        Keyboard.print("y");
      }
    }
  }

  digitalWrite(colE, HIGH);                     // Set this row back to HIGH

  // --------------------- Check Column F ------------------------

  digitalWrite(colF, LOW);

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(":");
      } else if (cShift == true) {
        Keyboard.print("Z");
      } else {
        Keyboard.print("z");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("£");
      } else if (cShift == true) {
        Keyboard.print("X");
      } else {
        Keyboard.print("x");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("?");
      } else if (cShift == true) {
        Keyboard.print("C");
      } else {
        Keyboard.print("c");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("/");
      } else if (cShift == true) {
        Keyboard.print("V");
      } else {
        Keyboard.print("v");
      }
    }
  }

  digitalWrite(colF, HIGH);                     // Set this row back to HIGH

  // --------------------- Check Column G ------------------------

  digitalWrite(colG, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.press(KEY_ENTER);
        Keyboard.release(KEY_ENTER);
      } else if (cShift == true) {
        Keyboard.press(KEY_ENTER);
        Keyboard.release(KEY_ENTER);
      } else {
        Keyboard.press(KEY_ENTER);
        Keyboard.release(KEY_ENTER);
      }
    }
  }

  if (row2.update()) {
    if (row2.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("=");
      } else if (cShift == true) {
        Keyboard.print("L");
      } else {
        Keyboard.print("l");
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("+");
      } else if (cShift == true) {
        Keyboard.print("K");
      } else {
        Keyboard.print("k");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("-");
      } else if (cShift == true) {
        Keyboard.print("J");
      } else {
        Keyboard.print("j");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("^");
      } else if (cShift == true) {
        Keyboard.print("H");
      } else {
        Keyboard.print("h");
      }
    }
  }

  digitalWrite(colG, HIGH);                     // Set this row back to HIGH

  // --------------------- Check Column H ------------------------

  digitalWrite(colH, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      if (sShift == true) {
        Keyboard.press(KEY_SPACE);
        Keyboard.release(KEY_SPACE);
      } else if (cShift == true) {
        Keyboard.press(KEY_SPACE);
        Keyboard.release(KEY_SPACE);
      } else {
        Keyboard.press(KEY_SPACE);
        Keyboard.release(KEY_SPACE);
      }
    }
  }

  if (row3.update()) {
    if (row3.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(".");
      } else if (cShift == true) {
        Keyboard.print("M");
      } else {
        Keyboard.print("m");
      }
    }
  }

  if (row4.update()) {
    if (row4.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print(",");
      } else if (cShift == true) {
        Keyboard.print("N");
      } else {
        Keyboard.print("n");
      }
    }
  }

  if (row5.update()) {
    if (row5.fallingEdge()) {
      if (sShift == true) {
        Keyboard.print("*");
      } else if (cShift == true) {
        Keyboard.print("B");
      } else {
        Keyboard.print("b");
      }
    }
  }

  digitalWrite(colH, HIGH);                     // Set this row back to HIGH

}

  // ---------------------------------------------------------------

void checkModifiers(){                          // Check for modifier keys
  
  digitalWrite(colF, LOW);
   
  if (row1.update()) {
    if (row1.fallingEdge()) {
      cShift = !cShift;
    }
  }

  digitalWrite(colF, HIGH);

  digitalWrite(colH, LOW);

  if (row2.update()) {
    if (row2.fallingEdge()) {
      sShift = !sShift;
    }
  }
  
  digitalWrite(colH, HIGH);
}
