Introduction: How to Make a USB Laptop Keyboard Controller

This Instructable will provide a step by step procedure for building a USB laptop keyboard and touchpad controller. I created this guide and video to hopefully make it easier for people to re-purpose an old laptop. A typical laptop relies on the motherboard for the keyboard scanning and touchpad interface. I use a Teensy microcontroller mounted on a connector board to take over this function. This Instructable was originally based on the Teensy LC and 3.2 as shown above in the first video. Because these older Teensies are now obsolete, I've updated the connector boards to use the Teensy 4.0 and 4.1 as shown in the second video. The original Instructable is given below as a PDF for those that can still find a Teensy LC or 3.2. The original and new circuit board files are at my GitHub repository along with all the software.

Teensies from PJRC are often used by the mechanical keyboard enthusiasts at Geekhack and Deskthority and the TMK or QMK software is the most popular controller code. The TMK/QMK code is a bit of an overkill if you just want a simple USB keyboard but it will certainly provide all the features you could ever need. If you would rather write your own keyboard software using Arduino, the Teensyduino functions give you total USB control. Whatever software you decide to use, it will require a key matrix that maps out how your keyboard is wired. One approach, (that I never want to do again) is to exhaustively check every connector pin combination with an ohm meter while holding down each key. I did this when I converted a Sony Vaio into a Raspberry Pi laptop. An Instructable from alpinedelta disassembles the keyboard in order for the connections to each switch to be visually traced back to the connector. Instead of taking the keyboard apart or using an ohm meter, this Instructable will load the Teensy with an automated continuity tester. The Teensy will report over USB, the two pin numbers that are connected when you press a key. After every key has been pressed, the results can be transferred to a row-column matrix and used by the TMK/QMK keyboard controller software or a home-brew Teensyduino routine. The touchpad code described in step 22 can be added to the keyboard routine to create a composite USB device.

The software and circuit board files shown in this Instructable can be downloaded from my repo by clicking the green "Code" download button on the right of the GitHub page. Choose the "Download ZIP" option from the Code pull-down menu. The ZIP file will contain the entire repository content. 

Step 1: Keyboard Cable Specifications

Laptop keyboards use a flexible printed circuit (FPC), also known as a flat flexible cable (FFC) that connects all the key switches in an array of rows and columns as shown above. The keyboard controller drives each row low, one at a time while reading the columns (with a pull up resistor) to see if any switch is pushed. The two bins of laptop keyboards shown above are from Re-PC, a local recycling store. About 75% of these keyboards had FPC cables with exposed metal traces on one side and a plastic backing on the other side with a thickness at the end of 0.30 mm. The trace spacing, known as the "pitch" was usually 1mm, 0.8mm, or 0.5mm. It can be difficult to measure the pitch so an alternative is to measure the width of the entire FPC cable and use this formula:

Pitch = Total width / (N + 1) where N is the number of pins

Most of the keyboards at Re-PC had 26 or less pins but a few went up to 34. There were also keyboards with dual FPC cables. I have included support for all of these variations. Connectors for keyboard cables are readily available from companies like Aliexpress, Mouser, or Digikey. The number of signal traces, the pitch, and whether the contacts are on the top or bottom are the parameters you will need when ordering. There were some old keyboards in the bins with rigid printed circuit board connectors and some other keyboards with specialized connectors soldered to the end of the FPC cable. These keyboards will not be the focus of this Instructable but a few examples will be given.

Decide how you will route the FPC cable to the Teensy connector board and then examine whether the contacts at the end of the cable are facing up or down. It's common to flip the FPC cable 180 degrees so it ends up underneath the keyboard. The surface mount FFC/FPC connectors from AliExpress, Mouser, Arrow, Newark, and Digikey can have top or bottom contacts as shown in the picture above. Besides right angle connectors, there are also vertical connectors. Here are 3 examples for the possible locking mechanisms; spring loaded with no locking bar, flip down locking bar or slide a locking drawer sideways.

Step 2: Modify Your FPC Cable As Needed

Before you solder the keyboard connector to the board, try inserting the FPC cable and confirm it fits. If it's not very tight after you lock it down, you may need to increase the thickness of the plastic backing with tape or a piece of paper. If your FPC cable doesn't slide into the connector, it might need to be trimmed. Locking nubs on the side of the cable are easy to remove with small scissors. If the FPC traces don't line up with the connector pins, use an X-ACTO knife to trim along the side of the cable. The Dell Latitude D630 keyboard needed the most modifications. It had a solder-less connector on the end of the FPC cable that was easily removed. Then I pulled off the extra thick plastic backing that was glued on the end of the cable and cut a notch on the side to align the contacts. To bring the thickness back to normal, I glued 2 pieces of paper to the end of the cable.

In order to minimize cable modifications, I sometimes install a connector on the board with more pins than the FPC cable. This lets me test various keyboards with different pin counts and I don't need to cut off the locking nubs. This method does require that I visually align the contacts.

Step 3: Teensy 4.0 Mounted on Top

I designed a circuit board for the Teensy 4.0 that routes its 34 I/O pins to 34 surface mount pads for an FPC connector with a 1mm, 0.8mm, or 0.5mm pitch. The Teensy will sit on top with header pins or wires connecting it to the board. The Eagle file "T4p0.brd" at my repo can be sent to fab houses like OSH Park or Eurocircuits. Three boards from OSH Park will cost about $20. The zipped Gerber file "T4p0_2023-12-03.zip" was translated from the Eagle file and is accepted by board houses like JLCPCB in China. JLCPCB will produce 5 boards for about $8 with economy shipping to the U.S. This price assumes you select HASL for the surface finish, not the more expensive ENIG finish (which is the only finish offered by OSH Park).

A connector with up to 34 pins can be soldered to this board based on your FPC cable pin count. For connectors with less than 34 pins, solder it starting at pin 1 and leave the unused pads at the other end blank. If you have a 34 pin FPC cable, you need to free up Teensy I/O 13 from the on-board LED. Unsolder the LED (or its current limit resistor) so I/O 13 can be used by the keyboard. You can purchase the Teensy with or without header pins. I prefer a Teensy without pre-soldered header pins so I can attach the Teensy to the board with wires that are easy to cut or reroute.

The Teensy 4.0 uses surface mount pads on its back side for I/O signals 24 thru 33 so it’s a little more work to solder these to the board. One approach is to solder 10 “flying leads” to the surface mount pads on the Teensy as shown above and then pass each wire thru the corresponding holes on the board for soldering. Stripped 30 gauge wire wrap wire works good.

For those that dislike flying leads, buy the Teensy header kit from Sparkfun and use the 2 x 7 right angle SMT. The surface mount pads on the Teensy 4.0 are small and require the right angle header pins to be trimmed by a 1/2 mm in order to not overhang the pads.

If you bought a Teensy 4.0 with header pins, cut the 2 x 7 right angle header down to 2 x 5, then use a small proto board with holes to hold the header in alignment while soldering (see picture above). Alignment is easy if you buy a Teensy without header pins because you can cut the 2 pins on each side of the 2 x 7 header so they are straight and can be inserted into the outer Teensy holes (see steps above). In either case, the right angle header pins make the Teensy sit a little higher off the board. See step 6 if you need a low profile solution.

I designed the circuit board to include surface mount pads for BSS138 transistors and pull up resistors that act as Clock and Data level translators. This allows you to control a 5 volt touchpad with a "bit-bang" PS/2 bus (see schematic above). The translator circuit protects the Teensy from being damaged by the 5 volt touchpad signals. A touchpad powered from 3.3 volts does not need the level translators. Step 22 provides all the details for connecting the Teensy to a touchpad. If you are not controlling a touchpad, leave these pads blank. You can always add the parts later or wire to an Adafruit 757 level translator instead of building your own.

The USB to the Teensy is normally connected via a Micro connector but I've included solder pads for hardwiring the USB signals. If you want to use this feature, you will need to solder two flying leads from the D+ and D- pads on the Teensy backside to the connector board.

Step 4: Teensy 4.1 Mounted on Top

The Teensy 4.1 will sit on top with header pins or wires attaching it to the connector board. To fabricate this board, use Eagle file "T4p1.brd" or the zipped Gerber file "T4p1_2023-12-03.zip" at my repo. The circuit board routes 34 I/O pins from the Teensy 4.1 to 34 surface mount pads for an FPC connector with a 1mm, 0.8mm, or 0.5mm pitch. The Teensy 4.1 is a little more expensive and larger than the 4.0 but it has 42 I/O pins around the outside so there's no backside surface mount I/O pads to solder or LEDs to remove. The schematic (given above) shows the BSS138 transistors and pull up resistors on I/O 39 and 40 that make level translators for a 5 volt touchpad. You can also add current limit resistors on I/O's 37 and 38 to drive CAPS and NUM lock LEDs.

Step 5: Teensy 4.1 "Easy-Soldering Board" or "No-Solder Method"

If your soldering skills are not ready for surface mount pads but you can solder a pin in a hole, the board shown above uses a vertical FPC connector with thru hole pins. Download the Eagle file "T4p1_thruhole.brd" or Gerber file "T4p1_thruhole_2023-11-01.zip" from my repo for fabrication. This board only works if your keyboard FPC cable has no more than 34 pins and a pitch of 1mm or 1.25mm (connectors like this in smaller pitches are hard to find). The board has 34 standard platted thru holes for the connector pins instead of surface mount pads. You can rotate the connector 180 degrees so the contacts are on the left or the right to match up with your FPC cable. The pin spacing shown above is designed for vertical connectors such as the 26 pin, 1mm pitch Amphenol HLW26S-2C7LF or SLW26S-1C7LF. Replace the 26 in the part number with the number of pins in your cable. These or similar connectors are available from supply houses like Digikey, Mouser, Arrow, Newark, and AliExpress. The 1.25mm pitch connectors (used on very old laptops) are a little harder to find but there are some available from AliExpress. If you want to drive CAPS or NUM Lock LEDs, there are pads for axial leaded current limit resistors driven by I/O's 37 and 38 (see schematic above). To control a 5 volt touchpad, I/O's 39 and 40 are brought to pads that can be wired to an Adafruit 757 level translator.

If you don't know how to solder but still want to make a USB keyboard, download the PDF file below. It will explain my “No-solder method" that uses an AliExpress FPC adapter board and jumper wires. This approach is also good for confirming the laptop keyboard and software are working before soldering a custom board.

Step 6: Teensy 4.0 & 4.1 Low Profile Connector Boards

A Teensy with header pins that is mounted on top of an FPC connector board may be too tall to fit in a thin laptop case so I designed the two "cutout" boards shown above. The two Eagle board files are "T4p0_cutout.brd" and "T4p1_cutout.brd". The Gerber files are "T4p0_cutout_2023-12-23.zip" and "T4p1_cutout_2023-12-23.zip", all at my repo. Purchase the Teensy without header pins, then solder U shaped header pins (or wires) to hold the Teensy in the board cutout. For the Teensy 4.0, I/O numbers 24 thru 33 on the backside surface mount pads must be connected with jumper wires to the board (see picture above). If you have a 34 pin FPC cable and you are using a Teensy 4.0, you must unsolder the LED to free up I/O 13. I used "U" shaped header pins from Ali Express that have a width of 6mm (see drawing above). Both boards will work with 1mm, 0.8mm, or 0.5mm pitch FPC connectors with up to 34 pins. There are surface mount pads for BSS138 transistors and resistors that make level translators for controlling a 5 volt touchpad (see schematics above).

Step 7: Teensy 2.0++ Connector Board


If it's hard to find a Teensy 4.0 or 4.1 in your area, you can order a Teensy 2.0++ clone from AliExpress. This an old 8 bit controller that is no longer offered by PJRC but the clone works fine as a keyboard controller. Make sure you order the Teensy 2.0++ with 20 pins on each side. The smaller 2.0 without the ++ only has 12 pins on each side and a lot less I/O. I designed the board shown above to work with surface mount FPC connectors up to 36 pins with a 1mm, 0.8mm, or 0.5mm pitch. The Eagle file "Keyboard_Scanner_2pp_RevA.brd" and the zipped Gerber file "Keyboard_Scanner_2pp_RevA_2023-10-31.zip" are at my repo. My original connector board used I/O pin D6 for one of the keyboard signals but this is tied to the onboard LED. The Rev A connector board avoids using I/O pin D6 so you don't need to unsolder the LED. Use header pins or wires to connect interior I/O's PA0 thru PA7 to the board. Interior I/O's E4 and E5 are too small for header pins so you must use 30 gauge wire. See the assembled board in the pictures above.

The Teensy 2.0++ outputs 5 volt logic signals that can directly control a 5 volt touchpad without level translators. If your touchpad is powered with 3.3 volts, use the Adafruit 757 to translate the PS/2 clock and data signals so you don't damage the touchpad.

The I/O pin names that are silkscreened on the Teensy can be used in the code but must be preceded with PIN_ (example PIN_B7). The code looks more "Arduino-ish" if you use I/O numbers. See the schematic above for translating the silkscreen pin names to Arduino I/O numbers.

Step 8: Load the Continuity Tester Into the Teensy

  • Follow the PJRC instructions for installing Arduino and Teensyduino on your computer.
  • Load the Matrix_Decoder code from my repo into the Arduino integrated development environment (IDE).
  • Matrix_Decoder_4p0.ino is for a Teensy 4.0, Matrix_Decoder_4p1.ino is for a Teensy 4.1, and Matrix_Decoder_2pp_RevA.ino is for a Teensy 2.0++.
  • Two integers near the top of the code may need to be adjusted for your keyboard. The min_pin is usually set to 1 and the max_pin is usually set to the FPC connector size. The routine will first test from min to max and then it tests from max to min (just in case there are diodes in the keyboard).
  • Connect a USB cable from the Teensy to the computer. Your computer should automatically load the necessary USB drivers.
  • In the Arduino IDE, under “tools”, "board", "Teensy", select Teensy 4.0, 4.1, or ++2.0 depending on what you’re using. Also under “tools”, select USB type: "Keyboard" or "Keyboard + Mouse + Joystick". If you forget to do this step, you will get an error message that says "Keyboard was not declared in this scope".
  • Compile and load the Matrix_Decoder code into the Teensy. If it’s your very first time loading the Teensy, you may have to push the button on the Teensy to enable the loader.
  • Disconnect the USB cable from the Teensy.
  • If you are using a Teensy 4.0 on a 34 pin FPC cable, you must unsolder the LED on the Teensy so it does not interfere with the scan.
  • French computers require the shift key in order to display the numbers 0 thru 9. I have made French matrix decoder code for the Teensy 4.0 and 4.1 that takes care of the shift key so that numbers are displayed on a French computer. You can find this code at my Github repo.

Step 9: Load the Key-List File Into an Editor

There are two “key-list” text files given below and at my repo named Keyboard_with_number_pad.txt and Keyboard_without_number_pad.txt. Download the one that matches your keyboard and open it in a text editor. I like to use Notepad++ because it has column editing but any editor will work. Place the cursor to the right of the very first key in the list as shown above. This will determine where the Teensy begins to display the pin numbers as you push each key. These “key-list” files have every key that the Teensy can send followed by tabs to make space for pin numbers. The GUI key is the "Windows key" on a PC or the "clover key" on a Mac.

Automated Method:

Marcel Hillesheim has written a Python program that takes much of the manual labor out of my original process. I forked his GitHub repo so I could add more Teensy's to the program. If you're comfortable running Python, download this program. It will save you a lot of time.

Manual Method:

If you don't have a Raspberry Pi or any other way of running Python, use the manual method described in step 12 .

Step 10: Connect the FPC Cable

Inspect your FPC connector to determine the correct orientation for the cable.

If your FPC connector has contacts on the bottom like the picture on the left, use your finger nail to gently lift the connector locking bar to the open position. Slide the FPC cable into the connector with the bare metal contacts pointed down (closest to the board) and the plastic backing strip pointed up. Lock the cable to the connector by gently pushing the bar down. The locking bar mashes the bare metal of the FPC cable down against pins on the bottom of the connector.

If your FPC connector has contacts on the top like the picture on the right, use your finger nail to slide the locking bar to the right. Insert the cable into the connector with the bare metal contacts pointed up and the plastic backing strip pointed down. The orientation is opposite from the first picture because when the locking bar is slid to the left, it pushes the cable up against pins on the top of the connector.

Connect a USB cable from the Teensy to the computer and wait 20 seconds for the Teensy to be recognized as a USB keyboard. This delay is in the code to make sure your computer is ready to receive numbers from the Teensy. If numbers are reported on the screen before any keys are pressed, these pins are shorted together and must be fixed. It may be a solder short on the connector which you can check by retrying without the keyboard connected. If it is still shorted without the keyboard, use flux and solder wick on the shorted connector pads. If the short goes away when the keyboard is removed, these pins are most likely ground pins that are tied together in the keyboard so one of them must be excluded from the routine. Adjust the max_pin or min_pin values in the code to allow the routine to skip over these pins. Reduce the max_pin value if some of the FPC traces are visibly tied together as shown in the picture above. The original motherboard controller used these shorted pins to identify the language of the keyboard but the Teensy code will report the short and then hang.

If the shorted FPC pins are in the middle, you can adjust the max_pin variable to just under the first shorted pin and press all the keys on the list (some keys will not work). Next recompile the code with the min_pin just past the short and the max_pin at the end. Press the remaining keys on the list so you end up with all the key information. Remember that a Teensy 4.0 will report pin 34 as shorted if you set the max_pin to 34 and the onboard LED has not been removed from the Teensy.

An alternative to adjusting max_pin and min_pin is to load the Matrix_Decoder_4p0_alternate or Matrix_Decoder_4p1_alternate routine. These routines allow you to exclude any pins necessary to avoid shorts. They report the Teensy I/O numbers, not the FPC pin numbers. You will need to manually convert the connection list back to FPC pin numbers using the tables in step 14. The edited text file can then be used by Marcel's Python program.

If certain keyboard keys do not give a response when pressed, it is usually caused by a bad solder connection, tarnished cable, or misaligned contacts. To prove the code will report all possible pin connections, use a small flat screwdriver to momentarily short pads 1 and 2 at the FPC connector, right on top of your solder joint. Move on to pads 2 and 3, 3 and 4....., proceeding up to the last two pads, taking note of any pad numbers that don't give a response. For the pads that don't work, reheat the solder joint on the FPC connector pad and if necessary, at the header pin on the Teensy. You can tell which Teensy pad to reheat using the pin translation table in step 14. Keep fixing your solder joints until you get a response for every pin when you short them with a screw driver. If some keyboard keys are still not working, there may be a bad connection to the FPC cable. If the metal traces look tarnished, gently clean the FPC cable with an eraser. Use a magnifying glass to inspect inside the FPC connector to look for debris and to see if the contact points are in alignment with the cable traces. You may need to trim the side of the FPC cable to get the proper alignment. If alignment looks good, push down on the FPC connector or lift up on the cable while trying the bad keys to see if you can sometimes make them work. You may need to add a thin piece of paper or tape to the plastic backing on the FPC cable to get a tighter fit. Erratic keys can sometimes be fixed by popping off the key cap and cleaning with isopropyl alcohol. Sometimes the keyboard has a bad key switch that will not give a reliable response, no matter what you do. The only solution is to replace the keyboard.

Step 11: Test the Keyboard

Press each key, one by one on the test keyboard as listed on the editor screen. The Teensy will send two pin numbers over USB that were connected when the key was pressed as shown in the picture above. The Teensy will then send a down arrow to position the cursor for the next key. If you make a mistake, just use your PC keyboard and mouse to erase the error and re-position the cursor. If a key is listed that is not on your keyboard, use your mouse or arrow keys on your PC to move the cursor to the next key. The Python program jumps over the unused keys so there's no need to edit them out manually. If you want to assign Media keys (a key event like "mute" associated with the Fn key), push the media key but do not push the Fn key. Make sure the letters "FN" are between the media key name and the pin numbers so the Python program puts these keys in the media matrix. After pressing every key on your keyboard, save the finished file for analysis. At this point you've created a very thorough keyboard tester.

Note: There may be special keys on your keyboard that do things like open a calculator or adjust brightness but these functions are not available in Teensyduino. Only the keys listed in the PJRC "All Keys Codes" table can be used.

Step 12: Determine Input and Output Pins

If you are using Marcel's matrixgenerator.py Python program, put the completed pin list file from step 11 in the same directory as the Python program so the start up menu can find it. On a Raspberry Pi, double click on the matrixgenerator.py program to launch the Thonny IDE. Select "Build", "Compile" and then "Build", "Execute". The start menu of the program (shown above) asks which text file and Teensy to use. The program then gives the results in a terminal window (example shown above) which you can copy and paste into a text file for transfer to your PC. The first results are the FPC connector pins that are inputs and outputs. Next it translates the pin numbers to Teensy I/O numbers according to the table shown in step 14. And finally it places all the key names in arrays for easy copy and paste into a USB keyboard routine.

Sometimes a strange keyboard will confuse Marcel's program and not everyone is familiar with running Python. For those cases, you should use my original manual procedure. The following instructions will determine the keyboard pins based around the Modifier keys; Control, Alt, Shift, GUI, and Fn. As a general rule (that is not always followed) 8 of the keyboard pins will be inputs to the Teensy and the remainder will be outputs. The Modifier keys usually have an output row all to themselves which allows these keys to be held down while other keys are pressed. This avoids a sneak path which would cause ghosting as described in the PDF below. These “rules” are not always followed (especially by the Fn key) so you may need to do some trial and error as you build the matrix. I have lots of keyboard examples at my Github repo to help you out.

Control-Left and Control-Right will have a common pin between them. Example:

Cntrl-L 19 20

Cntrl-R 20 22

The common pin, Pin 20 in this example, will be a Teensy output, and 19 & 22 will be inputs.

Similarly Alt-Left and Alt-Right will have a common pin between them, just as Shift-Left and Shift-Right will also have a common pin. Example:

Alt-L 7 24

Alt-R 7 15

Shift-L 21 23

Shift-R 23 25

The Alt common pin will be a Teensy output, and 15 & 24 will be inputs.

The Shift common pin will be a Teensy output, and 21 & 25 will be inputs.

The GUI key is usually a single key as in this example;

GUI 9 26

Search all the other pins in the list to see if 9 or 26 are used on other keys. In this example, pin 9 was not used for any other key which means it will be a Teensy output and 26 will be an input. Sometimes both pins are used for other keys but one of the pins is used for common keys like letters and numbers and the other pin is used for less-common keys like page-up. In this case the pin used for common keys will be a Teensy input and the other pin will be an output. Note that the GUI key will still work if you swap the pins.

The Fn key is also a single key as in this example;

Fn 12 18

Using the same approach as the GUI key, search all the other pins to see if 12 or 18 are used on other keys. In this example, pin 12 was not used for any other key therefore it will be an output and 18 will be an input. If both pins are used on other keys, follow the same rules as the GUI example. Sometimes both of the Fn pins are used by common keys which means you can pick either pin as an input and the other as an output.

The eight input pins for the HP DV9000 example keyboard have been identified as; 15, 18, 19, 21, 22, 24, 25, and 26. All other pins will be Teensy outputs. Make a keyboard matrix table like the one shown above with the 8 input pins across the top in ascending order and all the other pins as outputs on the side, also in ascending order.

The orientation of the keyboard matrix is just my personal preference. You can swap the rows/columns and inputs/outputs if you want. Swapping pins may be necessary if you have a rare laptop keyboard that has diodes in series with each switch. With diodes, you need to make sure the cathode (first pin listed) is designated an output row from the Teensy and the anode (second pin listed) is designated an input column to the Teensy.

Sometimes only 7 pins can be identified as inputs because two modifier keys share the same input pin (usually the Shift-R and Control-R). I've even seen keyboards that had the same two input pins for the Shift, Alt, and Control keys so after determining the GUI and Fn input pins, only 4 inputs were identified. For some keyboards, the input pins are grouped together (i.e., 17 thru 24) which makes it easy to fill in the missing pins. Other keyboards have no grouping of pins which means you’ll have to begin filling out the matrix even though some input pins are missing. The remaining input pins will be revealed when some of the keys can’t be placed. Pick one of the pins from these keys as an input and continue filling out the matrix. If you get stuck, go back and pick the other pin instead. I had to do this for the MacBook Pro A1286 keyboard as described in the PDF below.

Keyboards with dual FPC cables are the easiest to figure out because the input pins are on the cable with fewer pins and the output pins are on the other cable.

Step 13: Fill the Matrix With Keys

To manually fill the matrix, place each key name at the row/column intersection of the pins as shown in the HP DV9000 keyboard example given above. The modifier keys are in bold print to make it easy to see that they have a row all to themselves. This keyboard followed the “rules” exactly.

Marcel's Python program creates the matrix automatically so it can be copied into the final USB routine.

Step 14: Translate FPC Pin Numbers to Teensy I/O Numbers

The FPC to Teensy I/O numbers are automatically translated by Marcel's Python program. If you are using the manual method, you will need to use the Teensy translation tables shown above.

Step 15: Load a USB Keyboard Routine Into the Teensy

A Deskthority post from "flabbergast" describes using the ChibiOS development environment to configure TMK for ARM based processors like those used on the Teensy. A toolchain such as the GNU ARM Embedded Toolchain is used to compile the Teensy code. You will need to install the ChibiOS development environment per these instructions. The teensy_lc_onekey example details the steps to create a working TMK build. The QMK keyboard routine is based on TMK and it also has ChibiOS support for the Teensy 4.1 and 4.2. QMK offers timestamp based debouncing with various options set when compiling. There is a Complete Newbs Guide for QMK.

Jay Thompson has created a QMK fork that gives all the information for his Teensy 3.2/Lenovo T420 keyboard project. Jay provides his build environment setup and the make instructions so you have an example to modify for your keyboard.

Gordon has made a Hackaday.IO project called "QMK Powered Laptop Keyboard" which details the "gymnastics" of using QMK.

The TMK/QMK keyboard software is very powerful with tons of features but it can be confusing, (at least to me). As an alternative, I wrote an Arduino USB keyboard routine using the Teensyduino “Micro-Manager” functions. There's just 1 file to load using the Arduino IDE and it's only about 385 lines with lots of comments. I'm a hardware guy so expect ugly code but it provides a basic keyboard controller with 6 key rollover that you can modify to suite your needs. Key debouncing is handled using a 30 msec scan rate.

Every keyboard listed below has a folder at my repo containing a Teensyduino USB keyboard routine giving you lots of examples. Pick the one that's closest to your keyboard and use its code as your starting point, (they're all based on the same basic code). Code written for the obsolete Teensy LC or 3.2 must have 2 lines changed for the Teensy 4.0, 4.1, and 2.0++. The 2.0++ also needs all lines with "int" changed to "unsigned int". For those routines that have not been translated, the procedure is described in the PDF file "Instructions to translate Teensy code". If you are using the manual approach to build the matrix, use the PDF file "Instructions for Manual code modification". If you are using Marcel's Python program, the PDF file "Instructions for Marcels Code" details the process. These 3 PDFs are available below and at my repo. When checking to see if your new code works for all keys, the function keys can be a bit ambiguous. You can tell if a Function key works by using the online tool at keyboardchecker.com. Just push the function key and it should show green.

If you plan to put your Teensy 4.0 or 4.1 keyboard in a laptop that will run off a battery, you will want the lowest current possible. In the Arduino IDE under tools - CPU Speed - select 24MHz instead of the default 600MHz. The Teensy current will go down to about 31ma instead of 100ma but it will still operate normally.

IBM380ED - Brian Chan and I teamed up to convert an IBM 380ED keyboard and trackpoint to USB as shown in this video. The Teensy 3.2 code, Eagle files, and project description are in a folder at my repo. This project was documented at Hackaday.IO and Hackaday.com. Stephen designed a stand alone case for the 380 that you can 3D print with his files at thingverse. Brian has converted his IBM 380ED into a KVM, documented at Hackaday.IO.

Commodore 64 - Olga modified my code for a Commodore 64 keyboard. The Teensy LC code, key list files and project description are in a folder at my repo.

Compaq 286 - Olga also modified my Teensy LC code for an old Compaq 286 keyboard but he did much more. Now the program will take the pin number results from running the keylist text file so you don't need to create a key matrix. The code and PDF description are in a folder at my repo.

Blackberry Q10 & HP Jornada & Atari Porfolio - T Caschy has modified my Teensy LC code to work with these keyboards. The code is in a folder at my repo.

Lenovo Y480 - Luigi Caradonna has modified my Teensy LC code to work with a Lenovo Y480 with an Italian layout and backlight control. The code is in a folder at my repo. Luigi also made a stunning marble base for this keyboard. Pictures are in the "I made it" section at the end of this Instructable.

Lenovo X1 Carbon - Maykro has modified my Teensy 2.0++ code to work with a Lenovo X1 Carbon. The PS/2 trackpoint is working in "stream mode" with adjustable speed. The code is at his repo.

Apple eMate 300 - Billy67 has modified my Teensy LC code to work with an Apple eMate 300 keyboard. The code is in a folder at my repo. Pictures are in the "I made it" section at the end of this Instructable. Check out his very thorough video plus reviews from Cult of Mac and The Register to see how he made a Raspberry Pi laptop from an Apple eMate 300.

Apple iBook G3 Clamshell - Billy67 used a Teensy 3.2 with my special connector board for this keyboard. I've updated the board and code to use a Teensy 4.0. See step 18 for the details.

Apple Powerbook models 100, 140 through 180, and 520 - Billy67 used a Teensy 3.2 for these Apple keyboard and trackball units. Pictures are in the "I made it" section at the end of this Instructable. The trackball uses an Apple Desktop Bus (ADB) interface that is controlled by the Teensy after it scans the keyboard matrix. The Teensy code for the Powerbook 100, Powerbook 520, and for Powerbooks 140 thru 180 are at my repo.

GRiD 1550 UK - SimonT192 and I modified my Teensy LC code to work with a GRiD 1550 keyboard with a UK layout. This laptop has a rotary encoded "IsoPoint" mouse which has been converted to USB using a Teensy LC. The code for the keyboard and mouse are in a folder at my repo along with a PDF describing the operation. Watch Simon's YouTube video for a very detailed description of his "Aliens Sentry Gun" GRiD laptop build. Hackaday featured his project as well.

GRiD 1550 US - Chris has modified his GRiD 1550 US keyboard to work with a Teensy LC. The code for the keyboard is in a folder at my repo along with a PDF. Chris was also able to get the IsoPoint mouse working.

GRiDCase 3 - Lucas and I converted his Bloomberg GRiDCase 3 laptop keyboard to USB with a Teensy 4.1. The project documentation and code is at my repo. The financial spreadsheet keys were redefined but some of the unique keys were maintained. It does not have a right shift key. The “CODE” key acts as a Figure Shift which allows access to the symbols on the alphabet keys. Shifted numbers do not send anything but shifted alphabet keys send the upper case letter. Lucas is accustomed to this key layout thanks to his day job of repairing typewriters. Check out his project writeup for a blow by blow description.

Lenovo Thinkpad T61 - I created a new Teensy 4.0 connector board for a T61 which will work on all T60 series keyboards. In addition to controlling the keyboard and trackpoint, the code also controls the touchpad. The code, circuit boards, and PDF are in a folder at my repo. See Step 17 for more details.

IBM Thinkpad T41 - I created a new Teensy 4.0 connector board for a T41 which will work on all T40 series keyboards. In addition to controlling the keyboard and trackpoint, the code also controls the touchpad. The code, circuit boards, and PDF are in a folder at my repo. See Step 17 for more details.

Psion MC400 - Zedstarr used my Teensy LC code on the mechanical keyboard from a Psion MC400. His website gives all the details including a video link.

Logitech K120 - I replaced the original controller from this desktop keyboard with a Teensy 4.1 and documented the results at Hackster.

Step 16: Non-Standard FPC Cable Connectors

If your keyboard has a non-standard FPC cable like the Thinkpad and iBook connectors shown above, the task becomes more challenging. If you can't find a mating connector at Aliexpress or any other site, your only alternative is to remove the connector from the laptop motherboard. Apply flux and Chip Quik removal alloy on all the pins and ground tabs. This alloy mixes with the original solder and allows it to become molten at a lower temperature. If you have a single row of pins, it may be possible to keep all pins molten long enough to lift the connector off the board. Two row connectors may need a second soldering iron. Instead of using a soldering iron, you can use a heat gun or low cost hot air rework station to blow hot air on the connector from the back side of the board. Doing it this way will protect the connector from excess heat. Once you have the connector off the board, clean up the legs with regular solder and wick.

You will need to make a board layout that routes the Teensy I/O signals to your keyboard connector. I like to do a preliminary layout on paper first in order to place the parts and route the signals with the fewest via's. It's easy to assign the Teensy I/O pins in software based on whatever pin order makes the layout work best. It's tempting to make the layout next, but do the schematic first so your layout will have air-wires showing you how to route each trace.

Eagle, KiCad, PCBWeb Designer, EasyEDA, and DesignSpark PCB are some of the free layout tools that are available. Sparkfun has excellent tutorials for Eagle schematic and layout. Also look at the Adafruit tutorial on creating parts in Eagle because you'll need to make a package and symbol for your connector. After you get your layout fabricated, you'll need to change the Matrix_Decoder software to work with the new I/O pin-out.

Step 17: Thinkpad T60 Series & T40 Series Keyboards

The Thinkpad T60 series and T40 series keyboard connectors are good examples of non-standard FPC cables. Both have 40 pin connectors but with different dimensions and pitch. The circuit board connector for the T60 series is AA01B-S040 and it's available at AliExpress. Unfortunately the KX14-40K5DE connector for the T40 series is unavailable so I had to unsolder it from the motherboard. I've made keyboard controller boards in the past for T60 series keyboards using the Teensy LC and 3.2 but since these are obsolete, I've updated the design to use a Teensy 4.0 and uploaded the files to my repo. I have also made a similar board design for the T40 series keyboards with files available at my repo. Both connector boards have pads for BSS138 FETs with pull up resistors to act as level translators for the PS/2 signals that control the trackpoint and touchpad. The code scans the keyboard, then polls the trackpoint and touchpad for any movement. See the two PDF files below for all the details.

Notes: The X60, T400 and T500 series keyboards (and perhaps others) use the same connector as the T60 series.

The T20 series keyboard (and perhaps others) use the same connector as the T40 series.

Step 18: Apple IBook G3 Clamshell

"Billy67" has used my code and circuit boards to convert several Apple keyboards to USB. Many are documented in the "I made it" section at the end of this Instructable. One of those keyboards is from an iBook G3 clamshell which has a special 40 pin connector on the end of its FPC cable. Because of height restrictions in the clamshell laptop, the Teensy must sit inside a cutout in the board. Wires or "U" shaped header pins tie Teensy I/O's 0 thru 23 to the connector board. I/O's 24 thru 33 use backside wires as pictured above. Billy did some experimenting and found connector part number HDR127MET40F-G-V-SM-DR mates up with this keyboard cable perfectly (see picture above). To build a prototype, he etched his own circuit board with fine pitch traces drawn freehand with an ink pen (wow, that's hard core). If you're like me and haven't used PCB etchant in a few decades, you're going to want a circuit board file to send to a fab house. I originally used a Teensy 3.2 but have updated the board design to use a Teensy 4.0. The new Eagle layout file is "iBookG3Clamshell_T4p0.brd". The zip'ed Gerber file is "iBookG3Clamshell_T4p0_2023-10-31.zip". These files and the keyboard code are available at my repo. Teensy I/O 13 is not used so the LED can remain on the board. I/O's 19, 20, and 21 can be used for NUM, SCROLL, and CAPS lock LEDs with current limit resistors.

Step 19: Keyboards With Two FPC Cables

If your keyboard has two FPC cables, you may be able to insert them side by side in one FPC connector or solder two FPC connectors on the board as shown above. It's common for one FPC cable to have top contacts and the other to have bottom contacts. Use some JB-Weld epoxy on the connector legs and unused pins to help secure it to the board. Some other two cable options are:

If you don't mind soldering a lot of wires, you can use the FPC breakout board shown above for one of the keyboard FPC connectors and put the other keyboard FPC connector and a Teensy on the regular board. Wire the breakout board to the Teensy per the tables on Step 14 so you won't need to modify the software. The front side of the breakout board will accept an FPC connector with up to 18 pins and either a 1mm or 0.8mm pitch. The back side of the board is for a 0.5mm pitch FPC connector. This approach will allow you to place the breakout board in whatever location is needed by the keyboard cables. The FPC_18pin1mm Eagle and Gerber zip files can be downloaded from my repo. Instead of building your own breakout board, you can buy one from AliExpress. The PDF below describes the procedure.

Your final option is to make a new layout like I did for the Lenovo 380 Keyboard shown above. A complete design description PDF is given below with all files available at my repo. This could serve as a starting point for a new board layout and you can add other circuitry like a trackpoint interface or backlight connector.

Step 20: Building a Keyboard Base

The easiest way to mount your keyboard is to use the base from the original laptop, (see the Fujitsu case above and PDF below). If you're not going to use the original laptop case, you can build a custom base out of various materials. Luigi Caradonna has made a stunning marble base using the CNC milling machine from his work. If you are lucky enough to have a 3D printer, you can make a custom case like TheGreenMamba's beautiful X61 Thinkpad keyboard. His 3D print files are at thingiverse. tcaschy has made a few 3D printed cases including the one shown above for a Blackberry keyboard with a Raspberry Pi Zero and LCD. Ben has the files for his T420 3D case at his repo. Harjoc used acrylic to make a cool see-thru base. The Thinkpad T43 keyboard shown above has been mounted on a wood base by "Than the FIT man". All of these projects are documented further in the "I made it" section at the end of this Instructable. I made a Thinkpad T61 keyboard base using 3 sheets of 1/4" plywood. Each sheet had its own cutouts to provide a cavity for the Teensy and wire routing. I've also built wood bases for the Toshiba 2415 keyboards that are documented below and at my repo. Warren has chiseled a wood base for a Dell Inspiron 1420 that is pictured on the PJRC forum with code at his Github repo. The Fujitsu Lifebook 755Tx keyboard has a thick backside so it can sit on a desk without any case. The picture above shows how I routed the dual FPC cables into a project box that houses the Teensy 3.2. The Fujitsu keyboard project documentation is at my repo. The Logitech K120 keyboard can be re-wired for control by a Teensy as shown in the picture above and documented at Hackster.

Step 21: Keyboard Backlight & LED Indicators

If your keyboard has a backlight, it can be controlled by the Teensy, as long as you have a spare I/O pin left over. The backlight brightness will be controlled using a pulse width modulated (PWM) signal that drives the gate of an N channel FET. The backlight white LEDs may all be wired in parallel or in series as shown in the schematics above. The N-FET will handle the current needed by the backlight WLEDs. Only certain Teensy I/O pins are PWM capable so you may need to swap an I/O from the keyboard. Swapping I/O's is easy if you use wires instead of header pins to mount the Teensy to the board. The backlight signals from the keyboard usually come out on a small FPC cable that is separate from the row/column keyboard cable. There are usually multiple pins in order to handle the current. You can glue a small connector on a blank board and solder wires to it but the fine pitch makes it difficult. I have designed two small connector breakout boards that make it easier to hook up the backlight cable. The Eagle and Gerber board files "FPC_8pin1mm" and "FPC_10pin0p5mm" can be downloaded from my repo. They will take an FPC connector with up to 8 pins and a 1mm pitch like this Molex connector or up to 10 pins and a 0.5mm pitch like this Molex connector. On the backside of each board are pads for a 1206 size current limit resistor and an MMBF170 N-FET. I’ve used a ½ watt, 22 ohm resistor with a parallel wired backlight. I didn't need a resistor for a series wired backlight because I used a small boost regulator to set the full brightness voltage. Whether you have a series or parallel wired backlight, you should experiment to determine the best resistance or voltage that gives good brightness without excessive current. Look at my test notes for the MacBook Pro A1286 keyboard backlight at my repo for an example of a 6 diode series string powered at 16 volts. An example for a Galaxy Book Flex 15.6" keyboard, also at my repo has 5 parallel strings with 10 diodes per string powered at 26 volts. I figured out the signals on this backlight FPC cable by tracing them back to the motherboard IC where I could read the WLED driver part number and download its datasheet.

Your Teensy code will need to set the PWM frequency but not too low or it will flicker. To set the PWM on pin 36 to 400Hz, use the following:

analogWriteFrequency(36,400);

The PWM duty cycle can range from 0 (fully off), to 255 (fully on). To set the PWM on pin 36 to 80%, use the following:

analogWrite(36,205); // 205/255 = 80%

Use a variable for the PWM duty cycle so it can be modified with an Fn-Function key press. Look at the MacBook Pro A1286 code at my repo for an example of how to adjust the backlight brightness.

The CAPS, NUM, and Scroll Lock indicator LEDs can be controlled by the Teensy as shown in the schematic above. Look at the Dell D630 folder at my repo for an example. The keyboard matrix shows the 3 LEDs have a common anode and separate cathodes that go to pins on the FPC connector. For your keyboard, determine the keyboard matrix pins first, then the unused pins are the ones you'll probe with your multimeter to find the LEDs. You may need to disconnect the pins from the Teensy so its ESD diodes don't interfere while you use the diode setting on your meter. The meter should give a small voltage reading and may provide enough current to light the LED when you have the correct polarity. You will need a current limit resistor when the Teensy is controlling the LED. It may take some experimenting to determine the current level that gives good brightness. I've had good luck using 715 ohms on several keyboards which used 2ma LEDs. Depending on how the LEDs are wired, the Teeny will either drive the control signal low to turn on the LED or drive the signal high. Look at the bottom of many of the keyboard.ino files to see when the keyboard_leds variable is checked. This byte is read by the Teensy over USB from the host. The low 3 bits in the byte indicate when an LED should be turned on. Num Lock is at bit position 0, Caps Lock is at bit position 1, and Scroll Lock is at bit position 2. I often only care about the Caps lock LED (like on the Dell D630) so the other 2 LEDs are not in the code or wired to the keyboard, especially if I'm running out of Teensy I/O pins. Look at the Toshiba 2415 for an example of all 3 LEDs being controlled. Note it is possible to put a single resistor on the common LED pin instead of 3 separate resistors. The downside to this is the LED brightness will vary depending on how many LEDs are turned on.

Step 22: Touchpad/Pointing Stick

The PS/2 signals from a laptop's pad/pointing stick can be converted to USB with an off-the-shelf converter as shown in numerous videos. If you also want to convert a laptop keyboard to USB, then it makes sense to combine these tasks with a Teensy and only use 1 USB port. It can be confusing to debug the keyboard and touchpad code so I find it best to get each one working by itself, then combine the code.

PJRC has created mouse functions in Teensyduino so the USB coding is easy. I wrote code for the Teensy that bit-bangs two I/O pins to make the clock and data for the PS/2 bus. You can download my PS/2 code "Touchpad_Remote_mode.ino" from my repo. In the Arduino IDE, under "Tools", set the code to the Teensy model you are using and to "Keyboard+Mouse+Joystick". Compile and load the code into the Teensy. The remote mode code sets the pad/pointing device to be polled at a regular rate to see if any movement or button presses have occurred. This makes it easy to merge in with the keyboard scanning code, which also repeats at a regular rate. The Thinkpad T61 shown earlier uses this method to merge the keyboard and PS/2 trackpoint code. The Dell Latitude D630 keyboard code at my repo has also been merged with the touchpad code. It can be difficult to figure out the touchpad clock, data, power, and ground pins if you don't have a schematic so I wrote a step by step procedure to identify the pins. This procedure also describes how to use a level translator (see schematic above) for the clock and data signals. This is needed to avoid damaging the Teensy 4.0 or 4.1 with 5 volt signals from the touchpad. The translator also protects a 3.3 volt touchpad from damage when driven with 5 volt signals from a Teensy 2.0++. Many of my circuit boards include pads to build a translator but you can always wire to a separate translator board like the Sparkfun 12009 or the Adafruit 757.

The clock, data, power, and ground wires from the Teensy can be soldered directly to test points on a Synaptics touchpad. The typical test point numbers for a PS/2 touchpad are:

  • Clock = T10. If T10 is not present or doesn't work, try T12 or T5
  • Data = T11. If T11 is not present or doesn't work, try T13, T9, or T6
  • Ground = T23 or solder to the Ground Plane
  • Power = T22. This test point provides an RC power filter. You can skip the power filter at T20

The touchpad often has an FPC connector and cable that used to go back to the motherboard. Use one of the breakout boards from the previous step and solder a compatible FPC connector. Solder clock, data, power, and ground jumper wires from the breakout board to the Teensy. An example of a breakout board for a Toshiba 2415 touchpad is shown above. The composite keyboard and touchpad code for the Toshiba 2415 is at my repo.

The code "Touchpad_Stream_mode.ino" at my repo commands the PS/2 touchpad to be in stream mode (instead of remote mode) so the touchpad sends movement data whenever there is activity. This code is constantly looping, looking for touchpad data. If the Teensy is also scanning the keyboard, this code would need to be modified to execute when PS/2 bus activity causes an interrupt.

For you "real" coders, the interrupt driven trackpoint routine at Martin Prochnow's Github repo is more efficient than polling. This code has been merged with my USB keyboard code (with many improvements by Ben) for his Thinkpad T420. His original Github repo has his initial code and circuit board but he just couldn't stop there. Now his second repo provides the code, circuit board files, and 3D printer files to make a keyboard that's USB and Bluetooth capable. It has rechargeable batteries in the case along with lots of weights to hold it in place.

A trackball, touchpad, or mouse that uses the Apple Data Bus can be converted to USB using the Teensy code at my repo. This code was merged with the keyboard scanning circuitry for a Mackintosh Powerbook 140 shown in the "I made it" section at the end of this Instructable.

I2C touchpads are becoming more popular in modern laptops. This 2 wire clock and data bus can be directly driven by the I2C pins of a Teensy so no bit-banging is needed. My Hackster.IO touchpad tutorial describes how to determine the touchpad's I2C address and registers using a Raspberry Pi. Example I2C Teensy code for a basic touchpad and for a very complex Azoteq TPS65-201A-S touchpad can be downloaded from my repo and merged into a keyboard scanning routine. The Azoteq touchpad shown above has tons of features described in it's datasheet and it only costs $5.81 at Mouser.

Before pads, nubs, and trackballs became popular, the GRiD 1550 laptop of the 1980's used a metal rod below the space bar called an IsoPoint. The rod can be spun clockwise or counterclockwise for the Y cursor movement. This spinning rod is rotary incremental encoded with 2 signals. The rod will also slide left or right for the X cursor movement which also has two rotary incremental encoded signals. The Teensy code at my repo translates these 4 signals into USB. A complete description of this project is at my repo.

If your trackpoint/pointing stick does not output a serial bus, it may only provide the 4 signals from its strain gauge resistors. The Dell D630 pointing stick has four 4K ohm strain gauge resistors that change resistance enough that the ADC in the Teensy can see the voltage changes above the noise. The Dell D630 pointing stick code and PDF are at my repo. Old Thinkpad trackpoints like the one on the 380 can also be converted to USB but its strain gauge resistors need to be amplified as documented in my Hackaday.IO project.

Some Fujitsu laptops have a pointing device called an Ergo Trac instead of a touchpad. The sensor part number is FID-828-100/20 and it uses magnetic field detection technology. The picture above shows the 4 connections that normally go to a controller chip on a CA20290-B40X daughterboard but it can also be driven by a Teensy. The Teensy code at my repo drives a reference logic pulse to the sensor and reads the resulting pulse voltage with two ADC channels. The code then converts the digital values to USB mouse movements.

Step 23: Conclusion

The next step after getting the original keyboard and touchpad working is to add a video converter card to drive the LCD and make a keyboard, video, mouse (KVM). A KVM is often used to troubleshoot servers and the one shown above is from a Dell D630 laptop. I also added a Raspberry Pi inside the case to make a stand alone laptop. This build is described in my KVM Instructable. The Toshiba 2415 laptop shown above was converted into a KVM in order to display the HDMI video from a desktop PC as well as send the keyboard & touchpad data over USB. The documentation and code for this build is at my repo.

If you really want a challenge, check out my Instructable to make a lithium battery charger in a Raspberry Pi Laptop. In addition to describing the Max1873 charger shown above, there is Pi software to read the battery status registers over an SMBus and display a "remaining charge" gauge.

I hope you find this Instructable useful for re-purposing your old laptop. Leave a comment below if you have any questions, comments, or corrections.

Good Luck

Frank Adams

First Time Author

Participated in the
First Time Author