Press and Hold button on MCP23017 for 3 seconds to perform action

I am now trying to get the if statement to detect an input and time to preform an action. I would like to start off with printing to the serial monitor. Since I am using an MCP23017 and a MC17 Keypad libary, I feel like the examples I have read so far are missing something or I am not getting it.

I simply want to hold a button down, any button from the MCP23017 for three seconds and write to the serial monitor.

#include <Keypad_MC17.h>
#include <Keypad.h>        // GDY120705
#include <Wire.h>

#define I2CADDR 0x20

#include "LedControl.h" //  need the library
LedControl lc = LedControl(12, 11, 10, 1); //LedControl(int dataPin, int clkPin, int csPin, int numDevices=1);

byte val[8][8] = {0};

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] = {4, 5, 6, 7}; //connect to the column pinouts of the keypad

byte row;
byte col;
byte matchCol;
byte matchRow;

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

unsigned long startTime;

void setup() {
  //  Wire.begin( );
  customKeypad.begin( );        // GDY120705
  Serial.begin(9600);

  lc.shutdown(0, false); // turn off power saving, enables display
  lc.setIntensity(0, 8); // sets brightness (0~15 possible values)
  lc.clearDisplay(0);// clear screen




}

void loop() {



  char customKey = customKeypad.getKey();

  for (row = 0; row < 4; row++)
  {
    for (col = 0; col < 4; col++)
    {
      if (hexaKeys[row][col] == customKey)
      {
        matchCol = col;
        matchRow = row;
      }
    }
  }

  startTime = millis();
  if (customKey != NO_KEY &&  (millis() - startTime) > 3000) {

    Serial.println(matchRow);
    Serial.println(matchCol);

  }
  if (customKey != '\0' && val[matchRow][matchCol] == 0)  {
    val[matchRow][matchCol] = 1;
    lc.setLed(0, matchRow, matchCol, true);
    customKey = '\0';
    //delay(200);
  }

  if (customKey != '\0' && val[matchRow][matchCol] == 1) {
    val[matchRow][matchCol] = 0;
    lc.setLed(0, matchRow, matchCol, false);
    customKey = '\0';
    //delay(200);
  }

}

Every pass through loop() you are setting startTime = millis(). How will the difference between them ever increase?

millis() - millis() will always be < 3000

 startTime = millis();
  if (customKey != NO_KEY &&  (millis() - startTime) > 3000) {

What would you recommend?

First, you’ve got to sense a key pressed or not pressed. You may or may not need debouncing on the key(s).

Next, you need a timer that is reset ‘timer = millis()’ when the key is not pressed and advances when the key *is *pressed.

Then you need to know whether or not the timer has reached its preset value (bool).

When the timer reaches preset you can either use that condition to continually send a message or do whatever, OR,
sense when the timer’s state changes from not reached to reached (IDE → file examples/digital/statechangedetection) and do something once only.

Thank you for taking the time out to help me. I do have state change code. I looked at the example you suggested and I already implemented that concept into my code. What I am having a problem with is understanding NO_KEY and if that can work as a button state? I do not need debouncing on the keys as the library seems to do a pretty good job of it.

Could you elaborate on

Then you need to know whether or not the timer has reached its preset value (bool).