Introduction: Arduino Keyboard Joystick Extender Box and Sound Controller Thing Using Deej

Why

For a while I've been wanting to add a small joystick to my keyboard to control interface elements, or other smaller tasks in games and simulators (MS Flight Sim, Elite: Dangerous, Star Wars: Squadrons, etc).

Also, for Elite: Dangerous, I've been struggling with mixing volume levels from external audio (the built in music, while good, gets repetitive after many hours in the black), in-game audio, and external voicepack support.

Windows built-in source mixer is 'ok', but a pain to switch screens and mouse-control sliders in the midst of a game. Having an extended keyboard control box seemed the way to go. Deej is the solution I found.

How

I've recently been learning about Arduino, and came across the deej project on reddit. It looked like this would solve both of those problems in one handy package. And it would let me design and print a nifty 3d case.

What is deej?

(from the site) deejis an **open-source hardware volume mixer** for Windows and Linux PCs. It lets you use real-life sliders (like a DJ!) to **seamlessly control the volumes of different apps** (such as your music player, the game you're playing and your voice chat session) without having to stop what you're doing.

My version

To keep the box small, I opted for knobs (rotary linear potentiometer (pots = resistors)) rather than sliders. Functionally they work the same. Current and popular deej designs don't include a joystick, so this will be a bit of a design hybrid. Otherwise, it's a pretty straight-forward build.

Deej will work with an Arduino Nano, Pro Micro or Uno, but the Nano and Pro Micro are 'officially recommended' by the developer. I chose the Arduino Pro Micro because I wanted the joystick, and the Arduino Joystick Library supports it. I may also use the Arduino Keyboard Library when I want to use the media keyboard mute function (rather than the 'soft mute') with the joystick button, but that is further down the road.

Step 1: Supplies

The box

Download the STL files (designed in Tinkercad):

The hardware (production unit)

  • 1x Arduino Pro Micro
  • 4x 10k rotary (knob) Potentiometers (not Rotary Controllers, use pots)
  • 1x Arduino KY-023 Joystick
  • 5ft scrap cat5 network cable
  • 1x USB A to USB B micro cable (USB A is the big square connecter, USB B micro is what's on the Arduino Pro Micro)
  • 1x 5mm red LED
  • 1x 220 ohm resistor

I had some extra parts around so I thought I'd build a development unit to test things out on. Just connecting things to a breadboard made it easier to visualize the final thing.

  • 1x Arduino Pro Micro
  • 4x 10k rotary (knob) Potentiometers (not Rotary Controllers, use pots)
  • 1x momentary push button switch (hard reset switch)
  • 1x USB A to USB B micro cable (USB A is the big square connecter, USB B micro is what's on the Arduino Pro Micro)
  • assorted jumper wires
  • breadboard
  • 1x 5mm red LED
  • 1x 220 ohm resistor

Step 2: The Enclosure

The design

I liked some of the other designs profiled in the deej community gallery, so based mine of the features that I liked:

  • Easy to design and print
  • Not get in the way of my other desktop peripherals
  • Not use screws or fasteners to secure the enclosure
  • Similar design aesthetic to the keyboard

I designed and printed two prototypes before settling on this final design. I like to have a physical version to play with in the space I'm using it in as it gives me a better sense of how the final object will work.

I briefly started designing in Fusion360, but don't know it as well as Tinkercad so switched over and worked there.

Since I wanted a screwless design, I created a nesting box. First prototype had a thin lid and a deep box for everything. Second design swapped that with a deep lid and a shallow bottom box. It only had to hold the Arduino Pro Mini so really didn't need to be large. Also incorporated the embossed icons.

Third design was resized to fit the space alongside my keyboard.

The print

I printed the box in PLA, programming a filament / layer swap from Black to Red for the lid where the icons would just start to be visible, and again back to Black for the remainder of the lid.

A problem

All through this, the joystick mount was a problem. Even in the third design, the stick bumps up against the mounts in one place. The next iteration will have better clearances. I could have worked more on the design but wanted to get on to the next phase, installation.

Step 3: The Circuit

Worst wiring job ever

Ok, this is my first full-up Arduino project. Yes, I've done things on breadboards before and am using one to build the Development version of this, but as for actually fabricating and assembling, this is my first. So my wiring looks like crap. There, that's out of the way :)

Update: I've since built another one and the wiring is much nicer there. See the images :)

Production unit -- What's going where

The Arduino Pro Micro is a tiny little board and will fit in the molded section in the base. Knobs and joystick fit in their respective holes in the lid. But don't mount anything until you get the soldering compete.

Wiring

I didn't have any proper circuit wire, but did have a leftover roll of solid-core cat5 network cable, so that's what I used. It's a bit stiffer and perhaps more brittle than the stranded circuit wire, but it works.

Laying out the components in an approximation of their final mounting position, I estimated the distance, for each wire, added a bit more for slack, etc, then cut and trimmed the wire. I left a lot of slack.

Referring to the wiring diagram, I ran the common ground (Black) and VCC (Red) to the knobs and joystick where indicated. Since network cable doesn't come in these colours, I just picked a colour and kept my wiring consistent to the function.

The individual Pot. analog lines (Yellow) ran to pins A0 - A3. The Joystick lines (Orange), also analog, ran to I/O pins 8 and 9. These will have to be designated as Analog in the Arduino code as A8 and A9.

The joystick switch pin (Blue) ran to pin 7. This will be a digital pin in the code.

Insulation

Since this stiff wire is going to be stuffed into a small space, I opted to insulate my solder connections with a healthy dollop of hot-melt glue. Then tucked everything into place and ran a simple test on the board and the pots using version of the Arduino Example AnalogInput code -- modified to read all the pots.

Second version

The last two images above show the next box I'm building. This one will have 5 knobs and one momentary push button for the mute. No joystick. Same size box.

Step 4: Finishing the Hardware

By the time I'd installed the Joystick, I realized there was not a lot of clearance between it's board and the pin headers left on the Pro Micro.

After a little careful bending of the pin headers, and a reapplication of hot melt glue (for insulation), the enclosure closed properly.

Installing the pots went without a hitch.

Again with the wires

Solid core wires are a bit stiff, and can be brittle if flexed too many times, so carefully fold them (with no sharp corners) into the available space. Some of mine were too long and required a bit of extra folding.

Once everything is all tucked into place, just fit the base onto the top and you should be finished with the hardware....

But wait, there's more

Of course, after a few weeks of use, I decided I needed an indicator to let me know what the status of the soft-coded MUTE function is.

After editing the code to add in the LED functionality (see next section), I quickly soldered up the LED / wires / resistor and connected them to the board.

I spent more time to drill the hole through the top of the case as I didn't want to mar the top finish. I marked a centre spot, dented it, then hand spun a drill bit to make the hole.

Additional careful filing cleaned up the hole and ensured a nice tight press-fit to ensure the LED did not protrude too far above the top surface.

Step 5: The Software

Overview

So, this is a two part process.

  1. Get and understand how Deej works and edit the Config.yaml file
  2. Edit the Arduino code to match the hardware and features desired
  3. Get the Arduino Joystick library

In my case, I wanted these features:

  • Knobs that control levels (Mic and output)
  • Mute switch
  • 2 axis joystick recognized by Windows for application use

Levels

Deej pretty much takes care of the first point as it comes. I didn't tweak this functionality

Mute switch

I'd determined early on that I was going to use the press/switch in the Joystick as a functional mute button.

When you examine the code, you'll see that I've chosen (initially) to use a 'soft' mute - when the button is pressed, the MIC volume is reduced to zero (and the LED is lit). When it's pressed again, the MIC volume is returned to it's previous setting and the LED is extinguished.

Eventually I'll be looking at implementing the Arduino keyboard library to toggle the Mute status through the extended media Keyboard code set.

Joystick implementation

This requires the use of the Arduino Joystick library to ensure the joystick is recognized as a HID device by Windows and consequently by any game/application.

I'm a bit of a noob when it comes to coding and found the Joystick library documentation a bit sparse on the actual implementation side -- but a bit of focused googling led me to other examples that helped me understand what's going on. Check the resources section at the end for details.

All I had to do was identify the X/Y pins, read their state and send that to the Joystick library. The Arduino appeared as a Leonardo to Windows, and was properly configured as a Joystick device.

I was able to set it up in Elite Dangerous, alongside my existing HOTAS setup and have the Joystick properly control things and not conflict with the HOTAS. It also works well in Star Wars: Squadrons -- I have it set as a quick toggle to set up the shields while in combat.

The files that work with my Joystick setup

I've uploaded my current (Oct. 2020) files to Codepile.

Step 6: End

Well, this one is done. It works and I'm rather pleased with how it came together. And I learned a bit more about hardware design, integration, and Arduino programming.

Step 7: Addendum..dum..dum

VLC -- that awesome audio and video player has a little oddness where the volume level, when controlled externally, jumps from 0% to 27%ish. This doesn't happen when adjusting the level using the in-app interface volume control, only with external controls like Deej.

The Deej developer quickly found an in-VLC workaround that does the job, see the image above:

"...if you want to disable this "Tracking" behavior you can do so by changing VLC's audio output module. I used DirectX in my attempts here. You'll need to restart VLC for the change to take effect. (you'll still have a windows audio session and be able to control it via deej, this will just prevent the VLC volume bar from moving with it)"

Step 8: Additional Resources

Found via the mighty Goog, listed in no particular order...