MHeironimus / ArduinoJoystickLibrary

An Arduino library that adds one or more joysticks to the list of HID devices an Arduino Leonardo or Arduino Micro can support.
GNU Lesser General Public License v3.0
2.07k stars 403 forks source link

Is it possible to trigger a joystick button with logic? #180

Closed Jak-Kav closed 3 years ago

Jak-Kav commented 3 years ago

Hello,

I've created a working joystick, BUT I am trying to make it activate joystick buttons with logic and can't seem to do it so far.

For example: I have a 3-way switch (on-off-on). Each on position is linked to a joystick button. But, is it possible to link the off position to a 3rd joystick button with logic? The closest I've managed to get (with some help with other people) is this (but it's still not working): if ((buttbx.key[10].kstate == RELEASED) && (buttbx.key[9].kstate == RELEASED)) { Joystick.setButton(buttbx.key[34].kchar, 1); } else { Joystick.setButton(buttbx.key[34].kchar, 0); }

This video I made may it explain what I mean better than I can type it out: https://youtu.be/yB0qKDKdMuI

Thank you in advance!

ttait-vantim commented 3 years ago

Yes it's easy. Here is what I did (note that I am using the ezButton library getState() to sense and debounce the switches, you can use whatever you want for that part):

  //////////////////////////////////////
  // Flap SW logic
  // Button 3 - Up
  // Button 4 - Takeoff
  // Button 5 - Landing
  if (!RightSw_Up.getState())
  { // Flaps Up
    Joystick.setButton(2, true);    
    Joystick.setButton(3, false);    
    Joystick.setButton(4, false);    
  }
  else if (!RightSw_Dn.getState())
  { // Flaps in Landing
    Joystick.setButton(2, false);    
    Joystick.setButton(3, false);    
    Joystick.setButton(4, true);    
  }
  else
  { // Flaps in Takeoff
    Joystick.setButton(2, false);    
    Joystick.setButton(3, true);    
    Joystick.setButton(4, false);    
  }

The on-off-on toggle is wired with gnd to the COM contact, and a different GPIO w/Pullup to the two ON contacts. If the switch is "On" in the upper pos, the first if clause is used triggering joy button 2, if it is "On" in the lower position the 2nd if clause is used triggering joy button 4, else the sw must be off and joy button 3 is sent.

Tim

Jak-Kav commented 3 years ago

Hi Tim,

Thanks for your reply! I've not come across ezButton before, can you point in the right direction on how I would set it up?

Do I make it additional to my keypad matrix and joystick? I'm also making my button box for flight simulation, so I think what you've said is exactly what I need!

Would you mind having a look at the code I've got so far?

ttait-vantim commented 3 years ago

ezButton page is here: https://www.arduino.cc/reference/en/libraries/ezbutton/

However I don't think it is compatible with matrix encoded switches, but its good for debouncing single buttons mapped to 1 GPIO pin. But you can use whatever decodes you have to drive the if statement, digitalRead() etc.

Are you mapping the matrix 1:1 to joystick buttons? That will cause an issue here because you want 2 switches to drive 3 joystick buttons in this case.

Post your code, maybe others can help as well.

Tim

Jak-Kav commented 3 years ago

Thanks again, Tim. Yes I've had a look at that, and because I'm using a matrix it's not going to work for me unfortunatley. I have more switches on my panel than I do pins, and as such can't use a button mapped to each GPIO pin. It's a shame really, as it would do exactly what I need!

I have a matrix of 0-24 'buttons'. A mixture of 'on-off-on' and 'on-off' switches (where the 'on-off-on' switches have 2 'buttons', up and down position. And the 'on-off' switches having one 'button', the up position). I'm then trying to get the code to hold a button (between 26-38) when a siwtch is in the off position.

Pseudocode of what I'm trying to acheive:

if ((switch1_up[joystick button 1] == idle) && (switch1_down[joystick button 2] == idle)
{ 
    hold [joystick button 3];
} else {
   release [joystick button 3]
}

So, trying to do this with just the joystick.h and keypad.h library isn't working properly. The joystick switches that are physically wired to the board all work as expected. So when the switches are in the 'on' position, the appropriate joystick button is held. But, the logic where I try to hold a 'virtual' button linked to an off position isn't working. The code I have so far is below, and it just flickers the 'virtual' button no matter what position the corresponding switch is in.

#include <Keypad.h>
#include <Joystick.h>

#define ENABLE_PULLUPS
#define NUMBUTTONS 23
#define NUMROWS 2
#define NUMCOLS 14

//define the symbols on the buttons of the keypads
byte buttons[NUMROWS][NUMCOLS] = {
  {0,1,2,3,4,5,6,7,8,9,10,11,12,13},
  {14,15,16,17,18,19,20,21,22},  
};

byte rowPins[NUMROWS] = {21,20}; //connect to the row pinouts of the keypad
byte colPins[NUMCOLS] = {16,15,14,10,9,8,7,6,5,4,3,2,1,0}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 

//initialize an Joystick with 38 buttons;
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, 
  JOYSTICK_TYPE_JOYSTICK, 38, 0,
  false, false, false, false, false, false,
  false, false, false, false, false);

void setup() {
  Joystick.begin();
}

void loop() { 
  CheckAllButtons();
delay(100);
}

void CheckAllButtons(void) {  
     buttbx.getKeys();

     for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
     {                              
       if ( buttbx.key[i].stateChanged )   // Only find keys that have changed state.
       {                                           
          switch (buttbx.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                  case PRESSED:
                  case HOLD:
                           Joystick.setButton(buttbx.key[i].kchar, 1);
                           break;
                  case RELEASED:
                  case IDLE:
                           Joystick.setButton(buttbx.key[i].kchar, 0);
                           break;                              
       }            
      }
      if (buttbx.key[14].kstate == IDLE && buttbx.key[15].kstate == IDLE)
      {
        Joystick.setButton(31, 1);
      } else {
        Joystick.setButton(31, 0);
      }
     }

}

On advice from someone else on a different forum, I'm going to look into the adafruit keypad library to see if that can offer anything different, but haven't had a chance to do so yet. Any advice on this would be REALLY appreciated.

Thank you!

ttait-vantim commented 3 years ago

Shouldn't that last if block be outside of the for loop as it does not depend on "i" and only needs to execute only once per loop()?

Still l don't think that explains the flickering. Is it flickering while nothing being switched?

Does the "#define ENABLE_PULLUPS" tell the keypad library function to enable input pullups? Can you verify it really did? If the key.state is not in idle, what state is it in?? Some debug prints could help there.

Tim

Jak-Kav commented 3 years ago

Yes, it should. I was one } out. But, it still has no change unfortunatley. And yes it does flicker whilst nothing is being switched, and whatever position the switch is in.

From reading the library, it should enable the input pullups. It's how the library says to activate them.

From what I understand of how the library works, all switches start in idle. They then go to either hold or pressed, then to released and then back to idle. The 'released' phase is a transition effectivley.

Jak-Kav commented 3 years ago

I've managed to find help and solve this at https://forum.arduino.cc/index.php?topic=719673.new#new

ttait-vantim commented 3 years ago

Ahh, so the matrix decoder returns a list of up to 10 keys that were pressed, not a state map of the state of all the keys. I was wondering where LIST_MAX was coming from. I had previously used a different matrix key decoder that was much simpler as I recall.

Glad you got it solved!

Tim