Wireless keyboard for InternetTV

I recently bought a Samsung TV with the new SmartTV Hub that offers some nice Internet capabilities. Ideal for a quick look into the News, some clips from Youtube, the weather forecast or a quick Google search! But there is one shortcoming that spoils the fun: Text entry has to be done with the remote control in a SMS like manner. Painful and impossible to handle, at least for me! Samsung already offers a remote control with a touchscreen keyboard, but it is rather expensive and has bad reviews, so I looked for a cheaper and better alternative...and I think I found one:

(See pictures below)

The keyboard is from my old desktop computer lying around in the cellar, an infrared diode also was also easily found and, of course, an Arduino Duemillanove. To interact with the keyboard I used the PS/2 keyboard library from the Arduino playground( Arduino Playground - PS2Keyboard ). I had to make some modifications to change the keyboard layout to German and to include the F1 to F12 keys.
To communicate via Infrared I used Ken Shiriff's Multi-Protocol Infrared Remote Library for the Arduino( A Multi-Protocol Infrared Remote Library for the Arduino ) and added the Samsung protocol as described in the discussion section of the above page. Thanks a lot to all contributors!
The hardware setup is very simple: first connect the keyboard to the arduino. In my case (with an IBM 3K 8820 keyboard the wires are connected like this:

red 5V
white ground
green pin 2
yellow pin 7

The infrared diode is connected to pin 3 with a 100 Ohm resistor and to ground. See the hardware section setup section in Ken Shirif's Blog (link above) for assistance on that.

The program I wrote is simulating the SMS-like text entry. If for example the b-Button is pressed, the infrared code for 2 is sent twice, if c was pressed, three times, and if 1 was pressed, 4 times. Because of this the keyboard is of course slower in reaction as a usual keyboard, but it works surprisingly well. Not good enough for lengthy texts, but sufficient for URLs or google search strings. Navigation is done with the arrow keys, page up and page down scroll the page and the F1 to F12 buttons are responsible for the function keys. At the moment I use the following layout:

ESC Back
F1 SMART
F2 TTX/MIX
F3 FAST FORWARD (>>)
F4 REWIND (<<)
F5 A (red)
F6 B (green)
F7 C (yellow)
F8 D (blue)
F9 TOOLS
F12 POWER

The keyboard can easily be connected and reprogrammed. I'm still trying around a lot and often add or relocate buttons, so the code is not final. There is also some debug code included that could be deleted in a final version.
As mentionend, I have a Samsung TV, but I'm quite sure the keyboard could be useful for other brand TVs as well with a little reprogramming...

The code had to be moved to a separate post, because the size of the post grew too big...

As announced here's the code:

#include <IRremote.h>
#include <PS2Keyboard.h>

#define DEBUG true;
const int SAMSUNG_NBITS=32;
const int DataPin = 7;  //keyboard data pin
const int IRQpin =  2;  //keyboard interrupt pin

IRsend irsend;
PS2Keyboard keyboard;


char* keycodes[10]={" ",".,-?!'@:1","abcäáà2","deféè3","ghi4","jkl5","mnoö6","pqrsß7","tuvü8","wxyz9"} ;
const unsigned long ircodes[10]={0xE0E08877,0xE0E020DF,0xE0E0A05F,0xE0E0609F,0xE0E010EF,0xE0E0906F,0xE0E050AF,0xE0E030CF,0xE0E0B04F,0xE0E0708F};
const unsigned long RC_ENTER=0xE0E016E9;
const unsigned long RC_RETURN=0xE0E01AE5;
const unsigned long RC_UPARROW=0xE0E006F9;
const unsigned long RC_LEFTARROW=0xE0E0A659;
const unsigned long RC_DOWNARROW=0xE0E08679;
const unsigned long RC_RIGHTARROW=0xE0E046B9;
const unsigned long RC_SMART=0xE0E09E61;
const unsigned long RC_PRECH=0xE0E0C837;  //PRE-CH key is used to delete a single character on the remote
const unsigned long RC_FASTWORWARD=0xE0E012ED;  //Fast Forward  (>>)
const unsigned long RC_REWIND=0xE0E0A25D;       //Rewind (<<)
const unsigned long RC_EXIT=0xE0E0B44B;
const unsigned long RC_POWER=0xE0E040BF;
const unsigned long RC_A=0xE0E036C9;
const unsigned long RC_B=0xE0E028D7;
const unsigned long RC_C=0xE0E0A857;
const unsigned long RC_D=0xE0E06897;
const unsigned long RC_TTX=0xE0E034CB;  //TTX/MIX
const unsigned long RC_TOOLS=0xE0E0D22D;

bool numlock=false;   //helper variable to toggle between numlock mode (the ir-code is only transferred once) or SMS mode
bool funcKey=false;   //helper variable to decide if a function key (ENTER,ESC,ARROW keys...) was pressed or not

int delayshort=250;   //minimal delay between sending two characters that are not on the same key
int delaylong=2000;   //minimal delay between sending two characters that are on the same key (yes, that's long, but that's the way it is...)
int previouskey=0;    //helper variable to store the previously sent key to distinguish if a long delay (if the same key is pressed again) or a short delay is sufficient...
void setup()
{
  delay(1000);
  keyboard.begin(DataPin, IRQpin);
   
  #ifdef DEBUG
    Serial.begin(9600);
    Serial.println("Ready!");
  #endif
}

//helper function to automatically set 
void sendFuncKey(unsigned long IRCode){
    irsend.sendSamsung(IRCode,SAMSUNG_NBITS);
    funcKey=true;
}
void loop() {
  if (keyboard.available()) {
    // read the next key
    char c = keyboard.read();
    // check for some of the special keys
    funcKey=false;
    switch (c){
      case PS2_ENTER: 
        sendFuncKey(RC_ENTER);
        break;
      case PS2_ESC:
        sendFuncKey(RC_RETURN);
        break;
      case PS2_F1:
        sendFuncKey(RC_SMART);
        break;
      case PS2_F2:  //to switch between the different modes of character input
        sendFuncKey(RC_TTX);
        break;
      case PS2_F3:  //to switch between the different pages of character input
        sendFuncKey(RC_REWIND);
        break;
      case PS2_F4:  //to switch between the different pages of character input
        sendFuncKey(RC_FASTWORWARD);
        break;
      case PS2_F5:
        sendFuncKey(RC_A);
        break;
      case PS2_F6:
        sendFuncKey(RC_B);
        break;
      case PS2_F7:
        sendFuncKey(RC_C);
        break;
      case PS2_F8:
        sendFuncKey(RC_D);
        break;
      case PS2_F9:
        sendFuncKey(RC_TOOLS);
        break;
      case PS2_F12:
        sendFuncKey(RC_POWER);      
        break;
      case PS2_UPARROW:
        sendFuncKey(RC_UPARROW);
        break;
      case PS2_LEFTARROW:
        sendFuncKey(RC_LEFTARROW);      
        break;
      case PS2_DOWNARROW:
        sendFuncKey(RC_DOWNARROW);       
        break;
      case PS2_RIGHTARROW:
        sendFuncKey(RC_RIGHTARROW);      
        break;
      case PS2_BACKSPACE:
        sendFuncKey(RC_PRECH);            
        break;
      case PS2_PAGEUP:
        sendFuncKey(RC_REWIND); 
        break;
      case PS2_PAGEDOWN:
        sendFuncKey(RC_FASTWORWARD); 
        break;
      case PS2_END:
        sendFuncKey(RC_EXIT); 
        break;
      case PS2_NUMLOCK:  //toggle numlock
        if (numlock) numlock=false;
        else numlock=true;
        Serial.println(numlock);
        break;
     case ' ':
        sendFuncKey(0xE0E08877); 
        break;
    }
    if (!funcKey){  //no special key...see above)
      //search which key on the remote (0-9) is responsible for the character from the keyboard
      for (int i=0;i<10;i++){
        for (int j=0;j<strlen(keycodes[i]);j++){
          if (c==keycodes[i][j]){
            if (numlock){
              Serial.println("Num mode");
              irsend.sendSamsung(ircodes[i],SAMSUNG_NBITS);
              delay(delayshort);
            }
            else{
              Serial.println("SMS mode");
              if (previouskey==i){
                //instead of a delay that takes at least 2 seconds a letter from another button is written and deleted again...is much faster...
                if (i==1 || i==9)
                  irsend.sendSamsung(ircodes[2],SAMSUNG_NBITS);
                else
                  irsend.sendSamsung(ircodes[i+1],SAMSUNG_NBITS);
                //delete the char again immediately...
                delay(delayshort);
                irsend.sendSamsung(RC_PRECH,SAMSUNG_NBITS);
                delay(delayshort);
              }
              for(int k=0;k<=j;k++){
                irsend.sendSamsung(ircodes[i],SAMSUNG_NBITS);
                delay(delayshort);
              }
              previouskey=i;
              break;
            }
          }
        }
      }  
    }
  }  
}

Very nicely done project and good summery and links! I suspect I can do something like this to an old keyboard. If you put your keyboard on the table, will it wobble due to the arduino box, even with the keyboard feet extended?

I agree, very nice! I'm a big fan of that keyboard - typing this on the newer Lenovo branded version. Got it to replace my IBM model M PS/2 keyboard when I had to change to a USB KVM switch.

If you ever decide to build another I bet you could fit an Arduino Nano or Mini inside the keyboard case and maybe some kind of Lipo as well. I't looks like it might be tight on you IBM version since it has the carved out back, but the new Lenovo version has a flat back with more room.

willnue

Hi!
Thanks for your posts! I'm delighted that you like it!

@liudr:
yes, the keyboard wobbles even with the feet out. That's because the arduino case is bigger than neccessary. The case was an old one that was lying around from another project. If it would be just the size needed I assume it would not wobble. I doesn't really disturb me because I mostly use it on my lap.

@willnue
At the beginning I planned to use an Arduino mini, but for 2 reasons took the "usual" Arduino instead:
-the mini has to be programmed with an USB port. Since I often reprogram the keyoard I prefer the Duemillanove with the built-in USB
-even for the mini there was not enough room in the keyboard. Or maybe the Mini would even fit in, but not the Mini AND the battery.
But maybe when I don't reprogram any more and I find a bit larger keyboard I will build a second version.

If you want the USB capability in a small package go with a Nano, it has a mini USB jack and it's not much bigger than the mini. Also, If you ever decide to get a Nano, order it directly from Gravitech without the header pins. Trust me it's a lot easier to add headers if you want rather than remove them...

willnue