Toggle and momentory switches, read all switches, keep sending keyboard press for one held down when a toggle state changes

Another SimRail controller i'm building (Polish railway simulator 'game') this time it's the door switch and 'driver safety / acknowledgement' button panel.

2 x toggle switches, a spring loaded toggle switch, 3 push buttons, 2 of them are illuminated buttons.

I have it working sending the required keyboard keys when i operate the switches, and push buttons, and lighting up the led's in the 2 push buttons when needed.

If i press one of the illuminated push buttons, it sends the keyboard key for changing the camera view,
if i press the other illuminated push button, it sends a different keyboard key for another camera view.

I'd like to be able to press both buttons together and have it send a 3rd keyboard key.

i.e. if left button pressed, sends key '1', right button pressed sends key '4', if both button pressed sends key '5'

i tried to do this with the 'state machine' is it? .. code i'm using, but it didn't work... one button is always detected pushed before the other, and of course that buttons key is sent as soon as it's pressed, then the other one.

I'm thinking i may need some more complex code to store the buttons pressed state and use a timer to detect if another button is pressed within a certain time send out the '5' key.
Or maybe better, detect a button held down for longer than say 150ms, and then wait for the next button to be pressed to send the '5' key (i could then have 2 extra keys sent, depending on which button i hold down first)

#include <Keyboard.h>  // Keyboard library

const int leftButtonPin = 2;            // Left 'doors open' light button
const int leftDoorTogglePin = 3;        // Pin left doors open / close toggle switch is connected to
const int doorsClosingBuzzerPin = 5;    // Doors closing buzzer switch
const int rightDoorTogglePin = 7;       // Right doors open / close toggle switch
const int rightButtonPin = 9;           // Right 'doors open' light button
const int shpPin = 10;                  // SHP button
const int leftDoorsOpenLightPin = A0;   // Left doors open light
const int rightDoorsOpenLightPin = A1;  // Right doors open light

int leftButtonState = 0;      // current state of the switch
int lastleftButtonState = 0;  // previous state of the switch

int leftDoorToggleState = 0;
int lastleftDoorToggleState = 0;

int doorsClosingBuzzerState = 0;
int lastdoorsClosingBuzzerState = 0;

int rightDoorToggleState = 0;
int lastrightDoorToggleState = 0;

int rightButtonState = 0;
int lastrightButtonState = 0;

int shpState = 0;
int lastshpState = 0;

void setup() {
  Keyboard.begin();  // start keyboard functions

  //==Serial.begin(9600);

  //Define input pin modes
  pinMode(leftButtonPin, INPUT_PULLUP);
  pinMode(leftDoorTogglePin, INPUT_PULLUP);
  pinMode(doorsClosingBuzzerPin, INPUT_PULLUP);
  pinMode(rightDoorTogglePin, INPUT_PULLUP);
  pinMode(rightButtonPin, INPUT_PULLUP);
  pinMode(shpPin, INPUT_PULLUP);
  //Define output pin modes
  pinMode(leftDoorsOpenLightPin, OUTPUT);
  pinMode(rightDoorsOpenLightPin, OUTPUT);
  analogWrite(leftDoorsOpenLightPin, 0);  // Make sure led if off on startup
  analogWrite(rightDoorsOpenLightPin, 0);

}  // End of void setup

void loop() {
  // read the switch input pins:
  leftButtonState = digitalRead(leftButtonPin);
  leftDoorToggleState = digitalRead(leftDoorTogglePin);
  doorsClosingBuzzerState = digitalRead(doorsClosingBuzzerPin);
  rightDoorToggleState = digitalRead(rightDoorTogglePin);
  rightButtonState = digitalRead(rightButtonPin);
  shpState = digitalRead(shpPin);

  if (leftButtonState != lastleftButtonState) {  // compare the switchState to its previous state
    if (leftButtonState == LOW) {                // if the current state is LOW then the button went from off to on:
      Keyboard.print('1');                       // Send single '1' key, sets camera to cab view
    }
  }

  if (leftDoorToggleState != lastleftDoorToggleState) {
    if (leftDoorToggleState == LOW) {
      analogWrite(leftDoorsOpenLightPin, 255);  // Turn on left led when left door switch is on
      Keyboard.print('[');                      // Send single '[' key for Doors Left Open
    } else {
      analogWrite(leftDoorsOpenLightPin, 0);  // Turn off led when switch off
      Keyboard.print('=');                    //Send single '=' key for doors close
    }
  }

  if (doorsClosingBuzzerState != lastdoorsClosingBuzzerState) {
    if (doorsClosingBuzzerState == LOW) {
      Keyboard.press('-');  // Press and hold '-' key for Doors Closing Buzzer
    } else {
      Keyboard.release('-');  // Release minus key
    }
  }

  if (rightDoorToggleState != lastrightDoorToggleState) {
    if (rightDoorToggleState == LOW) {
      analogWrite(rightDoorsOpenLightPin, 255);
      Keyboard.print(']');  //Send single ']' key for Doors Open Right
    } else {
      analogWrite(rightDoorsOpenLightPin, 0);
      Keyboard.print('=');  // Send single '=' key for Doors Close
    }
  }

  if (rightButtonState != lastrightButtonState) {
    if (rightButtonState == LOW) {
      Keyboard.print('4');  // Send single '4' key, changes camera to external view, looking back along train, press again to cycle to next external view camera
    }
  }

  /*  NOT WORKING:
  if (rightButtonState != lastrightButtonState && leftButtonState != lastleftButtonState) { 
  if (rightButtonState == LOW && leftButtonState == LOW) {// If both buttons pressed together
    Keyboard.print('5');  // trying to send single 5 key that will change camera to 'previous' external view, 
}*/

  if (shpState != lastshpState) {
    if (shpState == LOW) {
      Keyboard.press(32);  // Press and hold spacebar key
    } else if (shpState == HIGH) {
      Keyboard.release(32);  // Release spacebar key
    }
  }

  delay(50);  // Delay to avoid switch bounce

  // Save the current state as the last state for next time through the loop
  lastleftButtonState = leftButtonState;
  lastleftDoorToggleState = leftDoorToggleState;
  lastdoorsClosingBuzzerState = doorsClosingBuzzerState;
  lastrightDoorToggleState = rightDoorToggleState;
  lastrightButtonState = rightButtonState;
  lastshpState = shpState;
}  //end of void loop

Then test for both buttons being pressed before testing the individual buttons

You will have to keep track of what the last key was and when it was pressed. Untested:

#include <Keyboard.h>  // Keyboard library

const int leftButtonPin = 2;            // Left 'doors open' light button
const int leftDoorTogglePin = 3;        // Pin left doors open / close toggle switch is connected to
const int doorsClosingBuzzerPin = 5;    // Doors closing buzzer switch
const int rightDoorTogglePin = 7;       // Right doors open / close toggle switch
const int rightButtonPin = 9;           // Right 'doors open' light button
const int shpPin = 10;                  // SHP button
const int leftDoorsOpenLightPin = A0;   // Left doors open light
const int rightDoorsOpenLightPin = A1;  // Right doors open light

int leftButtonState = 0;      // current state of the switch
int lastleftButtonState = 0;  // previous state of the switch

int leftDoorToggleState = 0;
int lastleftDoorToggleState = 0;

int doorsClosingBuzzerState = 0;
int lastdoorsClosingBuzzerState = 0;

int rightDoorToggleState = 0;
int lastrightDoorToggleState = 0;

int rightButtonState = 0;
int lastrightButtonState = 0;

int shpState = 0;
int lastshpState = 0;

int lastKey;
unsigned long laskKeyTime;
const unsigned long lastKeyInterval = 250;   // max time to press 2 keys "at the same time"

void setup() {
  Keyboard.begin();  // start keyboard functions

  //==Serial.begin(9600);

  //Define input pin modes
  pinMode(leftButtonPin, INPUT_PULLUP);
  pinMode(leftDoorTogglePin, INPUT_PULLUP);
  pinMode(doorsClosingBuzzerPin, INPUT_PULLUP);
  pinMode(rightDoorTogglePin, INPUT_PULLUP);
  pinMode(rightButtonPin, INPUT_PULLUP);
  pinMode(shpPin, INPUT_PULLUP);
  //Define output pin modes
  pinMode(leftDoorsOpenLightPin, OUTPUT);
  pinMode(rightDoorsOpenLightPin, OUTPUT);
  analogWrite(leftDoorsOpenLightPin, 0);  // Make sure led if off on startup
  analogWrite(rightDoorsOpenLightPin, 0);

}  // End of void setup

void loop() {
  // read the switch input pins:
  leftButtonState = digitalRead(leftButtonPin);
  leftDoorToggleState = digitalRead(leftDoorTogglePin);
  doorsClosingBuzzerState = digitalRead(doorsClosingBuzzerPin);
  rightDoorToggleState = digitalRead(rightDoorTogglePin);
  rightButtonState = digitalRead(rightButtonPin);
  shpState = digitalRead(shpPin);

  if (leftButtonState != lastleftButtonState) {  // compare the switchState to its previous state
    if (leftButtonState == LOW) {                // if the current state is LOW then the button went from off to on:
      //Keyboard.print('1');                       // Send single '1' key, sets camera to cab view
      if ( lastKey == '4' ) {
        // send combo
        Keyboard.print('5');
        lastKey = 0;
      }
      else {
        // remember key press but do not transmit yet
        lastKey = '1';
        lastKeyTime = millis();
      }
    }
  }

  if (rightButtonState != lastrightButtonState) {
    if (rightButtonState == LOW) {
      //Keyboard.print('4');  // Send single. '4' key, changes camera to external view, looking back along train, press again to cycle to next external view camera
      if ( lastKey == '1' ) {
        // send combo
        Keyboard.print('5');
        lastKey = 0;
      }
      else {
        // remember key press but do not transmit yet
        lastKey = '4';
        lastKeyTime = millis();
      }
    }
  }

  // check if single key press waiting long enough
  if ( lastKey && millis() - lastKeyTime >= laskKeyInterval ) {
    Keyboard.print(lastKey);
    lastKey = 0;
  }

  if (leftDoorToggleState != lastleftDoorToggleState) {
    // transmit saved key, if present
    if ( lastKey ) {
      Keyboard.print(lastKey );
      lastKey = 0;
    }
    if (leftDoorToggleState == LOW) {
      analogWrite(leftDoorsOpenLightPin, 255);  // Turn on left led when left door switch is on
      Keyboard.print('[');                      // Send single '[' key for Doors Left Open
    } else {
      analogWrite(leftDoorsOpenLightPin, 0);  // Turn off led when switch off
      Keyboard.print('=');                    //Send single '=' key for doors close
    }
  }

  if (doorsClosingBuzzerState != lastdoorsClosingBuzzerState) {
    // transmit saved key, if present
    if ( lastKey ) {
      Keyboard.print(lastKey );
      lastKey = 0;
    }
    if (doorsClosingBuzzerState == LOW) {
      Keyboard.press('-');  // Press and hold '-' key for Doors Closing Buzzer
    } else {
      Keyboard.release('-');  // Release minus key
    }
  }

  if (rightDoorToggleState != lastrightDoorToggleState) {
    // transmit saved key, if present
    if ( lastKey ) {
      Keyboard.print(lastKey );
      lastKey = 0;
    }
    if (rightDoorToggleState == LOW) {
      analogWrite(rightDoorsOpenLightPin, 255);
      Keyboard.print(']');  //Send single ']' key for Doors Open Right
    } else {
      analogWrite(rightDoorsOpenLightPin, 0);
      Keyboard.print('=');  // Send single '=' key for Doors Close
    }
  }


  /*  NOT WORKING:
    if (rightButtonState != lastrightButtonState && leftButtonState != lastleftButtonState) {
    if (rightButtonState == LOW && leftButtonState == LOW) {// If both buttons pressed together
    Keyboard.print('5');  // trying to send single 5 key that will change camera to 'previous' external view,
    }*/

  if (shpState != lastshpState) {
    // transmit saved key, if present
    if ( lastKey ) {
      Keyboard.print(lastKey );
      lastKey = 0;
    }
    if (shpState == LOW) {
      Keyboard.press(32);  // Press and hold spacebar key
    } else if (shpState == HIGH) {
      Keyboard.release(32);  // Release spacebar key
    }
  }

  delay(50);  // Delay to avoid switch bounce

  // Save the current state as the last state for next time through the loop
  lastleftButtonState = leftButtonState;
  lastleftDoorToggleState = leftDoorToggleState;
  lastdoorsClosingBuzzerState = doorsClosingBuzzerState;
  lastrightDoorToggleState = rightDoorToggleState;
  lastrightButtonState = rightButtonState;
  lastshpState = shpState;
}  //end of void loop

Thankyou for the sketch,

Changed 2 k's that should be t's and it compiles and runs,

it's working regards the sending of keyboard key '5' when both buttons are pressed,
but a single button press sends '49' for the left button press, or '52' for the right button press.

found it.

"Keyboard.print(lastKey);" is sending the ascii code .. 1 being 49, and 4 being 52.

So i changed it to "Keyboard.write(lastKey);" and it's working.

Thankyou very much for the help with this.

The working code is posted below,
So if people search for 'SimRail' on the forum they will find this post (and my other ones about my 3D printed controllers i've been making)
And hopefully this can help others who are making controllers for the sim before we get the full input/output home cockpit capability.

/*            SimRail EN57 door switch and SHP / Czuwak button panel
Read toggle switches and button state changes, send keyboard keys to control functions in the simulator, illuminate the led's in the left or right buttons when left or right doors open toggle switch is on.
The illuminated pushbuttons are used to change camera views, pressing the right button changes the camera to 'external view back along train' pressing it again cycles the views forwards.
Pressing the left button cycles the external views backwards. Pressing left then right buttons changes the view to the in cab camera, and pressing right then left buttons changes to rear of train camera.
*/

#include <Keyboard.h>  // Keyboard library

const int leftButtonPin = 2;            // Left 'doors open' light button
const int leftDoorTogglePin = 3;        // Pin left doors open / close toggle switch is connected to
const int doorsClosingBuzzerPin = 5;    // Doors closing buzzer switch
const int rightDoorTogglePin = 7;       // Right doors open / close toggle switch
const int rightButtonPin = 9;           // Right 'doors open' light button
const int shpPin = 10;                  // SHP button
const int leftDoorsOpenLightPin = A0;   // Left doors open light
const int rightDoorsOpenLightPin = A1;  // Right doors open light

int leftButtonState = 0;      // current state of the switch
int lastleftButtonState = 0;  // previous state of the switch

int leftDoorToggleState = 0;
int lastleftDoorToggleState = 0;

int doorsClosingBuzzerState = 0;
int lastdoorsClosingBuzzerState = 0;

int rightDoorToggleState = 0;
int lastrightDoorToggleState = 0;

int rightButtonState = 0;
int lastrightButtonState = 0;

int shpState = 0;
int lastshpState = 0;

int lastKey;                                // Used to store last key detected, allows pressing 2 buttons together to send a different key
unsigned long lastKeyTime;                  // Store time since last key pressed
const unsigned long lastKeyInterval = 300;  // max time (in milliseconds)to press 2 keys "at the same time"

void setup() {
  Keyboard.begin();  // start keyboard functions
  //Define input pin modes
  pinMode(leftButtonPin, INPUT_PULLUP);
  pinMode(leftDoorTogglePin, INPUT_PULLUP);
  pinMode(doorsClosingBuzzerPin, INPUT_PULLUP);
  pinMode(rightDoorTogglePin, INPUT_PULLUP);
  pinMode(rightButtonPin, INPUT_PULLUP);
  pinMode(shpPin, INPUT_PULLUP);
  //Define output pin modes
  pinMode(leftDoorsOpenLightPin, OUTPUT);
  pinMode(rightDoorsOpenLightPin, OUTPUT);
  analogWrite(leftDoorsOpenLightPin, 0);  // Make sure led is off on startup
  analogWrite(rightDoorsOpenLightPin, 0);

}  // End of void setup

void loop() {
  // read the switch input pins:
  leftButtonState = digitalRead(leftButtonPin);
  leftDoorToggleState = digitalRead(leftDoorTogglePin);
  doorsClosingBuzzerState = digitalRead(doorsClosingBuzzerPin);
  rightDoorToggleState = digitalRead(rightDoorTogglePin);
  rightButtonState = digitalRead(rightButtonPin);
  shpState = digitalRead(shpPin);

  if (leftButtonState != lastleftButtonState) {  // compare the switchState to its previous state
    if (leftButtonState == LOW) {                // if the current state is LOW then the button went from off to on:
      if (lastKey == '4') {                      // Check if 'rightButton' is pressed
        // send combo
        Keyboard.write('6');  // if right then left buttons pressed within 300ms, send single '6' key (change view to last camera, end of train)
        lastKey = 0;          // reset lastKey int to empty
      } else {
        // remember key press but do not transmit yet
        lastKey = '5';           // Send single '5' key, sets view to previous outside camera.
        lastKeyTime = millis();  // when timer runs out, send key
      }
    }
  }

  if (rightButtonState != lastrightButtonState) {
    if (rightButtonState == LOW) {
      if (lastKey == '5') {  // check if 'leftButton' is pressed
        Keyboard.write('1'); // if left then right buttons pressed within 300ms, send single '1' key when both buttons pressed together (change to cab view camera)
        lastKey = 0;
      } else {
        lastKey = '4'; // send single '4' key, (change view to look back along train)
        lastKeyTime = millis();
      }
    }
  }

  // check if single key press waiting long enough
  if (lastKey && millis() - lastKeyTime >= lastKeyInterval) { 
    Keyboard.write(lastKey); // send relevent keyboard key event
    lastKey = 0; // reset lastKey int to empty
  }

  if (leftDoorToggleState != lastleftDoorToggleState) {
    // transmit saved key, if present
    if (lastKey) {
      Keyboard.write(lastKey);
      lastKey = 0;
    }
    if (leftDoorToggleState == LOW) {
      analogWrite(leftDoorsOpenLightPin, 255);  // Turn on left led when left door switch is on
      Keyboard.write('[');                      // Send single '[' key for Doors Left Open
    } else {
      analogWrite(leftDoorsOpenLightPin, 0);  // Turn off led when switch off
      Keyboard.write('=');                    //Send single '=' key for doors close
    }
  }

  if (doorsClosingBuzzerState != lastdoorsClosingBuzzerState) {
    // transmit saved key, if present
    if (lastKey) {
      Keyboard.write(lastKey);
      lastKey = 0;
    }
    if (doorsClosingBuzzerState == LOW) {
      Keyboard.press('-');  // Press and hold '-' key for Doors Closing Buzzer
    } else {
      Keyboard.release('-');  // Release minus key
    }
  }

  if (rightDoorToggleState != lastrightDoorToggleState) {
    // transmit saved key, if present
    if (lastKey) {
      Keyboard.write(lastKey);
      lastKey = 0;
    }
    if (rightDoorToggleState == LOW) {
      analogWrite(rightDoorsOpenLightPin, 255);
      Keyboard.write(']');  //Send single ']' key for Doors Open Right
    } else {
      analogWrite(rightDoorsOpenLightPin, 0);
      Keyboard.write('=');  // Send single '=' key for Doors Close
    }
  }

  if (shpState != lastshpState) {
    // transmit saved key, if present
    if (lastKey) {
      Keyboard.write(lastKey);
      lastKey = 0;
    }
    if (shpState == LOW) {
      Keyboard.press(32);  // Press and hold spacebar key
    } else if (shpState == HIGH) {
      Keyboard.release(32);  // Release spacebar key
    }
  }

  delay(50);  // Delay to avoid switch bounce

  // Save the current state as the last state for next time through the loop
  lastleftButtonState = leftButtonState;
  lastleftDoorToggleState = leftDoorToggleState;
  lastdoorsClosingBuzzerState = doorsClosingBuzzerState;
  lastrightDoorToggleState = rightDoorToggleState;
  lastrightButtonState = rightButtonState;
  lastshpState = shpState;
}  //end of void loop

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.