
Building your own custom mechanical keyboard is an exciting project that combines electronics, programming, and mechanical design. As engineering students in India, you'll find this project not only enhances your technical skills but also gives you a keyboard perfectly tailored to your typing preferences. The feeling of typing on a keyboard you built yourself is unmatched, and with Arduino Pro Micro, you have a powerful yet affordable microcontroller at your disposal.
This comprehensive guide will walk you through every step of building a custom 60% mechanical keyboard. We'll cover everything from component selection to programming, with a focus on practical implementation using components readily available in the Indian market. Let's dive into the world of custom mechanical keyboards!

Before we start building, let's gather all the necessary components. Here's a detailed breakdown of what you'll need for your custom mechanical keyboard project:
| Component | Specification | Price (₹) | Supplier/Availability |
|---|---|---|---|
| Arduino Pro Micro | ATmega32U4, 5V, USB-capable | 350 | Available at TechNiche, Robu.in |
| Mechanical Key Switches | Cherry MX compatible, 60% layout | 2,500-4,000 | Available at Keychron India, MechBoards |
| Keyboard PCB | Perforated protoboard or custom PCB | 150-500 | Available at Robu.in, PCB Power |
| OLED Display | 0.96" I2C SSD1306 | 200 | Available at TechNiche, Robu.in |
| Rotary Encoder | With push button | 120 | Available at Robu.in, Amazon India |
| USB-C Cable | 1.2m, data transfer capable | 80 | Available at Croma, Reliance Digital |
| Micro USB Cable | For programming | 50 | Available at any electronics store |
| 3D Printed Case | Optional | 300-800 | Available at 3DPrintIndia, MakerGhat |
| Hot Glue Gun | For securing switches | 250 | Available at hardware stores |
| Soldering Iron | 40W with tips | 400 | Available at Robu.in, Amazon India |
| Solder Wire | 60/40 rosin core | 150 | Available at Robu.in, electronics markets |
| Desoldering Pump | For corrections | 200 | Available at Robu.in, electronics markets |
Total Estimated Cost: ₹5,800 - ₹9,250 (excluding 3D printed case)
Before diving into the building process, let's understand the fundamental concepts of custom mechanical keyboards:
Unlike membrane keyboards that use rubber domes, mechanical keyboards use individual mechanical switches for each key. These switches provide tactile feedback and have a longer lifespan (typically 50-100 million keystrokes). The Arduino Pro Micro will handle the key scanning and USB communication, while the keyboard PCB routes the signals to the microcontroller.
The Arduino Pro Micro is ideal for custom keyboard projects due to:
For this guide, we'll focus on a 60% layout, which includes:

A mechanical keyboard uses a matrix layout where switches share rows and columns. This reduces the number of I/O pins required. For a 60% keyboard, we need approximately 24 keys, which translates to a 6×4 matrix (6 rows, 4 columns).
For beginners, I recommend using a perforated protoboard initially. Here's how to prepare it:
Here's how to connect the switches to the Arduino Pro Micro:
Row Pins (to Arduino)
R1 → D2
R2 → D3
R3 → D4
R4 → D5
R5 → D6
R6 → D7
Column Pins (to Arduino)
C1 → D8
C2 → D9
C3 → D10
C4 → D11
Connect the OLED display using I2C:
Connect the rotary encoder to simulate media controls:

Now let's write the code to bring your keyboard to life. Here's a comprehensive Arduino sketch with syntax highlighting:
#include <Keyboard.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED Display configuration
#define OLED_RESET -1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
// Pin definitions for row and column matrix
const uint8_t ROWS = 6;
const uint8_t COLS = 4;
const uint8_t rowPins[ROWS] = {2, 3, 4, 5, 6, 7};
const uint8_t colPins[COLS] = {8, 9, 10, 11};
// Rotary encoder pins
const uint8_t encoderPinA = 12;
const uint8_t encoderPinB = 13;
const uint8_t encoderButton = 14;
// Keymap for 60% layout
const uint8_t keys[ROWS][COLS] = {
// Row 0 (Function layer)
{0, 0, 0, 0},
// Row 1
{'1', '2', '3', '4'},
// Row 2 (Home row - Left hand)
{'q', 'w', 'e', 'r'},
// Row 3 (Home row - Right hand)
{'t', 'y', 'u', 'i'},
// Row 4 (Bottom row - Left hand)
{'z', 'x', 'c', 'v'},
// Row 5 (Bottom row - Right hand)
{'a', 's', 'd', 'f'}
};
// Layer management
int currentLayer = 0;
// Rotary encoder variables
int lastEncoderState = 0;
int volumeLevel = 0;
void setup() {
// Initialize keyboard
Keyboard.begin();
// Initialize OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
// OLED initialization failed
while(1);
}
// Set all pins as inputs with pullups
for(uint8_t i = 0; i < ROWS; i++) {
pinMode(rowPins[i], INPUT_PULLUP);
}
for(uint8_t i = 0; i < COLS; i++) {
pinMode(colPins[i], INPUT_PULLUP);
}
// Set encoder pins
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
pinMode(encoderButton, INPUT_PULLUP);
// Initialize display
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println("Keyboard Ready!");
display.display();
delay(2000);
display.clearDisplay();
}
void loop() {
checkKeyboard();
checkEncoder();
updateDisplay();
}
void checkKeyboard() {
for(uint8_t row = 0; row < ROWS; row++) {
// Set all column pins to OUTPUT and HIGH (inactive)
for(uint8_t col = 0; col < COLS; col++) {
pinMode(colPins[col], OUTPUT);
digitalWrite(colPins[col], HIGH);
}
// Set current row to INPUT (active low)
pinMode(rowPins[row], INPUT_PULLUP);
// Check all columns in this row
for(uint8_t col = 0; col < COLS; col++) {
if(digitalRead(colPins[col]) == LOW) {
// Key pressed at (row, col)
pressKey(row, col);
break; // Debounce
}
}
}
}
void pressKey(uint8_t row, uint8_t col) {
if(row < ROWS && col < COLS) {
uint8_t key = keys[row][col];
if(key != 0) {
Keyboard.press(key);
delay(10); // Small delay to register press
Keyboard.release(key);
}
}
}
void checkEncoder() {
int currentState = (digitalRead(encoderPinA) << 1) | digitalRead(encoderPinB);
// Check for button press
if(digitalRead(encoderButton) == LOW) {
delay(50); // Debounce
Keyboard.press(KEY_MEDIA_PLAY_PAUSE);
delay(50);
Keyboard.release(KEY_MEDIA_PLAY_PAUSE);
}
// Check for rotation
if(currentState != lastEncoderState) {
if((currentState == 0b01 && lastEncoderState == 0b00) ||
(currentState == 0b10 && lastEncoderState == 0b00) ||
(currentState == 0b00 && lastEncoderState == 0b01) ||
(currentState == 0b00 && lastEncoderState == 0b10)) {
// Determine rotation direction
if(currentState == 0b01 && lastEncoderState == 0b00) {
volumeLevel = (volumeLevel + 1) % 100;
} else if(currentState == 0b10 && lastEncoderState == 0b00) {
volumeLevel = (volumeLevel - 1 + 100) % 100;
}
}
lastEncoderState = currentState;
}
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Custom KB");
display.println("Layer: " + String(currentLayer));
display.println("Vol: " + String(volumeLevel) + "%");
display.println("Encoder: OK");
display.display();
}
After uploading the code, test each aspect:
pressKey() functionFor comprehensive testing, write a test sketch that:

Even with careful assembly, you might encounter some issues. Here's a comprehensive troubleshooting guide:
| Problem | Possible Cause | Solution |
|---|---|---|
| No keys register | Wrong wiring | Check row/column connections |
| Keys register wrong | Incorrect keymap | Verify keys[][] array |
| OLED doesn't display | I2C issues | Check SDA/SCL connections |
| Encoder doesn't work | Wrong pin assignment | Verify encoderPinA/B/Button pins |
| Random key presses | Electrical noise | Add pullup resistors or check grounding |
| Slow response | Matrix scanning too slow | Optimize loop timing |
| USB not recognized | Wrong Pro Micro variant | Ensure you're using USB-C compatible version |
| PCB switches don't stay | Poor soldering | Reflow solder joints |
| Encoder jitter | Mechanical issues | Clean encoder or replace if damaged |
| Keys stick down | Switch debris | Clean switches with isopropyl alcohol |
Q: What programming language should I use for custom keyboard firmware? A: For Arduino-based keyboards, you'll primarily use Arduino IDE with C/C++. The provided code uses the standard Arduino library, making it accessible for
Explore our collection of DIY kits and components. All project components mentioned in this blog are available in our store.
Browse All Projects