Keypad library - determine if no key is pressed

Hi! I am working on a small 4x4 MIDI keyboard/controller. I am using an Arduino clone, the Teensy. So for I have gotten it to "hold" whatever key I am pressing on the keypad, but not let go. I am using the Keypad library and I am wondering if it is possible to determine if no key is pressed and if it's possible to send one note off command for every note, at once.

Here is my code so far:

/* @file CustomKeypad.pde
|| @version 1.0
|| @author Alexander Brevig
|| @contact alexanderbrevig@gmail.com
||
|| @description
|| | Demonstrates changing the keypad size and key values.
|| #
*/
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'0','1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'},
  {'C','D','E','F'}
};
byte rowPins[ROWS] = {0,1,2,3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {7,6,5,4}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

void setup(){
  Serial.begin(9600);
}
  
void loop(){
  
  char customKey = customKeypad.getKey();
  int ckey = customKey - '0';
  int cKey = ckey - 7;
  int finalKey;
  int finalNote;
  if (customKey) {
    if (ckey <= 9) {
  finalKey = ckey;
    }
    if (ckey >9) {
      finalKey = cKey;
    }
     finalNote = finalKey + 60;
     usbMIDI.sendNoteOn(finalNote, 64, 1);
     
  }
  else {
     usbMIDI.sendNoteOff(finalNote, 0, 1);
  }
  
}

I am sure there are many mistakes, but I am hoping you can help me achieve my goal. Thanks in advance.

I am wondering if it is possible to determine if no key is pressed

void loop(){
  char customKey = customKeypad.getKey();
  
  if (customKey){
    Serial.println(customKey);
  }
}

What do you see on the Serial monitor when no key is pressed ?

...nothing...
EDIT: oops, wrong code. edited now

Domnulvlad:
...nothing...

There is your clue. If a key is pressed then getKey() will return false, otherwise it will return the key pressed and will, therefore, be true

You can do the same using

void loop()
{
  char customKey = customKeypad.getKey();
  
  if (customKey != NO_KEY)
  {
    Serial.println(customKey);
  }
}

You should also be aware of that getKey() will return a value each time the state of a key changes.
The states are PRESSED, HOLD and RELEASED, and if not taken into consideration, you will get upto three key events (depending on how long time the key is pressed).

Use getState()

void loop() {
  char customKey = customKeypad.getKey();

  if (customKey) {
    switch (customKeypad.getState()) {
      case PRESSED:
        Serial.print("Pressed: ");
      case HOLD:
        Serial.print("Hold: ");
      case RELEASED:
        Serial.print("Released: ");
    }
    Serial.println(customKey);
  }
}

Edit:
This code works as it is written, but not as intended......

Hmm... I can't figure out how the getState() works...
Clearly

void loop() {

char customKey = customKeypad.getKey();

if (customKey) {
    switch (customKeypad.getState()) {
      case PRESSED:
        Serial.print("Pressed: ");
      case HOLD:
        Serial.print("Hold: ");
      case RELEASED:
        Serial.print("Released: ");
    }
    Serial.println(customKey);
  }
}

is wrong... It just doesn't do what it's supposed to do.

is wrong... It just doesn't do what it's supposed to do.

What DOES it do?

Using this

void loop() {

char customKey = customKeypad.getKey();

if (customKey) {
    switch (customKeypad.getState()) {
      case PRESSED:
        Serial.print("Pressed: ");
      case HOLD:
        Serial.print("Hold: ");
      case RELEASED:
        Serial.print("Released: ");
    }
    Serial.println(customKey);
  }
}

code, it just prints "Pressed: Hold: Idle: [no. of button]" to the Serial monitor, without actually saying its state.

Please review THIS and see what is missing from your code.

Paul

Please review the code posted by leongjerland and determine what is missing from it

break; ?

/* @file CustomKeypad.pde
  || @version 1.0
  || @author Alexander Brevig
  || @contact alexanderbrevig@gmail.com
  ||
  || @description
  || | Demonstrates changing the keypad size and key values.
  || #
*/
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'0', '1', '2', '3'},
  {'4', '5', '6', '7'},
  {'8', '9', 'A', 'B'},
  {'C', 'D', 'E', 'F'}
};
byte rowPins[ROWS] = {0, 1, 2, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

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

void loop() {
  char customKey = customKeypad.getKey();

  if (customKey) {
    switch (customKeypad.getState()) {
      case PRESSED:
        Serial.print("Pressed: ");
        break;
      case HOLD:
        Serial.print("Hold: ");
        break;
      case RELEASED:
        Serial.print("Released: ");
        break;
    }
    Serial.println(customKey);
  }
}

This code just says "Pressed: [no. of button]" and it seems to do the right thing, until you realize that's the only thing it does. The other cases don't seem to work.

I am sorry for trusting my poor memory and publishing nontested code :frowning:

getKey() returns the key pressed only once for each 'keypress'.

Testing for state is done based on if 'customKey' is not equal to 0, and therefore only done once.

You can use keyStateChanged() to detect state changes and then getState().

At least this example works for single key presses on my Nano (with different keypad/pins) :slight_smile:

/* @file CustomKeypad.pde
  || @version 1.0
  || @author Alexander Brevig
  || @contact alexanderbrevig@gmail.com
  ||
  || @description
  || | Demonstrates changing the keypad size and key values.
  || #
*/
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'0', '1', '2', '3'},
  {'4', '5', '6', '7'},
  {'8', '9', 'A', 'B'},
  {'C', 'D', 'E', 'F'}
};
byte rowPins[ROWS] = {0, 1, 2, 3}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

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

void loop() {

  char customKey = customKeypad.getKey();

  if (customKeypad.keyStateChanged()) {
    switch (customKeypad.getState()) {
      case PRESSED:
        Serial.print("Pressed: ");
        break;
      case HOLD:
        Serial.print("Hold: ");
        break;
      case RELEASED:
        Serial.print("Released: ");
        break;
      case IDLE:
        Serial.print("Idle: ");
        break;
    }
    Serial.println(customKeypad.key[0].kchar);
  }
  delay(20);
}

I had to add a small delay in main loop to avoid multiple changes to each state, and have not investigated that any further....

For handling 'multikey' and adding an 'eventhandler', look at the examples here.