Check out my (Atari key-)Pad, Part 2: HID Hacking September 9, 2013
Once I figured out the hardware inside the Atari CX85 keypad, all that was left was the software. And by “all that was left,” I mean the remaining 90% of the work. Not long ago, getting a microcontroller to emulate a USB human input device for a prototype would have been an ordeal. With the introduction of boards like the Arduino Leonardo, however, this is almost as easy as writing any other Arduino sketch. Almost.
For some reason, the standard Arduino library offers only limited keyboard emulation. You can ‘print’ characters as key presses, but you can’t send specific key codes: you can send the character 9, which comes out as the 9 key at the top of your keyboard, but you can’t send the number pad 9 key. This can be easily fixed, but it requires modifying part of the Arduino’s standard library.
The method that sends raw key codes is private — that is, only available to other parts of the library, not the user. This is easily fixable, however, by modifying the standard library. On the Mac, the location of the file is (by default) /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/USBAPI.h
; it will have a similar path on other platforms, at least from hardware/
on.
To enable the ability to send low-level keyboard codes, just swap lines 126 and 127 in that file, so they read like so:
122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
class Keyboard_ : public Print { private: KeyReport _keyReport; public: void sendReport(KeyReport* keys); Keyboard_(void); void begin(void); void end(void); virtual size_t write(uint8_t k); virtual size_t press(uint8_t k); virtual size_t release(uint8_t k); virtual void releaseAll(void); }; |
Note that this will make the sendReport()
method available on an official Arduino board, but other boards may have their own version of USBAPI.h
that will also need changing. For example, the version for SparkFun’s ProMicro boards is located in ~/Documents/Arduino/hardware/SF32u4_boards/cores/arduino/
. Again, that’s the path on the Mac; it’ll be somewhat different under Windows or Linux.
Exposing sendReport()
is only part of the solution. If you look at the method’s signature, you can see that it takes a KeyReport
pointer as an argument. To generate the KeyReport
, I cribbed some code from someone else’s project, namely their sendKey()
function.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
void sendKey(byte key, byte modifiers) { KeyReport report = {0}; // Create an empty KeyReport /* First send a report with the keys and modifiers pressed */ report.keys[0] = key; // set the KeyReport to key report.modifiers = modifiers; // set the KeyReport's modifiers report.reserved = 1; Keyboard.sendReport(&report); // send the KeyReport /* Now we've got to send a report with nothing pressed */ for (int i=0; i<6; i++) report.keys[i] = 0; // clear out the keys report.modifiers = 0x00; // clear out the modifires report.reserved = 0; Keyboard.sendReport(&report); // send the empty key report } |
Ultimately, I didn’t use their sendKey()
entirely verbatim, but enough so that credit is due.
My implementation is next.
Leave a Reply
You must be logged in to post a comment.