Joystick Mouse With Zoom and Scroll

Just a little side project I thought was pretty cool. It actually works really well and is easy to get going wired.

Creating a wireless mouse is actually much more work than I expected and I am focusing elsewhere currently but thought this mouse was pretty interesting and fun.

It is actually really usable and I really like the zoom toggle and scroll button that I have added.

#include <Mouse.h>    // Built-in library for mouse emulation
#include <Keyboard.h> // Built-in library for keyboard emulation

const int joystickXPin = A1;
const int joystickYPin = A0;
const int joystickClickPin = 2;
const int signalPin = 4; // Define the signal pin
const int buttonPins[] = {5, 6, 7, 8}; // Pins for additional buttons
const int numButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);

// Joystick center values and dead zone for stability
const int centerX = 506;
const int centerY = 513;
const int deadzone = 20; // Adjust for joystick sensitivity
const int scrollThreshold = 5; // Threshold to start scrolling

static unsigned long lastScrollTime = 0;
unsigned long currentTime = millis();
const int buttonScrollThreshold = 7; // Threshold to start scrolling

void setup() {
  // Start the built-in Mouse and Keyboard libraries
  Mouse.begin();
  Keyboard.begin();

  // Initialize joystick and button pins
  pinMode(joystickClickPin, INPUT_PULLUP);
  pinMode(signalPin, INPUT); // Configure signalPin as input
  for (int i = 0; i < numButtons; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }

  Serial.begin(9600);
  Serial.println("Mouse and Keyboard HID initialized");
}

void loop() {
  // Read joystick values
  int xValue = analogRead(joystickXPin);
  int yValue = analogRead(joystickYPin);

  // Calculate mouse movement
  int deltaX = map(xValue, 0, 1023, -10, 10);
  int deltaY = map(yValue, 0, 1023, -10, 10);

  // Check if signalPin is HIGH
  if (digitalRead(signalPin) == HIGH) {
    // Hold the Control key and use deltaY for scrolling
    Keyboard.press(KEY_LEFT_CTRL); // Press Control key

    // Scroll up or down based on deltaY exceeding thresholds
    if (deltaY > scrollThreshold) {
      Mouse.move(0, 0, 1); // Scroll up
      Serial.println("Scrolling up");
    } else if (deltaY < -scrollThreshold) {
      Mouse.move(0, 0, -1); // Scroll down
      Serial.println("Scrolling down");
    }

    Keyboard.release(KEY_LEFT_CTRL); // Release Control key
  } else {
    // Normal mouse movement mode
    if (abs(xValue - centerX) < deadzone) {
      deltaX = 0;
    }
    if (abs(yValue - centerY) < deadzone) {
      deltaY = 0;
    }

    // Move the mouse
    if (digitalRead(buttonPins[0]) != LOW && (deltaX != 0 || deltaY != 0)) {
      Mouse.move(deltaX, -deltaY); // Invert Y-axis if needed
    }

    // Handle right click (buttonPins[0])
    if (digitalRead(buttonPins[1]) == LOW || digitalRead(buttonPins[0]) == LOW) {
      currentTime = millis();
      if (currentTime - lastScrollTime > 100) { // Scroll every 100ms
          if (deltaY > buttonScrollThreshold) {
              Mouse.move(0, 0, 1);
          } else if (deltaY < -buttonScrollThreshold) {
              Mouse.move(0, 0, -1);
          }
          lastScrollTime = millis(); // Update the last scroll time
      }   
    }

    // Handle right click (buttonPins[2])
    if (digitalRead(buttonPins[2]) == LOW) {
      Mouse.press(MOUSE_RIGHT);
    } else {
      Mouse.release(MOUSE_RIGHT);
    }

    // Handle joystick button click
    if (digitalRead(buttonPins[3]) == LOW || digitalRead(joystickClickPin) == LOW) {
      Mouse.press(MOUSE_LEFT); // Joystick button now triggers left click
      Serial.println("Joystick button pressed - Left click");
    } else {
      Mouse.release(MOUSE_LEFT);
    }    

    // NOTE: This is the inconsistent button so I just made it scroll as well above
    // if (digitalRead(buttonPins[1]) == LOW) {
    //     Keyboard.press(KEY_LEFT_GUI); // Press the SUPER/Windows/Command key
    //     Keyboard.press(' ');          // Press the SPACE key
    //     delay(100);                   // Optional: small delay to ensure both keys are registered
    //     Keyboard.releaseAll();        // Release all keys
    //     Serial.println("SUPER + SPACE triggered");
    // }    

    // // Handle left click (buttonPins[3])
    // if (digitalRead(buttonPins[3]) == LOW) {
    //   Mouse.press(MOUSE_LEFT);
    // } 
    // else {
    //   Mouse.release(MOUSE_LEFT);
    // }
  }

  // Optional: Debug information
  Serial.print("X: ");
  Serial.print(xValue);
  Serial.print(" Y: ");
  Serial.print(yValue);
  Serial.print(" DX: ");
  Serial.print(deltaX);
  Serial.print(" DY: ");
  Serial.println(deltaY);

  delay(10); // Small delay to control mouse speed
}