Keyboard function, can't press and hold more than 6 keys simultaneously.

Arduino Leonardo, Serial speed 19200.

I'm doing a custom keyboard, which simulates 11 keys press. Currently I have 8 keys wired and use pin 3 to 10 to receive input (pinMode INPUT).

The Screenshot shows how I connect to one of the keys. And all other keys have the exact same connection.
Power is provided by USB itself, it connects to computer.
All LEDs are 5V but with different color, these 8 keys I'm testing now are 4 yellow, and 4 blue.
All connected resistors are all 2000 Ohm.
All Buttons are microswitches.

I assigned key 1 to 7 with "s d f h j k l" characters, and key 8 is shift. Whey a key is pressed, the program will call Keyboard.press(), and when its released, then it will call Keyboard.release(). I've already dealt with the button bounce issue.

Now the issue is, I can't press all keys simultaneously. I'm trying to hit first 7 keys together, and hope in keyboard rollover tester, all 7 keys should be pressed down. But it turns out, that the last key I press down won't be detected, regardless which key I press last. For example, I press "s d f j k l" 6 chars together down, and all 6 are pressed in keyboard tester, but when I press down the 7th key "h", it won't detect, until I release one. However, all LEDs lit fine when key is pressed, regardless of the windows receives the key press or not.

But shift ( key 8 ) works differently, when I press shift after 6 chars are pressed down, shift won't trigger. But When I hold shift as one of the first 6 buttons holds down, I can press one more button, and now 7 keys are pressed down simultaneously with shift.

I thought it's some limitation on Keyboard function, but it also could be something to do with the board. Can anyone help me?

Do You have any software we can look at?

Railroader:
Do You have any software we can look at?

Current version of the code, if it helps.

InoIIDX.zip (1.06 KB)

Read the first topics like "How to use this Forum", "How to attache code".
"if it helps"...... What else would help?

You need to use a library that supports NKRO or "n-Key Roll Over" such as NicoHood's HID library. Also be aware there is a limit on how many keys the operating system can handle at the same time. I believe it is around 5-7 in Windows.

chopsuwe:
You need to use a library that supports NKRO or "n-Key Roll Over" such as NicoHood's HID library. Also be aware there is a limit on how many keys the operating system can handle at the same time. I believe it is around 5-7 in Windows.

Thanks I'll looking into it.
But are you sure windows has its limit? because I have a NKRO keyboard myself and I can press 20keys on it just fine. I tested it on this website through Chrome:

And my arduino can only press 6 or 7 with shift on my side.

Hi,
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

What is the application?
Why do you need to detect more than one key/button pressed?

Thanks.. Tom.... :slight_smile:

// ino file
#include "Config.h"
#include <Keyboard.h>

bool buttonCurrentStates[BUTTON_COUNT] = {false, false, false, false, false, false, false, false, false, false, false};
bool buttonLastStates[BUTTON_COUNT] = {false, false, false, false, false, false, false, false, false, false, false};
bool buttonHasNoise[BUTTON_COUNT] = {false, false, false, false, false, false, false, false, false, false, false};
long buttonNoiseTime[BUTTON_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned long currentMillis = 0;

bool testOutputTrigger = false;

void setup()
{
    Serial.begin(SERIAL_SPEED);
    for (uint8_t i = 0; i < BUTTON_USE; i++)
    {
        pinMode(BUTTON_PINS[i], INPUT);
    }
    Keyboard.begin();
}

void loop()
{
    UpdateState();
    UpdateTestOutput();
}

void UpdateState()
{
    currentMillis = millis();
    for (uint8_t i = 0; i < BUTTON_USE; i++)
    {
        buttonCurrentStates[i] = digitalRead(BUTTON_PINS[i]);
        if (buttonCurrentStates[i] != buttonLastStates[i])
        {
            if (!buttonHasNoise[i])
            {
                // No Noise
                if (buttonCurrentStates[i])
                {
                    Keyboard.press(BUTTON_CHAR[i]);
                    buttonHasNoise[i] = true;
                    buttonNoiseTime[i] = currentMillis;
                }
                else
                {
                    Keyboard.release(BUTTON_CHAR[i]);
                }

                testOutputTrigger = true;
                buttonLastStates[i] = buttonCurrentStates[i];
            }
            else
            {
                // Noise
                if ((currentMillis - buttonNoiseTime[i]) > DEBOUNCE_THRESHOLD_MILLIS)
                {
                    buttonHasNoise[i] = false;
                }
            }
        }
    }
}

void UpdateTestOutput()
{
    if (testOutputTrigger)
    {
        Serial.print(currentMillis);
        Serial.print("\t");
        for (uint8_t i = 0; i < BUTTON_COUNT; i++)
        {
            Serial.print(buttonCurrentStates[i]);
        }

        Serial.println();
        testOutputTrigger = false;
    }
}
// .h file
#include <Keyboard.h>

#define BUTTON_COUNT 11
#define BUTTON_USE 8

const uint8_t BUTTON_PINS[BUTTON_COUNT] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const char BUTTON_CHAR[BUTTON_COUNT] = {
    's', 'd', 'f', 'h', 'j', 'k', 'l', KEY_LEFT_SHIFT, KEY_RIGHT_SHIFT, KEY_ESC, KEY_RETURN};

const int SERIAL_SPEED = 19200;
const uint8_t DEBOUNCE_THRESHOLD_MILLIS = 4;

Here is the code

TomGeorge:
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

What is the application?
Why do you need to detect more than one key/button pressed?

Thanks.. Tom.... :slight_smile:

I don't have a schematic or CAD for this project. I followed my friends' instructions about how to get signal from button and lit LED at the same time (Its their profession). And I got the TinkerCAD design for one button, which is what I posted in the first post. I simply copied all the button connections with the exact same way, like this screenshot in attachment (6 buttons, same for the others).

About the application, I'm trying to do a custom "beatmania iidx controller" (You can google it for what it is like). It doesn't really require all buttons pressed down at the same time in the beginning, but it should be doable and I expect all buttons press down at the same time in higher difficulty. Which means my 8 main buttons should be able to be pressed down and be detected at the same time. I have more buttons planned in final form, there will be 11 buttons in total, but the first 8 buttons should be able to be detected.

Currently, all connected buttons can be detected one by one, but only 6 buttons can be successfully detected simultaneously.

Hi,
The images you are posting are not schematics, they are called Fritzy and may help with placing components, but with all the wires crisscrossing any trouble shooting is just about impossible.
A proper schematic will help.

  • Can you post a picture of your project so we can see your component layout?
  • Do you have a DMM to check that the correct level button signals are reaching the Leonardo?
  • Do the LEDs associated with each button light up when you press them?

You image shows ONLY 6 buttons connected.
If the LEDs are 5V type, in other words LED indicators, then how do you expect the input of the controller to go from gnd to 5V to register a HIGH. It can't as combined with the pull down resistor will make a button press voltage a lot less than 5V.
If you remove the LED indicators and replace each of them with a wire link, you may have a different result.
Are the LED indicators the correct way around.

Why have you posted two codes?
Where in the first do you assign the value 8 to BUTTON_USE? Does it compile?

Can I suggest you write a very simple code that JUST checks your button inputs and outputs on the serial monitor.

Forget about debounce, forget about config and keyboard libraries even forget about arrays. JUST write a simple basic code nothing fancy.
At this stage we are looking a functional code, not economic, sleek fast code.

Sorry, but you now need to go into troubleshoot mode and that means checking your project in individual stages.

Thanks.. Tom... :slight_smile:

@TomGeorge

Hi,

Sorry but I'm getting nervous with your comments. I'll try to make myself clear again.

  • As I stated in last comment, I got the TinkerCAD design for one button, which is what I posted in the first post. I simply copied all the button connections with the exact same way. I don't really want to post that screenshot just BECAUSE I WANT TO PREVENT SHOWING wires crisscrossing. This is just an example of how I connected to each button, simply "copy paste" them.
  • ALL 8 CONNECTED BUTTONS WORKS. Computer gets the signals when individually pressed, and when less or equal than 6 buttons pressed, the computer gets all 6 signals.
  • As I stated in the first post, ALL LEDS WORKS FINE when its key is pressed, regardless of the Windows receives the key press or not.
  • THE CODE WORKS AND COMPILES, otherwise I won't post it, and the button won't work if the code doesn't work!
  • There are 2 codes because one of them is "Config.h" file and another is ".ino" file. I commented it in the first line in each code. I thought you can understand it.
  • BUTTON_USE is 8 instead of BUTTON_COUNT because I didn't connect all the 11 pins. I only use 8 pins so in this way, I can only init the first 8 pins in define instead of 11. Otherwise other unconnected pin will get weird behaviour.
  • I have serial print out on each buttons behaviour in this code. It is the "UpdateTestOutput()" method.
  • About your suggest about simple code. I'VE ALREADY DONE IT BEFORE THE WHOLE PHASE. I already tested all the LEDs and Buttons, I tested every single button, and tried different connections, consulted my friends about some issues. I already made sure everything works before I continue to this phase. I'm not that stupid that forget hardware "unit test" before wiring.

You do have a point about the correct level on pin input. Could it be possible that because there are too many leds lits at the same time and the current to the input pins gets down below the acceptable input?

Update, I do forget to mention and test one thing and just came clear.

Serial print suggests that all buttons works fine even when all 8 buttons is pressed and hold down, all of them gets 1.

So the issue is definitely on Keyboard.press().

I'll try @chopsuwe suggestion next.

chopsuwe:
Also be aware there is a limit on how many keys the operating system can handle at the same time. I believe it is around 5-7 in Windows.

That applies to simultaneous key presses like ctrl-alt-del, not consecutive key presses. For somewhat obvious reasons, there can be no limit to consecutive presses, except for the limitations of the keyboard switch matrix hardware.

The Keyboard library is hardcoded for up to 6 keys pressed at the same time.
(I don't know if this is limited by the key report or the library itself.)

Declaration of key report in Keyboard.h:

//  Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct
{
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
} KeyReport;

And this is how keypresses are added to the key report in Keyboard.cpp:

	// Add k to the key report only if it's not already present
	// and if there is an empty slot.
	if (_keyReport.keys[0] != k && _keyReport.keys[1] != k && 
		_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
		_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
		
		for (i=0; i<6; i++) {
			if (_keyReport.keys[i] == 0x00) {
				_keyReport.keys[i] = k;
				break;
			}
		}
		if (i == 6) {
			setWriteError();
			return 0;
		}	
	}

Problem solved when using the NicoHood's HID library, it provides NKROKeyboard which is what I need. I also have to change the use the custom enum instead of char to pass the parameter to press().

Thank you all for your comments.