Back

Custom 4x4 keyboard

Project description

This 16 key mechanical keyboard is run on an Arduino micro and is sending keystrokes to the computer. Autohotkey is used to detect those keystrokes and automate stuff on the computer. It is really helpfull, as it makes it quicker to open apps, mute and unmute on voicecalls and press specific keystrokes.

Finding the switches

I wanted this keyboard to be clicky with a loud sound, so I used gateron blue switches.

switches

Create the circuit

The arduino doesn't have 16 analog pins, so i had to find a circuit that can minimize the nummber of pins required. I connected each key row to a pin, using the circuit below, which I found online. It measures the voltage, which changes acording to which key is pressed, because the current runs through more resistors.

circuit

Design the case

The keys have to be attached to a base in order to be stable. I measured them and designed a 3d model of the key base and the box, which I 3d printed.

I have a separate page about the designs

Solder the pieces

This part was a little bit tricky, as this was one of my first projects that required soldering.

solders

Program the Arduino

The Arduino reads the voltage from the 4 analog pins and depending on the voltage it understands which key from a row is pressed. Because each row coresponds to one pin, two buttons from the same row cannot be pressed at once, because the arduino will only understand the firts button in the line. I made the buttons send F13-F24 and then some specific keystrokes.

Finished

finished_keypad
bool pressed1;
#include "Keyboard.h"
void setup() {
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0-3:
  int sensorValue0 = analogRead(A0);
  int sensorValue1 = analogRead(A1);
  int sensorValue2 = analogRead(A2);
  int sensorValue3 = analogRead(A3);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage0 = sensorValue0 * (5.0 / 1023.0);
  float voltage1 = sensorValue1 * (5.0 / 1023.0);
  float voltage2 = sensorValue2 * (5.0 / 1023.0);
  float voltage3 = sensorValue3 * (5.0 / 1023.0);
  pressed1 = ( voltage0 > 4.5) && (voltage0 < 5.5);


  Serial.print("   0: ");
  Serial.print(voltage0);
  Serial.print("   1: ");
  Serial.print(voltage1);
  Serial.print("   2: ");
  Serial.print(voltage2);
  Serial.print("   3: ");
  Serial.println(voltage3);


  if ((voltage0 > 4.6) && (voltage0 < 5.2)) {
    Keyboard.press(240); //F13
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage0 > 2.20) && (voltage0 < 3)) {
    Keyboard.press(241); //F14
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage0 > 1.4) && (voltage0 < 1.7)) {
    Keyboard.press(242); //F15
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage0 > 1) && (voltage0 < 1.4)) {
    Keyboard.press(243); //F16
    delay(200);
    Keyboard.releaseAll();
  }


    if ((voltage1 > 4.6) && (voltage1 < 5.2)) {
    Keyboard.press(244);//F17
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage1 > 2.20) && (voltage1 < 3)) {
    Keyboard.press(245);//F18
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage1 > 1.4) && (voltage1 < 1.7)) {
    Keyboard.press(246); //F19
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage1 > 1) && (voltage1 < 1.4)) {
    Keyboard.press(247); //F20
    delay(200);
    Keyboard.releaseAll();


  }
    if ((voltage2 > 4.6) && (voltage2 < 5.2)) {
    Keyboard.press(248); //F21
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage2 > 2.20) && (voltage2 < 3)) {
    Keyboard.press(249); //F22
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage2 > 1.4) && (voltage2 < 1.7)) {
    Keyboard.press(250); //F23
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage2 > 1) && (voltage2 < 1.4)) {
    Keyboard.press(251); //F24
    delay(200);
    Keyboard.releaseAll();
  }


      if ((voltage3 > 4.6) && (voltage3 < 5.2)) {
    Keyboard.press(0x80); //Ctrl
    Keyboard.press(0x81); //shift
    Keyboard.press(0x82); //alt
    Keyboard.press(0xDA); //Up arrow
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage3 > 2.20) && (voltage3 < 3)) {
    Keyboard.press(0x80); //Ctrl
    Keyboard.press(0x81); //shift
    Keyboard.press(0x82); //alt
    Keyboard.press(0xD8); //Left arrow
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage3 > 1.4) && (voltage3 < 1.8)) {
    Keyboard.press(0x80); //Ctrl
    Keyboard.press(0x81); //shift
    Keyboard.press(0x82); //alt
    Keyboard.press(0xD7); //Right arrow
    delay(200);
    Keyboard.releaseAll();
  }
    if ((voltage3 > 1) && (voltage3 < 1.4)) {
    Keyboard.press(0x80); //Ctrl
    Keyboard.press(0x81); //shift
    Keyboard.press(0x82); //alt
    Keyboard.press(0xD9); //Down arrow
    delay(200);
    Keyboard.releaseAll();
  }
}

Autohotkey

If I want to automate a process and not just a keypress, I have to use Autohotkey. The script below uses the F13 key to open the calculator(windows), the F14 key to open spotify, the F15 key to open AfterFX, and the F20 key to send a series of keypresses and delays, which I used to automaticaly send "gg" (meaning good game) and exit the lobby in minecraft.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#InstallKeybdHook

F13::run calc.exe
F14::run C:\Users\georg\AppData\Roaming\Spotify\Spotify.exe
F15::run "C:\Program Files\Adobe\Adobe After Effects 2022\Support Files\AfterFX.exe"

F20::Send, t
sleep 1
Send, gg{enter}
sleep 1
Send  /l{enter}