From c37e4a6789ee0502372860467fcb616430465d0f Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 14:49:53 -0400
Subject: [PATCH 1/8] Add new behavior for a button that sends separate
 keypresses on press and release. This required a refactor of the button
 abstraction as well.

---
 Joystick.cpp | 50 +++++++++++++++++++++++++++++++++-----------------
 Joystick.h   | 23 +++++++++++++++--------
 Readme.md    |  2 +-
 3 files changed, 49 insertions(+), 26 deletions(-)

diff --git a/Joystick.cpp b/Joystick.cpp
index 57c76b5..738f423 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -1,5 +1,8 @@
 #include "Joystick.h"
 #include <Arduino.h>
+#include <list>
+
+using std::list;
 
 bool operator ==(JoyReport a, JoyReport b){
   for (uint8_t i=0; i < JOYSTICK_NUM_AXES; i++) {
@@ -17,16 +20,13 @@ bool operator !=(JoyReport a, JoyReport b){
 
 Joystick::Joystick(bool debug) {
   _debug = debug;
-  _num_buttons = 0;
+  _last_button_index = 0;
   _num_axes = 0;
   _have_pulsed_button = false;
   
   for (uint8_t i=0; i < JOYSTICK_NUM_AXES; i++) {
     _joyReport.axis[i] = 0;
   }
-  for (uint8_t i=0; i < JOYSTICK_NUM_BYTES; i++) {
-    _joyReport.button[i] = 0;
-  }
 }
 
 void Joystick::Init() {
@@ -42,9 +42,21 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
   Button button;
   button.type = type;
   button.bouncer.attach(pin, mode);
+  uint8_t index = _last_button_index + 1;
+  uint8_t increment = 1;
+  button.index0 = index;
 
-  _buttons[_num_buttons] = button;
-  _num_buttons++;
+  if (type == BUTTON_PULSED_DOUBLE_ACTION_SPLIT) {
+    increment = 2;
+    button.index1 = index + 1;
+  }
+  
+  if (_last_button_index + increment > JOYSTICK_NUM_BUTTONS) {
+      // todo: fail here
+  }
+
+  _buttons.push_back(button);
+  last_button_index += increment;
 
   if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
 }
@@ -57,8 +69,8 @@ void Joystick::AddAxis(uint8_t pin) {
 void Joystick::Update() {
   JoyReport oldReport = _joyReport;
   
-  for (int i = 0; i < _num_buttons; i++) {
-    _UpdateButton(i);
+  for (list<Button>::iterator cursor = _buttons.begin(); cursor != _buttons.end(); cursor++) {
+    _UpdateButton(*cursor);
   }
 
   for (int i = 0; i < _num_axes; i++) {
@@ -100,8 +112,9 @@ void Joystick::ReleaseAllButtons() {
 }
 
 void Joystick::_ReleasePulsedButtons() {
-  for (uint8_t i = 0; i < _num_buttons; i++) {
-    if (_buttons[i].type & _BUTTON_PULSED_TYPES) ReleaseButton(i);
+  for (list<Button>::iterator i = _buttons.begin(); i != buttons.end(); i++) {
+    if (i->type & _BUTTON_PULSED_TYPES) ReleaseButton(i->index0);
+    if (i->type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(i->index1);
   }
 }
 
@@ -124,20 +137,23 @@ void Joystick::Write() {
   delay(250);
 }
 
-void Joystick::_UpdateButton(uint8_t index) {
-  Button* button = &_buttons[index];
+void Joystick::_UpdateButton(Button* button) {
   bool changed = button->bouncer.update();
 
   switch (button->type) {
-    case BUTTON_LATCHED:
-      if (button->bouncer.rose()) PressButton(index);
-      else if (button->bouncer.fell()) ReleaseButton(index);
+    case BUTTON_PASSTHRU:
+      if (button->bouncer.rose()) PressButton(button->index0);
+      else if (button->bouncer.fell()) ReleaseButton(button->index0);
       break;
     case BUTTON_PULSED:
-      if (button->bouncer.rose()) PressButton(index);
+      if (button->bouncer.rose()) PressButton(button->index0);
       break;
     case BUTTON_PULSED_DOUBLE_ACTION:
-      if (changed) PressButton(index);
+      if (changed) PressButton(button->index0);
+      break;
+    case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
+      if (button->bouncer.rose()) PressButton(button->index0);
+      else if (button->bouncer.fell()) PressButton(button->index1);
       break;
     default:
       if (_debug) {
diff --git a/Joystick.h b/Joystick.h
index d1d3af6..8d95820 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -3,6 +3,9 @@
 
 #include <Arduino.h>
 #include <Bounce2.h>
+#include <list>
+
+using std::list;
 
 // If you're using the arduino-big-joystick firmware, these numbers can't be
 // changed. If you're writing your own Report Descriptor, tune these to match by
@@ -16,9 +19,10 @@
 #define JOYSTICK_NUM_BYTES (JOYSTICK_NUM_BUTTONS+7)/8
 
 enum ButtonType {
-  BUTTON_LATCHED = 0x1,
-  BUTTON_PULSED = 0x2,
-  BUTTON_PULSED_DOUBLE_ACTION = 0x4
+  BUTTON_PASSTHRU = 0x1, // always use the (debounced) absolute state of the input
+  BUTTON_PULSED = 0x2, // on button press, send an on signal followed immediately by an off signal.
+  BUTTON_PULSED_DOUBLE_ACTION = 0x4, // Send a button press twice - once for press and once for release.
+  BUTTON_PULSED_DOUBLE_ACTION_SPLIT = 0x8 // Send two separate button presses - one button on press, another on release.
 };
 
 struct JoyReport {
@@ -29,6 +33,9 @@ struct JoyReport {
 struct Button {
   ButtonType type;
   Bounce bouncer;
+  uint8_t index0;
+  uint8_t index1;
+  bool inverted = false; // if true, send button press on release and vice versa.
 };
 
 bool operator ==(JoyReport a, JoyReport b);
@@ -40,10 +47,10 @@ class Joystick {
     void Init();
     void Update();
     
-    void AddButton(uint8_t pin, ButtonType type, bool pullup=false);
+    void AddButton(uint8_t pin, ButtonType type, bool pullup=true);
     void AddAxis(uint8_t pin); // Axes don't actually work yet!
     
-    // These functions are deprecated and may become private in a future
+    // Public access to these functions is deprecated and they may become private in a future
     // version. Prefer the above API instead.
     void SetAxis(uint8_t axis, int16_t value);
     void PressButton(uint8_t button);
@@ -56,8 +63,8 @@ class Joystick {
     void _UpdateButton(uint8_t index);
     void _UpdateAxis(uint8_t index);
     
-    Button _buttons[JOYSTICK_NUM_BUTTONS];
-    uint8_t _num_buttons;
+    list<Button> _buttons;
+    uint8_t _last_button_index;
     bool _have_pulsed_button;
 
     uint8_t _axes[JOYSTICK_NUM_AXES];
@@ -68,6 +75,6 @@ class Joystick {
 };
 
 // Internal use only.
-#define _BUTTON_PULSED_TYPES (BUTTON_PULSED | BUTTON_PULSED_DOUBLE_ACTION)
+#define _BUTTON_PULSED_TYPES (BUTTON_PULSED | BUTTON_PULSED_DOUBLE_ACTION | BUTTON_PULSED_DOUBLE_ACTION_SPLIT)
 
 #endif
diff --git a/Readme.md b/Readme.md
index 845e609..3d12ea6 100644
--- a/Readme.md
+++ b/Readme.md
@@ -2,7 +2,7 @@
 This is a library that builds and sends USB HID Joystick reports, making it easy to build USB Joysticks with Arduino.
 
 ## Dependencies
-* Your Arduino's USB communication chip be programmed with the arduino-big-joystick firmware (or similar). See <https://github.com/harlequin-tech/arduino-usb> for more info.
+* Your Arduino's USB communication chip must be programmed with the arduino-big-joystick firmware (or similar). See <https://github.com/harlequin-tech/arduino-usb> for more info.
 * The Bounce2 library, available at <https://github.com/thomasfredericks/Bounce2>.
 
 ## Installation

From 6a692687f5511349629961fcfddd1891076a866e Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 15:24:05 -0400
Subject: [PATCH 2/8] Add BUTTON_LATCHED_MOMENTARY type, to allow a pushbutton
 to mimic the behavior of a toggle switch.

---
 Joystick.cpp                     | 12 +++++++++++-
 Joystick.h                       |  6 ++++--
 examples/type_test/type_test.ino | 22 ++++++++++++++++++++++
 3 files changed, 37 insertions(+), 3 deletions(-)
 create mode 100644 examples/type_test/type_test.ino

diff --git a/Joystick.cpp b/Joystick.cpp
index 738f423..9712454 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -50,7 +50,7 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
     increment = 2;
     button.index1 = index + 1;
   }
-  
+
   if (_last_button_index + increment > JOYSTICK_NUM_BUTTONS) {
       // todo: fail here
   }
@@ -155,6 +155,16 @@ void Joystick::_UpdateButton(Button* button) {
       if (button->bouncer.rose()) PressButton(button->index0);
       else if (button->bouncer.fell()) PressButton(button->index1);
       break;
+    case BUTTON_LATCHED_MOMENTARY:
+      if (button->bouncer.rose()) {
+        if !(button->pressed) {
+          PressButton(button->index0);
+          button->pressed = true;
+        } else {
+          ReleaseButton(button->index0);
+          button->pressed = false;
+        }
+      break;
     default:
       if (_debug) {
         Serial.print("DEBUG: Unhandled button type: ");
diff --git a/Joystick.h b/Joystick.h
index 8d95820..32cc0a4 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -22,7 +22,8 @@ enum ButtonType {
   BUTTON_PASSTHRU = 0x1, // always use the (debounced) absolute state of the input
   BUTTON_PULSED = 0x2, // on button press, send an on signal followed immediately by an off signal.
   BUTTON_PULSED_DOUBLE_ACTION = 0x4, // Send a button press twice - once for press and once for release.
-  BUTTON_PULSED_DOUBLE_ACTION_SPLIT = 0x8 // Send two separate button presses - one button on press, another on release.
+  BUTTON_PULSED_DOUBLE_ACTION_SPLIT = 0x8, // Send two separate button presses - one button on press, another on release.
+  BUTTON_LATCHED_MOMENTARY = 0x10
 };
 
 struct JoyReport {
@@ -34,7 +35,8 @@ struct Button {
   ButtonType type;
   Bounce bouncer;
   uint8_t index0;
-  uint8_t index1;
+  uint8_t index1; // only used by BUTTON_PULSED_DOUBLE_ACTION_SPLIT
+  bool pressed = false; // only used by BUTTON_LATCHED_MOMENTARY
   bool inverted = false; // if true, send button press on release and vice versa.
 };
 
diff --git a/examples/type_test/type_test.ino b/examples/type_test/type_test.ino
new file mode 100644
index 0000000..03f6e35
--- /dev/null
+++ b/examples/type_test/type_test.ino
@@ -0,0 +1,22 @@
+// An example sketch using the joystick library.
+// In this example, we have 3 toggle switches and 2 momentary pushbuttons.
+// Each button is configured in a different one of the available behaviors.
+
+#include <Bounce2.h>
+#include <Joystick.h>
+
+bool debug = false;
+Joystick joystick(debug);
+
+void setup() {
+  joystick.AddButton(9, BUTTON_PASSTHRU);
+  joystick.AddButton(10, BUTTON_LATCHED_MOMENTARY);
+  joystick.AddButton(11, BUTTON_PULSED);
+  joystick.AddButton(12, BUTTON_PULSED_DOUBLE_ACTION);
+  joystick.AddButton(13, BUTTON_PULSED_DOUBLE_ACTION_SPLIT);
+  joystick.Init();
+}
+
+void loop() {
+  joystick.Update();
+}

From 5322744f4213ee9384f0915d4e1737d86fb9cf25 Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 15:38:01 -0400
Subject: [PATCH 3/8] Revert to non-STL-using code, since that's not available
 when compiling for Arduino...

---
 Joystick.cpp | 16 +++++++++-------
 Joystick.h   |  5 +++--
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/Joystick.cpp b/Joystick.cpp
index 9712454..de8e1e0 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -55,7 +55,8 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
       // todo: fail here
   }
 
-  _buttons.push_back(button);
+  _buttons[_num_buttons] = button;
+  _num_buttons++;
   last_button_index += increment;
 
   if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
@@ -69,8 +70,8 @@ void Joystick::AddAxis(uint8_t pin) {
 void Joystick::Update() {
   JoyReport oldReport = _joyReport;
   
-  for (list<Button>::iterator cursor = _buttons.begin(); cursor != _buttons.end(); cursor++) {
-    _UpdateButton(*cursor);
+  for (uint i = 0; i < _num_buttons; i++) {
+    _UpdateButton(i);
   }
 
   for (int i = 0; i < _num_axes; i++) {
@@ -112,9 +113,9 @@ void Joystick::ReleaseAllButtons() {
 }
 
 void Joystick::_ReleasePulsedButtons() {
-  for (list<Button>::iterator i = _buttons.begin(); i != buttons.end(); i++) {
-    if (i->type & _BUTTON_PULSED_TYPES) ReleaseButton(i->index0);
-    if (i->type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(i->index1);
+  for (uint8_t i = 0; i < _num_buttons; i++ ) {
+    if (i->type & _BUTTON_PULSED_TYPES) ReleaseButton(_buttons[i].index0);
+    if (i->type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(_buttons[i].index1);
   }
 }
 
@@ -137,7 +138,8 @@ void Joystick::Write() {
   delay(250);
 }
 
-void Joystick::_UpdateButton(Button* button) {
+void Joystick::_UpdateButton(uint8_t button_num) {
+  Button *button = &_button[button_num];
   bool changed = button->bouncer.update();
 
   switch (button->type) {
diff --git a/Joystick.h b/Joystick.h
index 32cc0a4..3e88523 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -65,8 +65,9 @@ class Joystick {
     void _UpdateButton(uint8_t index);
     void _UpdateAxis(uint8_t index);
     
-    list<Button> _buttons;
-    uint8_t _last_button_index;
+    Button _buttons[JOYSTICK_NUM_BUTTONS];
+    uint8_t _num_buttons;
+    uint8_t _last_button_index; // a single physical button can have multiple logical buttons. _last_button_index tracks the number of logical / virtual buttons we have defined.
     bool _have_pulsed_button;
 
     uint8_t _axes[JOYSTICK_NUM_AXES];

From 6ea618776913bab2874f1bc036c604772c860ed5 Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 15:38:39 -0400
Subject: [PATCH 4/8] Remove now-useless includes.

---
 Joystick.cpp | 1 -
 Joystick.h   | 1 -
 2 files changed, 2 deletions(-)

diff --git a/Joystick.cpp b/Joystick.cpp
index de8e1e0..aded9f5 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -1,6 +1,5 @@
 #include "Joystick.h"
 #include <Arduino.h>
-#include <list>
 
 using std::list;
 
diff --git a/Joystick.h b/Joystick.h
index 3e88523..cca7225 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -3,7 +3,6 @@
 
 #include <Arduino.h>
 #include <Bounce2.h>
-#include <list>
 
 using std::list;
 

From 2a35a862307132135b0065e3cbf5f7d2356c7b52 Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 15:39:13 -0400
Subject: [PATCH 5/8] Reverting more cruft.

---
 Joystick.cpp | 2 --
 Joystick.h   | 2 --
 2 files changed, 4 deletions(-)

diff --git a/Joystick.cpp b/Joystick.cpp
index aded9f5..23613dd 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -1,8 +1,6 @@
 #include "Joystick.h"
 #include <Arduino.h>
 
-using std::list;
-
 bool operator ==(JoyReport a, JoyReport b){
   for (uint8_t i=0; i < JOYSTICK_NUM_AXES; i++) {
     if (a.axis[i] != b.axis[i]) return false;
diff --git a/Joystick.h b/Joystick.h
index cca7225..98cf64d 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -4,8 +4,6 @@
 #include <Arduino.h>
 #include <Bounce2.h>
 
-using std::list;
-
 // If you're using the arduino-big-joystick firmware, these numbers can't be
 // changed. If you're writing your own Report Descriptor, tune these to match by
 // defining them *before* you include Joystick.h.

From 398668205da4e5ef22f610b3677324fcf495352b Mon Sep 17 00:00:00 2001
From: annabunches <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 15:44:32 -0400
Subject: [PATCH 6/8] Fixed various errors.

---
 Joystick.cpp | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/Joystick.cpp b/Joystick.cpp
index 23613dd..0814b09 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -54,7 +54,7 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
 
   _buttons[_num_buttons] = button;
   _num_buttons++;
-  last_button_index += increment;
+  _last_button_index += increment;
 
   if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
 }
@@ -67,11 +67,11 @@ void Joystick::AddAxis(uint8_t pin) {
 void Joystick::Update() {
   JoyReport oldReport = _joyReport;
   
-  for (uint i = 0; i < _num_buttons; i++) {
+  for (uint8_t i = 0; i < _num_buttons; i++) {
     _UpdateButton(i);
   }
 
-  for (int i = 0; i < _num_axes; i++) {
+  for (uint8_t i = 0; i < _num_axes; i++) {
     _UpdateAxis(i);
   }
 
@@ -111,8 +111,9 @@ void Joystick::ReleaseAllButtons() {
 
 void Joystick::_ReleasePulsedButtons() {
   for (uint8_t i = 0; i < _num_buttons; i++ ) {
-    if (i->type & _BUTTON_PULSED_TYPES) ReleaseButton(_buttons[i].index0);
-    if (i->type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(_buttons[i].index1);
+    Button button = _buttons[i];
+    if (button.type & _BUTTON_PULSED_TYPES) ReleaseButton(button.index0);
+    if (button.type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(button.index1);
   }
 }
 
@@ -136,7 +137,7 @@ void Joystick::Write() {
 }
 
 void Joystick::_UpdateButton(uint8_t button_num) {
-  Button *button = &_button[button_num];
+  Button *button = &_buttons[button_num];
   bool changed = button->bouncer.update();
 
   switch (button->type) {
@@ -156,13 +157,14 @@ void Joystick::_UpdateButton(uint8_t button_num) {
       break;
     case BUTTON_LATCHED_MOMENTARY:
       if (button->bouncer.rose()) {
-        if !(button->pressed) {
+        if (!button->pressed) {
           PressButton(button->index0);
           button->pressed = true;
         } else {
           ReleaseButton(button->index0);
           button->pressed = false;
         }
+      }
       break;
     default:
       if (_debug) {

From 3fd595c7c2ac171801537d55b6f7ec8925ff36d8 Mon Sep 17 00:00:00 2001
From: Anna Wiggins <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 22:09:11 +0000
Subject: [PATCH 7/8] Rename variables for clarity, fix enumeration bug.

---
 .gitignore                       |  2 ++
 Joystick.cpp                     | 31 +++++++++++++++----------------
 Joystick.h                       |  6 +++---
 examples/type_test/type_test.ino |  2 +-
 4 files changed, 21 insertions(+), 20 deletions(-)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d6c2e45
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.elf
+*.hex
diff --git a/Joystick.cpp b/Joystick.cpp
index 0814b09..97fcb0e 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -17,7 +17,7 @@ bool operator !=(JoyReport a, JoyReport b){
 
 Joystick::Joystick(bool debug) {
   _debug = debug;
-  _last_button_index = 0;
+  _virtual_buttons = 0;
   _num_axes = 0;
   _have_pulsed_button = false;
   
@@ -39,22 +39,21 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
   Button button;
   button.type = type;
   button.bouncer.attach(pin, mode);
-  uint8_t index = _last_button_index + 1;
   uint8_t increment = 1;
-  button.index0 = index;
+  button.vbutton0 = _virtual_buttons;
 
   if (type == BUTTON_PULSED_DOUBLE_ACTION_SPLIT) {
     increment = 2;
-    button.index1 = index + 1;
+    button.vbutton1 = _virtual_buttons + 1;
   }
 
-  if (_last_button_index + increment > JOYSTICK_NUM_BUTTONS) {
+  if (_virtual_buttons + increment > JOYSTICK_NUM_BUTTONS) {
       // todo: fail here
   }
 
   _buttons[_num_buttons] = button;
   _num_buttons++;
-  _last_button_index += increment;
+  _virtual_buttons += increment;
 
   if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
 }
@@ -112,8 +111,8 @@ void Joystick::ReleaseAllButtons() {
 void Joystick::_ReleasePulsedButtons() {
   for (uint8_t i = 0; i < _num_buttons; i++ ) {
     Button button = _buttons[i];
-    if (button.type & _BUTTON_PULSED_TYPES) ReleaseButton(button.index0);
-    if (button.type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(button.index1);
+    if (button.type & _BUTTON_PULSED_TYPES) ReleaseButton(button.vbutton0);
+    if (button.type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(button.vbutton1);
   }
 }
 
@@ -142,26 +141,26 @@ void Joystick::_UpdateButton(uint8_t button_num) {
 
   switch (button->type) {
     case BUTTON_PASSTHRU:
-      if (button->bouncer.rose()) PressButton(button->index0);
-      else if (button->bouncer.fell()) ReleaseButton(button->index0);
+      if (button->bouncer.rose()) PressButton(button->vbutton0);
+      else if (button->bouncer.fell()) ReleaseButton(button->vbutton0);
       break;
     case BUTTON_PULSED:
-      if (button->bouncer.rose()) PressButton(button->index0);
+      if (button->bouncer.rose()) PressButton(button->vbutton0);
       break;
     case BUTTON_PULSED_DOUBLE_ACTION:
-      if (changed) PressButton(button->index0);
+      if (changed) PressButton(button->vbutton0);
       break;
     case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
-      if (button->bouncer.rose()) PressButton(button->index0);
-      else if (button->bouncer.fell()) PressButton(button->index1);
+      if (button->bouncer.rose()) PressButton(button->vbutton0);
+      else if (button->bouncer.fell()) PressButton(button->vbutton1);
       break;
     case BUTTON_LATCHED_MOMENTARY:
       if (button->bouncer.rose()) {
         if (!button->pressed) {
-          PressButton(button->index0);
+          PressButton(button->vbutton0);
           button->pressed = true;
         } else {
-          ReleaseButton(button->index0);
+          ReleaseButton(button->vbutton0);
           button->pressed = false;
         }
       }
diff --git a/Joystick.h b/Joystick.h
index 98cf64d..9802925 100644
--- a/Joystick.h
+++ b/Joystick.h
@@ -31,8 +31,8 @@ struct JoyReport {
 struct Button {
   ButtonType type;
   Bounce bouncer;
-  uint8_t index0;
-  uint8_t index1; // only used by BUTTON_PULSED_DOUBLE_ACTION_SPLIT
+  uint8_t vbutton0;
+  uint8_t vbutton1; // only used by BUTTON_PULSED_DOUBLE_ACTION_SPLIT
   bool pressed = false; // only used by BUTTON_LATCHED_MOMENTARY
   bool inverted = false; // if true, send button press on release and vice versa.
 };
@@ -64,7 +64,7 @@ class Joystick {
     
     Button _buttons[JOYSTICK_NUM_BUTTONS];
     uint8_t _num_buttons;
-    uint8_t _last_button_index; // a single physical button can have multiple logical buttons. _last_button_index tracks the number of logical / virtual buttons we have defined.
+    uint8_t _virtual_buttons; // a single user-defined button can have multiple virtual buttons.
     bool _have_pulsed_button;
 
     uint8_t _axes[JOYSTICK_NUM_AXES];
diff --git a/examples/type_test/type_test.ino b/examples/type_test/type_test.ino
index 03f6e35..14199bb 100644
--- a/examples/type_test/type_test.ino
+++ b/examples/type_test/type_test.ino
@@ -5,7 +5,7 @@
 #include <Bounce2.h>
 #include <Joystick.h>
 
-bool debug = false;
+bool debug = true;
 Joystick joystick(debug);
 
 void setup() {

From bcfd67b50df1cfc2fa324fecee9b59776a6aeb01 Mon Sep 17 00:00:00 2001
From: Anna Wiggins <annabunches@gmail.com>
Date: Mon, 1 Nov 2021 22:19:05 +0000
Subject: [PATCH 8/8] Fix behavior when using pull-up resistors.

---
 Joystick.cpp                     | 19 ++++++++++++-------
 examples/type_test/Makefile      |  8 ++++++++
 examples/type_test/type_test.ino |  2 +-
 3 files changed, 21 insertions(+), 8 deletions(-)
 create mode 100644 examples/type_test/Makefile

diff --git a/Joystick.cpp b/Joystick.cpp
index 97fcb0e..5b4c99a 100644
--- a/Joystick.cpp
+++ b/Joystick.cpp
@@ -38,6 +38,7 @@ void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
 
   Button button;
   button.type = type;
+  button.inverted = pullup;
   button.bouncer.attach(pin, mode);
   uint8_t increment = 1;
   button.vbutton0 = _virtual_buttons;
@@ -138,24 +139,28 @@ void Joystick::Write() {
 void Joystick::_UpdateButton(uint8_t button_num) {
   Button *button = &_buttons[button_num];
   bool changed = button->bouncer.update();
+  if (!changed) return;
+
+  bool on = button->bouncer.rose();
+  if (button->inverted) on = button->bouncer.fell();
 
   switch (button->type) {
     case BUTTON_PASSTHRU:
-      if (button->bouncer.rose()) PressButton(button->vbutton0);
-      else if (button->bouncer.fell()) ReleaseButton(button->vbutton0);
+      if (on) PressButton(button->vbutton0);
+      else ReleaseButton(button->vbutton0);
       break;
     case BUTTON_PULSED:
-      if (button->bouncer.rose()) PressButton(button->vbutton0);
+      if (on) PressButton(button->vbutton0);
       break;
     case BUTTON_PULSED_DOUBLE_ACTION:
-      if (changed) PressButton(button->vbutton0);
+      PressButton(button->vbutton0);
       break;
     case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
-      if (button->bouncer.rose()) PressButton(button->vbutton0);
-      else if (button->bouncer.fell()) PressButton(button->vbutton1);
+      if (on) PressButton(button->vbutton0);
+      else PressButton(button->vbutton1);
       break;
     case BUTTON_LATCHED_MOMENTARY:
-      if (button->bouncer.rose()) {
+      if (on) {
         if (!button->pressed) {
           PressButton(button->vbutton0);
           button->pressed = true;
diff --git a/examples/type_test/Makefile b/examples/type_test/Makefile
new file mode 100644
index 0000000..d1058d4
--- /dev/null
+++ b/examples/type_test/Makefile
@@ -0,0 +1,8 @@
+TARGET_BOARD=arduino:avr:uno
+COM_PORT=/dev/ttyACM0
+
+build:
+	arduino-cli compile -b ${TARGET_BOARD}
+
+upload:
+	arduino-cli upload -b ${TARGET_BOARD} -p ${COM_PORT}
diff --git a/examples/type_test/type_test.ino b/examples/type_test/type_test.ino
index 14199bb..03f6e35 100644
--- a/examples/type_test/type_test.ino
+++ b/examples/type_test/type_test.ino
@@ -5,7 +5,7 @@
 #include <Bounce2.h>
 #include <Joystick.h>
 
-bool debug = true;
+bool debug = false;
 Joystick joystick(debug);
 
 void setup() {