Problems with using getKey() in keypad library

All I'm trying to do is check whether a certain button on the keypad is held down, but no matter what I've tried the if (key == '#') { parameter never seems to be fulfilled. I've had the program print out the 'key' variable right before the if statement and they appear to be the same. I'm new to C++ so I'm probably making some silly mistake, but I've spent hours trying to figure it out and its driving me crazy!

#include <Wire.h>
#include <Keypad.h>

// Keypad
const uint8_t ROWS = 4;
const uint8_t COLS = 3;
char keys[ROWS][COLS] = {
  { '1', '2', '3' },
  { '4', '5', '6' },
  { '7', '8', '9' },
  { '*', '0', '#' }
};
uint8_t colPins[COLS] = { 8, 7, 6 }; // Pins connected to C1, C2, C3
uint8_t rowPins[ROWS] = { 12, 11, 10, 9 }; // Pins connected to R1, R2, R3, R4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

char key;
KeyState state;
bool change;
bool started;

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

void loop() {
  if (started == false) {
    started = gamestart();
  }
}

int getkey() {
  key = keypad.getKey();
  bool change = keypad.keyStateChanged();
  if ((key != NO_KEY) && (change == true)) {
    //tone(19, 1250, 200);
    Serial.println(key);
  }
  return key;
}

bool gamestart() {
  bool startheld = false;
  keypad.setHoldTime(1000);
  key = getkey();
  state = keypad.getState();
  if (key == '#') {
    if (state == HOLD) {
      Serial.println("HOLD");
      startheld = true;
    }
  }
  return startheld;
}

Have you tried printing out the value of key before checking if (state == HOLD)? The keypad.getKey() function in the keypad library should only return the character the first time keypad.getKey() is called after pressing a key, when the key is being held it will be returning a value of zero.

The key states are usually only used with the getKeys() function, which returns an array of the 10 most recently active keys.

(note - it is very confusing when you name a function the same as a library function, anyone commenting on the code then has to explicitly state which function they are referring to)

1 Like

The function getkey() internally makes use of a global variable declared as "char key" and pointlessly, returns the value of "key" as an integer. The global value "key" is then assigned to that integer return value, and used by other routines internally as a character.

This is very poor programming practice, and although it may not be the main problem, needs to be rewritten.

Re-write codes in literate way so that your programming intentions are unambiguously expressed.

Here is your code. It is the exact same logic. Only the names were more self-explaining
and the leading word "my" indicates variables that you have declared.

For the pressed key the variable-type is always char

Your getkey-function adds the serial printing but does nothing else.
The name of the function "getkey" does not say anything about that you do print the a value inside that function.

You should describe the functionality that you want in normal words and avoid all programming-terms.

In normal words you know what their meaning is. In programming you might have a mis-conception and this mis-conception will be misunderstood of what you really want to do.

#include <Wire.h>
#include <Keypad.h>

// Keypad
const uint8_t ROWS = 4;
const uint8_t COLS = 3;
char myKeysPadChars[ROWS][COLS] = {
  { '1', '2', '3' },
  { '4', '5', '6' },
  { '7', '8', '9' },
  { '*', '0', '#' }
};

uint8_t colPins[COLS] = { 8, 7, 6 }; // Pins connected to C1, C2, C3
uint8_t rowPins[ROWS] = { 12, 11, 10, 9 }; // Pins connected to R1, R2, R3, R4
Keypad myKeypad = Keypad(makeKeymap(myKeysPadChars), rowPins, colPins, ROWS, COLS);

char myKey;
KeyState myKeyPressState;
bool change;
bool started;

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

void loop() {
  if (started == false) {
    started = gamestart();
  }
}


char getThePressedKey() {
  char myKeyResult = myKeypad.getKey();
  bool change = myKeypad.keyStateChanged();
  
  if ((myKeyResult != NO_KEY) && (change == true)) {
    //tone(19, 1250, 200);
    Serial.println(myKeyResult);
  }
  return myKeyResult;
}

bool gamestart() {
  bool startheld = false;
  myKeypad.setHoldTime(1000);
  myKey = getThePressedKey();
  myKeyPressState = myKeypad.getState();
  
  if (myKey == '#') {
    if (myKeyPressState == HOLD) {
      Serial.println("HOLD");
      startheld = true;
    }
  }
  return startheld;
}

best regards Stefan

2 Likes

Thank you for this! I meant to sort out the code a bit before I posted on here, but I just got a bit fed up and decided to post it anyway. Setting the getThePressedKey() function to return an int is something that I did to test if the problem was data types, I just forgot to change it back.

Thank you, I've figured out how to do it. I now save the returned key in a separate variable as long as it has a value, and use that in the if statement instead.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.