#include <Keypad.h>

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] =
{
    { '1', '2', '3', 'A' },
    { '4', '5', '6', 'B' },
    { '7', '8', '9', 'C' },
    { '*', '0', '#', 'D' }
};

uint8_t colPins[COLS] = { 44, 42, 40, 38 };  // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 52, 50, 48, 46 };  // Pins connected to R1, R2, R3, R4

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

const byte hookPinA = 23;  // your interrupt pin
const byte interruptPin = 22;  // your interrupt pin

const byte column4InterruptPin = 2;  // Column 4 interrupt pin connected to column4Pin via a wire link. Could add a 1K series resistor to protect against short circuit to ground if it were output low when pin 38 is output high.
const byte column4Pin = 38;  // Column 4 pin connected to column4InterruptPin via a wire link.

// States updated by ISR.
volatile byte isr_hookOffState = 0;
volatile byte isr_interruptState = 0;
volatile bool isr_column4Pressed = false;

// Working copies of ISR data.
byte hookOffState = 0;
byte interruptState = 0;
bool column4Pressed = false;

// Use a single byte for the state variable and initialise it to OFF.
enum class State : byte
{
    OFF = 0,
    IDLE = 1,
    LISTEN_KEY = 2,
    PLAYER = 3
} state = State::OFF;

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

    pinMode(hookPinA, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(hookPinA), hookOffToggle, CHANGE);

    pinMode(interruptPin, INPUT);
    attachInterrupt(digitalPinToInterrupt(interruptPin), interruptToggle, RISING); // test interrupt with a regular button

    pinMode(column4InterruptPin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(column4InterruptPin), interruptColumn4, FALLING);  // Triggered by pulling column 4 low, e.g. digitalWrite(column4Pin, LOW) or within myKeypad.getKey().
}

void loop()
{
    const char key = keypad.getKey();

    if (key != NO_KEY)
    {
        Serial.println(key);
    }

    // Get a fresh copy of the ISR data and reset the interrupt state flag atomically
    // by temporarily disabling interrupts.
    cli();
    hookOffState = isr_hookOffState;
    interruptState = isr_interruptState;
    column4Pressed = isr_column4Pressed;
    isr_interruptState = 0;  // Reset to detect next interrupt.
    isr_column4Pressed = false; // Reset to detect next interrupt.
    sei();

    // Non-interrupt alternative method to test whether any button in column 4 is pressed.
    /*
    pinMode(column4Pin, OUTPUT);
    digitalWrite(column4Pin, LOW);
    column4Pressed = !digitalRead(52) || !digitalRead(50) || !digitalRead(48) || !digitalRead(46);
    digitalWrite(column4Pin, HIGH);
    pinMode(column4Pin, INPUT);
    */

    // Debug prints.
    //Serial.println(column4Pressed);
    if (column4Pressed)
    {
        Serial.println("Column 4 is pressed.");
    }

    // Process the working copies of the ISR data.
    // You will need to change the state machine logic to process column4Pressed obtained from the ISR or the alternative method.

    switch (state)
    {
    case State::OFF:
        break;
    case State::IDLE:
        break;
    case State::LISTEN_KEY:
        break;
    case State::PLAYER:
        break;
    }
}

void hookOffToggle()
{
    isr_hookOffState = digitalRead(hookPinA);
}

void interruptToggle()
{
    isr_interruptState = 1;
}

void interruptColumn4()
{
    // Test whether any button in column 4 is pressed.
    isr_column4Pressed = !digitalRead(52) || !digitalRead(50) || !digitalRead(48) || !digitalRead(46);
}
D0D1D2D3D4D5D6D7GNDLOGIC