Using two different library functions in one code

What I am trying to do here is assign some pins to use the "Keyboard.h" library function ".write" while having other pins use the function ".press". The desired effect would be to have toggle switches operate on a basis of ".write" while having momentary switches use ".press". I have cannibalized this code from a popular keyboard macro repository, but I don't have enough knowledge to know if what I am trying to do is possible.

/*
 *  Project     'Stream Cheap' Mini Macro Keyboard
 *  @author     David Madison
 *  @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
 *  @license    MIT - Copyright (c) 2018 David Madison
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
 
// ---------------------------------
// Key definitions
#define BUTTON_KEY1 'r'
#define BUTTON_KEY2 KEY_F14
#define BUTTON_KEY3 KEY_F15
#define BUTTON_KEY4 KEY_F16
#define BUTTON_KEY5 KEY_F17
#define BUTTON_KEY6 KEY_F18
#define BUTTON_KEY7 KEY_F19
#define BUTTON_KEY8 KEY_F20
 
// Pin definitions
#define BUTTON_PIN1 2
#define BUTTON_PIN2 3
#define BUTTON_PIN3 4
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
// ---------------------------------
 
#include <Keyboard.h>
 
// Button helper class for handling press/release and debouncing
class button {
  public:
  const char key;
  const uint8_t pin;
 
  button(uint8_t k, uint8_t p) : key(k), pin(p){}
 
  void write(boolean state){
    if(state == pressed || (millis() - lastPressed  <= debounceTime)){
      return; // Nothing to see here, folks
    }
 
    lastPressed = millis();
 
    state ? Keyboard.write(key) : Keyboard.write(key); //So in this case "write" is used in lieu of ".press" and ".release" for toggle switches.    
    pressed = state;
  }
 
  void update(){
    write(!digitalRead(pin));
  }
 
  private:
  const unsigned long debounceTime = 30;
  unsigned long lastPressed = 0;
  boolean pressed = 0;
 
} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_KEY1, BUTTON_PIN1},
  {BUTTON_KEY2, BUTTON_PIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};
 
const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t ledPin = 17;
 
void setup() { 
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if(!digitalRead(1)){
    failsafe();
  }
 
  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;
 
  for(int i = 0; i < NumButtons; i++){
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}
 
void loop() {
  for(int i = 0; i < NumButtons; i++){
    buttons[i].update();
  }
}
 
void failsafe(){
  for(;;){} // Just going to hang out here for awhile :D
}

Sorry if this is in the wrong forum space.

Cheers!
~Blake

Confused. Are you not able to test the code? What does the library documentation have to say about the matter? What does the write() function do?

Okay, so I've tested the code using both "Keyboard.write" and "Keyboard.press" and they both work as intended i.e: "Keyboard.write" sends a single character on change in state, while "Keyboard.press" "presses" the character until followed by a state change that signals "Keboard.release". What I am trying to do is have one instance of the code working on the basis of "Keyboard.press" (followed by "Keyboard.release") on say, pins 3-8 while pins 1 and 2 work on the basis of "Keyboard.write".

I can't find anything in the documentation on combining the two functions.

Does that clear things up?

I have done some testing with duplicating parts of the code, but I'm having trouble isolating the functions to specific pins on my Arduino micro. I hope that makes sense?

Keyboard.write(x);
just does

Keyboard.press(x);
Keyboard.release(x);

so there should be no problem using both in the same sketch.

Ah, good to know. I appreciate the insight! Now I just have to figure out how this code works... I don't understand how it can know which pin is changing state without the matrix setup you see normally on keyboard projects. I may end up having to just stumble through writing up a sketch from scratch, or at least piecemeal something more on my level of understanding. The seeming simplicity of this code is proving to be deceptive in my case. If you have any recommendations for understanding the concepts behind the code, I would be all ears.

Each pin has a 'button' object. The button object keeps track of the previous state in 'pressed' so it can tell when a button is pressed or released.

Since you want some pins to act differently, you could add a third argument to the 'button' constructor:
button(uint8_t k, uint8_t p, bool b) : key(k), pin(p), behavior(b) {}
That way you can have the object remember which behavior you want for that pin.

EDIT: fixed code formatting

Okay, I think I'm beginning to understand the concept here.

I'm slowly trying to merge the two functions, slowly eliminating compiling errors. Still not sure if it will do what I want it to do, but here's what I've got so far:

/*
    Project     'Stream Cheap' Mini Macro Keyboard
    @author     David Madison
    @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
    @license    MIT - Copyright (c) 2018 David Madison

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.

*/

// ---------------------------------
// Key definitions
#define BUTTON_TOGGLE1 'r'
#define BUTTON_TOGGLE2 'b'
#define BUTTON_KEY3 'b'
#define BUTTON_KEY4 KEY_F16
#define BUTTON_KEY5 KEY_F17
#define BUTTON_KEY6 KEY_F18
#define BUTTON_KEY7 KEY_F19
#define BUTTON_KEY8 KEY_F20

// Pin definitions
#define BUTTON_TPIN1 2
#define BUTTON_TPIN2 3
#define BUTTON_PIN3 4
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
// ---------------------------------

#include <Keyboard.h>

// Button helper class for handling press/release and debouncing
class button {
  public:
    const char key;
    const char toggle;
    const uint8_t pin;
    const uint8_t tpin;
    
    button(uint8_t k, uint8_t p, uint8_t t, uint8_t tp) : key(k), pin(p), toggle(t), tpin(tp) {}

    void press(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }

      lastPressed = millis();

      state ? Keyboard.press(key) : Keyboard.release(key); 
      pressed = state;
    }

    void write(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }
 
      lastPressed = millis();

      state ? Keyboard.write(toggle) : Keyboard.write(toggle);
      pressed = state;
    }
        
    void update() {
      press(!digitalRead(pin));
      write(!digitalRead(tpin));
    }

  private:
    const unsigned long debounceTime = 30;
    unsigned long lastPressed = 0;
    boolean pressed = 0;

} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_TOGGLE1, BUTTON_TPIN1},
  {BUTTON_TOGGLE2, BUTTON_TPIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};

const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t ledPin = 17;

void setup() {
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if (!digitalRead(1)) {
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for (int i = 0; i < NumButtons; i++) {
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}

void loop() {
  for (int i = 0; i < NumButtons; i++) {
    buttons[i].update();
  }
}

void failsafe() {
  for (;;) {} // Just going to hang out here for awhile :D
}

I'm stuck on the error: could not convert '{'r', 2}' from '<brace-enclosed initializer list>' to 'button'

Am I on the right track or completely lost?

You have accelerated my learning tenfold, so I appreciate any help!

It looks like you took John's advice and added two more elements to the button constructor, but you haven't provided them in the declaration of your buttons array. I added two arbitrary numbers to the first element of the array and now the compiler accepts that line and is complaining about the second one.

Could I see your modified code? I'm having trouble understanding what you mean, sorry. I don't really have a mind for this sort of thing, but I appreciate your patience and assistance.

// Button objects, organized in array
button buttons[] =
{
  {BUTTON_TOGGLE1, BUTTON_TPIN1, 2, 3},
  {BUTTON_TOGGLE2, BUTTON_TPIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};

Oh that's fascinating! Why does that do anything? Just adding arbitrary numbers to the end of all of the array objects allows for error free compiling, whether it will function properly is the next challenge I suppose.

They are supposed to specify what the toggle and toggle pin that you added are supposed to be for that particular button. I used arbitrary numbers to prove it would compile because I don't know what you want them to be.

Okay, interesting. I don't think I'm understanding what the individual numbers do. In the example of: {BUTTON_TOGGLE1, BUTTON_TPIN1, 2, 3} , "2, 3" points to what? If I change the numbers, it seems to have no effect. Is that because I need to assign functions to those numbers somewhere else in the code? Say to the two different "Keyboard.___" functions? Again, so sorry, slow learner.

EDIT: So I found some correlation between the second digit and the pin number. If the digit corresponds with the pin number, the hardware functions as you would expect for the state ? Keyboard.press(key) : Keyboard.release(key); section of code. So that's all well and good. However, the first digit seems to have no effect at all. I can make it any digit it seems, including 0, it just has to be there or it wont compile. I'm not entirely sure what to make of all of this, but I think I'm making progress?

Perhaps I don't understand what you're trying to do. I thought the idea was to read pins using digitalRead and then send keyboard commands to something (a PC?).

You're using a button class to encapsulate the pins and the idea was to add a mode to indicate whether a particular pin detecting a press sends keyboard press and release or just one of them.

Instead your code writes on the pin and the new toggle pin, which is another mystery. Could you clarify what you're trying to make?

Yes I should clarify: Originally, I had written a simple program that would detect a change in state and write a character on state change. I'm trying to formulate a more sophisticated sketch that can change which keyboard library function is used on each pin. For example, as far as hardware is concerned, I have a few toggle switches that I would like to simply write a character on state change (that uses the Keyboard.write function). However, I've added some momentary switches that I would like to behave more like standard keyboard keys using the Keyboard.press and Keyboard.release functions. I can do either one successfully in independent sketches, but combining the two into one sketch is what's giving me trouble.

Can you post the two pieces of code that work? The one you're working on is confusing, especially as it never actually reads any of the pins on the Arduino.

You added two arguments to the 'constructor' function of the 'button' class but you did not specify values for those two arguments in your table of buttons.

You COULD have two different constructor functions. One which takes two arguments and one that takes four.

OR you could provide default values for the added arguments so the compiler would know what value to use if you don't specify them.

Sure thing. So the first one does a toggle-like function, while the second one does a momentary-like function.

Code (1)

/*
    Project     'Stream Cheap' Mini Macro Keyboard
    @author     David Madison
    @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
    @license    MIT - Copyright (c) 2018 David Madison

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.

*/

// ---------------------------------
// Key definitions
#define BUTTON_KEY1 'a'
#define BUTTON_KEY2 'b'
#define BUTTON_KEY3 'c'
#define BUTTON_KEY4 'd'
#define BUTTON_KEY5 'e'
#define BUTTON_KEY6 'f'
#define BUTTON_KEY7 'g'
#define BUTTON_KEY8 'h'

// Pin definitions
#define BUTTON_PIN1 2
#define BUTTON_PIN2 3
#define BUTTON_PIN3 4
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
// ---------------------------------

#include <Keyboard.h>

// Button helper class for handling press/release and debouncing
class button {
  public:
    const char key;
    const uint8_t pin;

    button(uint8_t k, uint8_t p) : key(k), pin(p) {}

    void press(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }

      lastPressed = millis();

      state ? Keyboard.press(key) : Keyboard.release(key);
      pressed = state;
    }

    void update() {
      press(!digitalRead(pin));
    }

  private:
    const unsigned long debounceTime = 30;
    unsigned long lastPressed = 0;
    boolean pressed = 0;

} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_KEY1, BUTTON_PIN1},
  {BUTTON_KEY2, BUTTON_PIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};

const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t ledPin = 17;

void setup() {
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if (!digitalRead(1)) {
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for (int i = 0; i < NumButtons; i++) {
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}

void loop() {
  for (int i = 0; i < NumButtons; i++) {
    buttons[i].update();
  }
}

void failsafe() {
  for (;;) {} // Just going to hang out here for awhile :D
}

Code (2)

/*
    Project     'Stream Cheap' Mini Macro Keyboard
    @author     David Madison
    @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
    @license    MIT - Copyright (c) 2018 David Madison

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.

*/

// ---------------------------------
// Key definitions
#define BUTTON_KEY1 'a'
#define BUTTON_KEY2 'b'
#define BUTTON_KEY3 'c'
#define BUTTON_KEY4 'd'
#define BUTTON_KEY5 'e'
#define BUTTON_KEY6 'f'
#define BUTTON_KEY7 'g'
#define BUTTON_KEY8 'h'

// Pin definitions
#define BUTTON_PIN1 2
#define BUTTON_PIN2 3
#define BUTTON_PIN3 4
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
// ---------------------------------

#include <Keyboard.h>

// Button helper class for handling press/release and debouncing
class button {
  public:
    const char key;
    const uint8_t pin;

    button(uint8_t k, uint8_t p) : key(k), pin(p) {}

    void write(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }

      lastPressed = millis();

      state ? Keyboard.write(key) : Keyboard.write(key); //So in this case "write" is used in lieu of ".press" and ".release" for toggle switches.
      pressed = state;
    }

    void update() {
      write(!digitalRead(pin));
    }

  private:
    const unsigned long debounceTime = 30;
    unsigned long lastPressed = 0;
    boolean pressed = 0;

} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_KEY1, BUTTON_PIN1},
  {BUTTON_KEY2, BUTTON_PIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};

const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t ledPin = 17;

void setup() {
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if (!digitalRead(1)) {
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for (int i = 0; i < NumButtons; i++) {
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}

void loop() {
  for (int i = 0; i < NumButtons; i++) {
    buttons[i].update();
  }
}

void failsafe() {
  for (;;) {} // Just going to hang out here for awhile :D
}

Okay, I get what you're saying, I've seen some examples of default values, however I'm unsure how to incorporate them in this code.

Would I add int values to the state section? void press(boolean state) { if (state == pressed || (millis() - lastPressed <= debounceTime)) { return; // Nothing to see here, folks
Or to the definitions? Or somewhere else?

UPDATE:
I have been playing around with creating two separate classes, and I can get the code to compile error free, but the code does not actually function at all. So my question is: am I on the right track with this code? Or am I miss understanding how classes work?

/*
    Project     'Stream Cheap' Mini Macro Keyboard
    @author     David Madison
    @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
    @license    MIT - Copyright (c) 2018 David Madison

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.

*/

// ---------------------------------
//Toggle definitions
#define TOGGLE_TKEY1 'a'
#define TOGGLE_TKEY2 'b'
#define TOGGLE_TKEY3 'c'

// Key definitions
#define BUTTON_KEY4 'd'
#define BUTTON_KEY5 'e'
#define BUTTON_KEY6 'f'
#define BUTTON_KEY7 'g'
#define BUTTON_KEY8 'h'

//Toggle Pin definitions
#define TOGGLE_TPIN1 2
#define TOGGLE_TPIN2 3
#define TOGGLE_TPIN3 4

// Pin definitions
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
// ---------------------------------

#include <Keyboard.h>

// Button helper class for handling press/release and debouncing
class button {
  public:
    const char key;
    const uint8_t pin;

    button(uint8_t k, uint8_t p) : key(k), pin(p) {}

    void press(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }

      lastPressed = millis();

      state ? Keyboard.press(key) : Keyboard.release(key); 
      pressed = state;
    }

    void update() {
      press(!digitalRead(pin));
    }

  private:
    const unsigned long debounceTime = 30;
    unsigned long lastPressed = 0;
    boolean pressed = 0;

} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
};

// Toggle helper class for handling press/release and debouncing
class toggle {
  public:
    const char tkey;
    const uint8_t tpin;

    toggle(uint8_t tk, uint8_t tp) : tkey(tk), tpin(tp) {}

    void write(boolean state) {
      if (state == pressed || (millis() - lastPressed  <= debounceTime)) {
        return; // Nothing to see here, folks
      }

      lastPressed = millis();

      state ? Keyboard.write(tkey) : Keyboard.write(tkey); //So in this case "write" is used in lieu of ".press" and ".release" for toggle switches.
      pressed = state;
    }

    void update() {
      write(!digitalRead(tpin));
    }

  private:
    const unsigned long debounceTime = 30;
    unsigned long lastPressed = 0;
    boolean pressed = 0;

} ;

// Button objects, organized in array
toggle toggles[] = {
  {TOGGLE_TKEY1, TOGGLE_TPIN1},
  {TOGGLE_TKEY2, TOGGLE_TPIN2},
  {TOGGLE_TKEY3, TOGGLE_TPIN3},
};

const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t NumToggles = sizeof(toggles) / sizeof(toggle);
const uint8_t ledPin = 17;

void setup() {
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if (!digitalRead(1)) {
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for (int i = 0; i < NumButtons; i++) {
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}

void loop() {
  for (int i = 0; i < NumButtons; i++) {
    buttons[i].update();
  }
}

void failsafe() {
  for (;;) {} // Just going to hang out here for awhile :D
}
void setup2() {
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if (!digitalRead(1)) {
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for (int i = 0; i < NumToggles; i++) {
    pinMode(toggles[i].tpin, INPUT_PULLUP);
  }
}

void loop2() {
  for (int i = 0; i < NumToggles; i++) {
    toggles[i].update();
  }
}

void failsafe2() {
  for (;;) {} // Just going to hang out here for awhile :D
}