I'm trying to make one event happen only if two other events occur . .

. . . in essence, I need for my Leonardo to take the direction: "if (and only if) Event A AND Event B occurs, then Event C will occur": I have given a Keystroke combination to a Rotary Encoder (Enter+Up/Down), but I'd like for it to occur only if and after a button (button1) has been pressed. Button 1 is, itself, another Keystroke (the Pause Key).

I read various threads last night, and learned about &&, and tried it out extensively but didn't achieve my goal.

Here is the entire sketch (it derives from TTapa's Control-Surface):

#include <RotaryEncoder.h>
#include <Keyboard.h>

// Rotary Encoder
#define RE_A  7  // "CLK"
#define RE_B  6  // "DT"
#define RE_SW 2  // "SW"
RotaryEncoder encoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03);

int     last_sw;
int     sw_cnt;

// Button Stuff

// constants won't change. They're used here to set pin numbers:
const int button1Pin = 9;  // the number of the pushbutton pin
const int button2Pin = 14; // the number of the pusbutton pin
const int button3Pin = 15; // the number of the pushbutton pin
const int ledPin = 13;     // the number of the LED pin

// variables will change:
int button1State = 0;  // variable for reading the pushbutton status
int button2State = 0;  // variable for reading the pushbutton status
int button3State = 0;  // variable for reading the pushbutton status

void setup() {
 
  // Initialise the encoder switch
  pinMode(RE_SW, INPUT_PULLUP);
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pins as an input:
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);  
  pinMode(button3Pin, INPUT);  
}

int re_pos = 0;
void loop() {
  
  // Read the rotary encoder
  encoder.tick();

  int new_pos = encoder.getPosition();
  if (new_pos != re_pos) {
    int re_dir = (int)encoder.getDirection();
    if (re_dir < 0) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);
      Keyboard.release(KEY_UP_ARROW);
    } 
      else if (re_dir > 0) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);      
      Keyboard.release(KEY_DOWN_ARROW);
    } 
      else {
      // if re_dir == 0; do nothing
      }  
        re_pos = new_pos;  
  }

  // read the state of the pushbutton value:
  button1State = digitalRead(button1Pin);
  button2State = digitalRead(button2Pin);  
  button3State = digitalRead(button3Pin);

  
  // check if the pushbutton 1 is pressed. If it is, the buttonState is LOW: 
  if (button1State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_PAUSE);
    Keyboard.release(KEY_PAUSE);
  } 
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);

  // check if the pushbutton 2 is pressed. If it is, the buttonState is LOW:
  if (button2State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  } 
    
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);  

  // check if the pushbutton 3 is pressed. If it is, the buttonState is LOW:
  if (button3State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  }              

 // Check the encoder switch with some software debouncing
  int re_sw = digitalRead(RE_SW);
  if (re_sw == HIGH) {
    // No switch pressed yet
    sw_cnt = 0;
    last_sw = HIGH;
  } else {
    sw_cnt++;
  }
  if ((last_sw==HIGH) && (sw_cnt >= 1000)) {
    // Switch is triggered!
    sw_cnt = 0;
    last_sw = LOW;
    Keyboard.press(KEY_RETURN);
    Keyboard.release(KEY_RETURN);
       }
      }
    }
  }

. . . and here are the things I've tried:



  int new_pos = encoder.getPosition();
  if (new_pos != re_pos) {
    int re_dir = (int)encoder.getDirection ();
    if  (re_dir < 0 && (button1State ==LOW)) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);
      Keyboard.release(KEY_UP_ARROW);
    } 
      else if (re_dir > 0 && (button1State ==LOW)) {  
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);      
      Keyboard.release(KEY_DOWN_ARROW);
    } 
      else {
      // if re_dir == 0; do nothing
      }  
        re_pos = new_pos;  
    }

Nope-didn't work.
Tried this:

int new_pos = encoder.getPosition();
  if (new_pos != re_pos && (button1State ==LOW)) {
    int re_dir = (int)encoder.getDirection ();
    if  (re_dir < 0 ) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);
      Keyboard.release(KEY_UP_ARROW);
    } 
      else if (re_dir > 0) {  
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);      
      Keyboard.release(KEY_DOWN_ARROW);
    } 
      else {
      // if re_dir == 0; do nothing
      }  
        re_pos = new_pos;  
    }

. . . still a no.

And I tried a whole bunch of other permutations, involving actually entering the Keystrokes that make up the macro button1State (Keyboard.press(KEY_PAUSE) and Keyboard.release(KEY_PAUSE)) as additional actions preceeding the whole KEY_RIGHT_CTRL, KEY_UP_ARROW, etc. in both the re_dir < 0 and re_dir > 0 sections. Still nothing.

Can someone out there help me figure out how to achieve this. I sense that it has to be possible and I'm just not yet knowledgeable enough to figure it out on my own.

What is keeping the button inputs HIGH when teh buttons are not pressed ?

If you don't have external pull-up resistors on these then they should probably be defined as INPUT_PULLUP, otherwise you cannot assume their value when not pressed.

I'm guessing its the resistors? I have 1.1k resistors going from the positive leg of the button to VCC. and then also on that same trace is the line going from button positive leg to the corresponding pin on the Leonardo (button 1 goes to pin 9, button 2 goes to pin 14 and button 3 goes to pin 15.

So, the resistors I've mentioned are exactly the "external pull-up resistors" that you're speaking of, right? That's what they are, Pull-up Resistors, correct?

Are you now doing this at the top of loop? That is, before your if( * && *) statement ?

Yes... but you can get rid of them if you use INPUT_PULLUP to define the pins.

Yes, these buttonstate reads are occurring before the whole Keyboard.press/release routine occurs.

So are you thinking that the button state read should go after all the Keyboard.press/release/&& routine?

No... just wanted to check you had moved from the original version. Can you post the complete code that is not working.

I just tried entering this code in question

( button1State = digitalRead(button1Pin);
button2State = digitalRead(button2Pin);
button3State = digitalRead(button3Pin):wink:

on line 68. Didn't work.

need ALL the code

#include <RotaryEncoder.h>
#include <Keyboard.h>

// Rotary Encoder
#define RE_A  7  // "CLK"
#define RE_B  6  // "DT"
#define RE_SW 2  // "SW"
RotaryEncoder encoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03);

int     last_sw;
int     sw_cnt;

// Button Stuff

// constants won't change. They're used here to set pin numbers:
const int button1Pin = 9;  // the number of the pushbutton pin
const int button2Pin = 14; // the number of the pusbutton pin
const int button3Pin = 15; // the number of the pushbutton pin
const int ledPin = 13;     // the number of the LED pin

// variables will change:
int button1State = 0;  // variable for reading the pushbutton status
int button2State = 0;  // variable for reading the pushbutton status
int button3State = 0;  // variable for reading the pushbutton status

void setup() {
 
  // Initialise the encoder switch
  pinMode(RE_SW, INPUT_PULLUP);
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pins as an input:
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);  
  pinMode(button3Pin, INPUT);  
}

int re_pos = 0;
void loop() {
  

  // read the state of the pushbutton value:
  button1State = digitalRead(button1Pin);
  button2State = digitalRead(button2Pin);  
  button3State = digitalRead(button3Pin);  

  // Read the rotary encoder
  encoder.tick();

  int new_pos = encoder.getPosition();
  if (new_pos != re_pos && (button1State ==LOW)) {
    int re_dir = (int)encoder.getDirection ();
    if  (re_dir < 0 ) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);
      Keyboard.release(KEY_UP_ARROW);
    } 
      else if (re_dir > 0 && (button1State ==LOW)) {  
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);      
      Keyboard.release(KEY_DOWN_ARROW);
    } 
      else {
      // if re_dir == 0; do nothing
      }  
        re_pos = new_pos;  
    }
  
  // check if the pushbutton 1 is pressed. If it is, the buttonState is LOW: 
  if (button1State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_PAUSE);
    Keyboard.release(KEY_PAUSE);
  } 
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);

  // check if the pushbutton 2 is pressed. If it is, the buttonState is LOW:
  if (button2State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  } 
    
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);  

  // check if the pushbutton 3 is pressed. If it is, the buttonState is LOW:
  if (button3State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  }              

 // Check the encoder switch with some software debouncing
  int re_sw = digitalRead(RE_SW);
  if (re_sw == HIGH) {
    // No switch pressed yet
    sw_cnt = 0;
    last_sw = HIGH;
  } else {
    sw_cnt++;
  }
  if ((last_sw==HIGH) && (sw_cnt >= 1000)) {
    // Switch is triggered!
    sw_cnt = 0;
    last_sw = LOW;
    Keyboard.press(KEY_RETURN);
    Keyboard.release(KEY_RETURN);
       }
      }
    }
  }
      
       
      

Second one coming . . .

#include <RotaryEncoder.h>
#include <Keyboard.h>

// Rotary Encoder
#define RE_A  7  // "CLK"
#define RE_B  6  // "DT"
#define RE_SW 2  // "SW"
RotaryEncoder encoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03);

int     last_sw;
int     sw_cnt;

// Button Stuff

// constants won't change. They're used here to set pin numbers:
const int button1Pin = 9;  // the number of the pushbutton pin
const int button2Pin = 14; // the number of the pusbutton pin
const int button3Pin = 15; // the number of the pushbutton pin
const int ledPin = 13;     // the number of the LED pin

// variables will change:
int button1State = 0;  // variable for reading the pushbutton status
int button2State = 0;  // variable for reading the pushbutton status
int button3State = 0;  // variable for reading the pushbutton status

void setup() {
 
  // Initialise the encoder switch
  pinMode(RE_SW, INPUT_PULLUP);
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pins as an input:
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);  
  pinMode(button3Pin, INPUT);  
}

int re_pos = 0;
void loop() {
  

  // read the state of the pushbutton value:
  button1State = digitalRead(button1Pin);
  button2State = digitalRead(button2Pin);  
  button3State = digitalRead(button3Pin);  

  // Read the rotary encoder
  encoder.tick();

  int new_pos = encoder.getPosition();
  if (new_pos != re_pos && (button1State ==LOW)) {
    int re_dir = (int)encoder.getDirection ();
    if  (re_dir < 0 ) {
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_UP_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);
      Keyboard.release(KEY_UP_ARROW);
    } 
      else if (re_dir > 0) {  
      Keyboard.press(KEY_RIGHT_CTRL);
      Keyboard.press(KEY_DOWN_ARROW);
      Keyboard.release(KEY_RIGHT_CTRL);      
      Keyboard.release(KEY_DOWN_ARROW);
    } 
      else {
      // if re_dir == 0; do nothing
      }  
        re_pos = new_pos;  
    }
  
  // check if the pushbutton 1 is pressed. If it is, the buttonState is LOW: 
  if (button1State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_PAUSE);
    Keyboard.release(KEY_PAUSE);
  } 
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);

  // check if the pushbutton 2 is pressed. If it is, the buttonState is LOW:
  if (button2State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  } 
    
    else {
    // turn LED off:
        digitalWrite(ledPin, HIGH);  

  // check if the pushbutton 3 is pressed. If it is, the buttonState is LOW:
  if (button3State ==LOW) {
    // initiates the pressing of the Pause Key:
    Keyboard.press(KEY_RETURN);
    Keyboard.press(KEY_KP_1);
    Keyboard.release(KEY_RETURN);
    Keyboard.release(KEY_KP_1);
  }              

 // Check the encoder switch with some software debouncing
  int re_sw = digitalRead(RE_SW);
  if (re_sw == HIGH) {
    // No switch pressed yet
    sw_cnt = 0;
    last_sw = HIGH;
  } else {
    sw_cnt++;
  }
  if ((last_sw==HIGH) && (sw_cnt >= 1000)) {
    // Switch is triggered!
    sw_cnt = 0;
    last_sw = LOW;
    Keyboard.press(KEY_RETURN);
    Keyboard.release(KEY_RETURN);
       }
      }
    }
  }
      
       
      

Just to be clear...

when you say "after"... you mean the rotary encoder should be ignored until you press button1... and then even if you release button1 you wait for the next encoder change? or does button1 need to be held down?

Good question: I would like for it to be wherein I simply have to press the Pause button (button 1), and only then does my program (Cubase) pay attention to the keystrokes sent by the Rotary Encoder (which would be the Enter+Up/Down).

And: I am looking for just one press and release of the button 1 in order to actuate this. In other words: I am not wanting to have to continue holding button 1 in order for the Encoder to continue to be listened to.

The Encoder is flipping through the Tempo field (i.e.: the bpm number field is selected via Pause (assigned to "Enter Tempo" in Key Commands in Cubase), and as soon as I come across a tempo I like, at that point I press the Encoder Switch, which is assigned to Enter, which finalizes the selection.

At that point the Tempo field is no longer selected, and so it is at this point where I want the Encoder to be returned to a state of being disregarded by Cubase-until the next time I press the button 1, and the whole cycle starts over again.

In that case you need to organise your program differently.

Think of it like this... you are either in "pause state" or you aren't. Pressing button1 can be used to toggle between "paused" and "not paused"

You could do this with a boolean to keep track of things.

boolean paused = false;

then toggle when button1 is pressed.

button1State = digitalRead(button1Pin);
if (button1State != button1Previous). 
{
  paused = !paused;  // Toggle paused state
  button1Previous = button1State;  // Keep track of previous value so we only do stuff when it changes.
}

Then use paused to work out whether to read the encoder...

if (paused)
{
  // do the encoder stuff
}

Ok-thank you for all of that.

I'm not sure if you were able to glean from all of this, but I am very, very new to the world of Coding, and so I'm going to have to take some time to get my head around the solution you're proposing.

It makes perfect sense to me conceptually, but as with all coding, it's all in how you say it.

Like, as a for instance: I'm not sure where I'd enter this code you've written. It looks like your last entry ("if (paused) . . . ) needs to go, maybe at line 49 (just before int new_pos = . . . ), though I'm not sure.

And I'm fine with learning through Trial and Error-that's what I've been doing for the past week and a half. It's just that, as I've said before, it'll take a little bit of time for me to digest the whole thing.

If you have any more insights into the syntax/placement issues I'm bringing up now, I'm certainly thankful for them. At any rate, thanks again for the insights you've already given.