Wii Nunchuck programming issue part II

Hi everyone!

For a while now, I'm trying to get my Wii nunchuck to work as a gamepad for VR purposes using the 32U4 based Arduino pro Micro.

I am an absolute beginner in programming, but I've managed to write a working sketch, based on 'if' - 'else' statements. The program runs quite well, the only problem is that the 'E' and 'Shift' key do not stay pressed down.

I have the following key configuration in mind:

Joystick right: Press and hold down D
Joystick left: Press and hold down A
Joystick up: Press and hold down W
Joystick down: Press and hold down S

Accelerometer (XYZ): press and hold down left mouse button

C-button: Press and hold down E
Z-button: Press and hold down Shift key
Both C and Z: Press and hold down left mouse button

Who can tell me what I'm doing wrong?

#include <Keyboard.h>
#include <Mouse.h>
#include <Wire.h>
#include "ArduinoNunchuk.h"

ArduinoNunchuk nunchuk = ArduinoNunchuk();

void setup()
{
Serial.begin(19200);
nunchuk.init();
Wire.begin();
Mouse.begin();
Keyboard.begin();
}

void loop()

//Joystick bewegingen lopen------------------------------------------------------
{
if (nunchuk.analogX <= 70 || nunchuk.analogX >= 170 || nunchuk.analogY <= 70 || nunchuk.analogY >= 170)
{
if (nunchuk.analogX <= 70)
{
Keyboard.press('A');
nunchuk.update();
}
else {
Keyboard.release('A');
}

if (nunchuk.analogX >= 170)
{
Keyboard.press('D');
nunchuk.update();
}
else {
Keyboard.release('D');
}

if (nunchuk.analogY <= 70)
{
Keyboard.press('S');
nunchuk.update();
}
else {
Keyboard.release('S');
}

if (nunchuk.analogY >= 170)
{
Keyboard.press('W');
nunchuk.update();
}
else {
Keyboard.release('W');
}
nunchuk.update();
}

//C- en Z-knoppen----------------------------------------------------------------

if (nunchuk.cButton == 1 && nunchuk.zButton == 0 || nunchuk.cButton == 0 && nunchuk.zButton == 1)
{
if (nunchuk.cButton == 1 || nunchuk.zButton == 1)
{
if (nunchuk.cButton == 1)
{
Keyboard.press(129);
nunchuk.update();
}
else {
Keyboard.release(129);
}

if (nunchuk.zButton == 1)
{
Keyboard.press('E');
nunchuk.update();
}
else {
Keyboard.release('E');
}
}
nunchuk.update();
}

//Indrukken van beide C- en Z-knoppen-----------

if (nunchuk.cButton >= 1 && nunchuk.zButton >= 1) //Voert de volgende regels uit als C en Z zijn ingedrukt
{
Mouse.press(MOUSE_LEFT);
nunchuk.update();
}
else {
Mouse.release(MOUSE_LEFT);
}
nunchuk.update();

//Accelerometers Y en Z--------------------------

if (nunchuk.accelY >= 1000)
{
Mouse.press(MOUSE_LEFT);
delay(250);
}
else {
Mouse.release(MOUSE_LEFT);
}
nunchuk.update();

if (nunchuk.accelZ >= 1000)
{
Mouse.press(MOUSE_LEFT);
delay(250);
}
else {
Mouse.release(MOUSE_LEFT);
}
nunchuk.update();

//-------------------------------------------------------------------------------

}

Instead of the magic number "129", use KEY_LEFT_SHIFT.

Why are you updating the nunchuck so often? Update it once at the beginning of loop(), and use that one state through all your logic.

Your logic is absurdly overcomplicated, and has a problem. It is incredibly unlikely that you will be able to press both C and Z buttons down within the same millisecond. A naive implementation like this will send the key press for whichever button gets pressed first, and then will detect the dual press and send the mouse click. Microcontrollers operate far faster than humans do, and will be able to see as separate events things that our meat brains might interpret as simultaneous.

I don't know why Shift and E aren't staying pressed, because there's too much unnecessary stuff in your code and it's not organized very well.

First of all thank you for your elaborate reply! I can use all the help!

Instead of the magic number "129", use KEY_LEFT_SHIFT.

Changed it!

Why are you updating the nunchuck so often? Update it once at the beginning of loop(), and use that one state through all your logic.

I have no clue what I am doing, because I only recently started programming.

Your logic is absurdly overcomplicated, and has a problem. It is incredibly unlikely that you will be able to press both C and Z buttons down within the same millisecond. A naive implementation like this will send the key press for whichever button gets pressed first, and then will detect the dual press and send the mouse click. Microcontrollers operate far faster than humans do, and will be able to see as separate events things that our meat brains might interpret as simultaneous.

I ran into this problem you are mentioning. Is there any other function I can use to (re)program the Micro/Leonardo so that it has some time to recognize it's buttons being pressed simultaneously?

Klavkjir:
First of all thank you for your elaborate reply! I can use all the help!

And here I was worried that I was too brief.

I have no clue what I am doing, because I only recently started programming.

I know the feeling. I just spent days trying to get a simple blinky program working on the PICs I bought so I'm feeling a little more humble now.

I ran into this problem you are mentioning. Is there any other function I can use to (re)program the Micro/Leonardo so that it has some time to recognize it's buttons being pressed simultaneously?

That is quite a complicated problem in its own right.

Basically, when one of the buttons gets pressed, you don't activate the function right away. You need to wait a small amount of time (probably about 100 ms) to give the second button a chance to come down too. If the second button comes down within the time limit, it's a dual press. If it doesn't, it's a single press.

There's a tone of problems with overloading things this way. What do you want to happen if you hold the dual press, the release and press one of the buttons while continuing to hold the other?

Overloading UI inputs like this is fraught with complications. I would avoid doing it unless you really want to have that feature.

Jiggy-Ninja make a great point that you should only call update once on a single pass of loop().

It doesn't seem right to me that you are releasing keys even if they may not be pressed. Your code is difficult to debug because Keyboard.press() is called in so many places. Below is how I might begin to structure the code if this was my project. It will only release keys that have been pressed and presses the 'A' and 'D' keys in the same block of code, so a single print statement can be used for debugging.

int joyKeyDown = (-1);

void setup()
{

}

void loop()
{
  int newJoyKeyDown = (-1);

  nunchuk.update();

  //// Joystick

  // joystick left
  if (nunchuk.analogX <= 70)      
  {
    newJoyKeyDown = 'A';

  } 
  // joystick right
  else if (nunchuk.analogX >= 170)      
  {
    newJoyKeyDown = 'D';          

  }

  // if a key is down and we have a new key to press
  if( (newJoyKeyDown > 0) && (newJoyKeyDown != joyKeyDown) )
  {
    if( joyKeyDown > 0 ) Keyboard.release(joyKeyDown);    // release old key
    Keyboard.press(newJoyKeyDown);                        // press new key
    joyKeyDown = newJoyKeyDown;                           // remember this key

  } 
  else {
    // no keys down, release pressed key
    if( joyKeyDown > 0 ) Keyboard.release(joyKeyDown);
    joyKeyDown = (-1);

  }

}

Thank you very much! I didn't know it could be done this way.

I have uploaded it on my Micro, but unfortunately the keys do not stay pressed. Because of my lack of experience, I have some trouble debugging this sketch.
Does anyone have an idea why the keys do not stay pressed?

I think there was a logic error on determining when there was no key pressed, which caused the pressed key to always be released. Here is a slight modification.

int joyKeyDown = (-1);

void setup()
{

}

void loop()
{
  int newJoyKeyDown = (-1);

  nunchuk.update();

  //// Joystick

  // joystick left
  if (nunchuk.analogX <= 70)      
  {
    newJoyKeyDown = 'A';

  }
  // joystick right
  else if (nunchuk.analogX >= 170)      
  {
    newJoyKeyDown = 'D';          

  }

  // if a key is down and we have a new key to press
  if( (newJoyKeyDown > 0) && (newJoyKeyDown != joyKeyDown) )
  {
    if( joyKeyDown > 0 ) Keyboard.release(joyKeyDown);    // release old key
    Keyboard.press(newJoyKeyDown);                        // press new key
    joyKeyDown = newJoyKeyDown;                           // remember this key

  }
  else if ( (newJoyKeyDown < 0) && (joyKeyDown > 0) ) {
    // no keys down, release pressed key
    Keyboard.release(joyKeyDown);
    joyKeyDown = (-1);
  }

}

As for debugging, I put print statements in the code like this:

    Serial.print("new  "); Serial.println(newJoyKeyDown);
    Serial.print("key down  "); Serial.println(joyKeyDown);

  // if a key is down and we have a new key to press
  if ( (newJoyKeyDown > 0) && (newJoyKeyDown != joyKeyDown) )
  {
    if ( joyKeyDown > 0 ) {
      Serial.print("release "); Serial.println(joyKeyDown); //Keyboard.release(joyKeyDown);    // release old key
    }
    //   Keyboard.press(newJoyKeyDown);                        // press new key
    Serial.print("************* press "); Serial.println((char)newJoyKeyDown);
    joyKeyDown = newJoyKeyDown;                           // remember this key

  }
  else if ( (newJoyKeyDown < 0) && (joyKeyDown > 0) ) {
    // no keys down, release pressed key
    //    Keyboard.release(joyKeyDown);
    Serial.print("************ release "); Serial.println(joyKeyDown);
    joyKeyDown = (-1);
  }

to see what was going on. I learned that in the incorrect version the variable joyKeyDown was always getting set to -1 since I was not checking newJoyKeyDown in the else clause of the if statment.

I uploaded your code and so far, so good! Thanks again!
I'll fiddle around with it a bit and try to get my other keys working.