Keypad question

I am using the multikey code for a keypad which works great as multiple keys can be pressed at the same time & says when the key is pressed, released etc.
Now my question is if I want each key press to run a certain function how can I code this in? I guess it will need to call variable assosiated with that key number in some way. Would I put if x if y etc for each case or is a better way?

Here is my code currently

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2'},
{'3','4'}
};
byte rowPins[ROWS] = {2, 3}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {6, 7}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;


void setup() {
    Serial.begin(9600);
    loopCount = 0;
    startTime = millis();
    msg = "";
}


void loop() {
    loopCount++;
    if ( (millis()-startTime)>5000 ) {
        Serial.print("Average loops per second = ");
        Serial.println(loopCount/5);
        startTime = millis();
        loopCount = 0;
    }

    // Fills kpd.key[ ] array with up-to 10 active keys.
    // Returns true if there are ANY active keys.
    if (kpd.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:
                    msg = " PRESSED.";
                break;
                    case HOLD:
                    msg = " HOLD.";
                break;
                    case RELEASED:
                    msg = " RELEASED.";
                break;
                    case IDLE:
                    msg = " IDLE.";
                }
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.println(msg);
            }
        }
    }
}  //

So at the event of pressed & released I need it reference to a function for the key that was pressed.

Yes a if/else or switch/case approach will work. Put that in a fonction which takes a key as parameter so that you don’t duplicate it

(You are declaring a 4x3 keypad but from the definition of the keys seems it’s only a 2x2?)

Okay to explain a bit better I have the below code;

 if (kpd.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:
                    sendKeyPress(false, KEY01);
                break;
                    case HOLD:;
                break;
                    case RELEASED:
                    sendKeyPress(true, KEY01);
                break;
                    case IDLE:;
                }
            }
        }
    }
}

This works as I want it to but each key does the same thing so bassically I need it to change the const string KEY01 reference to be KEY + the key number that is pressed. Can this be done?

I see you took the code from the MultiKey/MultiKey.ino example

what’ the sendKeyPress() function? something you wrote? if so, just pass the right key to this function as well and build your message there (no need to use the String class…)

I have now got my project working to a degree so sendKeyPress function takes the value from the pressed key which is the value from the char array. Now can I use variables for this so that all my keys in the array are for example k01 k02 etc… then there is a list of INT k01 = SHIFT k02 = 1 etc but would sendKeyPress then take the int variable?

here is my current working code;

/*******************************************************************************
 * Includes
 ******************************************************************************/
#include <Key.h>
#include <Keypad.h>
#include <OSCBoards.h>
#include <OSCBundle.h>
#include <OSCData.h>
#include <OSCMatch.h>
#include <OSCMessage.h>
#include <OSCTiming.h>
#ifdef BOARD_HAS_USB_SERIAL
  #include <SLIPEncodedUSBSerial.h>
  SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB);
  #else
  #include <SLIPEncodedSerial.h>
  SLIPEncodedSerial SLIPSerial(Serial);
  #endif
#include <string.h>

  /*******************************************************************************
  * Macros and Constants
  ******************************************************************************/
const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
//define the cymbols on the buttons of the keypads
char Keys[ROWS][COLS] = 
{
{'1','2'}, // RFM: There was an error here
{'3','4'}
};
byte rowPins[ROWS] = {3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {7, 6}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad kpd = Keypad( makeKeymap(Keys), rowPins, colPins, ROWS, COLS);

unsigned long loopCount;
unsigned long startTime;
String keyEvent;
String keyPress;

#define SUBSCRIBE   1
#define UNSUBSCRIBE 0

#define EDGE_DOWN   0
#define EDGE_UP     1

#define OSC_BUF_MAX_SIZE 512

const String HANDSHAKE_QUERY = "ETCOSC?";
const String HANDSHAKE_REPLY = "OK";

const String EOS_KEY = "/eos/key/";

/*******************************************************************************
 * Local Types
 ******************************************************************************/


/*******************************************************************************
 * Global Variables
 ******************************************************************************/


/*******************************************************************************
 * Local Functions
 ******************************************************************************/
/*******************************************************************************
 * Issues all our subscribes to Eos. When subscribed, Eos will keep us updated
 * with the latest values for a given parameter.
 *
 * Parameters:  none
 *
 * Return Value: void
 *
 ******************************************************************************/
void issueSubscribes()
{
    // Add a filter so we don't get spammed with unwanted OSC messages from Eos
    OSCMessage filter("/eos/filter/add");
    filter.add("/eos/out/pantilt*");
    SLIPSerial.beginPacket();
    filter.send(SLIPSerial);
    SLIPSerial.endPacket();

    // subscribe to Eos pan & tilt updates
    OSCMessage subPan("/eos/subscribe/param/pan");
    subPan.add(SUBSCRIBE);
    SLIPSerial.beginPacket();
    subPan.send(SLIPSerial);
    SLIPSerial.endPacket();

    OSCMessage subTilt("/eos/subscribe/param/tilt");
    subTilt.add(SUBSCRIBE);
    SLIPSerial.beginPacket();
    subTilt.send(SLIPSerial);
    SLIPSerial.endPacket();
}

/*******************************************************************************
 * Given an unknown OSC message we check to see if it's a handshake message.
 * If it's a handshake we issue a subscribe, otherwise we begin route the OSC
 * message to the appropriate function.
 *
 * Parameters:
 *  msg - The OSC message of unknown importance
 *
 * Return Value: void
 *
 ******************************************************************************/
void parseOSCMessage(String& msg)
{
    // check to see if this is the handshake string
    if (msg.indexOf(HANDSHAKE_QUERY) != -1)
    {
        // handshake string found!
        SLIPSerial.beginPacket();
        SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length());
        SLIPSerial.endPacket();

        // Let Eos know we want updates on some things
        issueSubscribes();
    }
    else
    {
        // prepare the message for routing by filling an OSCMessage object with our message string
        OSCMessage oscmsg;
        oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length());
    }
}

/*******************************************************************************
 * Sends a message to Eos informing them of a keys press.
 *
 * Parameters:
 *  down - whether a key has been pushed down (true) or released (false)
 *  key - the key that has moved
 *
 * Return Value: void
 *
 ******************************************************************************/
void sendKeyPress(bool down, String key)
{
    key = EOS_KEY + key;
    OSCMessage keyMsg(key.c_str());

    if (down)
        keyMsg.add(EDGE_DOWN);
    else
        keyMsg.add(EDGE_UP);

    SLIPSerial.beginPacket();
    keyMsg.send(SLIPSerial);
    SLIPSerial.endPacket();
}

/*******************************************************************************
 * Checks the status of all the buttons relavent to Eos (i.e. Next & Last)
 *
 * NOTE: This does not check the shift key. The shift key is used in tandom with
 * the encoder to determine coarse/fine mode and thus does not report to Eos
 * directly.
 *
 * Parameters: none
 *
 * Return Value: void
 *
 ******************************************************************************/
 void checkButtons()
 {
  loopCount++;
    if ( (millis()-startTime)>5000 ) 
    {
        startTime = millis();
        loopCount = 0;
    }

    // Fills kpd.key[ ] array with up-to 10 active keys.
    // Returns true if there are ANY active keys.
    if (kpd.getKeys())
    {        
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:;
                    keyPress = kpd.key[i].kchar;
                    sendKeyPress(false, keyPress);
                break;
                    case HOLD:;
                break;
                    case RELEASED:;
                    keyPress = kpd.key[i].kchar;
                    sendKeyPress(true, keyPress);
                break;
                    case IDLE:;
                }
            }
        }
    }
}
    

/*******************************************************************************
 * Here we setup our encoder, lcd, and various input devices. We also prepare
 * to comunicate OSC with Eos by setting up SLIPSerial. Once we are done with
 * setup() we pass control over to loop() and never call setup() again.
 *
 * NOTE: This function is the entry function. This is where control over the
 * arduino is passed to us (the end user).
 *
 * Parameters: none
 *
 * Return Value: void
 *
 ******************************************************************************/
void setup()
{
    SLIPSerial.begin(115200);
// This is a hack around an arduino bug. It was taken from the OSC library examples
    #ifdef BOARD_HAS_USB_SERIAL
      while (!SerialUSB);
      #else
      while (!Serial);
    #endif
 
    // this is necessary for reconnecting a device because it need some timme for the serial port to get open, but meanwhile the handshake message was send from eos
    SLIPSerial.beginPacket();
    SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length());
    SLIPSerial.endPacket();
    // Let Eos know we want updates on some things
    issueSubscribes();
    
    loopCount = 0;
    startTime = millis();
}

void loop()
{
    
    checkButtons();

    static String curMsg;
    int size;
    size = SLIPSerial.available();
    if (size > 0)
    {
        // Fill the msg with all of the available bytes
        while (size--)
            curMsg += (char)(SLIPSerial.read());
    }
    if (SLIPSerial.endofPacket())
    {
        parseOSCMessage(curMsg);
        curMsg = String();
    }
}

well you say that you are passing a String object as the second parameter
void sendKeyPress(bool down, [color=red]String key[/color])
this is somewhat overkill given that what you really send is kpd.key[ i].kchar that you copied into a String...

keyPress = kpd.key[i].kchar;
sendKeyPress(false, keyPress);

that's costly

you could just pass kpd.key[ i] to your function and let it extract what it needs

PS
it's better when comments are useful :slight_smile: rather than confusing

const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns

So I can change that but what else can I do to make it all function as I want?