Introduction: Arduino Programmable Button Panel As Keyboard
This is a pretty simple and fun project with Arduino which is an ideal option for your first interaction with Arduino. You will create a panel with different buttons, each one will do an action in your computer (Mac or Pc) by emulating keyboard shortcuts or commands. In my case, I use it with coding software to have an easy and fun shortcut to copy, paste, duplicate line, save, capture screen and open a couple of apps.
You will need:
- 1 Arduino Leonardo (or any Arduino with usb interface)
- 1 Resistor (this one is optional, any between 110 to 330 ohm will do)
- 1 or more push buttons
- 1 Box
- A couple of cables
- Software: Arduino IDE
This tutorial will, not only guide you through the project, but it will also introduce you to Arduino in general, starting with a very simple push button as keyboard input and will teach you how to add buttons and features in the next steps.
It will be easier if you already have experience with coding, but I encourage you to learn by trial and error if this is your first approach.
Step 1: Let's Start
If this is your first Arduino project, you should know that the basic structure of an Arduino script consists of two parts: the setup and the loop. In the setup, you will define the variables and modes that will be needed in the project; the loop is the set of instructions that Arduino will be running over and over to check the status of its different inputs and outputs.
The first thing to consider: as you will be emulating keyboard inputs, you should be careful not to leave a free keyboard action in the loop repeating and repeating itself, because you will lose control of the computer. In the first step you are going to create a simple action to “copy” when you press a push button.
The code
The software that you'll need to upload the script to the board is called Arduino IDE, you can download it here.
You will include the keyboard library to emulate a keyboard. Then you will define the pin in which you want to connect the push button.
The other two variables will be needed to save the current state (if it is pressed or not) of the button on every cycle and the previous state to check if the state is different in the current cycle:
#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_GUI); // Command key in Mac, use KEY_LEFT_CTRL for Pc Keyboard.press('v'); delay(100); Keyboard.releaseAll(); // This is important after every Keyboard.press it will continue to be pressed } prevButtonState = buttonState; }
In this example, I'm using pin 2 in the mode INPUT_PULLUP, which means that it is an input and will be using the onboard resistor of Arduino. You need to compare the current state with the previous to force Arduino to do the output only once per press and not repeating and repeating the output in every cycle.
You can find another tutorial to create a push button in the arduino website.
The Keyboard library has different codes for every key in the keyboard. You can find the full list here.
You can run apps by command using the following:
In windows: You can open the Run dialog box using the Windows key + R, then set a delay to wait a couple of milliseconds and use Keyboard.print to run a command and Keyboard.press(KEY_RETURN) to run it.
In Mac: You can use the key combo Command + space bar to open Spotlight, then set a small delay and write the name of the app and use Keyboard.press (KEY_RETURN) to run it.
Always remember to consider delays between instructions and Keyboard.releaseAll() after emulating a key combination. As an alternative, you can assign keyboard combinations to shortcuts (Windows) and then using Arduino to emulate the combinations or you can create a macro that reacts to a key combination using software.
You can connect the Arduino board to the computer in any step. The first time, probably, will install some drivers.
The Arduino software is very simple to use. First select your Arduino board model from the Tools > Board menu, otherwise it will not be able to incorporate the keyboard library. When you think that your code is ready, test it with the Verify button, fix whatever problem the code is having, then verify it again and press the Upload button. In some versions you will have to press the reset button on the Arduino board during the upload process. When the upload process is complete, the push buttons will be working immediately. In Mac, it will detect the Arduino as a new keyboard and it will open a window to help you configuring it, just ignore it.
If the project is big, I encourage you to use Atom for the coding, with the language-arduino language support.
Now let’s set up the hardware.
Step 2: The Wiring
The push buttons, usually, have two or three connectors. If yours has two, we must connect one to gnd and the other one will be connected to the pin, whichever you like. In the example code we are using pin 2. If the push button has a third connector, ignore it. It's used to send a different signal when the button is not pressed. We can emulate this kind of action using the script.
You will need to use a resistor because the button can catch interference from the static electricity caused by the components and your own hands, which will result in false press detection. Arduino has a built-in pull-up resistor, you can turn this feature on by setting the button pinMode as INPUT_PULLUP. If you want to use an external resistor, you must connect it between the button and the gnd in the card, and then set the pinMode simply as INPUT.
You can learn more about pull up resistors and buttons in this video.
Step 3: Adding a Debouncer
Some push buttons are not very accurate and can give false press signals. You will notice this bug when you press a button and the output actions are triggered twice. This phenomenon is called bouncing, and the method to avoid it is called debouncing.
We are going to set up a variable to record the time in milliseconds and then compare every press signal change, to know if has been more than 50 milliseconds between them. If it´s been less than that, then is, for sure, a false push signal, and the script must ignore it.
#include "Keyboard.h"
const int buttonPin = 2;int buttonState = 0;int prevButtonState = HIGH; long lastDebounceTime = 0;long debounceDelay = 50;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
digitalWrite(buttonPin, HIGH);
Keyboard.begin();
}void loop() {
buttonState = digitalRead(buttonPin);
if ((buttonState != prevButtonState) && (buttonState == HIGH)) {
// Here starts the output action
Keyboard.press(KEY_LEFT_GUI); // Command key in Mac, use KEY_LEFT_CTRL for Pc
Keyboard.press('v');
delay(100);
Keyboard.releaseAll(); // This is important after every Keyboard.press it will continue to be pressed}
prevButtonState = buttonState;
}
Step 4: Scale to Multiple Buttons
The wiring is, pretty much, the same as with a single button. The signal cable will be connected straight to the pin and all the gnd will be connected by a single resistor.
For the code, you will have to define all our variables as arrays and create a "for" loops to check the status of every pin:
#include "Keyboard.h"
const int buttonPin[] = {2, 3, 4, 5}; int pinCount = 4; int buttonState[] = {0, 0, 0, 0}; int prevButtonState[] = {HIGH, HIGH, HIGH, HIGH}; long lastDebounceTime[] = {0, 0, 0, 0}; long debounceDelay = 50; void setup() { for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) { pinMode(buttonPin[thisPin], INPUT); digitalWrite(buttonPin[thisPin], HIGH); } Keyboard.begin(); } // Output actions. Probably the only part that you need to change int outputAction(int currentButton) { if (currentButton == 1) { Keyboard.press(ctrlKey); Keyboard.press('c'); delay(100); Keyboard.releaseAll(); } if (currentButton + 1 == 2) { Keyboard.press(ctrlKey); Keyboard.press('v'); delay(100); Keyboard.releaseAll(); } } void loop() { for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) { buttonState[thisPin] = digitalRead(buttonPin[thisPin]); if ((buttonState[thisPin] != prevButtonState[thisPin]) && (buttonState[thisPin] == HIGH)) { if ((millis() - lastDebounceTime[thisPin]) > debounceDelay) { outputAction(thisPin); lastDebounceTime[thisPin] = millis(); } } prevButtonState[thisPin] = buttonState[thisPin]; } }
For the wiring connection to remain firm even when you need to open the box, consider tin soldering the wires to the buttons. You can find easy tutorials about this on YouTube.
Step 5: Choose the Hardware and Other Tips
The box: this is probably the most difficult part of the project. Finding the perfect box and making the holes. Unfortunately, I can't guide you through the construction of the hardware because it is not my area of expertise. I’m just going to give you some tips:
- Test it with any cardboard box first (any cereal box will do), to find out what's the best size and configuration. In my first attempt I put the cable hole on the wrong side of the box and it was too little to fit the bigger buttons.
- Don't choose thick cardboard boxes or hard wood, since you’ll find it difficult to make the holes. Take into account that some drill sizes are hard to find and even with the right one, you can tear them apart.
- Use a piece of thin plastic, leather or paper to cover the imperfections of the drilling. You can use a snap-off blade to create the holes in it..
- If you really want an excellent finish, better buy a laser cut box with the right size.
The buttons: some are too hard, some are too soft, some are inaccurate, test a couple before buying the bunch. I am using the classic arcade buttons but there are some with Led indicators. This project is more fun than useful, so keep in mind using the buttons that seem cooler to you.
Step 6: My Current Setup
I’m using a box with 8 arcade-like buttons set in two lines. I created different functions to detect three different types of pressing. I will show you how to do this in another tutorial.
Button [1] Short press: “copy” Long press: “copy” + “search” Lingering press: “copy” + project search in Atom (command + shift + f)
Button [2] Short press: “paste” Long press and lingering press: “paste” + enter
Button [3] Short press: enter Long press and lingering press: duplicate line (the enter is canceled first)
Button [4] Short press: save Long press: save as… Lingering press: save for web in Photoshop
Button [5] Short press: screen capture (command + shift + ctrl + 3 in Mac) Long press and lingering press: screen capture + open Photoshop (Mac)
Button [6] Short press: New doc or tab Long press: New doc + enter (useful in Photoshop) Lingering press: close current tab
Button [7] Any press: go to end of next line in text processor
Button [8] Any press: random YouTube videos
You can follow the progress of the project and my setup in github.
I hope you'll have fun with this project.
You can follow me on Twitter: @pato_pitaluga