class GetKeyEvent { private: bool stable = false; bool lastRaw = false; unsigned long lastChange = 0; unsigned long lastRepeat = 0; unsigned long debounceTime = 50; unsigned long repeatDelay = 1000; unsigned long repeatInterval = 300; enum State { Idle, Pressed, Repeating }; State state = Idle; public: void update(bool raw) { unsigned long now = millis(); if (raw != lastRaw) { lastRaw = raw; lastChange = now; } bool debounced = stable; if ((now - lastChange) >= debounceTime) { debounced = raw; } switch (state) { case Idle: if (debounced && !stable) { stable = true; state = Pressed; lastRepeat = now; } break; case Pressed: if (!debounced) { stable = false; state = Idle; } else if ((now - lastRepeat) >= repeatDelay) { state = Repeating; lastRepeat = now; } break; case Repeating: if (!debounced) { stable = false; state = Idle; } break; } } bool keyPressed() const { return (state == Pressed && stable); } bool keyRepeated() { if (state == Repeating) { unsigned long now = millis(); if ((now - lastRepeat) >= repeatInterval) { lastRepeat = now; return true; } } return false; } bool keyReleased() const { return (!stable && state == Idle); } bool isDown() const { return stable; } }; GetKeyEvent keyA; GetKeyEvent keyB; // Usage void loop() { // Replace with real input logic: bool rawA = digitalRead(GPIO_NUM_34); bool rawB = digitalRead(GPIO_NUM_35); keyA.update(rawA); keyB.update(rawB); if (keyA.keyPressed()) Serial.println("A down"); if (keyA.keyRepeated()) Serial.println("A repeat"); if (keyA.keyReleased()) Serial.println("A up"); if (keyB.keyPressed()) Serial.println("B down"); if (keyB.keyRepeated()) Serial.println("B repeat"); if (keyB.keyReleased()) Serial.println("B up"); if (keyA.isDown() && keyB.isDown()) { Serial.println("A + B combo"); } }