Help expanding this code,

hello,
i put together this code for a 1 button shortcut keyboard that i wanted to expand to 5 keys.

can i get help with this as i have failed every time trying.
Thanks

board: Atmega32u4 pro micro Arduino microcontroller

#include "Keyboard.h"

const int buttonPin = 2;
int buttonState = 0;
int prevButtonState = HIGH;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(buttonPin, HIGH);
  Keyboard.begin();
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('s');
    delay(100);
    Keyboard.releaseAll(); 
  }
  prevButtonState = buttonState;
}

Please post your best effort at expanding this sketch to do what you want. Did you use at least one array ?

#include "Keyboard.h"

const int buttonPin = 2, 3, 4, 5, 6,;
int buttonState = 0;
int prevButtonState = HIGH;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(buttonPin, HIGH);
  Keyboard.begin();
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('s');
    delay(100);
    Keyboard.releaseAll(); 
  }

  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('j');
    delay(100);
    Keyboard.releaseAll(); 
  }

  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('k');
    delay(100);
    Keyboard.releaseAll(); 
  }

  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('r');
    delay(100);
    Keyboard.releaseAll(); 
  }

  buttonState = digitalRead(buttonPin);
  if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('d');
    delay(100);
    Keyboard.releaseAll(); 
  }
  prevButtonState = buttonState;
}

as you can see im not sure how to specify the different pins under void loop.

That is not the smartest way to do it but it will work if you make changes

Let's start with just 2 buttons named button0 and button1

  • Declare 2 variables named buttonPin0 and buttonPin1 and give them values of 2 and 3 respectively
  • declare 2 variables named prevButtonState0 and prevButtonState1
  • use pinMode with INPUT_PULLUP as usual on the 2 button pins
  • In loop() test for a button press on buttonPin0 and if you find it has been pressed send the keystrokes
  • copy buttonState to previousButtonState0
  • test for a button press on buttonPin1 and if you find it has been pressed send the keystrokes
  • copy buttonState to previousButtonState1

Do you see how the previous states have been saved to separate variables ?

Get that working and we will move on to a much better way of doing it involving arrays which uses less code and is easily expandable to multiple inputs and outputs

Hello,
this task screams for the usage of structured arrays.

I entirely agree and that is what I am working towards but do you think that @benimars is ready for them yet ? You and I may think that an array of structs is an easy solution but I doubt that @benimars would

Let him/her get the clumsy version working and I will lead him/her to a better solution. There is already a hint of it in the variable names that I deliberately suggested.

You could also use a library for the buttons. My MobaTools lib contains a class to manage several buttons in one instance:

#include "Keyboard.h"
#define MAX8BUTTONS   // only to save storage space if not using more than 8 buttons
#include <MobaTools.h>

const byte buttonPin[] = { 2, 3, 4, 5, 6 };
const byte buttonCount = sizeof( buttonPin ); // buttonPin must be declared as byte to work correctly
MoToButtons buttons( buttonPin, buttonCount, 20, 500 ); // 20ms debounce time, 500ms longpress ( not used here )

void setup() {
  Keyboard.begin();
}

void loop() {
  buttons.processButtons();
  
  if (buttons.pressed(0) ) {
    // first button ( pin2 ) pressed
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('s');
    delay(100);
    Keyboard.releaseAll(); 
  }

  if (buttons.pressed(1) ) {
    // second button ( pin 3 ) pressed
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('j');
    delay(100);
    Keyboard.releaseAll(); 
  }

  if (buttons.pressed(2) ) {
    // third button ( pin 4 ) pressed
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('k');
    delay(100);
    Keyboard.releaseAll(); 
  }

  if (buttons.pressed(3) ) {
    // 4th button ( pin 5 ) pressed
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('r');
    delay(100);
    Keyboard.releaseAll(); 
  }

  if (buttons.pressed(4) ) {
    // 5th button ( pin 6 ) pressed
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('d');
    delay(100);
    Keyboard.releaseAll(); 
  }
}

(untested) edit: now tested :wink: - The MobaTools lib can be installed by means of the library manager.

wow thanks for explaining it so clear.

im going to give it a shot and get back.

i really prefer this method of walking me through it.

Your sketch is not compiled even! The compiler does not find the object (Keyboard) on which you have applied the press() method.

Did you try? It compiles error free. The object 'Keyboard' is created in keyboard.cpp and declared extern in keyboard.h .
The sketch in #3 contains other errors, but 'Keyboard' is ok.

Sorry! I had a wrong board selection. Now, the sketch of Post#1 compiles with right (Arduino Pro) borad selection.

thank you so much.
im going to give it a try writing one my self but if i cant ill use this your code to educate myself.

thanks

im almost certain this is wrong but can you give me some hints?

#include "Keyboard.h"

const int buttonPin0 = 2;
const int buttonPin1 = 3;

int prevButtonState0 
int prevButtonState1

void setup() {
  pinMode(buttonPin0, INPUT_PULLUP);
   pinMode(buttonPin1, INPUT_PULLUP);
  digitalWrite(buttonPin0, HIGH);
  Keyboard.begin();
}


void loop() {
  buttonState = digitalRead(buttonPin0);
  if (buttonState == HIGH) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('s');
    delay(100);
    Keyboard.releaseAll(); 
  }
  prevButtonState = buttonState0;
  
void loop() {
  buttonState = digitalRead(buttonPin1);
  if (buttonState == HIGH) {
    Keyboard.press(KEY_LEFT_CTRL); 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('s');
    delay(100);
    Keyboard.releaseAll(); // 
  }
  prevButtonState = buttonState1;
}

You did not define buttonState

And you correctly defined

int prevButtonState0 
int prevButtonState1

separate for each button, but you didn't use it:

  prevButtonState = buttonState0;
...
...
  prevButtonState = buttonState1;

Also this code can be significantly improved, and a lot can be learned in the process. E.g. store the characters to be transferred in tables, query the buttons by index in a loop and transfer the characters according to the table. Arrays and structs are keyvalues to be learnd :wink:
And getting rid of delay is always a good exercise.

But always step by step :sunglasses:

Your latest code is not checking whether the buttons have become pressed as your original code did and you can't have two loop() functions

Yes, the loop should look similar to your code in #3, but each if block should have its own variables ( but only two if blocks for now )

also noticed buttoncount (longpress) in your code so opens up other possibilities i can look into later.

also do i have to specify a pin or buttonstate for each block in "If"

  if ((buttonState != prevButtonState) && (buttonState == HIGH)){

@benimars There have been many suggestions for changing your approach, or improving upon the one you have taken..

Meanwhile, you are very close to making your original method work, just multiplied times five.

My suggestion is that you see through to success the simple replication of the original code block that handles one, to write five that handle five, with all the necessary additions as have been outlined.

There is no shame in using literal code when it is what you know how to do. The program will work just fine, and I believe it will help you see all of what might go into ways to do it that more experience coders won't be offended by.

The sheer gratification of getting this to work will be valuable.

And when you scale it up again to, say, 50 buttons, the sheep amount of cutting, pasting and editing that would take will be strong motivation to nake the next small step into programming and investigate some arguably better techniques.

So to @MicroBahner's "step by step" I would add "first things first".

HTH

a7

1 Like

You and I are thinking the same way. Even if there are better ways to do what @benimars wants to do, which there are, the primary objective should be to make the code work. Improvements can come later