How to do this
I built a simple sketch that uses the remote from my DVD player to move and click the mouse, enter digits, or page up or down. Follow these steps:- The hardware is nearly trivial. Connect a IR detector to the Teensy: detector pin 1 to Teensy input 11, detector pin 2 to ground, and detector pin 3 to +5 volts.
- Install the latest version of my IR remote library, which has support for the Teensy.
- Download the IRusb sketch.
- In the Arduino IDE, select Tools > Board: Teensy 2.0 and select Tools > USB Type: Keyboard and Mouse.
- Modify the sketch to match the codes from your remote. Look at the serial console as you push the buttons on your remote, and modify the sketch accordingly. (This is explained in more detail below.)
How the sketch works
The software is straightforward because the Teensy has USB support built in. First, the IR library is initialized to receive IR codes on pin 11:#include <IRremote.h> int RECV_PIN = 11; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { irrecv.enableIRIn(); // Start the receiver Serial.begin(9600); }Next, the decode method is called to receive IR codes. If the hex value for the received code corresponds to a desired button, a USB mouse or keyboard command is sent. If a code is not recognized, it is printed on the serial port. Finally, after receiving a code, the resume method is called to resume receiving IR codes.
int step = 1; void loop() { if (irrecv.decode(&results)) { switch (results.value) { case 0x9eb92: // Sony up Mouse.move(0, -step); // up break; case 0x5eb92: // Sony down Mouse.move(0, step); // down break; ... case 0x90b92: // Sony 0 Keyboard.print("0"); break; ... default: Serial.print("Received 0x"); Serial.println(results.value, HEX); break; } irrecv.resume(); // Resume decoding (necessary!) } }You may wonder where the codes such as 0x9eb92 come from. These values are for my Sony DVD remote, so chances are they won't work for your remote. To get the values for your remote, look at the serial console as you press the desired buttons. As long as you have a supported remote type (NEC, Sony, RC5/6), you'll get the hex values to put into the sketch. Simply copy the hex values into the sketch, and perform the desired action.
There are a few details to note. If your remote uses the RC5 or RC6 format, there are actually two different codes assigned to each button, and the remote alternates between them. Push the button twice to see if you'll need to use two different codes. If you want to send a non-ASCII keyboard code, such as Page Down, you'll need to use a slightly more complex set of commands (documentation). For example, the following code sends a Page UP if it receives a RC5 Volume Up from the remote. Note that there are two codes for volume up, and note that KEY_PAGE_UP is sent, followed by 0 (no key).
case 0x10: // RC5 vol up case 0x810: Keyboard.set_key1(KEY_PAGE_UP); Keyboard.send_now(); Keyboard.set_key1(0); Keyboard.send_now(); break;
Improvements
My first implementation of the sketch as described above was very easy, but there were a couple displeasing things. The first problem was the mouse movement was either very slow (with a small step size) or too jerky (with a large step size). Second, if you press a number on the remote, the keyboard input rapidly repeats because the IR remote repeatedly sends the IR code, so you end up with "111111" when you just wanted "1".
The solution to the mouse movement is to implement acceleration - as you hold the button down, the mouse moves faster. This was straightforward to implement. The sketch checks if the button code was received within 200ms of the previous code. If so, the sketch speeds up the mouse movement by increasing the step size. Otherwise it resets the step size to 1. The result is that tapping the button gives you fine control by moving the mouse a little bit, while holding the button down lets you zip across the screen:
if (millis() - lastTime > GAP) { step = 1; } else if (step > 20) { step += 1; }Similarly, to prevent the keyboard action from repeating, we only output keypresses if the press is more then 200ms after the previous. This results in a single keyboard action no matter how long a button is pressed down. The same thing is done to prevent multiple mouse clicks.
if (millis() - lastTime > GAP) { switch (results.value) { case 0xd0b92: Mouse.click(); break; case 0x90b92: Keyboard.print("0"); break; ...
Now you can control your PC from across the room by using your remote. Thanks to Paul Stoffregen of PJRC for porting my IR remote library to the Teensy and sending me a Teensy for testing.