Turns out it was being caused by what is commonly referred to as "contact bounce". This is where the button or switch is literally bouncing on the pad/contacts, each time you press or release it. I did some Googling and I came across a little Arduino/Wiring library known as Bounce2 that handles this problem.
I was able to whip up a little sketch that works very well. Both eliminating bounce, and giving me access to a nice little easy to manage piece of code for all my future handheld projects. It's based on a 12 button setup. You will have to number your pins accordingly, depending on which ones you've wired your buttons to on the teensy.
Enjoy!
References:
/*
Description:
A 12 button input control sketch for the teensy 2.0,
using the Bounce2 library. This sketch eliminates (debounces)
side effects caused by mechanical bounce, such as rapid
fire, multiple undesired button presses etc. It also detects
when the button is being held down, and if so retriggers it.
Written by: Steve Sherrod
Date: 06/19/16
URL: http://retro-rpi.blogspot.com/
*/
// Include the Bounce2 library found here :
// https://github.com/thomasfredericks/Bounce2
#include <Bounce2.h>
#define DEBUG 1 //enable debugging/serial output
#define INTERVAL 5 //button update interval
#define RETRIG_RATE 100 //ms until button is considered being held
//buttons current state and timestamp
int buttonState;
unsigned long buttonPressTimeStamp;
//pin number placeholders
const int pinBtnUp = 10;
const int pinBtnRight = 8;
const int pinBtnDown = 23;
const int pinBtnLeft = 9;
const int pinBtnSelect = 6;
const int pinBtnStart = 4;
const int pinBtnB = 2;
const int pinBtnA = 0;
const int pinBtnY = 1;
const int pinBtnX = 3;
const int pinBtnTrigLeft = 5;
const int pinBtnTrigRight = 7;
const int pinLEDOutput = 11;
//array of pin numbers
byte pins[] = { pinBtnUp, pinBtnRight, pinBtnDown, pinBtnLeft, pinBtnSelect, pinBtnStart,
pinBtnB, pinBtnA, pinBtnY, pinBtnX, pinBtnTrigLeft, pinBtnTrigRight
};
//bounce object placeholders
Bounce btnUp = Bounce();
Bounce btnRight = Bounce();
Bounce btnDown = Bounce();
Bounce btnLeft = Bounce();
Bounce btnSelect = Bounce();
Bounce btnStart = Bounce();
Bounce btnB = Bounce();
Bounce btnA = Bounce();
Bounce btnY = Bounce();
Bounce btnX = Bounce();
Bounce btnTrigLeft = Bounce();
Bounce btnTrigRight = Bounce();
//array of Bounce objects
Bounce buttons[] = {btnUp, btnRight, btnDown, btnLeft, btnSelect, btnStart, btnB, btnA, btnY,
btnX, btnTrigLeft, btnTrigRight};
//array of key presses to be sent
short keys[] = {KEY_U, KEY_R, KEY_D, KEY_L, KEY_ENTER, KEY_TAB, KEY_B, KEY_A, KEY_Y, KEY_X, KEY_P, KEY_Q};
void myset_key1(uint8_t c){Keyboard.set_key1(c);}
void myset_key2(uint8_t c){Keyboard.set_key2(c);}
void myset_key3(uint8_t c){Keyboard.set_key3(c);}
void myset_key4(uint8_t c){Keyboard.set_key4(c);}
void myset_key5(uint8_t c){Keyboard.set_key5(c);}
void myset_key6(uint8_t c){Keyboard.set_key6(c);}
//sendkey function pointers
typedef void KeyFunction_t(uint8_t c);
KeyFunction_t* buttonActive[12];
KeyFunction_t* keyList[] = {myset_key6, myset_key5, myset_key4, myset_key3, myset_key2, myset_key1};
int keySlot = sizeof(keyList) / sizeof(KeyFunction_t*);
//setup the buttons
void setup() {
if (DEBUG)
Serial.begin(57600);
//set pin mode to input on all pins:
for (byte i=0; i< 12; i++) {
pinMode(pins[i], INPUT);
digitalWrite(pins[i],HIGH);
if (DEBUG)
Serial.printf("Pin %d -> input HIGH\n", pins[i]);
//setup our bounce instances
buttons[i].attach(pins[i]); //attach to corresponding pin
buttons[i].interval(INTERVAL);
}
//setup the LED pin
pinMode(pinLEDOutput,OUTPUT);
}
void loop() {
for (byte i=0; i< 12; i++) {
//update buttons
boolean changed = buttons[i].update();
//last action
bool keysPressed = false;
bool keysReleased = false;
//button state changed
if ( changed ) {
//read the update value
int value = buttons[i].read();
if ( value == HIGH) {
//button released
keysReleased = true;
buttonState = 0;
releaseButton(i);
if (DEBUG)
Serial.println("Button released");
} else {
//button pressed
buttonState = 1;
keysPressed = true;
activateButton(i);
if (DEBUG)
Serial.println("Button pressed");
buttonPressTimeStamp = millis();
}
}
//check for long button press and if so retrigger the button
if ( buttonState == 1 ) {
if ( millis() - buttonPressTimeStamp >= RETRIG_RATE ) {
buttonPressTimeStamp = millis();
if (DEBUG)
Serial.println("Button held, retriggering");
}
}
if (keysPressed || keysReleased)
Keyboard.send_now(); //update all the keypresses
}
}
void activateButton(byte index)
{
if (keySlot) //any key slots left?
{
keySlot--; //Push the keySlot stack
buttonActive[index] = keyList[keySlot]; //Associate the keySlot function pointer with the button
(*keyList[keySlot])(keys[index]); //Call the key slot function to set the key value
}
}
void releaseButton(byte index)
{
keyList[keySlot] = buttonActive[index]; //retrieve the keySlot function pointer
buttonActive[index] = 0; //mark the button as no longer pressed
(*keyList[keySlot])(0); //release the key slot
keySlot++; //pop the keySlot stack
}
https://en.wikipedia.org/wiki/Contact_bounce
http://www.allaboutcircuits.com/textbook/digital/chpt-4/contact-bounce/
https://github.com/thomasfredericks/Bounce2/wiki
https://www.pjrc.com/teensy/td_libs_Bounce.html
https://www.pjrc.com/teensy/pinout.html
https://learn.adafruit.com/raspberry-gear/wiring-front-case