HWM

Since I spend a lot of time using my computer, I've learned a bunch of hotkeys. Many involve the Windows key. There is one tiny problem: My keyboard doesn't have a Windows key, so I put together a hotkey keyboard to fix this.




This hotkey keyboard is based on the Arduino pro micro with the 32U4 microcontroller, since this specific one can emulate a USB device. The keyboard has 16 buttons designated for hotkeys and 4 menu buttons. These can be used to scroll through multiple pages, so that every hotkey can be used for multiple functions.


You'll need a few pieces of hardware to get started:
- An arduino pro micro with 32U4 microcontroller
- A YL-4 4x5 button matrix with 8 leds
- A micro USB cable
- Soldering supplies



Since the schematic becomes a giant mess with this many connections, here's a list of the wire connections you need to make between the arduino and the button matrix. Left is the Arduino pin and right is the pin on the button matrix.


Button matrix
  • 5 - R1
  • 4 - R2
  • 3 - R3
  • 2 - R4
  • 9 - L1
  • 8 - L2
  • 7 - L3
  • 6 - L4
Individual Buttons
  • VCC - VCC
  • GND - GND
  • 10 - S1
  • 16 - S2
  • 14 - S3
  • 15 - S4
LEDs
  • VCC - VCC
  • A0 - D3
  • A1 - D4
  • A2 - D5
  • A3 - D6


You'll need to begin by making sure you have four libraries installed in your Arduino IDE: Keypad.h, Mouse.h, OneButton.h and Keyboard.h. From there, it's time to start writing the code.

				
#include 
#include 
#include "Keyboard.h"
#include "Mouse.h"

OneButton nextButton(15, true); //make buttons with the OneButton library.
OneButton prevButton(16, true);
OneButton menuButton(14, true);

uint8_t pageNumber = 0;
uint8_t resetPin = 10;

uint8_t led0 = 18; //Leds that are used to show what page we're on
uint8_t led1 = 19;
uint8_t led2 = 20;
uint8_t led3 = 21;

bool programmingMode = false;
bool autoClick = false;
bool menuOpen = false;

//This is where we define the keypad matrix
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'0', '1', '2', '3'},
  {'4', '5', '6', '7'},
  {'8', '9', 'A', 'B'},
  {'C', 'D', 'E', 'F'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
  pinMode(resetPin, INPUT_PULLUP);
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  digitalWrite(led0, LOW);
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);

  Serial.begin(9600);
  nextButton.attachClick(nextPg); //The function "nextPg()" will be called when the button called "nextButton" is pressed
  prevButton.attachClick(prevPg);
  menuButton.attachClick(menu);

  if (digitalRead(resetPin) == LOW) //If programming mode is active, the buttons will not respond
  {
    programmingMode = true;
  }
  else
  {
    programmingMode = false;
    Mouse.begin();
    Keyboard.begin();
  }
}
				
			

There are several things we need to do to set up this device. First off, we include the libraries I mentioned earlier. From there, we define some variables, define our keypad and bring the device in a starting state.


				
				void loop() {

  char key = keypad.getKey();
  if (programmingMode == false) //Only check for input when programming mode isn't active
  {
    nextButton.tick(); //Check input from the menu buttons
    prevButton.tick();
    menuButton.tick();
  }
  else
  {
    key = NULL;
  }

  if (autoClick == true)
  {
    autoClicker();
  }
				
			

Next off, The loop starts. We check if any one of the menu buttons is pressed. If one is, take action.


				
				
				switch (key)  //Take action, depending on what key you pressed
  {
    case '0':
      switch (pageNumber)
      {
        case 0: //Autoclicker
          autoClick = !autoClick;
          break;
        case 1:
          Keyboard.print("while(True)\n{\n");
          Keyboard.press(KEY_TAB);
          Keyboard.releaseAll();
          Keyboard.print("\n}");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '1':
      switch (pageNumber)
      {
        case 0: //Screenshot
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.press(KEY_LEFT_SHIFT);
          Keyboard.press('s');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '2':
      switch (pageNumber)
      {
        case 0: //Select whole words right to left
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_LEFT_SHIFT);
          Keyboard.press(KEY_LEFT_ARROW);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '3':
      switch (pageNumber)
      {
        case 0: //Select whole words left to right
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_LEFT_SHIFT);
          Keyboard.press(KEY_RIGHT_ARROW);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '4':
      switch (pageNumber)
      {
        case 0: //refresh web page
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press('r');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '5':
      switch (pageNumber)
      {
        case 0: //Open new tab
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press('t');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '6':
      switch (pageNumber)
      {
        case 0: //Open previous tab
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_LEFT_SHIFT);
          Keyboard.press('t');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '7':
      switch (pageNumber)
      {
        case 0: //Switch tabs
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press(KEY_TAB);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '8':
      switch (pageNumber)
      {
        case 0: //Open program on taskbar with admin permissions
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.press(KEY_LEFT_SHIFT);
          Keyboard.press('1');
          delay(600);
          Keyboard.press(KEY_LEFT_ARROW);
          Keyboard.releaseAll();
          delay(100);
          Keyboard.press(KEY_RETURN);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case '9':
      switch (pageNumber)
      {
        case 0: //Open file explorer
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.press('e');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'A':
      switch (pageNumber)
      {
        case 0: //Open calculator
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.releaseAll();
          delay(100);
          Keyboard.print("calculator");
          delay(100);
          Keyboard.press(KEY_RETURN);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'B':
      switch (pageNumber)
      {
        case 0: //Open discord
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.releaseAll();
          delay(100);
          Keyboard.print("discord");
          delay(100);
          Keyboard.press(KEY_RETURN);
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'C':
      switch (pageNumber)
      {
        case 0: //Open run menu
          Keyboard.press(KEY_LEFT_GUI);
          Keyboard.press('r');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'D':
      switch (pageNumber)
      {
        case 0: //Set zoom to 100%
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press('0');
          Keyboard.releaseAll();
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'E':
      switch (pageNumber)
      {
        case 0: //mute audio
          Keyboard.print("This is page 0");
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
    case 'F':
      switch (pageNumber)
      {
        case 0: //unmute audio
          Keyboard.print("This is page 0");
          break;
        case 1:
          Keyboard.print("This is page 1");
          break;
        case 2:
          Keyboard.print("This is page 2");
          break;
        case 3:
          Keyboard.print("This is page 3");
          break;
      }
      break;
  }
}
		
			

This is the fun part. The code checks which one of the 16 buttons is pressed and takes action, depending on which one of the 4 pages is selected, giving the user 64 different hotkeys to create and use. I'd love to hear what hotkeys you use. Feel free to contact me through any of the options int the contact page.


				
				

		void nextPg()
{
  if (pageNumber < 3)
  {
    pageNumber++;
    digitalWrite(led0, HIGH);
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
        switch (pageNumber)
    {
      case 0:
        digitalWrite(led0, LOW);
        break;
      case 1:
        digitalWrite(led1, LOW);
        break;
      case 2:
        digitalWrite(led2, LOW);
        break;
      case 3:
        digitalWrite(led3, LOW);
        break;
    }
  }
}

void prevPg()
{
  if (pageNumber > 0)
  {
    pageNumber--;
    digitalWrite(led0, HIGH);
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
        switch (pageNumber)
    {
      case 0:
        digitalWrite(led0, LOW);
        break;
      case 1:
        digitalWrite(led1, LOW);
        break;
      case 2:
        digitalWrite(led2, LOW);
        break;
      case 3:
        digitalWrite(led3, LOW);
        break;
    }
  }
}

void menu()
{
  if (menuOpen == false)
  {
    menuOpen = true;
    Keyboard.press(KEY_LEFT_GUI);
    Keyboard.releaseAll();
    delay(500);
    Keyboard.print("notepad");
    delay(100);
    Keyboard.press(KEY_RETURN);
    Keyboard.releaseAll();
    delay(250);
    Keyboard.print("---------------------------------------------\n");
    Keyboard.print("| Auto     | Screen   | Select   | Select   |\n");
    Keyboard.print("| Click    | Shot     | Words    | Words    |\n");
    Keyboard.print("|          |          | Left     | Right    |\n");
    Keyboard.print("---------------------------------------------\n");
    Keyboard.print("| Refresh  | Open     | Open     | Switch   |\n");
    Keyboard.print("| Tab      | New      | Previous | Tabs     |\n");
    Keyboard.print("|          | Tab      | Tab      |          |\n");
    Keyboard.print("---------------------------------------------\n");
    Keyboard.print("| Open     | Open     | Open     | Open     |\n");
    Keyboard.print("| HWM      | File     | Calc-    | Discord  |\n");
    Keyboard.print("|          | Explorer | ulator   |          |\n");
    Keyboard.print("---------------------------------------------\n");
    Keyboard.print("| Open     | Set      | Nothing  | Nothing  |\n");
    Keyboard.print("| Run      | Zoom to  | yet      | yet      |\n");
    Keyboard.print("| Menu     | 100%     |          |          |\n");
    Keyboard.print("---------------------------------------------");
  }
  else
  {
    menuOpen = false;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('w');
    delay(100);
    Keyboard.press(KEY_RIGHT_ARROW);
    delay(100);
    Keyboard.press(KEY_RETURN);
    Keyboard.releaseAll();
  }

}

void autoClicker()
{
  Mouse.click(MOUSE_LEFT);
  delay(10);
}
		
		
			

These are the functions that are called when the corresponding menu buttons are pressed. The menu button currently only has 1 page, since I've only managed to come up with 14 different hotkeys, but if you have more, you can add a switch statement and make more menu pages that way.


With the hardware assembled and the code uploaded, your hotkey keyboard is now complete. Customize the different commands to your liking and please let me know what shorcut keys you've added through any way listed on the contact page.