Editing a Library

Hi guys, I'm pretty new to the Arduino language and right now I'm trying to edit the Keypad library from the arduino website. So far, I'm not getting anywhere.

I'm trying to edit the Keypad.cpp and when I do, the main code gets an error saying it doesn't exist anymore. Here's the link to the changes I'm trying to make:

http://arduino.cc/forum/index.php/topic,95027.0.html

What I'm doing in steps:

  1. Opening the Keypad.cpp in the Arduino Package Contents.
  2. Replacing the bool::Keys functions and initializePins() with the modified code from the link.
  3. Running it in main program.
  4. Getting these errors :

/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp: In member function 'bool Keypad::scanKeys()':
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp:84: error: 'intializePins' was not declared in this scope
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp:86: error: 'size' was not declared in this scope
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp:92: error: 'currentKey' was not declared in this scope
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp: In member function 'void Keypad::initializePins()':
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp:230: error: 'size' was not declared in this scope
/Applications/Arduino.app/Contents/Resources/Java/libraries/Keypad/Keypad.cpp:234: error: 'size' was not declared in this scope

Any help for a total newbie at programming? :slight_smile:

Post the code you're trying to compile.

//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:
//MIDI 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');
    }

  for (int i = 0; i < 16; i++)
  {
    if (i == someInt)
      {
        noteOn(144,MIDInotes[someInt], 127);
      }
      else 
      {
        noteOn(144, MIDInotes[i], 0);
      }  
      delay(1);
    }
  noteOn(144, MIDInotes[someInt], 127); 
  delay(100); 
 }

Please re-edit that posting and put the code in code tags. Use the # button

// like this to get code tags, or input them directly

That's not the code part which is responsible for the compiler errors, is it? Please post your changed Keypad library code.

So I just found out there were just some syntax errors from the code I got from the link (that was really silly of me).

However, the problem now is that no output is coming out. What I'm trying to achieve is outputting multiple keypresses at the same time.

Here is the original code:

bool Keypad::scanKeys() {
	boolean anyKey=false;

	// Scan keypad once every XX mS. This makes the loop() count
	// go from about 4,000 loops per second to about 40,000.
	if ( (millis()-startTime)>debounceTime ) {

		// When sharing row pins with other hardware they may need to be re-intialized.
		for (byte r=0; r<sizeKpd.rows; r++) {
			pin_mode(rowPins[r],INPUT_PULLUP);
			pin_write(rowPins[r],HIGH);	// Enable the internal 20K pullup resistors. (Arduino<101)
		}

		// Scan the entire keypad/keyboard and provide a key pressed status to
		// setKeyState().  Also, determine which keys are being pressed.
		for (byte c=0; c<sizeKpd.columns; c++) {
			pin_mode(columnPins[c],OUTPUT);
			pin_write(columnPins[c], LOW);	// Begin column pulse output.
			for (byte r=0; r<sizeKpd.rows; r++) {
				bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low but invert to high.
				if (bitRead(bitMap[r], c) == 1)
					anyKey = true;
			}
			// Set pin to high impedance input. Effectively ends column pulse.
			pin_write(columnPins[c],HIGH);
			pin_mode(columnPins[c],INPUT);
		}
		updateList();	// Manage the Active-Key list. Adding/Removing active keys.

		// Reset debounceTime delay.
		startTime = millis();
	}
	return anyKey;	// Report if any keys are active.
}

Now here's the new code:

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;
}

Post the whole code, this doesn't work if you have changed just this bit.

However, the problem now is that no output is coming out.

Define what that means. For which input you get what output.

pylon:
Post the whole code, this doesn't work if you have changed just this bit.

However, the problem now is that no output is coming out.

Define what that means. For which input you get what output.

Alright, sorry for not posting the right stuff for you guys to work with, I'm just not thinking straight right now.
MY INTENTIONS:
-I am trying to build a 16 buttonpad MIDI controller using the sparkfun 4x4 board (Button Pad 4x4 - LED Compatible - COM-07835 - SparkFun Electronics)
-Right now, the controller can take in one button input and output one thing (monophonic)
-I am trying to program the arduino so more than one button input can be taken in (polyphonic)
-With the new code for the library, nothing is coming out correctly

Here's the whole original 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.  Return whether a key has been pressed or not.
bool Keypad::scanKeys() {
	boolean anyKey=false;

	// Scan keypad once every XX mS. This makes the loop() count
	// go from about 4,000 loops per second to about 40,000.
	if ( (millis()-startTime)>debounceTime ) {

		// When sharing row pins with other hardware they may need to be re-intialized.
		for (byte r=0; r<sizeKpd.rows; r++) {
			pin_mode(rowPins[r],INPUT_PULLUP);
			pin_write(rowPins[r],HIGH);	// Enable the internal 20K pullup resistors. (Arduino<101)
		}

		// Scan the entire keypad/keyboard and provide a key pressed status to
		// setKeyState().  Also, determine which keys are being pressed.
		for (byte c=0; c<sizeKpd.columns; c++) {
			pin_mode(columnPins[c],OUTPUT);
			pin_write(columnPins[c], LOW);	// Begin column pulse output.
			for (byte r=0; r<sizeKpd.rows; r++) {
				bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low but invert to high.
				if (bitRead(bitMap[r], c) == 1)
					anyKey = true;
			}
			// Set pin to high impedance input. Effectively ends column pulse.
			pin_write(columnPins[c],HIGH);
			pin_mode(columnPins[c],INPUT);
		}
		updateList();	// Manage the Active-Key list. Adding/Removing active keys.

		// Reset debounceTime delay.
		startTime = millis();
	}
	return anyKey;	// Report if any keys are active.
}

// 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() {
    // Configure column pin modes and states. Row pins get configured
    // in scanKeys(). See explanation there.
    // See http://arduino.cc/forum/index.php/topic,95027.0.html for an explanation
    // of why changing the column pins to INPUTs prevents inter-column shorts.
    for (byte C=0; C<sizeKpd.columns; C++) {
        pin_mode(columnPins[C],INPUT);
        pin_write(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 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); 
 } 
}

I would say the original code is doing more what you're expecting from the library. The problem is that you cannot use getKey() when you wanna get a multi-key stroke. Use the is_pressed() method instead.

Hi euphoricnoise, sorry about the late reply but I am just getting over the flu.

euphoricnoise:
-I am trying to build a 16 buttonpad MIDI controller using the sparkfun 4x4 board (Button Pad 4x4 - LED Compatible - COM-07835 - SparkFun Electronics)
-Right now, the controller can take in one button input and output one thing (monophonic)
-I am trying to program the arduino so more than one button input can be taken in (polyphonic)

The latest version, 3.0, of the keypad library supports up to 10 active keys all being pressed at the same time. I wanted to give you an example but I see that I botched the upload so the multikey example included with the library download is completely off the mark.

I've included my initial draft of that example here. Two things to notice are that you should use kpd.getKeys() for scanning multiple key presses and that you will get a list of keys in the kpd.key[] array.

The array kpd.key[] is an array containing keys that have the following members:

  char kchar;
  KeyState kstate;            // IDLE, PRESSED, HOLD, RELEASED
  boolean stateChanged;

Hopefully this is enough to get you going on your project. I will work on the multikey example over the holidays and see if I can update the Keypad page Arduino Playground - Keypad Library too.

/* @file MultiKey.ino

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the kpd

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup(){
  Serial.begin(9600);
}

void loop(){

  // Fills kpd.key[] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {
    for (int i=0; i<LIST_MAX; i++)   // Scan the entire list.
    {
      if (kpd.key[i].kchar != NO_KEY)    // Test for an active key.
      {
        switch (kpd.key[i].kstate) {  // Test for key state IDLE, PRESSED, HOLD, or RELEASED
            case HOLD:
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.print(" is being HELD and the state ");
                if (!kpd.key[i].stateChanged)
                    Serial.println("has not changed.");
                else
                    Serial.println("has changed.");
                break;
            case PRESSED:
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.print(" is PRESSED and the state ");
                if (!kpd.key[i].stateChanged)
                    Serial.println("has not changed.");
                else
                    Serial.println("has changed.");
                break;
            case RELEASED:
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.print(" has been RELEASED and the state ");
                if (!kpd.key[i].stateChanged)
                    Serial.println("has not changed.");
                else
                    Serial.println("has changed.");
                break;
            default:
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.print(" is IDLE and the state ");
                if (!kpd.key[i].stateChanged)
                    Serial.println("has not changed.");
                else
                    Serial.println("has changed.");
        }
      }
    }
  }
}  // End loop