Vim Clutch

11:28PMMay 21 2021Daniel Tompkins

Archive

Good­will Strikes Again

A symptom of heavy Vim usage is that your brain be­gins to re-par­ti­tion old mem­o­ries for key­board short­cuts— trashing old brain files for small boosts in finger dex­terity.

It was this mass of tan­gled brains in my own dome that com­pelled me to pur­chase a weighty foot-pedal at Good­will. The model I got is ac­tu­ally a com­bi­na­tion of three, springy switches. Sold for the rea­son­able price of $3.

Picture of pedal assembly on it's face with the bottom up. Getting ready to unscrew the clamshell housing with a screwdriver.
Picture of pedal assembly on it's face with the bottom up. Getting ready to unscrew the clamshell housing with a screwdriver.
The foot pedal has a wide, center pedal (with an embossed "PLAY"). Two, thinner pedals on either side read "REW" and "FWD", respectively. All 3 switches are really clicky.
The foot pedal has a wide, center pedal (with an embossed "PLAY"). Two, thinner pedals on either side read "REW" and "FWD", respectively. All 3 switches are really clicky.

It's a sur­pris­ingly hefty con­trap­tion. The base is a thick stock of foam that helps keep it from sliding across the floor. It's a clamshell de­sign, sand­wiched to­gether by a screw at each of the four cor­ners.

Tra­di­tion­ally, I've coded with my fin­gers, and my feet re­main flat on the floor. The thought of throwing an­other ap­pendage into the mix had, how­ever, ac­tu­ally crossed my mind (if you can be­lieve it).

The serendipity of dis­cov­ering the pedal among the other as­sort­ment of do­nated goods gave the idea shape.🦆

What the heck is a Vim Clutch?

Some­times it feels like we're living in the fu­ture. A sci-fi fan­tasy where you can buy elec­tric cars with dig­ital coins and spec­u­late on blockchains founded on memes.

Un­sur­pris­ingly, I'm not the only one under the Vim­pe­rious curse... (yes, that was a Vim + Harry Potter pun) In fact, there have been a good many other model Vim Clutches:

Looking at these ex­am­ples, it's clear that a Vim Clutch can as­sume many forms. At its core, a Vim Clutch is a pedal that en­gages or dis­en­gages the INSERT mode in the Vim ed­itor. In Vim (Vi­sual-ed­itor IM­proved) you can type i,I,a,A, or a few other keys to enter INSERT mode, pin­ning the cursor to spe­cific starting lo­ca­tions.

INSERT mode lets you type nor­mally— like you would in a Google doc or in Notepad. Pressing the Esc button brings you back to NORMAL mode...

Vim logo

If you've used Vim, then you know NORMAL mode is any­thing but "normal". You can jump to matched char­ac­ters, do clever search and re­place ma­neu­vers, build macros on-the-fly and much much more from within NORMAL mode.

A proper Vim Clutch would have to take the place of one of the INSERT-en­abling and dis­abling key presses. De­pressing the pedal would enter INSERT mode, and re­leasing the pedal re­turns to NORMAL mode.

In­stead of set­tling into a cu­bi­cle'd menagerie of iso­lated and burnt-out de­vel­opers, the Vim Clutch puts you in the cockpit with Vim Diesel— racing stick, staying above 50 words-per-minute to save all the in­no­cent bus riders.

So that's the "what" and the "why", but be­fore I give you the "how"— If you've made a dope Vim Clutch, and you're not in the list— what gives?? Leave a com­ment, paste in some links or im­ages. I'll put it in with the others.

Vim-Clutch Hard­ware

The Good­will pedal had about 4-feet of flat, fet­tuc­cine-looking cable coming out the back. It ter­mi­nated in a tele­phone jack. After a quick Google search, it seemed like the pedal would have been used to con­trol play­back on a tran­scribing ma­chine.

You'd en­gage the center pedal for normal play­back, step on the left pedal to rewind, or step right to fast-foward while lis­tening to a recording of speech. It would've pro­vided a quick way to nav­i­gate (prob­ably a casette) back and forth while si­mul­ta­ne­ously having both hands free to type out the ac­tual let­ters and spellings of what was said— at a key­board or elec­tric type­writer, I'm guessing. Sim­ilar models go for a de­cent chunk of change on Amazon:

This Dictaphone model was one of several other models that were indistinguishable from the one I snagged at Goodwill. It was a range of about $30-$90, and some of the pedals terminated in a USB connector rather than a telephone jack.
This Dictaphone model was one of several other models that were indistinguishable from the one I snagged at Goodwill. It was a range of about $30-$90, and some of the pedals terminated in a USB connector rather than a telephone jack.

All the more re-as­sured by the deal that I got, I de­cided to hack it apart and see what was hap­pening in­side. The pre­vious owner def­i­nitely had cats. The in­sides con­tained a trea­sure-trove of hair, whiskers and dust bun­nies.

There were two metal weights af­fixed to the bottom-half of the clamshell. They keep the pedal from scooting across the floor. Springs at each of the switches set-off the plastic pedals from en­gaging the switch mech­a­nism. I looked up the string of num­bers and let­ters that are printed on the side of each of the switches (out of cu­ri­ousity); but no con­clu­sive re­sult about the de­sign or man­u­fac­turer. The pedal it­self has no dis­tin­guishing brand mark­ings.

I wasn't really sure how I would convert switch presses to keypresses... but this was a good look at the pedal guts. There's a slightly thicker red wire that loops the current into all three switches. Each independent switch completes or closes it's own isolated loop through another wire (going out to the telephone jack). This was good news to me. It meant that each switch can be tracked separately, and the pedal could probably do combination presses.
I wasn't really sure how I would convert switch presses to keypresses... but this was a good look at the pedal guts. There's a slightly thicker red wire that loops the current into all three switches. Each independent switch completes or closes it's own isolated loop through another wire (going out to the telephone jack). This was good news to me. It meant that each switch can be tracked separately, and the pedal could probably do combination presses.

The springs are were also an ex­citing find. They could prob­ably be swapped out, giving some con­trol over the quality of the ped­al's ac­tion. After playing with it, I feel like it'd be more com­fort­able to have a stiffer press. Right now, the weight of my foot is enough to create an ac­ci­dental key-click.

A Con­troller: RPi Zero

We'll have to add $10 to our budget. I de­cided to use the Rasp­berry Pi 0 for the key­press con­troller— the thing that'll turn our pedal presses into "i" and "Esc". That's $13 total… still worth it. I had a couple of the Pi 0 SBCs lying around from pro­jects past, so it was a con­ve­nient op­tion.

The Rasp­berry Pi 0 was a go-to board for some of my school pro­jects in the past. I like the Zero model a lot. It's in­sane to have a pro­gram­mable de­vice that can use a dis­play, pro­vide WiFi and an SSH con­nec­tion, GPIO and more for such a low price. Plus it's about the size of a few sticks of gum! Which is more than small enough to fit com­fort­ably within the foot-pedal casing.

So now it's a pro­ject. I think the Pi will come in handy if I ever want to try sending key­presses via Blue­tooth. Could you imagine that? The first (AFAIK) wire­less Vim Clutch. That would be legit. We'll see. Prob­ably don't have the en­ergy. I don't know, maybe that would be worth it…

Bot­tom­line, the Pi 0 gives you a lot of flex­i­bility in an ex­cep­tion­ally tiny form-factor. The phys­ical in­ter­faces of the Pi 0 are di­verse and low-pro­file— the micro-USB is con­ve­nient for si­mul­ta­ne­ously pow­ering the de­vice and sending data.

The Raspberry Pi 3 measures about the same as the model 4, on a 85 x 56mm PCB. The Pi 0 (and Zero W, wireless, model), has a 65 x 30mm footprint. I haven't gotten my hands on the smallest Raspberry Pi, the Pico— which measures only 51 x 20mm and is supposed to cost $4.
The Raspberry Pi 3 measures about the same as the model 4, on a 85 x 56mm PCB. The Pi 0 (and Zero W, wireless, model), has a 65 x 30mm footprint. I haven't gotten my hands on the smallest Raspberry Pi, the Pico— which measures only 51 x 20mm and is supposed to cost $4.

In the past, I'd tried set­ting up the head­less Pi 0 using a single USB for both data and power. The tu­to­rials on­line seem super straight-for­ward and fool-proof; but I've still never gotten it to work seam­lessly.

The first Pi Zero I bought as a kit with all the silly don­gles and adapters to plug in a mouse, key­board, and dis­play. I had more re­solve to get it working this time, but still got into some muddy wa­ters with set­ting up the Eth­ernet gadget for SSH'ing over USB.

A useful, suc­cinct tu­to­rial by An­drew Mul­hol­land pro­vides the basic doc­u­men­ta­tion for set­ting it up. There's also a good one from Adafruit that pro­vides more con­text for Mac and Win­dows users. Most people seem to get it working by fol­lowing those di­rec­tions, but it al­ways gets a little sticky for me.

Rasp­berry Pi OS Config

On Linux (Ubuntu 20.04), I would in­stall the Rasp­berry Pi Im­ager with ap­ti­tude:

sudo apt-get install rpi-imager
shell

The RPi Im­ager has be­come in­cred­ibly easy to use and gives you a nice pre-pop­u­lated cat­alog of com­pat­ible OS's. I was able to quickly flash "Rasp­berry Pi OS Lite" after se­lecting it from a menu of rec­om­mended op­tions. I used an 8GB micro-SD card (prob­ably overkill for this pro­ject).

The Raspberry Pi Imager has releases for multiple platforms. The interface is really simple. Just click "Raspberry Pi OS" and select the "Lite" image. Then select your SD card and write the image to the card.
The Raspberry Pi Imager has releases for multiple platforms. The interface is really simple. Just click "Raspberry Pi OS" and select the "Lite" image. Then select your SD card and write the image to the card.

After flashing the SD card, it'll prompt you to eject it. I just pop it out and back in. You'll prob­ably see two things: rootfs and boot. The next step is to open boot, then edit config.txt.

At the bottom of config.txt, add a new line:

config.txt
dtoverlay=dwc2
text

Next, you have to edit the cmdline.txt file. As An­drew pointed out in his gist , each pa­ra­meter is sep­a­rated by a single space (no new lines). In here, you will in­sert the fol­lowing after "root­wait":

cmdline.txt
modules-load=dwc2,g_ether
text

After this, you should be able to plug in the Rasp­berry Pi 0 with a micro-USB cable (making sure to use the port that isn't the power port) and SSH into pi@raspberrypi.local as a USB Eth­ernet gadget. I man­aged to get this "working" in a hacky sort of way (helped along by this blog post ), but ul­ti­mately re­moved the "g_ether" op­tion and con­fig­ured the Pi to SSH over my local WiFi in­stead.

Maybe one day I'll get it to work on the first try. Con­fig­uring the Pi to con­nect to the Wi-Fi net­work is a per­fectly ac­cept­able al­ter­na­tive so­lu­tion. On a run­ning Pi, you would use sudo raspi-config to con­figure Wi-Fi and other im­por­tant op­tions— like lan­guage and lo­cale.

Al­ter­na­tively, you can create a file on the micro SD card called wpa_supplicant.conf:

sudo vim /etc/wpa_supplicant/wpa_supplicant.conf
shell

In this file, in­clude the 2-letter ISO code for your country as well as the SSID and pass­word of your net­work.

wp_supplicant.conf
country=US network={ ssid="Chance the Router" psk="CocoabutterKisses" }
conf

If you have other Rasp­berry Pi com­puters on the net­work, I rec­om­mend you turn them off or dis­con­nect them tem­porarily (un­less they have a dif­ferent host name). I had a Pi 4 that was al­ready broad­casting as raspberrypi.local and it was an­other stick in the spokes. I've since set the newly-con­nected Pi's host­name as vimclutch.local.

One last rec­om­men­da­tion (just to make your life easier)— don't go crazy with the pass­word. I had a whacky pass­word with a double-quote or some­thing stupid, and I'm still con­vinced it was the cul­prit after going down yet an­other de­bug­ging rabbit-hole.

Soft­ware

One last ex­cuse to use the Pi (rather than an Ar­duino, for ex­ample) was that it gave me a chance to try out some of the GPIO Python li­braries. The one I ended up im­porting is gpi­ozero .

This li­brary pro­vides a ton of con­ve­nient fea­tures around the "Button" ob­ject. A gpi­ozero "Button" is in­stan­ti­ated with the GPIO pin number— for ex­ample, pedal = Button(2). It ac­cepts a few other pa­ra­me­ters that will dic­tate the But­ton's at­trib­utes and be­havior.

You can then use methods like: pedal.is_pressed, pedal.is_held, pedal.when_released, and much more. Have a look at the Button-spe­cific doc­u­men­ta­tion for a full list of ca­pa­bil­i­ties.

After setting up a breadboard, I wired up a basic circuit with another switch I had on-hand. Messed around with the gpiozero Python library for a bit (it is awesome). Finally managed to get everything setup so that a button press would print "Hello World".
After setting up a breadboard, I wired up a basic circuit with another switch I had on-hand. Messed around with the gpiozero Python library for a bit (it is awesome). Finally managed to get everything setup so that a button press would print "Hello World".

Set­ting a Button() lets the script de­tect that the 5V boolean "high" signal "is_­pressed", or "is_re­leased". Now we have to turn that "high" or "low" into key­presses. The script below opens the Pi as a human in­ter­face de­vice (HID) that sends em­u­lated key­presses (as structs) to the com­puter the Pi is plugged into.

keypress.py
def press(char): mod,key=hid_codes[char] raw=struct.pack("BBBBL", mod, 0x00, key, 0x00, 0x00000000) with open("/dev/hidg0", "w") as fd: fd.write(raw) fd.write(struct.pack("Q" 0)) sleep(0.005)
python

The struct li­brary in­ter­prets Python bytes as packed bi­nary data. The weird "BBBBL" pat­tern is just dic­tating 4 un­signed chars (BBBB) fol­lowed by one un­signed long (L) in­teger. The code is bummed a little fur­ther than some other ex­am­ples I've found (mostly using Python's write_report func­tion. I ripped it from a rather cool pre­sen­ta­tion, One De­vice to PWN Them All).

The gist of the func­tion above is that we're able to build the un­read­able key­press sig­nals (one long string of bytes) by ref­er­encing the read­able char­acter (i.e., the letter "o" or "i") in a lookup table. The lookup table packs the bytes for that key and its mod­i­fier (i.e., Shift or Ctrl) into the longer struct. If there's someone smart reading this ar­ticle, they can please ex­plain this better.

As far as how those bi­nary bits are ac­tu­ally in­ter­preted as key­presses, I'm not sure how that works…

Be­fore this script will work, we need the Pi to say, "hello, I am a key­board", when­ever it's plugged into an­other com­puter via USB. I put a link to the blog post with the rel­e­vant script (as well as a few other useful links) in the footer to this pro­ject's GitHub README . Here it is below as well:

/usr/bin/vimclutch_usb
#!/usr/bin/env bash cd /sys/kernel/config/usb_gadget/ mkdir -p vimclutch cd vimclutch echo 0x1d6b > idVendor # Linux Foundation echo 0x0104 > idProduct # Multifunction Composite Gadget echo 0x0100 > bcdDevice # v1.0.0 echo 0x0200 > bcdUSB # USB2 mkdir -p strings/0x409 echo "fedcba9876543210" > strings/0x409/serialnumber echo "l00sed" > strings/0x409/manufacturer echo "VimClutch USB Device" > strings/0x409/product mkdir -p configs/c.1/strings/0x409 echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration echo 250 > configs/c.1/MaxPower # Add functions here mkdir -p functions/hid.usb0 echo 1 > functions/hid.usb0/protocol echo 1 > functions/hid.usb0/subclass echo 8 > functions/hid.usb0/report_length echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc ln -s functions/hid.usb0 configs/c.1/ # End functions ls /sys/class/udc > UDC
bash

Save this script to /usr/bin/vimclutch_usb on the Rasp­berry Pi Zero (or give it an­other name). It also needs to be made ex­e­cutable:

chmod +x /usr/bin/vimclutch_usb
shell

Then put a line in /etc/rc.local (be­fore the exit 0 line) that will allow the script to be au­to­mat­i­cally run, set­ting up the Pi as a USB key­board:

/etc/rc.local
... + /usr/bin/vimclutch_usb exit 0
diff

Sol­dering

The fet­tuc­cine cable run­ning out the back of the pedal was re­moved. I sev­ered the leads from the switches, and sol­dered them di­rectly to the GPIO pins (2, 3, and 26) of the Pi. I also sol­dered the thicker red wire to the Pi's 5V out, and closed the other end of the loop to ground. De­pressing any of the three switches now closes the cir­cuit with its spe­cific GPIO pin.

Soldered the connections directly to the Pi Zero's GPIO pins— plus two more wires, one to 5V and one to ground. Not very pretty, but I got the job done.
Soldered the connections directly to the Pi Zero's GPIO pins— plus two more wires, one to 5V and one to ground. Not very pretty, but I got the job done.

To keep the Pi firmly in place, I drilled some holes through the base of the pedal and mounted the cor­ners of the board to two stand­offs. The single USB cable con­nects to the side of the Pi and exits out the same hole in the back— pro­tected by a rubber grommet.

I've been using the pedal to code for about a month now, and it re­ally is a lot of fun. It took some get­ting used to at first, but after a couple days prac­tice it's easy to build up the muscle memory. It also in­cen­tivized me to learn about the dif­ferent ways to enter INSERT mode— I had no idea about SHIFT+a until I looked it up for this pro­ject!

Un­for­tu­nately (after a couple weeks of usage) the main center ped­al's switch started to get a bit funky… might just be a bad solder joint; but hope­fully the switch isn't faulty. Luckily I could just SSH into the pedal and swap out the keys. I still have the right and left working swim­mingly.

Con­clu­sion

This has been an en­light­ening pro­ject. I think it's given me a lot of useful knowl­edge that I will carry for­ward in my fu­ture pro­jects. Ex­cited to be doing more with elec­tronics and linking phys­ical in­ter­ac­tions with dig­ital events and vice versa.

Until then, thank you so much for taking a minute to share my ex­cite­ment over this pro­ject. Like I said ear­lier, if you've made a Vim Clutch, or an­other bonkers HID, please share a link in the com­ments! Happy coding.