Keypad (Keypad-3.1.1) getKey() Issue

I can read keys just fine and all keys are mapped properly. The problem comes in when a key is being pressed then getKey() is called. It does not return the key being pressed. In fact, the same occurs with isPressed() as it shows its not currently being pressed. If I release the key then call getKey() ,the key is returned.

How can I get pre-pressed keys to be processed properly prior to calling getKey() ?

If this library does not support this, do you know one that does.

I’m not sure exactly what your question is, but usually, the entry-level add-on libraries only queue a single event (key action in this case).

If you want to detect more events prior to calling the getkey() event, I’d suggest you write a simple wrapper to fill and empty an array of ‘keys’ while your main code is off doing other things.

It’s not hard, and will be a great practice to creating non-blocking code.

How is your keypad wired?

Have a look at the EventKeypad example that comes with the library.

In IBMPC, the Keyboard returns two scan codes - one for the open key and another for the closed key.

In Arduino, Kepad.h Library (so far I know) returns only one scan code, and it is for the closed key.

Look at the MultiKey example. The library is capable of handling up to ten simultaneous keypresses, and can return the state of each of those keys, as either PRESSED (when keypad is first scanned after the keypress), HOLD (key being held down), RELEASED (when key is released from being held), and IDLE (after being released, but not yet displaced out of the key array). Diodes are necessary on the keys to prevent ghosting with multiple keys pressed simultaneously.

I'm curious how OP has the keypad wired, it seems odd that the keypress is only recognized when the key is released.

In 4x4 Key that we usually use with UNO with the support of Keypad.h Library does have any diodes in the Key Matrix (Fig-1).

4x4KeyPadUNO
Figure-1:

Thanks for all the support input.

The keypad works fine. I push a mapped key and when read in loop() I get the key pressed.
Note: this works for all keys in 4x4 matrix.

Now I run a function based on the key pressed but would like to check for my “stop” key mapped as ‘E’. This would signify the operator wants to exit the testing function.

The problem is if you have Pressed AND Held the key, a call to getkey() does not return any key press. In fact, after returning to the main loop() the key does not register either. The only way to read it is to 1st release it then press it again, now it reads it and sends it back.

Why would the library ignore the getkey() scan on buttons already pushed AND held?

Thanks

I think that is the intended behavior. getkey() returns the key that has become pressed since the last call to getkey(). This actually makes most code much simpler, because generally you only want to act on a particular key press once.

I'm a bit confused now, are you trying to detect the 'E' key while also pressing another key? Or are you trying to determine if the initial key is still being held? Detecting two keys being pressed at the same time will not work on the generic keypads that do not have diodes on the keys.

The keypad library can detect when a key is being held, but it is a bit more complex than just calling getkey(). Each key that is pressed cycles through the states IDLE > PRESSED > HELD > RELEASED > IDLE, and the library (with an appropriate keypad) can keep track of up to ten keys being pressed simultaneously. The keys and their current states are kept in an array, where your code can check to see what the current state is.

As an example:

#include <Keypad.h>

// Keypad variables - 4 x 4 Matrix (8 pins, pin 1 to 4 = C1 to C4, pin 5 to 8 = R1 to R4
const byte ROWS = 4; // four rows
const byte COLS = 4; // four columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {5, 6, 7, 8 };
byte colPins[COLS] = {9, 10, 11, 12};

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

char key ;

const char* keystates[] = {
  "IDLE",
  "PRESSED",
  "HELD",
  "RELEASED"
};

void setup() {
  // Setup Serial Monitor
  Serial.begin(115200);
  Serial.println("Entering Setup");
}  // END SETUP

void loop() {
  // First check the keypad
  key = readkey();

  if (key) {
    Serial.print("key:");
    Serial.println(key);
    while (true) {
      KeyState keystate = keypad.key[keypad.findInList(key)].kstate; //get state of active key
      Serial.print("keystate:");
      Serial.println(keystates[keystate]);
      if (keystate == IDLE) break; //stay in while loop until key has been released
      delay(250); //delay to slow down scrolling in serial monitor
      keypad.getKeys(); //update the key states in key array
    }
  }
}

char readkey() {
  if (keypad.getKeys()) {                      //populate key array with all active keys
    for (int i = 0; i < LIST_MAX; i++) {       //Scan the whole key list.
      if ( keypad.key[i].stateChanged ) {      //Only find keys that have changed state.
        if (keypad.key[i].kstate == PRESSED) { //Only looks for first key that was pressed
          return keypad.key[i].kchar;          //return with value of first key pressed
        }
      }
    }
  }
  return NO_KEY; //return NO_KEY if no key has been pressed
}

Thanks for the input.

I've designed an atmega2560 converted into a DAQ. It can be controlled via serial or run standalone (using keypad). The keypad is just for simple "one key" presses and release. Since I'm using background timer interrupts etc, a non-blocking, no delay() keypad scanner was needed. I just thought there was a library out there that would do this simple operation.

The key = readkey() function does not scan and update when a key is already pushed before calling it. I've got much on my plate and did not want to dig further into the library. The Adafruit library works as advertised. The simple sample code I have listed below works perfectly for what I'm doing.

Thanks again for the quick response...

Regards

#include <Adafruit_Keypad.h>

boolean key_pressed(char key)
{
	keypad.tick();
	pressed = keypad.isPressed(key);
	keypad.clear();
	return(pressed);
}

void wait_for_key_release(char key)
{
	do
	{
		keypad.tick();
	} while (keypad.isPressed(key));
	keypad.clear();
}

void test_1()
{
	char key;
	USE_SERIAL.println("Starting Test_1-a");
	delay(3000);
	if (key_pressed('E'))
	{
		USE_SERIAL.println("Abort Detected");
		wait_for_key_release('E');
		return;
	}
	USE_SERIAL.println("Starting Test_1-b");
	delay(3000);
	if (key_pressed('E'))
	{
		USE_SERIAL.println("Abort Detected");
		wait_for_key_release('E');
		return;
	}
}

loop()
{
	if ((millis() - key_scan_start_time) > 200)
	{
		keypad.tick();
		key_scan_start_time = millis();
	}
	keypadEvent e = keypad.read();
	switch ((char)e.bit.KEY)
		{
		case 'S':
			Serial.println((char)e.bit.KEY);
			wait_for_key_release((char)e.bit.KEY);
			test_1();
			break;
		case 'E':
			Serial.println((char)e.bit.KEY);
			wait_for_key_release((char)e.bit.KEY);
			break;
		default:
			break;
		}
}

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