Mouse buttons don't work on Arduino Leonardo -what's wrong with my code?

I wanted to ask for some help figuring out what I did wrong with my code…

I’m using an Arduino Leonardo to make an analog mouse with absolute positioning (to use an arcade gun with a Windows PC). My code works to move the mouse cursor but none of the mouse buttons work.

This is the code I am using. Can anyone here see what I’ve done wrong?

#include <HID.h>
#include <Wire.h>
#include <AbsMouse.h>

// Set which digital pin you’ve connected the trigger to here
int triggerPinLeft = 5;
int triggerPinMiddle = 6;
int triggerPinRight = 7;

// This is the trigger state
int lastTriggerStateLeft = 0;
int lastTriggerStateMiddle = 0;
int lastTriggerStateRight = 0;

void setup() {
// Init the abs mouse class and tell it the maximum values
AbsMouse.init(1024, 1024);

// Setup the trigger pin as an input
pinMode(triggerPinLeft, INPUT);
pinMode(triggerPinMiddle, INPUT);
pinMode(triggerPinRight, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
// Read 2 analogue channels
int xValue = analogRead(A0);
int yValue = analogRead(A1);

// Move the mouse to this point
AbsMouse.move(xValue, yValue);

// Check to see if we need to do a left click
int triggerStateLeft = digitalRead(triggerPinLeft);
if (triggerStateLeft != lastTriggerStateLeft) {
if (triggerStateLeft == LOW) {
AbsMouse.press(MOUSE_LEFT);
} else {
AbsMouse.release(MOUSE_LEFT);
}
delay(10); // Unsure what this delay is for, but might need it.
}
// Check to see if we need to do a middle click
int triggerStateMiddle = digitalRead(triggerPinMiddle);
if (triggerStateMiddle != lastTriggerStateMiddle) {
if (triggerStateMiddle == LOW) {
AbsMouse.press(MOUSE_MIDDLE);
} else {
AbsMouse.release(MOUSE_MIDDLE);
}
delay(10); // Unsure what this delay is for, but might need it.
}
// Check to see if we need to do a right click
int triggerStateRight = digitalRead(triggerPinRight);
if (triggerStateRight != lastTriggerStateRight) {
if (triggerStateRight == LOW) {
AbsMouse.press(MOUSE_RIGHT);
} else {
AbsMouse.release(MOUSE_RIGHT);
}
delay(10); // Unsure what this delay is for, but might need it.
}

delay(1); // delay in between reads for stability
}

The formatting came out weird for some reason. This is the code on github:

I've been using an analog thumbstick like this to test the code with a Leonardo and it's wired like in this pic:

Courtesy post of github listing in code tags:

#include <HID.h>
#include <Wire.h>
#include <AbsMouse.h>

// Set which digital pin you've connected the trigger to here
int triggerPinLeft = 5;
int triggerPinMiddle = 6;
int triggerPinRight = 7;

// This is the trigger state
int lastTriggerStateLeft = 0;
int lastTriggerStateMiddle = 0;
int lastTriggerStateRight = 0;

void setup() {
  // Init the abs mouse class and tell it the maximum values
  AbsMouse.init(1024, 1024);

  // Setup the trigger pin as an input
  pinMode(triggerPinLeft, INPUT);
  pinMode(triggerPinMiddle, INPUT);
  pinMode(triggerPinRight, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // Read 2 analogue channels
  int xValue = analogRead(A0);
  int yValue = analogRead(A1);

  // Move the mouse to this point
  AbsMouse.move(xValue, yValue);

  // Check to see if we need to do a left click
  int triggerStateLeft = digitalRead(triggerPinLeft);
  if (triggerStateLeft != lastTriggerStateLeft) {
    if (triggerStateLeft == LOW) {
      AbsMouse.press(MOUSE_LEFT);
    } else {
      AbsMouse.release(MOUSE_LEFT);
    }
    delay(10);  // Unsure what this delay is for, but might need it.
  }
  
  // Check to see if we need to do a middle click
  int triggerStateMiddle = digitalRead(triggerPinMiddle);
  if (triggerStateMiddle != lastTriggerStateMiddle) {
    if (triggerStateMiddle == LOW) {
      AbsMouse.press(MOUSE_MIDDLE);
    } else {
      AbsMouse.release(MOUSE_MIDDLE);
    }
    delay(10);  // Unsure what this delay is for, but might need it.
  }
  
  // Check to see if we need to do a right click
  int triggerStateRight = digitalRead(triggerPinRight);
  if (triggerStateRight != lastTriggerStateRight) {
    if (triggerStateRight == LOW) {
      AbsMouse.press(MOUSE_RIGHT);
    } else {
      AbsMouse.release(MOUSE_RIGHT);
    }
    delay(10);  // Unsure what this delay is for, but might need it.
  }

  delay(1);        // delay in between reads for stability
}

Make sure you update the “last” switch state variable when you see a change (left click shown for example):

    // Check to see if we need to do a left click
    int triggerStateLeft = digitalRead(triggerPinLeft);
    if (triggerStateLeft != lastTriggerStateLeft) 
    {
        lastTriggerStateLeft = triggerStateLeft;    //<--- add this line to each switch state-change check
        
        if (triggerStateLeft == LOW) 
        {
            AbsMouse.press(MOUSE_LEFT);
        }//if
        else 
        {
            AbsMouse.release(MOUSE_LEFT);
        }//else
    
        delay(10);  // Unsure what this delay is for, but might need it.
    }//if

You are using pinMode INPUT and not INPUT_PULLUP. Do you have the required pull-up or pull-down resistors on each INPUT pin?

Blackfin:
Make sure you update the “last” switch state variable when you see a change (left click shown for example):

    // Check to see if we need to do a left click

int triggerStateLeft = digitalRead(triggerPinLeft);
   if (triggerStateLeft != lastTriggerStateLeft)
   {
       lastTriggerStateLeft = triggerStateLeft;    //<— add this line to each switch state-change check
       
       if (triggerStateLeft == LOW)
       {
           AbsMouse.press(MOUSE_LEFT);
       }//if
       else
       {
           AbsMouse.release(MOUSE_LEFT);
       }//else
   
       delay(10);  // Unsure what this delay is for, but might need it.
   }//if

Did you spot something that’s wrong in the code or is this a general FYI?
Sorry I don’t really understand any of the code. I’m trying to make a one-off project work using someone else’s code. Are you saying that something is missing that is preventing the left, middle and right clicks from working?

johnwasser:
You are using pinMode INPUT and not INPUT_PULLUP. Do you have the required pull-up or pull-down resistors on each INPUT pin?

I have been using one of these analog thumbsticks to test it and it's wired the same as in this pic:

In says on that page that resistors aren't needed when using one of these thumbsticks. As the X and Y axis works, I'm assuming that isn't the problem. Is this wrong?

The intended application is for my Sega arcade IR guns which output like regular analog controllers. When I tested them with the Arduino it was the same result - I can move the cursor but not click:

Is there something different about the mouse buttons that would require additional resistors even if the X and Y axis worked without them?

goemonz:
Did you spot something that's wrong in the code or is this a general FYI?
Sorry I don't really understand any of the code. I'm trying to make a one-off project work using someone else's code. Are you saying that something is missing that is preventing the left, middle and right clicks from working?

It seems like it to me (wrong). If you don't save the "last" switch read then comparisons for subsequent reads are messed up.

I'm not certain it's causing your problem. For now I'm just saying add the line indicated to each of the switch reads, with the names of the variables changed to match each switch.

goemonz:
I have been using one of these analog thumbsticks to test it and it's wired the same as in this pic:
https://www.arduino.cc/en/Tutorial/BuiltInExamples/JoystickMouseControl
In says on that page that resistors aren't needed when using one of these thumbsticks. As the X and Y axis works, I'm assuming that isn't the problem. Is this wrong?

Something is very wrong with the information on that page. The Fritzing diagram (the pic) and the schematic both show no resistor and the switch connected to Pin 6. The example sketch uses INPUT mode and Pin 2!
There has to be a pull-up or pull-down resistor somewhere. There could be one in the joystick but it would be very unusual. I think using the built-in pull-up resistor (pinMode INPUT_PULLUP) is your best solution.

Blackfin:
It seems like it to me (wrong). If you don't save the "last" switch read then comparisons for subsequent reads are messed up.

I'm not certain it's causing your problem. For now I'm just saying add the line indicated to each of the switch reads, with the names of the variables changed to match each switch.

Ok I'll give that a try. Thanks.

johnwasser:
Something is very wrong with the information on that page. The Fritzing diagram (the pic) and the schematic both show no resistor and the switch connected to Pin 6. The example sketch uses INPUT mode and Pin 2!
There has to be a pull-up or pull-down resistor somewhere. There could be one in the joystick but it would be very unusual. I think using the built-in pull-up resistor (pinMode INPUT_PULLUP) is your best solution.

The way I understand the wording on that page is that those thumbsticks already have the required resistors. If they are wrong about that, would the pots still work for the X and Y axis?
One thing I have been wondering about is whether I need to add 5v to the mouse click switch in addition to them connecting pin 6 and ground. It kinda looks like every button is tied to 5v in their diagram.

The X and Y axis pots on the thumbstick have 5v in, 0-5v out + ground. I have been assuming that either the single 5v in on the thumbstick is also tied to the digital button, or that this isn't necessary.

My other control boards only require connections to one pin and ground for each button. If this is wrong then that would explain why the buttons don't work... The thumbstick pcb is partially covered. By the pots so I can't see what the 5v pin is tied to...

If I try using the built in resistor as you suggest, would I just have to do a find and replace to change "pinMode INPUT" to "INPUT_PULLUP" ?

goemonz:
The way I understand the wording on that page is that those thumbsticks already have the required resistors.

If they had the required resistor and were wired correctly then the button would be working.

goemonz:
If they are wrong about that, would the pots still work for the X and Y axis?

Yes. Analog inputs connected to pots don't need any additional pull-up or pull-down resistors. The two sides of the pot (+5 to wiper and wiper to Ground) act as a voltage divider. One acts as a pull-up and the other acts as a pull-down.

goemonz:
One thing I have been wondering about is whether I need to add 5v to the mouse click switch in addition to them connecting pin 6 and ground. It kinda looks like every button is tied to 5v in their diagram.

If you are right and the thumbstick already has a pull-down resistor for the switch it would be using the same 5V connection that the joystick uses.

goemonz:
The X and Y axis pots on the thumbstick have 5v in, 0-5v out + ground. I have been assuming that either the single 5v in on the thumbstick is also tied to the digital button, or that this isn't necessary.

I'm not sure what you mean by this. The +5V is certainly necessary for the joystick. If you are correct that the thumbstick board includes a pull-up or pull-down resistor for the switch, the +5V would ALSO be necessary for the switch.

goemonz:
My other control boards only require connections to one pin and ground for each button.

What other control boards?

goemonz:
If this is wrong then that would explain why the buttons don't work... The thumbstick pcb is partially covered. By the pots so I can't see what the 5v pin is tied to...

If you have a multimeter you can measure the resistance between the 'sw' pin and the ground pin when the switch is pressed. If the resistance is near zero the switch neds a pull-up resistor. If you measure the resistance from the 'sw' pin to the 5V pin and the resistance is near infinite, you need to add a pull-up resistor. The easiest way is to use INPUT_PULLUP.

goemonz:
If I try using the built in resistor as you suggest, would I just have to do a find and replace to change "pinMode INPUT" to "INPUT_PULLUP" ?

There is only one line to change. Change "INPUT" to "INPUT_PULLUP" for the pin connected to your thumbstick switch.

Blackfin:
It seems like it to me (wrong). If you don't save the "last" switch read then comparisons for subsequent reads are messed up.

I'm not certain it's causing your problem. For now I'm just saying add the line indicated to each of the switch reads, with the names of the variables changed to match each switch.

After changing the code as you suggested the Arduino now controls the 3 mouse buttons but they seem to all be pressed before I touch a button (or even if no buttons are connected).

Is there something in the code to make the arduino act as though the mouse buttons are always pressed?

This is the updated code:

goemonz:
Is there something in the code to make the arduino act as though the mouse buttons are always pressed?

If the code was written for a switch with an eternal pull-down resistor then it is expecting the pin to read as LOW until the switch is closed. Using a pull-up resistor (as with INPUT_PULLUP) the pin will read as HIGH until the switch is closed. One way to fix the code is to change "digitalRead(switchPin)" to "(digitalRead(switchPin) == LOW)"

johnwasser:
If the code was written for a switch with an eternal pull-down resistor then it is expecting the pin to read as LOW until the switch is closed. Using a pull-up resistor (as with INPUT_PULLUP) the pin will read as HIGH until the switch is closed. One way to fix the code is to change “digitalRead(switchPin)” to “(digitalRead(switchPin) == LOW)”

Is this a general point or did you spot an error in the code that this find n replace you suggested would correct?
Sorry… I don’t understand code so I can’t tell. I can see it mention something like "if triggerstateleft == LOW but I don’t know what it is referring to, or if it is in the right place, or if your suggestion is already in there or not etc…
The guy who wrote the code has never used an Arduino before… He’s a fellow arcade fan (and programmer) who wrote it for me as a favor. I think he (and I) thought it would be easier to use an Arduino for this…
If I made the change you suggested, would I just do it to the first line of this for each button and leave the rest as is?

int triggerStateLeft = digitalRead(triggerPinLeft);
if (triggerStateLeft != lastTriggerStateLeft) {
AbsMouse.press(MOUSE_LEFT);

Can you copy the code from the IDE into some code tags without the colors? I can't read that...

[color=var(--color-text-primary)] int triggerStateLeft = digitalRead(triggerPinLeft);[/color]
[color=var(--color-text-primary)] if (triggerStateLeft != lastTriggerStateLeft) {[/color]
[color=var(--color-text-primary)] if (triggerStateLeft == LOW) {[/color]
[color=var(--color-text-primary)] AbsMouse.press(MOUSE_LEFT);[/color]
[color=var(--color-text-primary)] } else {[/color]
.
.
.

goemonz:
Is this a general point or did you spot an error in the code that this find n replace you suggested would correct?

. I could not read your code so I could not spot a specific error.

The code appears to be using Active LOW inputs so you should change these lines in setup():

  // Setup the trigger pin as an input
  pinMode(triggerPinLeft, INPUT);
  pinMode(triggerPinMiddle, INPUT);
  pinMode(triggerPinRight, INPUT);

To:

  // Setup the trigger pin as an input
  pinMode(triggerPinLeft, INPUT_PULLUP);
  pinMode(triggerPinMiddle, INPUT_PULLUP);
  pinMode(triggerPinRight, INPUT_PULLUP);

The other main problem appears to be three cases of failing to update the lastTriggerState:

  if (triggerStateLeft != lastTriggerStateLeft)
  {
    lastTriggerStateLeft = triggerStateLeft;  // THIS LINE IS MISSING
    if (triggerStateLeft == LOW)
    {
  if (triggerStateMiddle != lastTriggerStateMiddle)
  {
    lastTriggerStateMiddle = triggerStateMiddle;  // THIS LINE IS MISSING
    if (triggerStateMiddle == LOW)
    {
  if (triggerStateRight != lastTriggerStateRight)
  {
    lastTriggerStateRight = triggerStateRight;  // THIS LINE IS MISSING
    if (triggerStateRight == LOW)
    {

This is how your sketch should have been posted:

#include <HID.h>
#include <Wire.h>
#include <AbsMouse.h>

// Set which digital pin you've connected the trigger to here
int triggerPinLeft = 5;
int triggerPinMiddle = 6;
int triggerPinRight = 7;

// This is the trigger state
int lastTriggerStateLeft = 0;
int lastTriggerStateMiddle = 0;
int lastTriggerStateRight = 0;

void setup()
{
  // Init the abs mouse class and tell it the maximum values
  AbsMouse.init(1024, 1024);

  // Setup the trigger pin as an input
  pinMode(triggerPinLeft, INPUT);
  pinMode(triggerPinMiddle, INPUT);
  pinMode(triggerPinRight, INPUT);
}

// the loop routine runs over and over again forever:
void loop()
{
  // Read 2 analogue channels
  int xValue = analogRead(A0);
  int yValue = analogRead(A1);

  // Move the mouse to this point
  AbsMouse.move(xValue, yValue);

  // Check to see if we need to do a left click
  int triggerStateLeft = digitalRead(triggerPinLeft);
  if (triggerStateLeft != lastTriggerStateLeft)
  {
    if (triggerStateLeft == LOW)
    {
      AbsMouse.press(MOUSE_LEFT);
    }
    else
    {
      AbsMouse.release(MOUSE_LEFT);
    }
    delay(10); // Unsure what this delay is for, but might need it.
  }
  // Check to see if we need to do a middle click
  int triggerStateMiddle = digitalRead(triggerPinMiddle);
  if (triggerStateMiddle != lastTriggerStateMiddle)
  {
    if (triggerStateMiddle == LOW)
    {
      AbsMouse.press(MOUSE_MIDDLE);
    }
    else
    {
      AbsMouse.release(MOUSE_MIDDLE);
    }
    delay(10); // Unsure what this delay is for, but might need it.
  }
  // Check to see if we need to do a right click
  int triggerStateRight = digitalRead(triggerPinRight);
  if (triggerStateRight != lastTriggerStateRight)
  {
    if (triggerStateRight == LOW)
    {
      AbsMouse.press(MOUSE_RIGHT);
    }
    else
    {
      AbsMouse.release(MOUSE_RIGHT);
    }
    delay(10); // Unsure what this delay is for, but might need it.
  }

  delay(1); // delay in between reads for stability
}