KeyPad Event Listeners - Problems with processing delays

Hi there,

First post !

Context :
I'm trying to implement a T9 style keypad (without the dictionnary) on a 4x4 keypad.
I need some keys to have 2 purposes (Short press and long press) with different outcome.

Typically, the key 'D' will be used either to back one step, or to return to the main menu.
Pressing 3 times the key '2' should rotate between characters "ABC".

I searched various topics / posts / blogs and found something to begin with.

Issue :
After getKey is being called, the handler take time to process the information. However, I need the handler to tell me which action has been asked (depending on key + long or short press) before continuing.
-> I need to know which key has been pressed (keypad.getKey) and which action is required (event handler) on the same time.

I 'need' the HOLD status for longPress so I need a listener. I need to 'wait' for the listener to resolve before continuing (is that event possible ?).

Behavior:
After successfully entering the password (1 2 here), the program enter browseMenu() and the first item of the menu.

Solving:
Having HOLD status without event listener;
or
'Pausing' the program unitil event listener completes;

I've tried to bypass the char* valueToSend by setting a char directly (10 being that action, 11 being that one ..) thinking strcpy was slow. Didn't worked.
Tried to get rid of any comparison with getKey() : program 'unstable' due to the event listener being processed at the same time as the rest of the program.

Any idea ? Questions ?

Thanks in advance.

CODE IN REPLY OF THIS POST (character limitations)

#include <Keypad.h>
#include <avr/sleep.h>
#include <Wire.h>

const byte ROWS = 4;
const byte COLS = 4;
const byte rowPins[ROWS] = {22, 23, 24, 25};
const byte colPins[COLS] = {26, 27, 28, 29};
const char validChar[75] = "0123456789.!*#><§_DISCOURSE_HOISTED_CODE_0_§-_/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\0";
char keys[ROWS][COLS] = {
  { 1, 2, 3, 4 },
  { 5, 6, 7, 8 },
  { 9, 10, 11, 12 },
  { 13, 14, 15, 16 }
};

const char* keyStringArray[17] = {
  ".*&!", "abc", "def", "caps",
  "ghi", "jkl", "mno", "delete",
  "pqrs", "tuv", "wxyz", "save",
  " ", "-_/", "#><$", "cancel"
};
const char* keyStringArrayUpper[17] = {
  ".*&!", "ABC", "DEF", "caps",
  "GHI", "JKL", "MNO", "delete",
  "PQRS", "TUV", "WXYZ", "save",
  " ", "-_/", "#><$", "cancel"
};
const char* keyStringArrayNo[17] = {
  "1", "2", "3", "caps",
  "4", "5", "6", "delete",
  "7", "8", "9", "save",
  "", "0", "", "cancel"
};
const char* longPressKeyStringArray[17] = {
  "1", "2", "3", "no-",
  "4", "5", "6", "",
  "7", "8", "9", "",
  "", "0", "", "menu"
};
char singlePressKeyButtons[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, '\0'};
char singlePressCmdButtons[] = {4, 8, 12, 16, '\0'};
char longPressCmdButtons[] = {1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 14, 16, '\0'};

static byte kpadState;
char textMode[5] = "no";
byte keyState = 0;
char valueToSend[8] = {};
char keyCounterArray = 0;
char keySaved = -1;
Keypad customKeypad = Keypad( makeKeymap(keys), rowPins, colPins, 4, 4);

unsigned long TimeInMillis;

int customKey;


#define interruptPin 2
const long sleepAfterMs = 10000;

typedef char (* genericFP)();


void printText(const String& text, const char x0, const char y0, const char h) {
  
}
void clearText() {
  
}

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

  Serial.println("Enter Setup");

  pinMode(interruptPin, INPUT_PULLUP); //< Exit sleep mode
  customKeypad.begin(makeKeymap(keys));
  customKeypad.addEventListener(keypadEvent);
  customKeypad.setDebounceTime(20);
  customKeypad.setHoldTime(500);
  TimeInMillis = millis();
  valueToSend[0] = 0;
 
}

void loop() {
  const String mainMenu[1] = { "M1" };
  const genericFP mainMenuFunctions[1] = { menu1};
  char returnValue = -1;

  if ((returnValue = passwordProtect()) == 1) {

    if (millis() - TimeInMillis > sleepAfterMs)
      goSleep();
    valueToSend[0] = 0;
    
    while (browseMenu(3, mainMenu, mainMenuFunctions) >= 0);

    goSleep();
  }
  else if (returnValue == -1) {
    goSleep();
  }
}


char browseMenu(int menuSize, String menuItem[], genericFP menuFunctions[])
{
  unsigned char menuIndex = 0;
  char returnChar = -1;

  valueToSend[0] = 0;
  
  while (true) {
    valueToSend[0] = 0;
    customKey = customKeypad.getKey();
    if (valueToSend[0] != 0) {
      if (strcmp(valueToSend, "save") == 0) {
        Serial.println("enter menu item");
        valueToSend[0] = 0;
        returnChar = menuFunctions[menuIndex]();
        if (returnChar == -1) {
          return (-1);
        }
        else if (returnChar == 0) {
          return (0);
        }
      }
      else if (isValueInArray(valueToSend[0], "abcABC2")) { //< 'UP' is pressed
        Serial.println("menuUP");
        if (menuIndex == 0) {
          menuIndex = menuSize - 1;
        }
        else {
          --menuIndex;
        }
      }
      else if (isValueInArray(valueToSend[0], "tuvTUV8")) { //< 'DOWN" is pressed
        Serial.println("menuDOWN");
        ++menuIndex;
        if (menuIndex > menuSize - 1) {
          menuIndex = 0;
        }
      }
      else if (strcmp(valueToSend, "cancel") == 0) {
        Serial.println("menuBACK");
        clearText();
        return (1);
      }
      else if (strcmp(valueToSend, "menu") == 0) {
        Serial.println("menuMENU");
        clearText();
        return (0);
      }
      valueToSend[0] = 0;
    }
    else {
      if (millis() - TimeInMillis > sleepAfterMs) {
        return -1;
      }
    }
  }
}

char inputString(char* _input, char _inputSize, bool _hidden) {
  customKey = -1;
  char i = 0;
  while (customKey != 12 && i < _inputSize - 1) {
    customKey = customKeypad.getKey();
    if (valueToSend[0] != 0) {
      if (strcmp(valueToSend, "delete") == 0)
      {
        if (i > 0) {
          --i;
          _input[i] = 0;
        }
      }
      else if (strcmp(valueToSend, "cancel") == 0) {
        clearText();
        valueToSend[0] = 0;
        return (0);
      }
      else if (strcmp(valueToSend, "menu") == 0) {
        clearText();
        valueToSend[0] = 0;
        return (-1);
      }
      else if (strlen(valueToSend) == 1) {
        _input[i] = valueToSend[0];
        ++i;
      }
      valueToSend[0] = 0;
    }
    else {
      if (millis() - TimeInMillis > sleepAfterMs) {
        return -1;
      }
    }
  }
  return (1);
}

char passwordProtect() {
  char input_pwd[15] = "00000000000000";
  char inputReturn = -1;

  //EEPROM.get(eep_address, pwd_read);
  char pwd[15] = "12000000000000";
  while (true)
  {
    strcpy(input_pwd, "00000000000000");
    inputReturn = inputString(input_pwd, 15, true);
    if (inputReturn <= 0) {
      return (inputReturn);
    }
    Serial.println("Check password\npwd:");
    Serial.println(input_pwd);

    if (strcmp(input_pwd, pwd) == 0) {
      delay(1500);
      return (1);
    }
    else {
      delay(1500);
      return (0);
    }
  }
}
char menu1() {
  printText("Should not access here", 0, 0, 8);
}
void goSleep() {
  //sleep
}

void wakeUp() {}


int TimeDiffBtwnKeyPress = 2000;

void getKeyFromKeyPress(const char keyVal, const char** charArray) {
  if ((millis() - TimeInMillis) < TimeDiffBtwnKeyPress && strstr(charArray[keyVal], valueToSend) != NULL)
    keyCounterArray++;
  else {
    keyCounterArray = 0;
  }
  TimeInMillis = millis();

  if (keyCounterArray >= strlen(charArray[keyVal]))
    keyCounterArray = 0;
  valueToSend[0] = charArray[keyVal][keyCounterArray];
  valueToSend[1] = '\0';
  Serial.print("Keypad key :");
  Serial.println(valueToSend);
}

//following function is used to cycle through strings
void getCommandFromKeyPress(const char keyVal, const char** charArray) {
    TimeInMillis = millis();
  if (charArray[keyVal] != "") {
    strcpy(valueToSend, charArray[keyVal]);
    Serial.print("Keypad Command :");
    Serial.println(valueToSend);
  }
}
//following function is used for long press functionality
void getCommandFormLongKeyPress(char keyVal) {
    TimeInMillis = millis();
  if (longPressKeyStringArray[keyVal] != "") {
    strcpy(valueToSend, longPressKeyStringArray[keyVal]);
    Serial.print("Keypad LongCommand :");
    Serial.println(valueToSend);
  }
}

void keypadEvent(KeypadEvent key) {
  kpadState = customKeypad.getState();
  char keyVal = key;
  switch (kpadState) {
    case PRESSED:
      break;

    case HOLD:
      if (isValueInArray(keyVal, longPressCmdButtons)) {
        keyState = 1;
        getCommandFormLongKeyPress(keyVal);
      }
      break;

    case RELEASED:
      if (keyState == 1)
        keyState = 0;
      else if (isValueInArray(keyVal, singlePressCmdButtons))
        getCommandFromKeyPress(keyVal - 1, keyStringArray);
      else if (isValueInArray(keyVal, singlePressKeyButtons)) {
        if (strcmp(textMode, "caps") == 0) {
          getKeyFromKeyPress(keyVal - 1, keyStringArrayUpper);
        }
        else if (strcmp(textMode, "no") == 0) {
          getKeyFromKeyPress(keyVal - 1, keyStringArrayNo);
        }
        else {
          getKeyFromKeyPress(keyVal - 1, keyStringArray);
        }
      }
      else
        getKeyFromKeyPress(keyVal - 1, keyStringArray);

      break;
  }
  if (strcmp(valueToSend, "caps") == 0) {
    if (strcmp(textMode, "caps") == 0) {
      strcpy(textMode, "small");
    }
    else {
      strcpy(textMode, "caps");
    }
  }
  else if (strcmp(valueToSend, "no") == 0) {
    strcpy(textMode, "no");
  }
  keySaved = keyVal;
}

bool isValueInArray(char val, char *arr) {
  for (char i = 0; arr[i] != '\0'; ++i)
  {
    if (arr[i] == val)
    return true;
  }
  return false;
}