Trying to get Leonardo and iPad talking.

Hi! I'm finally starting to get into the brilliant arduino world!

So, one of my first bigger project is to make an arcade machine for my iPad using the arduino
leonardo connected to my push buttons & joystick (it will work with a jailbreaked device and some tweeks).

  • First... I can't seem to figure out how to get the pushbuttons to work as the directional arrows. I have tried a lot, actually...
    It won't work on my mac either...

  • Second... When I connect the leonardo to my iPad via the camera connector, I got an error message saying that the connected device isn't supported (I use a DC adapter for powering the leonardo). Thats ok, but the buttons won't work at all (I tried to map regular keypresses too, like "u", "d" etc.)!

Here is my code. As you can see, I'm quite a n00b... But at least I'm trying, right? :wink:

int ButtonDelay = 25;

void setup() {
  pinMode(0, INPUT_PULLUP); 
  pinMode(1, INPUT_PULLUP); 
  pinMode(2, INPUT_PULLUP); 
  pinMode(3, INPUT_PULLUP); 
  pinMode(4, INPUT_PULLUP); 
  pinMode(5, INPUT_PULLUP); 
  pinMode(6, INPUT_PULLUP); 
  pinMode(7, INPUT_PULLUP); 
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  
  Keyboard.begin();
}

void loop() {
  
  if(digitalRead(0) == LOW)                     //UP
  Keyboard.press('KEY_UP_ARROW');
  Keyboard.release('KEY_UP_ARROW');
  delay(ButtonDelay);

  if(digitalRead(1) == LOW)                      //DOWN
  Keyboard.press('KEY_DOWN_ARROW');
  Keyboard.release('KEY_DOWN_ARROW');
  delay(ButtonDelay);


  if(digitalRead(2) == LOW)                      //LEFT
  Keyboard.press('KEY_LEFT_ARROW');
  Keyboard.release('KEY_LEFT_ARROW');
  delay(ButtonDelay);

  if(digitalRead(3) == LOW)                      //RIGHT
  Keyboard.press('KEY_RIGHT_ARROW');
  Keyboard.release('KEY_RIGHT_ARROW');
  delay(ButtonDelay);

  if(digitalRead(4) == LOW)                      //RETURN
  Keyboard.press('KEY_RETURN');
  Keyboard.release('KEY_RETURN');
  delay(ButtonDelay);

}

Am I doing everything wrong, or am I just "unlucky" :slight_smile:

You need to put the stuff in your IF statements in { }

example.

if(digitalRead(0) == LOW)                      //UP
 {
  Keyboard.press('U');
  Keyboard.release('U');
  delay(ButtonDelay);
 }

Ah! Of course!
But now, the return button only types "N" and the directional buttons all type "W"
Is this correct?

This is my new code:

int ButtonDelay = 100;

void setup() {
  pinMode(0, INPUT_PULLUP); 
  pinMode(1, INPUT_PULLUP); 
  pinMode(2, INPUT_PULLUP); 
  pinMode(3, INPUT_PULLUP); 
  pinMode(4, INPUT_PULLUP); 
  pinMode(5, INPUT_PULLUP); 
  pinMode(6, INPUT_PULLUP); 
  pinMode(7, INPUT_PULLUP); 
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  
  Keyboard.begin();
}

void loop() {
  
  //UP
  if(digitalRead(0) == LOW)
  {
  Keyboard.press('KEY_UP_ARROW');
  Keyboard.release('KEY_UP_ARROW');
  delay(ButtonDelay);
  }
  
  //DOWN
  if(digitalRead(1) == LOW)
  {
  Keyboard.press('KEY_DOWN_ARROW');
  Keyboard.release('KEY_DOWN_ARROW');
  delay(ButtonDelay);
  }

  //LEFT
  if(digitalRead(2) == LOW)
  {
  Keyboard.press('KEY_LEFT_ARROW');
  Keyboard.release('KEY_LEFT_ARROW');
  delay(ButtonDelay);
  }
  
  //RIGHT
  if(digitalRead(3) == LOW)
  {
  Keyboard.press('KEY_RIGHT_ARROW');
  Keyboard.release('KEY_RIGHT_ARROW');
  delay(ButtonDelay);
  }
  
  //RETURN
  if(digitalRead(4) == LOW)
  {
  Keyboard.press('KEY_RETURN');
  Keyboard.release('KEY_RETURN');
  delay(ButtonDelay);
  }

}

Your interfacing Windows key commands with an IPad, I dont think the Key functions are the same. Did you do any research as to what keys can be recognised? Try going back to "U, D, L, R" keys

Well, you were right. A standard usb keyboard for PC doesn't work either (on iPad, keyboards needs external power to work, but not on iPhones, so I checked it out). PC bluetooth keyboards work like a charm, but usb makes it more complicated for some reason.

I have no idea how to find what type of input the iPad supports though... I guess I have to do some research. :~

Im guessing your trying to make an ICade? In which case, others have posted codes that do work(recognize key functions) with the IPad, but they also had other issues.

That is a possibility, but then I can't control the whole iPad (home screen etc) with my joystick. I use BeeKeyboard (jailbreak app) to control everything, and with
a dedicated button, regular keystrokes get turned into iCade controls. I know my brother tries to make an arduino iCade, but he got some debounce issues that he can't seem to figure out (I think it's on this forum somewhere).

hansibull? his post is on page 7

Yes, that is right. :slight_smile: He didn't find out how to get past the debounce issue... Too bad.

On topic: Is there anyone who know how I can "teach" my arduino leonardo to talk with an ipad as a keyboard?
Maybe I'm blind or stupid, but I can't seem to find anything anywhere!

sirbull:
Hi! I'm finally starting to get into the brilliant arduino world!

So, one of my first bigger project is to make an arcade machine for my iPad using the arduino
leonardo connected to my push buttons & joystick (it will work with a jailbreaked device and some tweeks).

Greetings. I have done just this, with an Arduino Leonardo and a Teensy 2.0. I will be glad to share my source with you when I have a moment from home. Somewhere in this forum I think I have a post about my efforts, and here was my blog post:

http://appleause.com/2012/12/18/hook-an-atari-2600-joystick-up-to-an-ipad-thanks-to-teensy-2-0/

In that posting, I was using a Teensy but with the Arduino IDE and the code works on both. I didn't have the Leonardo in yet, but I have since gotten one.

It would be super nice if you posted the code! That would probably save my whole project! :wink:

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.

sirbull:
It would be super nice if you posted the code! That would probably save my whole project! :wink:

Sorry for such a late reply. Code:

I have posted my Teensy 2.0 (easy to adapt for Leonardo) code that reads digital inputs and emits USB keyboard keys in iCade format:

I also posted various other work-in-progress experiments, including one that uses a Circuits@Home USB Host shield to read from a standard Playstation style USB arcade joystick and then translate the keys to iCade, allowing me to use my cheap fighter stick with any iCade game on the iPad. Maybe it will be of use to someone. Eventually I will have time to go in and clean up the code and finish it. I have learned much since I started that project.