Switching between two modes. (relative and absolute) on trackpad

Hi Everyone!

I have two modes, Relative and Absolute that I need help switching . I want to use Serial read or some kind of button press to switch between these two modes. I wasn't sure how to structure the code in the proper way.

Do I use a single generic setup() and have a choice prompted using serial.read in loop() to agument the intial setup using a fucntion like setupRelative() or setupAbsolute()?

//Absolute mode

#include <CirquePinnacle.h>

#define SS_PIN 0
#define DR_PIN 1

PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);

// an object to hold data reported by the Cirque trackpad
AbsoluteReport data;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }
  if (!trackpad.begin()) {
    Serial.println(F("Cirque Pinnacle not responding!"));
    while (true) {
      // hold program in infinite loop
    }
  }
  Serial.println(F("CirquePinnacle/examples/absolute_mode"));
  trackpad.setDataMode(PINNACLE_ABSOLUTE);
  trackpad.absoluteModeConfig(1);  // set count of z-idle packets to 1
  Serial.println(F("Touch the trackpad to see the data."));
}


  void loop() {
  if (trackpad.available()) {
    trackpad.read(&data);
    Serial.print(F("Left:"));
    Serial.print(data.buttons & 1);
    Serial.print(F(" Right:"));
    Serial.print(data.buttons & 2);
    Serial.print(F(" Middle:"));
    Serial.print(data.buttons & 4);
    Serial.print(F("\tX:"));
    Serial.print(data.x);
    Serial.print(F("\tY:"));
    Serial.println(data.y);
  }
}


//Relative Mode

#include <CirquePinnacle.h>

#define SS_PIN 0
#define DR_PIN 1

PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);

// an object to hold data reported by the Cirque trackpad
RelativeReport data;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }
  if (!trackpad.begin()) {
    Serial.println(F("Cirque Pinnacle not responding!"));
    while (true) {
      // hold program in infinite loop
    }
  }
  Serial.println(F("CirquePinnacle/examples/relative_mode"));
  trackpad.setDataMode(PINNACLE_RELATIVE);
  trackpad.relativeModeConfig();  // uses default config
  Serial.println(F("Touch the trackpad to see the data."));
}

void loop() {
  if (trackpad.available()) {
    trackpad.read(&data);
    Serial.print(F("Left:"));
    Serial.print(data.buttons & 1);
    Serial.print(F(" Right:"));
    Serial.print(data.buttons & 2);
    Serial.print(F(" Middle:"));
    Serial.print(data.buttons & 4);
    Serial.print(F("\tX:"));
    Serial.print(data.x);
    Serial.print(F("\tY:"));
    Serial.print(data.y);
    Serial.print(F("\tScroll:"));
    Serial.println(data.scroll);
  }
}

This is my attempt. I get data in absolute mode but not when swtich to relative mode. Something about declaring

AbsoluteReport data; vs RelativeReport data;

I am not sure how to switch this before setup() but it appears I have to declare it from the beginning. I can declare it also in the void loop() but cant seem to swtich it from the serial read.

#include <CirquePinnacle.h>

#define SS_PIN 0
#define DR_PIN 1

PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);

// an object to hold data reported by the Cirque trackpad
RelativeReport data;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }
  if (!trackpad.begin()) {
    Serial.println(F("Cirque Pinnacle not responding!"));
    while (true) {
      // hold program in infinite loop
    }
  }
}



void loop() {
  while (Serial.available()) {
    Serial.println(F("CirquePinnacle/examples/absolute_mode vs relative_mode"));
    Serial.println(F("\n*** Enter 'R' for relatve"));
    Serial.println(F("*** Enter 'A' for absolute.\n"));
    char input = Serial.read();
    if (input == 'r' || input == 'R') {
      // an object to hold data reported by the Cirque trackpad
      RelativeReport data;
      Serial.println(F("CirquePinnacle/examples/relative_mode"));
      trackpad.setDataMode(PINNACLE_RELATIVE);
      trackpad.relativeModeConfig();  // uses default config
    } else if (input == 'a' || input == 'A') {
      // an object to hold data reported by the Cirque trackpad
      AbsoluteReport data;
      Serial.println(F("CirquePinnacle/examples/absolute_mode"));
      trackpad.setDataMode(PINNACLE_ABSOLUTE);
      trackpad.absoluteModeConfig(1);  // set count of z-idle packets to 1
    }
  }

  if (trackpad.available()) {
    trackpad.read(&data);
    Serial.print(F("Left:"));
    Serial.print(data.buttons & 1);
    Serial.print(F(" Right:"));
    Serial.print(data.buttons & 2);
    Serial.print(F(" Middle:"));
    Serial.print(data.buttons & 4);
    Serial.print(F("\tX:"));
    Serial.print(data.x);
    Serial.print(F("\tY:"));
    Serial.println(data.y);
  }
}




First, are you sure this is OK?

#define SS_PIN 0
#define DR_PIN 1

Pins 0 and 1 on some Arduino boards should not be used.

I have no Pinnacle device. But.

You want to switch modes if there is a character. That's a simple change.

Here's a mode-changer sketch, it only uses the serial monitor for input and output. I tried to leave the Pinnacle stuff in there, but I had to comment it out to test this. The comments should help you see where your Pinnacle stuff could go.

Your mode switching declares variables, but those are local and disappear one you leave the { block } they are in.

You need to have the two Pinnacle variables be global and distinct, and pretty much write everything out explicitly for each mode.

You may be able to use the one

  if (trackpad.available()) {
    trackpad.read(&data);      // but you need to read into the appropriate variable.

  }

Here's the Pinnacle-less sketch. If what you are trying to do is possible, this should give you something to work with.
enum mode_t {RELATIVE, ABSOLUTE};
mode_t theMode = RELATIVE;

// Pinnacle variables
//RelativeReport rData;
//AbsoluteReport aData;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }

  Serial.println("Hello there.\n");
  Serial.println("Starting in relative mode.\n");

  Serial.println("Type A for absolute or R for relative mode.\n");
}

void loop() {
  if (Serial.available()) {
    char input = Serial.read();
    if (input == 'r' || input == 'R') {
      theMode = RELATIVE;
      Serial.println(F("        switching to relative_mode\n\n"));
      Serial.println("Type A for absolute, R for relative.\n");

//      trackpad.setDataMode(PINNACLE_RELATIVE);
//      trackpad.relativeModeConfig();  // uses default config
    } 

    if (input == 'a' || input == 'A') {
      theMode = ABSOLUTE;
      Serial.println(F("        switching to absolute_mode\n"));
      Serial.println("Type A for absolute or R for relative mode.\n");

//      trackpad.setDataMode(PINNACLE_ABSOLUTE);
//      trackpad.absoluteModeConfig(1);  // set count of z-idle packets to 1
    }
  }

  switch (theMode) {
  case RELATIVE :
// do what you gotta do for realtive mode here
    break;

  case ABSOLUTE :
// do what you gotta do for absoute mode here
    break;
  }
}

Sry, I'm unable to go further w/o the hardware you have, plus I will claim to have run out of a few of those things one runs out of, for now.

You'll have to read the code carefully. Use your best common sense and try to backfit the working example sketches you have into this framework.

First try the sketch unaltered to see how the mode switch and prompt works. It would also be easy to put that logic on a toggle switch, and a bit harder but still easy to use a pusbutton to change modes.

a7

Thank you very much for detailed explanation and code example. I tried to run the code without the pinnacle data but get error message with

enum mode_t

So I switched it to:

enum mode_tron {RELATIVE, ABSOLUTE};
mode_tron theMode = RELATIVE;

and your test code worked.

I failed to mention that I am using a XIAO BLE SENSE board where 0,1 can be used as digital pins for I/O.

I will try implementing the cirque code next. Thank you.

At a guess I ran across a symbol that was in use. mode_t.

Since I made that up, a solution is probably to just change it

enum myPinnacleModeType {RELATIVE, ABSOLUTE};
myPinnacleModeType theMode = RELATIVE;

and I'll be surprised if myPinnacleModeType has been used elsewhere. Shocked.

It worked in the other environment where there was no collision.

It has worked for me because my code didn't manage to invite anything along for the ride that had the name conflict.

And I say probably for the fix only because I cannot test it. But you can!

a7

OIC whilst I am typing, you are figuring it out for yourself. Good work.

a7

Sorry I jumped the gun and didnt know it was easy fix. Thank you for an even faster response. lol.

I added the pinnacle variables and it almost seemed to work. It does switch between data modes just from the impression I get on the serial monitor output. However, the data doesn't seem to change as I move my finger on the trackpad. It appears as if it just received the initial input and repeats.

Relative

|10:13:38.927 -> |X:-4|Y:-4|
|10:13:38.927 -> |X:-4|Y:-4|
|10:13:38.927 -> |X:-4|Y:-4|
|10:13:38.927 -> |X:-4|Y:-4|

Absolute

|10:14:23.146 -> |X:3324|Y:4092|
|10:14:23.146 -> |X:3324|Y:4092|

It also doesn't seem to prompt the initial serial prompts

  Serial.println("Hello there.\n");
  Serial.println("Starting in relative mode.\n");
  Serial.println("Type A for absolute or R for relative mode.\n");

Rule 0. New sketch, new problem = post the sketch.

I can suppose you just did X and Y, but without seeing it we can't know if you bungled it or what.

a7

Thanks for explaining rule 0.

I added this bit of code missing from OG, expecting it to do nothing, but in fact, it actually solved the whole problem.

Here is entire code working code.

#include <CirquePinnacle.h>

#define SS_PIN 0
#define DR_PIN 1

PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);

enum mode_tron {RELATIVE, ABSOLUTE};
mode_tron theMode = RELATIVE;

// Pinnacle variables
RelativeReport rData;
AbsoluteReport aData;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }
    if (!trackpad.begin()) {
    Serial.println(F("Cirque Pinnacle not responding!"));
    while (true) {
      // hold program in infinite loop
    }
  }

  Serial.println("Hello there.\n");
  Serial.println("Starting in relative mode.\n");

  Serial.println("Type A for absolute or R for relative mode.\n");
}

void loop() {
  if (Serial.available()) {
    char input = Serial.read();
    if (input == 'r' || input == 'R') {
      theMode = RELATIVE;
      Serial.println(F("        switching to relative_mode\n\n"));
      Serial.println("Type A for absolute, R for relative.\n");

     trackpad.setDataMode(PINNACLE_RELATIVE);
     trackpad.relativeModeConfig();  // uses default config
    } 

    if (input == 'a' || input == 'A') {
      theMode = ABSOLUTE;
      Serial.println(F("        switching to absolute_mode\n"));
      Serial.println("Type A for absolute or R for relative mode.\n");

      trackpad.setDataMode(PINNACLE_ABSOLUTE);
      trackpad.absoluteModeConfig(1);  // set count of z-idle packets to 1
    }
  }

  switch (theMode) {
  case RELATIVE :
  if (trackpad.available()) {
    trackpad.read(&rData);
    Serial.print(F("\tX:"));
    Serial.print(rData.x);
    Serial.print(F("\tY:"));
    Serial.println(rData.y);
  }
  break;

  case ABSOLUTE :
  if (trackpad.available()) {
    trackpad.read(&aData);
    Serial.print(F("\tX:"));
    Serial.print(aData.x);
    Serial.print(F("\tY:"));
    Serial.println(aData.y);
  }
  break;
  }
}

I still don't get the serial prompt asking Absolute or Relative prompt in serial, but knowing the question and typing A or R does in fact work and switch modes on the fly!

Thank you very much for this awesome solution in nearly 1 shot! Would you mind directing me on how I can convert this to a button change and preferably as an interrupt?

I'm surprised you got anywhere without

  if (!trackpad.begin()) {

Many objects you will come across use a begin() method to grab an opportunity to initialise themselves, usually not calling it results in unsatisfactory behaviour when its other methods are used.

Are you saying that the mode switch happens, but

      Serial.println(F("        switching to relative_mode\n\n"));
      Serial.println("Type A for absolute, R for relative.\n");

and the corresponding lines in the code that switches to absolute mode do not issue? What about the print statements in setup()? I cannot see just now how that can be. I look again later.

If you know about interrupts, use them, but interrupts will not be necessary. If you know little about interrupts, forget them for now, here they will be more trouble than help.

A pushbutton to change modes with each press? I'm a big fan of knowing how to do this simple thing by one's self, but for now, try the sketch below. I think you are clever enough to see how this could be weaved into your current sketch. Pro tip - leave the A/a - R/r logic intact, it will always be handy for testing and so forth, no reason to jettison it just yet.

The sketch uses the ezButton library, which gets my highest praise for button libraries ("it doesn't suck!"). Add the library using the IDE mechanism. Throw a button on pin 3 wired other side to ground and see. When you move it to your code, do not overlook all the stuff you can find with you text editor searching for someButton.

# include "ezButton.h"

ezButton someButton (3, INPUT_PULLUP);

void setup() {
  Serial.begin(9600);
  Serial.println("Hello ezButton World!\n");

  someButton.setDebounceTime(50);
}

int count = 1;
int toggle;  // leftover, used to turn on and off an LED when the button got pressed

void loop() {
  someButton.loop();

  if (someButton.isPressed()) { Serial.print("you pressed "); count++; Serial.println(count); }

  if (someButton.isReleased()) { Serial.print("          you unpressed ");  Serial.println(count);}
}

I'm soon out the door, she who must not be kept waiting is rolling towards me as I type. It is just not going to be the kind of day for being inside. I bet you got this, or others will help with the details.

a7

Ok Ill take your word and forget the interrupt! Maybe ive been using button libraries that suck so thank you very much for the ez button library! What a gift. You are truly "Alto" in this game! Enjoy your day.

I am trying to add a "button" using taps on the trackpad to trigger. (this will not be the button for A or R switching but simple a mouse click function.) Ive given a global variable at the top as you suggested I do. But not sure exactly where this codes fits. I tired placing it after the switchcase for mouse movement without luck as well as other various places. Any idea? This will really help me understand where I can add other functions.

///FOR TRACKPAD CLICKS
int buttonState;
uint8_t prevButtonStates;  

    prevButtonStates = rData.buttons;  // for edge detection
    // edge detection for binary button data
    uint8_t buttonsChanged = prevButtonStates ^ rData.buttons;
    if (buttonsChanged) {
      //Serial.print("PRESSED");
      uint8_t toggledOff = buttonsChanged ^ (rData.buttons & buttonsChanged);
      uint8_t toggledOn = buttonsChanged ^ toggledOff;
      if (toggledOn) {
        Mouse.press(MOUSE_LEFT);
        //Serial.print("On");
        buttonState = HIGH;
      }
      if (toggledOff) {
        Mouse.release(MOUSE_LEFT);
        buttonState = LOW;
    }
  }

My working code (except for the click)


#include <TinyUSB_Mouse_and_Keyboard.h>
#include <CirquePinnacle.h>

#define SS_PIN 0
#define DR_PIN 1

///VARIABLES FOR TIMING
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 360;  //the value is a number of milliseconds

////////////FOR SCROLLING
int direction;
int oldDirection;

int sector;
int oldSector;
int dirCount = 0;

///FOR TRACKPAD CLICKS
int buttonState;
uint8_t prevButtonStates;  

PinnacleTouchSPI trackpad(DR_PIN, SS_PIN);
// If using I2C, then use the following line (not the line above)
// PinnacleTouchI2C trackpad(DR_PIN);

enum mode_tron { RELATIVE,
                 ABSOLUTE };
mode_tron theMode = ABSOLUTE;

// Pinnacle variables
RelativeReport rData;
AbsoluteReport aData;

void setup() {
  Mouse.begin();
  Serial.begin(115200);
  while (!Serial) {
    // wait till Serial monitor is opened
  }
  if (!trackpad.begin()) {
    Serial.println(F("Cirque Pinnacle not responding!"));
    while (true) {
      // hold program in infinite loop
    }
  }

  Serial.println("Hello there.\n");
  Serial.println("Starting in relative mode.\n");

  Serial.println("Type A for absolute or R for relative mode.\n");

currentMillis = millis();
}

void loop() {
  if (Serial.available()) {
    char input = Serial.read();
    if (input == 'r' || input == 'R') {
      theMode = RELATIVE;
      Serial.println(F("        switching to relative_mode\n\n"));
      Serial.println("Type A for absolute, R for relative.\n");

      trackpad.setDataMode(PINNACLE_RELATIVE);
      trackpad.relativeModeConfig(true, true, false);  // uses default config
        startMillis = millis();  //initial start time

    }

    if (input == 'a' || input == 'A') {
      theMode = ABSOLUTE;
      Serial.println(F("        switching to absolute_mode\n"));
      Serial.println("Type A for absolute or R for relative mode.\n");

      trackpad.setDataMode(PINNACLE_ABSOLUTE);
      trackpad.absoluteModeConfig(1);  // set count of z-idle packets to 1
    }
  }

  switch (theMode) {
    case RELATIVE:
      if (trackpad.available()) {
       // currentMillis = millis();
        trackpad.read(&rData);

        if (rData.x || rData.y) {
          // invert the x-axis, use the others as is
          //Mouse.move(rData.x * -1, rData.y, rData.scroll);


          /////////////////////TRYIN ACCELERATION/////////////////
          int x = map(rData.x, -15, 15, 1, 9);
          int y = map(rData.y, -15, 15, 1, 9);

 
          switch (x | y) {
            case 1 | 1:
              Mouse.move(rData.x * -8, rData.y * 8);
              break;
            case 2 | 2:
              Mouse.move(rData.x * -6, rData.y * 6);
              break;
            case 3 | 3:
              Mouse.move(rData.x * -4, rData.y * 4);
              break;
            case 4 | 4:
              Mouse.move(rData.x * 1.5, rData.y * 2);
              break;
            case 5 | 5:
              Mouse.move(rData.x * -1, rData.y);
              break;
            case 6 | 6:
              Mouse.move(rData.x * -1.5, rData.y * 2);
              break;
            case 7 | 7:
              Mouse.move(rData.x * -4, rData.y * 2);
              break;
            case 8 | 8:
              Mouse.move(rData.x * -6, rData.y * 4);
              break;
            case 9 | 9:
              Mouse.move(rData.x * -8, rData.y * 8);
              break;
            default:
              Mouse.move(rData.x * -1, rData.y);
              break;
          } // END SWITCH FOR MOUSE


    prevButtonStates = rData.buttons;  // for edge detection
    // edge detection for binary button data
    uint8_t buttonsChanged = prevButtonStates ^ rData.buttons;
    if (buttonsChanged) {
      //Serial.print("PRESSED");
      uint8_t toggledOff = buttonsChanged ^ (rData.buttons & buttonsChanged);
      uint8_t toggledOn = buttonsChanged ^ toggledOff;
      if (toggledOn) {
        Mouse.press(MOUSE_LEFT);
        //Serial.print("On");
        buttonState = HIGH;
      }
      if (toggledOff) {
        Mouse.release(MOUSE_LEFT);
        buttonState = LOW;
    }
  }








        }  //  End DATA
      }  //END IF TRACKPAD AVAILABLE
      break;

    case ABSOLUTE:
      if (trackpad.available()) {
        trackpad.read(&aData);
        Serial.print(F("\tX:"));
        Serial.print(aData.x);
        Serial.print(F("\tY:"));
        Serial.println(aData.y);
      }
      break;
  }  ///END SWITCHTHEMODE
 // save buttons' previous state before getting updates
            scrollIt();
}  ///END VOID LOOP

void scrollIt() {
  currentMillis = millis();
  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis <= period) {  //test whether the period has elapsed
    //SECTOR 1 or 2
    if (rData.x >= 0 and rData.y >= 0)  ///@ 45 degrees x == y
      if (rData.x > rData.y)           //// 45 degrees or more
        sector = 2;
      else if (rData.x < rData.y)
        sector = 1;

    //SECTOR 3 or 4
    if ((rData.x) > 0 and (-rData.y) >= 0)  ///@ 90 degrees x == y
      if ((rData.x) > (-rData.y))           //// 90 degrees or more
        sector = 3;
      else if ((rData.x) < (-rData.y))
        sector = 4;

    //SECTOR 5 or 6
    if ((-rData.x) > 0 and (-rData.y) >= 0)  ///@ 225 degrees x == y
      if ((-rData.x) > (-rData.y))           //// 225 degrees or more
        sector = 6;
      else if ((-rData.x) < (-rData.y))
        sector = 5;

    /////SECTOR 7 or 8
    if (rData.x < 0 and rData.y >= 0)  ///SECTOR EITHER 7 or 8  @ 315 degrees -x == y
      if ((-rData.x) > rData.y)        //// 315 degrees or more
        sector = 7;
      else if ((-rData.x) < rData.y)
        sector = 8;

    ///THIS SECTION PREVENTS THE WRAPAROUND ISSUE
    if (sector == (oldSector + 1) or (sector == 1 and oldSector == 16)) {
      direction = 1;
    } else if (sector == (oldSector - 1) or (sector == 16 and oldSector == 1)) {
      direction = -1;
    } else
      direction = 0;
    oldSector = sector;

    if (!direction == 0)
      if (direction == oldDirection) {
        dirCount++;
        if (dirCount == 3) {
          //Serial.println(sector);
          Mouse.move(0, 0, direction);
          dirCount = 0;
        } 
      } else {
        dirCount = 0;
        oldDirection = direction;
      }
    startMillis = currentMillis;
  }
}  // END OF SCROLLIT FUNCTION


void pushit(){
                 // get new data

    
  

}

 

There seems to be some nonsensical operations in your working code, so Imma ignore that for now, since it works, except to ask where did you find this, and/or do you know what it is doing? I have not seen the logical bitwise or operator used in this fashion:

          int x = map(rData.x, -15, 15, 1, 9);
          int y = map(rData.y, -15, 15, 1, 9);

 
          switch (x | y) {
            case 1 | 1:
              Mouse.move(rData.x * -8, rData.y * 8);
              break;
            case 2 | 2:

Any integer x | x is exactly x, so those case values shoukd just be 1, 2 &c.

As for the clicks, if I let my eyes go out of focus the patterns look kinda sorta plausible, but with laser vision operating on a peephole basis I can see problems immediately.

    prevButtonStates = rData.buttons;
  
    uint8_t buttonsChanged = prevButtonStates ^ rData.buttons;

I stripped the comments. I routinely ignore/delete most comments in code I read here, and elsewhere TBH, as they are almost invariably gratuitous, misleading, out of date or just plain wrong.

The first line of code makes prevButtonStates the same as rData.buttons. The second line of code takes the bitwise exclusive or of identical variables, this will be 0, zero, as the bits in the two are the same, meaning that the xor result will be 0.

I can't go deeper at this time (in transit, tiny window). It is probably a matter of moving the code that grabs the previous state to after you are all done with any need to compare the current state to the previous state.

Here

        Mouse.press(MOUSE_LEFT);
        //Serial.print("On");
        buttonState = HIGH;

I'd leave the printing, and maybe even comment out the call to press() for now. And add printing to mouse up branch and so fort. In fact as a matter of keeping sane whilst developing code like this, I would use printing heavily and in preference to actually doing anything else, as exemplified by the sketch I provided for mode changing. Get the tree formed and working, then hang ornaments on it.

Most of my sketches are very chatty, I often don't even bother to remove the printing that was used to help with confirming the plausibility of the values of key variables and their proper informing of the flow through the code.

Where else are you gonna get the endless scrolling of text that is always on at least a few of the screens in any TV show about hackers or authorities chasing them? :expressionless:

Adding functionality should not be done by ripping out the guts of functions that do what you want, or nearly. Functions are meant to be used to afford a higher level organization to your code. It would be better to fix/tweak/enhance functions you find to bend them to your will, then call them.

Your working code has many lines all piled into the loop. Ideally, any code should make sense over a few dozen lines at most. A screenful. Longer shoukd be your clue that it needs to be broken up and swaths placed in functions.

a7

The switch x | y routine was my novice attempt at adding acceleration to the mouse. Maybe there is a better way and i've taken the long route. (as usual..)

As far as the button goes, I meant to remove

  buttonState = HIGH;

etc from lines of code as it was a flag for some other snippet I wanted to use for double clicks etc. so please ignore.

Thanks for pointing out:

 prevButtonStates = rData.buttons;

It was in the incorrect place and belongs before trackpad read and after trackpad is available.


  switch (theMode) {
    case RELATIVE:
    
      if (trackpad.available()) {
       // currentMillis = millis();
           prevButtonStates = rData.buttons;  // for edge detection

        trackpad.read(&rData);

And that worked!

I really appreciate all your help, guidance, and above all humor!

Nice. I'm about to call it, so it is good to see this.

Here

I hope you see that equivalent would be to grab the previous state at the end of the code section, as it is after all looping.

save the (old) value
read new value 

deal with old and new values


save the (old) value
read new value 

deal with old and new values


save the (old) value
read new value 

deal with old and new values

is identimical to

read new value 
deal with old and new values

save the new value


read new value 
deal with old and new values

save the new value


read new value 
deal with old and new values

save the new value

As a style matter, it is more usual to see the current recently read value being saved for "next time" at the end. But as we see here, it makes no difference, just is swimming upstream a bit.

As you read code, you will see while there is room creativity, the more you hew to convention the more readable by the masses (!) your code will be.

a7

Well said. I see the simplicity in your advice. I’ll improve the code and and the ez button and see where I can take this.