Leonardo + Serial / LCD Print HID Keyboard Data

Just working with some code i have modified that in summary uses 5 columns and 4 rows i.e A0 closed with Digital pin 7 = "F2 key" or A2 + Digital 6 = "F" key etc

This can be customized by changing the below to suit what ever key you want etc

uint8_t buttonCodes[5][4] = {
{0x30, 0x31, 0x32, 0x33},

To match what key you want i.e i could change 0x30 to 0xD8 changing from key "0" to "Left Arrow"

LEFT_ARROW = 0xD8
RIGHT_ARROW = 0xD7

Where i am stuck and dont even know what to Google to self heal is this bit..

How do i LCD Print a custom command against a specific key -

For example a push button sends the command "F1" or "F" what ever into windows (say notepad) but on the LCD it prints a custom message like "You Pressed F1" or "You just clicked F" / "F2 Key was just pressed"?

You need a second 2D array, of type char *, that contains the messages. The indices into the buttonCodes array would be used to find the message to print.

After some Google action of 2D arrays i can tell i am getting closer so thanks for that PaulS, here is the code in its current format:

uint8_t buttonCodes[5][4] = {
{0x30, 0x31, 0x32, 0x33},
{0x34, 0x35, 0x36, 0x37},
{0x38, 0x39, 0xC2, 0xC3},
{0xC4, 0xC5, 0xC6, 0xC7},
{0xC8, 0xC9, 0xCA, 0xCB}
};

What i cant get my head around is how to make it call from two separate arrays as {0x30, "This is 0", 0x31, "This is 1", 0x32, "This is 2", 0x33, "This is 3"}, isn't correct.. is this right?

uint8_t buttonCodes[5][4] = {
{0x30, 0x31, 0x32, 0x33},
{0x34, 0x35, 0x36, 0x37},
{0x38, 0x39, 0xC2, 0xC3},
{0xC4, 0xC5, 0xC6, 0xC7},
{0xC8, 0xC9, 0xCA, 0xCB}
};
//Test
uint8_t buttonName[5][4] = {
{"30", "31", "32", "33"},
{"34", "35", "36", "37"},
{"38", "39", "C2", "C3"},
{"C4", "C5", "C6", "C7"},
{"C8", "C9", "CA", "CB"}
};

That way when the button at 0X30 aka "this is 0" is pressed it calls both? if you were to

Keyboard.release(buttonCodes[cPin][rPin]);
Keyboard.release(buttonName[cPin][rPin]);

... So close yet so far... Thanks to anyone looking at this to by the way.

AdydasNZ:
So close yet so far

Does this mean your problem isn't yet solved? I must admit I'm having trouble getting my head around what the problem is.

Perhaps if you posted your full code I'd get a better idea of what you're attempting to achieve and why it's going wrong.

      LEFT_ARROW = 0xD8
      RIGHT_ARROW = 0xD7
      UP_ARROW = 0xD
      DOWN_ARROW = 0xD9
 * -------------------------------------------------------------------------
 */
// Array of pins for the columns
//int cPins[] = {2, 3, 4, 5, 6};
int cPins[] = {A0, A1, A2, A3, A4};
// Number of pins in the column array
int cPinsNo = 5;

// Array of pins for the rows
//int rPins[] = {8, 9, 10, 11};
int rPins[] = {9, 8, 7, 6};

// Number of pins in the row array
int rPinsNo = 4;

// Array for the last known switch states [cPinsNo][rPinsNo]
int colPrev[5][4] = {0};

// Key codes to be used for each button
// (see table above for codes to use)
// (columns and rows are transposed on device)
//uint8_t buttonCodes[5][4] = {
int buttonCodes[5][4] = {
  {0x30, 0x31, 0x32, 0x33},
  {0x34, 0x35, 0x36, 0x37},
  {0x38, 0x39, 0xC2, 0xC3},
  {0xC4, 0xC5, 0xC6, 0xC7},
  {0xC8, 0xC9, 0xCA, 0xCB}
};
int cPinn[] = {A0, A1, A2, A3, A4};
int cPinnNo = 5;
int rPinn[] = {9, 8, 7, 6};
int rPinnNo = 4;
//Test
//int buttonNames[5][4] = {
//  {"30", "31", "32", "33"},
//  {"34", "35", "36", "37"},
//  {"38", "39", "C2", "C3"},
// {"C4", "C5", "C6", "C7"},
//  {"C8", "C9", "CA", "CB"}
//};
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  //Start Serial
  lcd.begin(20, 4);
  lcd.print("Testing");
  Serial.begin(9600);

  //Set the Column Pin Mode
  Serial.println("Setting Column Pins...");

  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    pinMode(cPins[cPin], OUTPUT);
    digitalWrite(cPins[cPin], HIGH);
  }

  //Set the Row Pin Mode
  Serial.println("Setting Row Pins...");

  for(int rPin = 0; rPin < rPinsNo; rPin++)
  {
    pinMode(rPins[rPin], INPUT);
    digitalWrite(rPins[rPin], HIGH);
  }
  Serial.println("Ready!");
} 

void loop()
{
  // Loop through the columns
  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    digitalWrite(cPins[cPin], LOW);

    // Loop through the rows
    for(int rPin = 0; rPin < rPinsNo; rPin++)
    {
      //Check if each switch is pressed
      if(digitalRead(rPins[rPin]) == LOW)
      {
        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 0)
        {
          // Do action here, switch is on
          Serial.print(cPins[cPin]);
          Serial.print(", ");
          Serial.print(rPins[rPin]);
          Serial.println(" ON");

          Keyboard.press(buttonCodes[cPin][rPin]);
          lcd.setCursor(0, 2);
          //lcd.print(buttonCodes[cPin][rPin]);
          lcd.print(rPins[rPin]);
          lcd.print(cPins[cPin]);
          delay(150);
          Keyboard.release(buttonCodes[cPin][rPin]); 
          delay(350);
          lcd.setCursor(0, 2);
          lcd.print("                             ");
          // Update last known state of this switch
          colPrev[cPin][rPin] = 1;
        }
      } 
      else {

        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 1)
        {
          // Do action here, switch is off
          Serial.print(cPins[cPin]);
          Serial.print(", ");
          Serial.print(rPins[rPin]);
          Serial.println(" OFF");

          // Update last known state of this switch
          colPrev[cPin][rPin] = 0;
        }
      }
    }
    digitalWrite(cPins[cPin], HIGH);
  }
//lcd.setCursor(0, 2);
}

So at the moment the below prints the pins being used in the image case 9 and 18 (9 and Analog 0) as being a closed circuit and prints those pins into LCD (or serial etc).

lcd.print(rPins[rPin]);
lcd.print(cPins[cPin]);

What i want is to be able to custom the output so that when i push 9 and 18 it says “Custom Message 1” not “918”, “Custom Message 2” not “818” etc

So do i need a if statement that looks up if rPins = 9 and cPins 18 to then LCD print something or can i use a separate array (current attempt is //'d out) as i cant get my head 100% around if that is correct coding as well as correct method to achieve.
lcd.print(rPins[rPin]);

To be honest I’m not really familiar with the Leonardo but I’d suggest using a switch statement to capture any special keys. Something like this might work.

int cPins[] = {A0, A1, A2, A3, A4};
// Number of pins in the column array
int cPinsNo = 5;

// Array of pins for the rows
int rPins[] = {9, 8, 7, 6};

// Number of pins in the row array
int rPinsNo = 4;

// Array for the last known switch states [cPinsNo][rPinsNo]
int colPrev[5][4] = {0};

// Key codes to be used for each button
// (see table above for codes to use)
// (columns and rows are transposed on device)
//uint8_t buttonCodes[5][4] = {
int buttonCodes[5][4] = {
  {0x30, 0x31, 0x32, 0x33},
  {0x34, 0x35, 0x36, 0x37},
  {0x38, 0x39, 0xC2, 0xC3},
  {0xC4, 0xC5, 0xC6, 0xC7},
  {0xC8, 0xC9, 0xCA, 0xCB}
};
int cPinn[] = {A0, A1, A2, A3, A4};
int cPinnNo = 5;
int rPinn[] = {9, 8, 7, 6};
int rPinnNo = 4;

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  //Start Serial
  lcd.begin(20, 4);
  lcd.print("Testing");
  Serial.begin(9600);

  //Set the Column Pin Mode
  Serial.println("Setting Column Pins...");

  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    pinMode(cPins[cPin], OUTPUT);
    digitalWrite(cPins[cPin], HIGH);
  }

  //Set the Row Pin Mode
  Serial.println("Setting Row Pins...");

  for(int rPin = 0; rPin < rPinsNo; rPin++)
  {
    pinMode(rPins[rPin], INPUT);
    digitalWrite(rPins[rPin], HIGH);
  }
  Serial.println("Ready!");
} 

void loop()
{
char output[20];  

  // Loop through the columns
  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    digitalWrite(cPins[cPin], LOW);

    // Loop through the rows
    for(int rPin = 0; rPin < rPinsNo; rPin++)
    {
      //Check if each switch is pressed
      if(digitalRead(rPins[rPin]) == LOW)
      {
        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 0)
        {
          // Do action here, switch is on

         switch(cPin *10 + rPin)
            {case 00:// col 0 row 0
               sprintf(output,"Custom message 1");
               Serial.println(output);
               break;
             
             case 01://col 0 row 1 
               sprintf(output,"Custom message 2");
               Serial.println(output);
               break;
             
             case 12://col 1 row 2
               sprintf(output,"col 1 row 2");  
               Serial.println(output);
               break;
               
            default:
               output[0]=buttonCodes[cPin][rPin];
               output[1]=0;//terminate string         
               Serial.print(cPins[cPin]);
               Serial.print(", ");
               Serial.print(rPins[rPin]);
               Serial.println(" ON");

            }

          lcd.setCursor(0, 2);
          lcd.print("                             ");
          lcd.setCursor(0, 2);
          lcd.print(output);
          sendKeys(output); 
          // Update last known state of this switch
          colPrev[cPin][rPin] = 1;
        }
      } 
      else {

        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 1)
        {
          // Do action here, switch is off
          Serial.print(cPins[cPin]);
          Serial.print(", ");
          Serial.print(rPins[rPin]);
          Serial.println(" OFF");

          // Update last known state of this switch
          colPrev[cPin][rPin] = 0;
        }
      }
    }
    digitalWrite(cPins[cPin], HIGH);
  }
}


void sendKeys(char* customString)
{
for(int n=0; customString[n]>0; n++)
  {
   Keyboard.press(customString[n]);
   delay(150);
   Keyboard.release(customString[n]);
   delay(150); 
  }
  
}

Thanks KenF this certainly helps me a bit but i still have some work to do, one thing i might not have explained well was that i still need the Leonardo to output the Hex?? code to windows but almost like an Alias display on the LCD a totally different output.

i.e if i open note pad and put the cursor in it, hit 1 or 2 buttons it should come up with the respective hex converted letter or number in my current case button 1 should display 1 and button 2 should display 2 in note pad.

My Goal is to have the LCD display a message that corresponds to that same button but has a customization message like you have helped me with here.

So i press button 1 and in windows if i had the cursor in a notepad say it would output a single character i.e "1" or "F" depending on the code in the corresponding array.

But in the LCD like your updated code it shows a different message but doesn't stop the Leonardo outputting the single character whilst at the same time it is outputting multiple printed characters into the LCD only.

Example of what i think i want but cant get to work or am on the wrong track.

uint8_t buttonCodes[5][4] = {
{0x30, 0x31, 0x32, 0x33},
};

But i allmost want a second array i think

uint8_t buttonNames[5][4] = {
{Name1, Name2, Name3, 0x33}
};

Keyboard.press(buttonCodes[cPin][rPin]);
lcd.print(buttonNames[cPin][rPin]);

So that in Notepad i get single character from "buttonCodes" i.e 0x30 aka the number 0 but on LCD i get "Name1" show up whilst it outputs the 0 / 0x30 into notepad.

How is Name1 defined? If you want to print it on the LCD as "Name1", it MUST be a string (NULL terminated array of char), NOT a uint8_t.

Thats my point / problem i dont know where or how to define it so it can be called upon, but i am going to start doing some googling for Strings as it gives me some hope that's where i need to be learning.

i am going to start doing some googling for Strings as it gives me some hope that's where i need to be learning.

You'd be wasting your time. Googling strings, on the other hand, would be useful.

char *names[5][4] = {
{ "Name 00", "Name 10", "Name 20", "Name 30", "Name 40" },
{ "Name 01", "Name 11", "Name 21", "Name 31", "Name 41" },
{ "Name 02", "Name 12", "Name 22", "Name 32", "Name 42" },
{ "Name 03", "Name 13", "Name 23", "Name 33", "Name 43" },
};

PaulS you are a legend this helps me confirm earlier thinking i was supposed to setup another array i just made the error of repeating it as uint8_t not char.

But i am still close yet so far away, at the moment my below code does show a different output between what is wrote into note pad when a button is pressed vs what is shown on LCD print - but it appears to be showing the … well i dont know it appears to be the row or colum rather than the text from the array.

// Array of pins for the columns
int cPins[] = {A0, A1, A2, A3, A4};
// Number of pins in the column array
int cPinsNo = 5;

// Array of pins for the rows
int rPins[] = {9, 8, 7, 6};

// Number of pins in the row array
int rPinsNo = 4;

// Array for the last known switch states [cPinsNo][rPinsNo]
int colPrev[5][4] = {0};

// Key codes to be used for each button
// (see table above for codes to use)
// (columns and rows are transposed on device)
uint8_t buttonCodes[5][4] = {
  {0x30, 0x31, 0x32, 0x33},
  {0x34, 0x35, 0x36, 0x37},
  {0x38, 0x39, 0x27, 0x2C},
  {0x2D, 0x2E, 0x2F, 0x3B},
  {0x5B, 0x5D, 0xD8, 0xD7}
};
#include "buttonname.h"
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  //Start Serial
  lcd.begin(20, 4);
  lcd.print("Title");
  lcd.setCursor(0, 2);
  lcd.print("Recently Pressed :");
  Serial.begin(9600);

  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    pinMode(cPins[cPin], OUTPUT);
    digitalWrite(cPins[cPin], HIGH);
  }

  //Set the Row Pin Mode
  Serial.println("Setting Row Pins...");

  for(int rPin = 0; rPin < rPinsNo; rPin++)
  {
    pinMode(rPins[rPin], INPUT);
    digitalWrite(rPins[rPin], HIGH);
  }
  Serial.println("Ready!");
} 

void loop()
{
  // Loop through the columns
  for(int cPin = 0; cPin < cPinsNo; cPin++)
  {
    digitalWrite(cPins[cPin], LOW);

    // Loop through the rows
    for(int rPin = 0; rPin < rPinsNo; rPin++)
    {
      //Check if each switch is pressed
      if(digitalRead(rPins[rPin]) == LOW)
      {
        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 0)
        {
          // Do action here, switch is on
          Serial.print(cPins[cPin]);
          Serial.print(", ");
          Serial.print(rPins[rPin]);
          Serial.println(" ON");

          Keyboard.press(buttonCodes[cPin][rPin]);
          delay(250);
          Keyboard.release(buttonCodes[cPin][rPin]); 
          lcd.setCursor(0, 3);
          lcd.print(buttonName[cPin][rPin]);
          // Update last known state of this switch
          colPrev[cPin][rPin] = 1;
        }
      } 
      else {

        // Check to see if the state has changed since last time
        if(colPrev[cPin][rPin] == 1)
        {
          // Do action here, switch is off
          Serial.print(cPins[cPin]);
          Serial.print(", ");
          Serial.print(rPins[rPin]);
          Serial.println(" OFF");

          // Update last known state of this switch
          colPrev[cPin][rPin] = 0;
        }
      }
    }
    digitalWrite(cPins[cPin], HIGH);
  }
}
char buttonName[5][4] = {
  {'testA1', 'testA2', 'testA3', 'testA4'},
  {'testB1', 'testB2', 'testB3', 'testB4'},
  {'testC1', 'testC2', 'testC3', 'testC4'},
  {'testD1', 'testD2', 'testD3', 'testD4'},
  {'testE1', 'testE2', 'testE3', 'testE4'}
};

At the moment if i press the button that corresponds to {0x5B, 0x5D i get the [ and ] as output in note pad and in LCD Print i get 1 and 2 - i guess this means Row 1 and Row 2 (but why no reference to Column 5?)

lcd.print(buttonName[cPin][rPin]);

The above i would have figured would call

testE1 and testE2 being that the code is supposed to be referencing “buttonName” colum 5 x 1 and 5 x 2 isnt it?

By the way when i used " not ’ i got errors that when i did some research were cleared up so it would compile - could this be the cause of why it isn’t showing the text “testE1”?? This was the error.

error: initializer-string for array of chars is too long [-fpermissive]

char buttonName[5][4] = {
  {'testA1', 'testA2', 'testA3', 'testA4'},
  {'testB1', 'testB2', 'testB3', 'testB4'},
  {'testC1', 'testC2', 'testC3', 'testC4'},
  {'testD1', 'testD2', 'testD3', 'testD4'},
  {'testE1', 'testE2', 'testE3', 'testE4'}
};

Single quotes are for single characters. The items in the array are NOT chars. They are strings (char *).