I probably could have done this more cleanly, but here's code I recently used to get a Sega Genesis controller talking to iPad (emulating the iCade). I'm using an Uno R3, and the atmega16u2 is flashed to act as a keyboard.
The iCade issues one keypress when a button is pushed and another when it is released. The button mappings can be found here: http://www.thinkgeek.com/files/iCADE/iCade_Dev_Resource_v1_3.pdf
const int UP=2,DOWN=3,LEFT=4,RIGHT=8,AB=7,SELECT=5,STARTC=6; // these are the pins the directions are connected to
int upstate=0;
int downstate=0;
int leftstate=0;
int rightstate=0;
int abstate = 0;
int selectstate = 0;
int lastselect = 0;
int lastStart = 0;
int startcstate = 0;
int uppressed = 0;
int downpressed = 0;
int leftpressed = 0;
int rightpressed = 0;
int apressed = 0;
int bpressed = 0;
int cpressed = 0;
int startpressed = 0;
uint8_t keyW[8] = { 0, 0, 26, 0, 0, 0, 0, 0 };
uint8_t keyE[8] = { 0, 0, 8, 0, 0, 0, 0, 0 };
uint8_t keyA[8] = { 0, 0, 4, 0, 0, 0, 0, 0 };
uint8_t keyQ[8] = { 0, 0, 20, 0, 0, 0, 0, 0 };
uint8_t keyX[8] = { 0, 0, 27, 0, 0, 0, 0, 0 };
uint8_t keyZ[8] = { 0, 0, 29, 0, 0, 0, 0, 0 };
uint8_t keyD[8] = { 0, 0, 7, 0, 0, 0, 0, 0 };
uint8_t keyC[8] = { 0, 0, 6, 0, 0, 0, 0, 0 };
uint8_t keyO[8] = { 0, 0, 18, 0, 0, 0, 0, 0 };
uint8_t keyG[8] = { 0, 0, 10, 0, 0, 0, 0, 0 };
uint8_t keyL[8] = { 0, 0, 15, 0, 0, 0, 0, 0 };
uint8_t keyV[8] = { 0, 0, 25, 0, 0, 0, 0, 0 };
uint8_t keyK[8] = { 0, 0, 14, 0, 0, 0, 0, 0 };
uint8_t keyP[8] = { 0, 0, 19, 0, 0, 0, 0, 0 };
uint8_t keyY[8] = { 0, 0, 28, 0, 0, 0, 0, 0 };
uint8_t keyT[8] = { 0, 0, 23, 0, 0, 0, 0, 0 };
uint8_t keyNone[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
void setup() {
pinMode(UP,INPUT);
pinMode(DOWN,INPUT);
pinMode(LEFT,INPUT);
pinMode(RIGHT,INPUT);
pinMode(AB,INPUT);
pinMode(SELECT,OUTPUT);
pinMode(STARTC,INPUT);
Serial.begin(9600);
delay(2000);
}
void loop() {
uint8_t ledStatus;
if(lastselect == LOW){
selectstate = HIGH;
//Serial.println("Select:"+selectstate);
digitalWrite(SELECT, selectstate);
}
if(lastselect == HIGH){
selectstate = LOW;
//Serial.println("Select:"+selectstate);
digitalWrite(SELECT, selectstate);
}
upstate=digitalRead(UP);
downstate=digitalRead(DOWN);
leftstate=digitalRead(LEFT);
rightstate=digitalRead(RIGHT);
abstate=digitalRead(AB);
startcstate=digitalRead(STARTC);
//dpad i originally had the dpad out of the selectstate if structures, but saw that left/right needed to be in with the select high
//then i saw that each time i hit A it was returning up as being pressed. i couldnt get this to occur with down or any other buttons
//so i put the whole dpad in the select high state
//select state high - check for pressed
if(selectstate == HIGH){
if(startcstate == LOW && cpressed == 0){
// Serial.println("C pressed");
cpressed = 1;
Serial.write(keyK, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(abstate == LOW && bpressed == 0){
// Serial.println("B pressed");
bpressed = 1;
Serial.write(keyO, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(leftstate == LOW && leftpressed == 0){
// Serial.println("LEFT pressed");
leftpressed = 1;
Serial.write(keyA, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(rightstate == LOW && rightpressed == 0){
// Serial.println("RIGHT pressed");
rightpressed = 1;
Serial.write(keyD, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(upstate == LOW && uppressed == 0){
// Serial.println("UP pressed");
uppressed = 1;
Serial.write(keyW, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(downstate == LOW && downpressed == 0){
// Serial.println("DOWN pressed");
downpressed = 1;
Serial.write(keyX, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
}
//select state low - check for pressed
if(selectstate == LOW){
if(startcstate == LOW && startpressed == 0){
// Serial.println("START pressed");
startpressed = 1;
Serial.write(keyY, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(abstate == LOW && apressed == 0){
// Serial.println("A pressed");
apressed = 1;
Serial.write(keyL, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
}
//select state high - check for released
if(selectstate == HIGH){
if(startcstate == HIGH && cpressed == 1){
// Serial.println("C released");
cpressed = 0;
Serial.write(keyP, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(abstate == HIGH && bpressed == 1){
// Serial.println("B released");
bpressed = 0;
Serial.write(keyG, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(leftstate == HIGH && leftpressed == 1){
// Serial.println("LEFT released");
leftpressed = 0;
Serial.write(keyQ, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(rightstate == HIGH && rightpressed == 1){
// Serial.println("RIGHT released");
rightpressed = 0;
Serial.write(keyC, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(upstate == HIGH && uppressed == 1){
// Serial.println("UP released");
uppressed = 0;
Serial.write(keyE, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(downstate == HIGH && downpressed == 1){
// Serial.println("DOWN released");
downpressed = 0;
Serial.write(keyZ, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
}
//select state low - check for released
if(selectstate == LOW){
if(startcstate == HIGH && startpressed == 1){
// Serial.println("START released");
startpressed = 0;
Serial.write(keyT, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
if(abstate == HIGH && apressed == 1){
// Serial.println("A released");
apressed = 0;
Serial.write(keyV, 8);
ledStatus = Serial.read();
delay(20);
Serial.write(keyNone, 8);
}
}
delay(20);
lastselect = selectstate;
if(lastStart == 0){
lastStart = 1;
}
}
Edited to add: I connect to the ipad using a powered hub; the ipad only puts out 20ma on its USB port, which is barely enough to power a standard USB keyboard.