Converting to 6 possible simultaneous button presses. NKRO

Status
Not open for further replies.

notbart

Member
I am a non-programmer NOOB. What I think I am doing (based on a prior NES controller example) is mapping each pin to a usb key command bia two arrays. Then I am checking to see if a button is pressed. (rinse and repeat) putting the requested key (key) corresponding to the appropriate pin. Keyboard.set_key1(keys); into keyboard.set_key1.

Here is the thing (I tried a bunch of case statements but have not go there yet); I want to allow multiple keys to be pressed and then shuttled into the next available keyboard.setkey ... eg keyboard.setkey1 or keyboard.setkey2.

could anyone suggest an approach or provide a code snippit that I could either use or learn from. (PS Paul.. the board is great; lots of fun.. I am mating the board with 3d printing, my first pcb design! such a noob am I.) PS my last programming was on a PDP 11 decades ago.


Code:
const int pinzero = 0;
const int pinone = 1;
const int pintwo = 2;
const int pinthree = 3;
const int pinfour = 4;
const int pinfive = 5;
const int pinsix = 6;
const int pinseven = 7;
const int pineight = 8;
const int pinnine = 9;
const int pinten = 10;
const int pineleven = 11;
const int pintwelve = 12;
const int pinthirteen = 13;
const int pinfourteen = 14;
const int pinfifteen = 15;
const int pinsixteen = 16;
const int pinseventeen = 17;
const int pineighteen = 18;
const int pinnineteen = 19;
const int pintwenty = 20;
const int pintwentyone = 21; 

//CHANGE NEEDED - USE PIN 20 AND 21 FOR MODIFYIER KEYS ALT AND CONTROL


//Variables for the states of the pins
byte numpins[] = {pinzero, pinone, pintwo, pinthree, pinfour, pinfive, pinsix, pinseven, pineight, pinnine, pinten, pineleven, pintwelve, pinthirteen, pinfourteen, pinfifteen, pinsixteen,
pinseventeen, pineighteen, pinnineteen}; 
byte keys[] = {KEY_W, KEY_A, KEY_S, KEY_D, KEY_SPACE, KEY_Q, KEY_R, KEY_Z, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_T, KEY_Y, KEY_O};


#define NUMBUTTONS sizeof(numpins)


void setup()
{
  

  //Special for the Teensy is the INPUT_PULLUP
  //It enables a pullup resitor on the pin.
  for (byte i=0; i< NUMBUTTONS; i++) {
    pinMode(numpins[i], INPUT_PULLUP);
  }
  
 

}


void loop()
{
//  //debugging the start button...
  //digitalWrite ( pinLEDOutput, digitalRead(pinBtnStart));

  //Progess the SNES controller buttons to send keystrokes.
  fcnProcessButtons();
  
}

//Process buttons
void fcnProcessButtons()
{
  static long currentkey = 0;
  byte nothingpressed = 1;
  
  // run through all the buttons
  for (byte i = 0; i < NUMBUTTONS; i++) {
    
    // are any of them pressed?
    if (! digitalRead(numpins[i])) {
      nothingpressed = 0; // at least one button is pressed!

// THIS SECTION NEEDS TO CHANGE TO ALLOW NKRO EG WE CAN HAVE Keyboard.set_key1 to Keyboard.set_key6 and then send
      
      // if its a new button, release the old one, and press the new one
      if (currentkey != keys[i]) {
        Keyboard.set_key1(0);
        Keyboard.send_now();
        Keyboard.set_key1(keys[i]);
        currentkey = keys[i];
        Keyboard.send_now();
      } else {
        // the same button is pressed, so repeat!
        Keyboard.set_key1(keys[i]);
        Keyboard.send_now();
        delay(100);
      }
    }
  }
  
  if (nothingpressed) {
    // release all keys
    Keyboard.set_key1(0);
    Keyboard.send_now();
  }
}
 
Last edited:
If you wrap your code it is more readable:
code.PNG
 
Perhaps the way to go is to count how many keys pressed

Doc.. I don't want to use the keypad library because I am connecting each teensy pin to a key, I am not wiring in a matrix with diodes.



Perhaps the way to go is to count how many keys are pressed at one time. Any ideas?
 
Sorry, I'm a bit confused as to what you're asking here.

Do you simply need to map each pin to a key, then queue up those key presses if multiple keys have been pressed? (Please be aware I'm not all that familiar with the Keyboard library)

I started writing this but haven't got time to finish it at the moment. It may be of some use in it's current form if you can see where I was going with it and finish it yourself. (Still needs to be able to allocate slots to new keys, and make sure that in the event a key is cleared, it isn't used again in the same loop (before Keyboard.send_now() is called).
I'll hopefully get time to take another look later this evening.

Code:
uint8_t keyStates[22] = {0};
uint8_t keyMapping[] = {KEY_W, KEY_A, KEY_S, KEY_D, KEY_SPACE, KEY_Q, KEY_R, KEY_Z, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_T, KEY_Y, KEY_O};
uint8_t keyQueueLookup[] = {255, 255, 255, 255, 255, 255};
uint8_t numberOfStateChanges = 0;

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  numberOfStateChanges = 0;
  for(uint8_t i=0; i<22; i++) {    //Cycle through each pin
    if(numberOfStateChanges >= 6)    //If 6 or more state changes have already taken place, we have no more slots!
      break;
    uint8_t btnState = !digitalRead(i);  //Get pressed state.
    if(btnState != keyState[i])            //If state has changed
    {
      numberOfStateChanges++;                //Keep count.
      for(uint8_t j=0; j<6; j++) {           //Check if a slot has been allocated
        if(keyQueueLookup[j] == i)             //Found a slot that belongs to that key.
        {
          keyState[i] = btnState;                //Update our stored button state.
          switch(j) {                            //Update relevant slot.
            case 0:
              Keyboard.set_key1(keyState[i] ? keyMapping[i] : 0);
              break;
            case 1:
              Keyboard.set_key2(keyState[i] ? keyMapping[i] : 0);
              break;
            case 2:
              Keyboard.set_key3(keyState[i] ? keyMapping[i] : 0);
              break;
            case 3:
              Keyboard.set_key4(keyState[i] ? keyMapping[i] : 0);
              break;
            case 4:
              Keyboard.set_key5(keyState[i] ? keyMapping[i] : 0);
              break;
            case 5:
              Keyboard.set_key6(keyState[i] ? keyMapping[i] : 0);
              break;            
          }
          if(!keyState) {                   //If we cleared a slot.
            keyQueueLookup[j] = 255;          //Mark slot as available.  
          }
        }
      }
    }   
  }
}
 
Last edited:
That looks like it would work.

Sorry, I'm a bit confused as to what you're asking here.

Do you simply need to map each pin to a key, then queue up those key presses if multiple keys have been pressed? (Please be aware I'm not all that familiar with the Keyboard library)

I started writing this but haven't got time to finish it at the moment. It may be of some use in it's current form if you can see where I was going with it and finish it yourself. (Still needs to be able to allocate slots to new keys, and make sure that in the event a key is cleared, it isn't used again in the same loop (before Keyboard.send_now() is called).
I'll hopefully get time to take another look later this evening.

Code:
uint8_t keyStates[22] = {0};
uint8_t keyMapping[] = {KEY_W, KEY_A, KEY_S, KEY_D, KEY_SPACE, KEY_Q, KEY_R, KEY_Z, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_T, KEY_Y, KEY_O};
uint8_t keyQueueLookup[] = {255, 255, 255, 255, 255, 255};
uint8_t numberOfStateChanges = 0;

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  numberOfStateChanges = 0;
  for(uint8_t i=0; i<22; i++) {    //Cycle through each pin
    if(numberOfStateChanges >= 6)    //If 6 or more state changes have already taken place, we have no more slots!
      break;
    uint8_t btnState = !digitalRead(i);  //Get pressed state.
    if(btnState != keyState[i])            //If state has changed
    {
      numberOfStateChanges++;                //Keep count.
      for(uint8_t j=0; j<6; j++) {           //Check if a slot has been allocated
        if(keyQueueLookup[j] == i)             //Found a slot that belongs to that key.
        {
          keyState[i] = btnState;                //Update our stored button state.
          switch(j) {                            //Update relevant slot.
            case 0:
              Keyboard.set_key1(keyState[i] ? keyMapping[i] : 0);
              break;
            case 1:
              Keyboard.set_key2(keyState[i] ? keyMapping[i] : 0);
              break;
            case 2:
              Keyboard.set_key3(keyState[i] ? keyMapping[i] : 0);
              break;
            case 3:
              Keyboard.set_key4(keyState[i] ? keyMapping[i] : 0);
              break;
            case 4:
              Keyboard.set_key5(keyState[i] ? keyMapping[i] : 0);
              break;
            case 5:
              Keyboard.set_key6(keyState[i] ? keyMapping[i] : 0);
              break;            
          }
          if(!keyState) {                   //If we cleared a slot.
            keyQueueLookup[j] = 255;          //Mark slot as available.  
          }
        }
      }
    }   
  }
}

Cos thanks... that looks like it would work (except I think for the repeat they key if pressed) and also the send key now.

This sort of coding is beyond me (BUT, once you put it forth I am able to go line by line and read the logic of it). As I said the last time I tried to do something like this was on a PDP 11.


uint8_t keyQueueLookup[] = {255, 255, 255, 255, 255, 255}; eg.. why are you using 255 here (but I do see six positions).


Regards and thanks Not Bart.
 
I think this might be working correctly for NKRO

So far so good. (and thanks to Cosford) I think the following implementation is working correctly as far as I can tell.
It is quite a learning curve for me. I figured out the arrays and how to populate them. I am not quite sure what
uint8_t does. is it just an 8 bit integer?

Code:
const int pinzero = 0;
const int pinone = 1;
const int pintwo = 2;
const int pinthree = 3;
const int pinfour = 4;
const int pinfive = 5;
const int pinsix = 6;
const int pinseven = 7;
const int pineight = 8;
const int pinnine = 9;
const int pinten = 10;
const int pineleven = 11;
const int pintwelve = 12;
const int pinthirteen = 13;
const int pinfourteen = 14;
const int pinfifteen = 15;
const int pinsixteen = 16;
const int pinseventeen = 17;
const int pineighteen = 18;
const int pinnineteen = 19;
const int pintwenty = 20;
const int pintwentyone = 21;
int i = 0;
int xcount =0;


//Variables for the states of the pins
byte numpins[] = {pinzero, pinone, pintwo, pinthree, pinfour, pinfive, pinsix, pinseven, pineight, pinnine, pinten, pineleven, pintwelve, pinthirteen, pinfourteen, pinfifteen, pinsixteen,
pinseventeen, pineighteen, pinnineteen}; 
byte keys[] = {KEY_W, KEY_A, KEY_S, KEY_D, KEY_SPACE, KEY_Q, KEY_R, KEY_Z, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_T, KEY_Y, KEY_O};
uint8_t keyState[22] = {0};

#define NUMBUTTONS sizeof (numpins)


void setup()
{
  

  //Special for the Teensy is the INPUT_PULLUP
  //It enables a pullup resitor on the pin.
  for (byte i=0; i< NUMBUTTONS; i++) {
    pinMode(numpins[i], INPUT_PULLUP);
  }
  
 

}


void loop()
{

xcount = 0;
for (byte i=0; i< NUMBUTTONS; i++) {

  uint8_t btnState = !digitalRead(i);  //Get pressed state.
  if(btnState != keyState[i]) {

        switch(xcount) {                            //Update relevant slot.
            case 0:
              Keyboard.set_key1(keys[i]);
              delay (10);
              break;
            case 1:
              Keyboard.set_key2(keys[i]);
              delay (10);
              break;
            case 2:
              Keyboard.set_key3(keys[i]);
              delay (10);
              break;
            case 3:
              Keyboard.set_key4(keys[i]);
              delay (10);
              break;
            case 4:
              Keyboard.set_key5(keys[i]);
              delay (10);
              break;
            case 5:
              Keyboard.set_key6(keys[i]);
              delay (10);
              break;            
          }
          if (xcount > 6) {
            xcount=0;
          }
          else
          {
          xcount = xcount + 1;

          }
    
    }
  
}

Keyboard.send_now();

//i used the following for debugging
//if (xcount > 0) { 
//Keyboard.print(xcount);
//}

Keyboard.set_key1(0);
Keyboard.set_key2(0);
Keyboard.set_key3(0);
Keyboard.set_key4(0);
Keyboard.set_key5(0);
Keyboard.set_key6(0);
delay (100);

}
 
Debounce da inputs

Steve what am a trying to accomplish with bounce that I am not doing so already?

Basic Usage

Bounce myButton = Bounce(pin, milliseconds);

Create a Bounce object called myButton, using "pin" and waiting for bouncing to end within "milliseconds" time. You may create multiple Bounce objects, for as many different pins as necessary.

myButton.update();
Read the button and update its status. This update() function must be called regularly, so input on the pin is properly recognized. Return is true if the input changes, or false otherwise.

myButton.fallingEdge();
Check for a high to low transition. For a pushbutton connected between the pin and ground, this corresponds to the button being pressed.
myButton.risingEdge();

Check for a low to high transition. For a pushbutton connected between the pin and ground, this corresponds to the button being released.
 
Status
Not open for further replies.
Back
Top