Issue with Keyboard Modifiers on the Leonardo

Hi. I am trying to create a sort of keyboard emulator using the Leonardo. I’m trying to set it up such that I can use an array of buttons to both type letters/words as well as some of the keyboard commands (i.e. KEY_CAPS_LOCK). In an attempt to make the code shorter, I’m trying to set it up so that I can have the output words or commands in an array (array might have a different name in C++…). My issue is getting the code to change the variable format of the commands so that the leonardo will do the command, rather than type the command.

I should note I am not much of a programmer, so my code might be a little messy and poorly written. If you see any other basic issues, feel free to let me know. Here is all of the sketch:

/* 
 Keyboard Button test
  
 */

int pinNumbers[] = {8, 9, 10, 11};
char* buttonColor[] = {"Red", "Blue", "Yellow", "Green"}; 
char* pinOutput[] = {"No ", "test2 ", "KEY_CAPS_LOCK", "Yes "}; //KEY_CAPS_LOCK
int buttonState[4];
int previousButtonState[] = {0,0,0,0};

int i;
int delayTime = 500;

void setup() {

  for (i = 0; i < sizeof(pinNumbers); i = i + 1) {
    pinMode(pinNumbers[i], INPUT);
  }

  Keyboard.begin();  // initialize control over the keyboard:
  Serial.begin(9600);
}

void loop() {
  while (digitalRead(2) == HIGH) {
    // do nothing until pin 2 goes low
    Serial.println("Board on Hold. Pin 2 is High");
    delay(500);
  }

  // read the pushbuttons:
  
  for (i = 0; i < sizeof(pinNumbers); i = i + 1) {
    buttonState[i] = digitalRead(pinNumbers[i]);
    if ((buttonState[i] != previousButtonState[i])
    && (buttonState[i] == HIGH)) {
      buttonPress(i);
      delay(delayTime);
    }
    previousButtonState[i] = buttonState[i];
  }
}

void buttonPress(int i){
  Serial.print(buttonColor[i]);
  Serial.println(" Button Pressed");
  //String keyToPress = "KEY_";
  String wordToType = pinOutput[i];
  if (wordToType.startsWith("KEY_")) {
    Serial.print("This is a modifier key: ");
    Serial.println(wordToType);
    char keyToPress;
    //keyToPress = char(pinOutput[i]);
    //keyToPress = wordToType.c_str();
    //keyToPress = pinOutput[i].c_str();
    //pinOutput[i].toCharArray(keyToPress, 1);
    Keyboard.press(keyToPress);
    Keyboard.release(keyToPress);
  }else{
    Keyboard.print(pinOutput[i]);
  }
}

The place where I have tried a few different things is commented out. These are what I’ve tried, though not all at once:

    //keyToPress = char(pinOutput[i]);
    //keyToPress = wordToType.c_str();
    //keyToPress = pinOutput[i].c_str();
    //pinOutput[i].toCharArray(keyToPress, 1);

depending on what isn’t commented out, I get errors like:

error: cast from 'char*' to 'char' loses precision

error: 'class String' has no member named 'c_str'

error: request for member 'toCharArray' in 'pinOutput[i]', which is of non-class type 'char*'

I’ve tried looking through some C++ forums and the like, but I can’t quite get things to work. If anybody can help, I’d be greatly appreciative. Also, it is sort of late where I am, so I might be a little slow to reply to any questions (I got to get some sleep…)

Thanks,
Tim

  String wordToType = pinOutput[i];
  if (wordToType.startsWith("KEY_")) {

This (crap) implies that you don't know how to tell if the first 4 characters of a string match another string. Some research into the stricmp() function might prove useful.

The strcmp() function might, too.

Thanks. But as I understand it, stricmp() or strcmp() will let me know if the whole string matches. In the future, I would want to be able to use any of the keyboard modifiers (that all begin with "KEY_"). I probably should have been more clear about this. I want this code to be able to work with many more buttons in the future. I don't think stricmp() and strcmp() will help me in that case, though I appreciate the suggestion.

But as I understand it, stricmp() or strcmp() will let me know if the whole string matches.

I'm sorry, that should have been strncmp() (compare n characters...).

I would want to be able to use any of the keyboard modifiers (that all begin with "KEY_").

So, strncmp() tells you whether the string starts with "KEY_". After that, you need to match the whole string to know which modifier key it is.

I want this code to be able to work with many more buttons in the future

How many modifier keys are there? Ctrl, Alt, Shift, and what else?

Ok. That makes more sense. The strncmp() works well in my sketch, and makes things cleaner.

So, in order to identify which keyboard modifier I want, I could then compare the rest of the string to an array of keyboard modifiers, and then call it out that way? There isn't a way to just convert the text "KEY_CAPS_LOCK" into a char variable type? (As an aside, I think having some programing experience, especially with variable types, might help me out here...)

There are a lot (~30) of keyboard modifiers available. I was hoping to keep things as general as possible so I could easily make adjustments down the road. A list of the keyboard modifiers is available at: http://arduino.cc/en/Reference/KeyboardModifiers

There isn't a way to just convert the text "KEY_CAPS_LOCK" into a char variable type?

You could have an array of names, and an array of values. Perform a series of strcmp() to compare the names in the one array to the string of interest. When you find a match, the position in the name array could be used as an index into the value array.

Paul, thanks. This seems to work well. Though, after I use a keyboard modifier, it also prints out a "%". Not sure why. I'll have to figure this out, but I am much closer than I was to getting this thing to work how I want it to.

Though, after I use a keyboard modifier, it also prints out a "%". Not sure why.

Without seeing your current code, neither am I.

I “fixed” the % issue. But, I am not sure why it works. I called out my array of keyboard modifiers as long. I saw someone else referring to the keyboard modifiers as int, so that was my hint.

And, just incase anyone else has a similar issue to me in the future, here is my resulting code:

/* 
 Keyboard Button test
  
 */
 
#include <string.h>

int pinNumbers[] = {8, 9, 10, 11};
char* buttonColor[] = {"Red", "Blue", "Yellow", "Green"}; 
char* pinOutput[] = {"No ", "test2 ", "KEY_CAPS_LOCK", "Yes "}; //KEY_CAPS_LOCK
char* keyMods[] = {"KEY_CAPS_LOCK", "KEY_LEFT_SHIFT", "KEY_BACKSPACE", "KEY_RETURN"};
long keyModValue[] = {KEY_CAPS_LOCK, KEY_LEFT_SHIFT, KEY_BACKSPACE, KEY_RETURN};
int buttonState[4];
int previousButtonState[] = {0,0,0,0};

int i;
int j;
int delayTime = 1000;

void setup() {

  for (i = 0; i < sizeof(pinNumbers); i = i + 1) {
    pinMode(pinNumbers[i], INPUT);
  }

  Keyboard.begin();  // initialize control over the keyboard:
  Serial.begin(9600);
}

void loop() {
  while (digitalRead(2) == HIGH) {
    // do nothing until pin 2 goes low
    Serial.println("Board on Hold. Pin 2 is High");
    delay(500);
  }

  // read the pushbuttons:
  
  for (i = 0; i < sizeof(pinNumbers); i = i + 1) {
    buttonState[i] = digitalRead(pinNumbers[i]);
    if ((buttonState[i] != previousButtonState[i])
    && (buttonState[i] == HIGH)) {
      buttonPress(i);
      delay(delayTime);
    }
    previousButtonState[i] = buttonState[i];
  }
}

void buttonPress(int i){
  Serial.print(buttonColor[i]);
  Serial.println(" Button Pressed");
  if (strncmp(pinOutput[i],"KEY_",4) == 0) {
    Serial.print("This is a modifier key: ");
    Serial.println(pinOutput[i]);
    for (j = 0; j < sizeof(keyMods); j = j + 1) {
      if(strcmp(pinOutput[i],keyMods[j]) == 0) {
        Keyboard.press(keyModValue[j]);
        Keyboard.release(keyModValue[j]);
      }
    }
  }else{
    Keyboard.print(pinOutput[i]);
  }
}