Here's the new code (library):
#include <Keypad.h>
// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes.
Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols) {
rowPins = row;
columnPins = col;
sizeKpd.rows = numRows;
sizeKpd.columns = numCols;
begin(userKeymap);
setDebounceTime(10);
setHoldTime(500);
keypadEventListener = 0;
initializePins();
startTime = 0;
}
// Let the user define a keymap - assume the same row/column count as defined in constructor
void Keypad::begin(char *userKeymap) {
keymap = userKeymap;
}
// Returns a single key only. Retained for backwards compatibility.
char Keypad::getKey() {
if (scanKeys() && (key[0].kstate==PRESSED) && key[0].stateChanged)
return key[0].kchar;
return NO_KEY;
}
bool Keypad::getKeys() {
if (scanKeys()) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].stateChanged) {
return true;
}
}
}
return false;
}
// Private
// Scan the keypad. Rerturn whether a key has been pressed or not.
bool Keypad::scanKeys() {
static unsigned int allKeys = 0;
byte curKey = 0;
boolean anyKey;
// Scan keypad once every XX mS. This makes the loop() count
// go from about 4,000 loops per second to about 40,000.
initializePins();
for (int c = 0; c < sizeKpd.columns; c++) {
pinMode(columnPins[c], OUTPUT);
digitalWrite(columnPins[c], LOW);
for (int r = 0; r <sizeKpd.rows; r++) {
curKey = digitalRead(rowPins[r]);
allKeys += curKey;
if (curKey == 0) curKey = keymap[c+(r*sizeKpd.columns)];
if (r==(sizeKpd.rows-1) && c==(sizeKpd.columns-1)) {
if (allKeys == (sizeKpd.rows*sizeKpd.columns))
anyKey = OPEN;
else
anyKey = CLOSED;
}
}
pinMode(columnPins[c], INPUT);
digitalWrite(columnPins[c], HIGH);
}
allKeys = 0;
return anyKey;
}
// Manage the key list. Any keys already on the list stay in their current slot
// and empty slots get filled with new keys.
void Keypad::updateList() {
// Delete Idle keys
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kstate==IDLE) {
key[i].kchar = NO_KEY;
key[i].stateChanged = false;
}
} =
// Fill the empty slots in key[] list with new CLOSED keys.
for (byte r=0; r<sizeKpd.rows; r++) {
for (byte c=0; c<sizeKpd.columns; c++) {
boolean button = bitRead(bitMap[r],c);
char keyChar = keymap[r * sizeKpd.columns + c];
int idx = findInList (keyChar); // -1 = not on list, else returns key index
// Update any key that was found on the list.
if (idx>=0)
setKeyState (idx, button);
// Add a key to the list when the button is CLOSED.
if ((idx==-1) && button) {
// Check the whole list for an empty key slot and put it there.
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar==NO_KEY) {
key[i].kchar = keyChar;
key[i].kstate = IDLE;
// All keys not on the list are considered IDLE. Using setKeyState
// on new key will transition the key to the PRESSED state as expected.
setKeyState (i, button);
break; // only fill the first empty slot.
}
}
}
}
}
}
// Private
void Keypad::setKeyState(byte idx, boolean button) {
// Clear stateChanged.
key[idx].stateChanged = false;
switch (key[idx].kstate) {
case IDLE: // Waiting for a keypress.
if (button==CLOSED) {
transitionTo (idx, PRESSED);
holdTimer = millis(); } // Get ready for next HOLD state.
break;
case PRESSED:
if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD...
transitionTo (idx, HOLD);
else if (button==OPEN) // or for a key to be RELEASED.
transitionTo (idx, RELEASED);
break;
case HOLD:
// Waiting for a key to be RELEASED.
if (button==OPEN)
transitionTo (idx, RELEASED);
break;
case RELEASED:
transitionTo (idx, IDLE);
break;
}
}
// New in 2.1
bool Keypad::isPressed(char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if ( (key[i].kchar == keyChar) && (key[i].kstate == PRESSED) )
return true;
}
return false; // Not pressed.
}
// New in 2.0
char Keypad::waitForKey() {
char waitKey = NO_KEY;
while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress.
return waitKey;
}
KeyState Keypad::getState() {
return key[0].kstate;
}
// The end user can test for any changes in state before deciding
// if any variables, etc. needs to be updated in their code.
// Useful for keypads/keyboards returning a single key only.
bool Keypad::keyStateChanged() {
return key[0].stateChanged;
}
// The number of keys on the key list, key[LIST_MAX], equals the number
// of bytes in the key list divided by the number of bytes in a key.
byte Keypad::numKeys() {
return sizeof(key)/sizeof(Key);
}
// Minimum debounceTime is 10 mS. Any lower *will* slow down the loop().
void Keypad::setDebounceTime(uint debounce) {
debounce<1 ? debounceTime=1 : debounceTime=debounce;
}
void Keypad::setHoldTime(uint hold) {
holdTime = hold;
}
void Keypad::addEventListener(void (*listener)(char)){
keypadEventListener = listener;
}
void Keypad::transitionTo(byte n, KeyState nextState) {
key[n].kstate = nextState;
key[n].stateChanged = true;
if (keypadEventListener!=NULL)
keypadEventListener(key[0].kchar);
}
void Keypad::initializePins() {
for (byte r = 0; r < sizeKpd.rows; r++) {
pinMode(rowPins[r], INPUT);
digitalWrite(rowPins[r], HIGH);
}
for (byte c = 0; c < sizeKpd.columns; c++) {
pinMode(columnPins[c], INPUT);
digitalWrite(columnPins[c], HIGH);
}
}
// Search for a key in the list of active keys.
// Returns -1 if not found or the index into the list of active keys.
int Keypad::findInList (char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar == keyChar) {
return i;
}
}
return -1; // No matching key in list.
}
Here's my own code (which calls from the libraries):
//extend Keypad class
#include <Keypad.h>
//initialize rows and columns
const byte ROWS = 4;
const byte COLS = 4;
//define the symbols on the buttons
char hexaKeys[ROWS][COLS] = {
{'0','1','2','3'},
{'4','5','6','7'},
{'8','9','A','B'},
{'C','D','E','F'}
};
//row pinouts
byte rowPins[ROWS] = {5, 4, 3, 2};
//column pinouts
byte colPins[COLS] = {9, 8, 7, 6};
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
int MIDInotes[16] = {60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83, 84, 86};
//SOME METHODS:
//MIDIiu noteON
void noteOn(int channel, int pitch, int velocity) {
Serial.write(channel);
Serial.write(pitch);
Serial.write(velocity);
delay(1);
}
void setup() {
Serial.begin(31250);
}
void loop() {
char customKey = customKeypad.getKey();
if (customKey){
char testChar = customKey;
int someInt;
if (testChar >= 'A' && testChar <= 'F')
{
someInt = 10 + (int)(testChar- 'A');
}
else
{
someInt = (int)(customKey - '0');
}
noteOn(144, MIDInotes[someInt], 127);
delay(100);
}
}