I’m using the Game Control Plus library to capture inputs from a new NES USB controller. All buttons are mapped correctly and respond to my inputs. I have used .plug() to set up a custom function that is supposed to trigger whenever the A button is released. My chngBgCol() function is correctly triggered and the text “Button A released” appears in the console but any drawing operations (like background() and circle()) fail to do anything on the screen.
I’m sure it’s me being a klutz here and that it’s an easy fix. Anybody able to spot the error? Ping @quark.
(Processing 4.1.2, Mac OS 12.4)
import org.gamecontrolplus.gui.*;
import org.gamecontrolplus.*;
import net.java.games.input.*;
ControlIO control;
ControlDevice stick;
void setup() {
size(800, 800);
control = ControlIO.getInstance(this);
stick = control.getMatchedDevice("joystick");
stick.getButton("A").plug(this, "chngBgCol", ControlIO.ON_RELEASE);
}
void draw() {
float px = stick.getSlider("X").getValue();
float py = stick.getSlider("Y").getValue();
boolean select = stick.getButton("SELECT").pressed();
boolean start = stick.getButton("START").pressed();
boolean a = stick.getButton("A").pressed();
boolean b = stick.getButton("B").pressed();
println(px, py, select, start, a, b); // these all work as intended
}
void chngBgCol() {
println("Button A released"); // this prints in the console
background(random(255), random(255), random(255)); // background doesn't change?
circle(random(width), random(height), 200); // circle doesn't appear?
}
As I say on my website, the original code was not created by me I simply updated it for Processing3 (very minor changes) and added the configurator. So I have had to look at the original source code and I believe I have the answer
I found this method which is used to poll the USB device and as you can see it runs in a separate thread and not on the main event thread.
/**
* Controllers are now polled in a separate thread to get independent from
* the framerate of the sketch
*/
public void run(){
while (active){
for (int i = 0; i < devices.size(); i++)
devices.get(i).update();
try {
Thread.sleep ( 10 );
} catch ( InterruptedException e ) { }
}
}
All Processing graphics methods must be executed on the main event thread so I suggest that you add a boolean flag (semaphore) to indicate when the button has been released like this
import org.gamecontrolplus.gui.*;
import org.gamecontrolplus.*;
import net.java.games.input.*;
ControlIO control;
ControlDevice stick;
boolean buttonAreleased = false;
void setup() {
size(800, 800);
control = ControlIO.getInstance(this);
stick = control.getMatchedDevice("joystick");
stick.getButton("A").plug(this, "chngBgCol", ControlIO.ON_RELEASE);
}
void draw() {
float px = stick.getSlider("X").getValue();
float py = stick.getSlider("Y").getValue();
boolean select = stick.getButton("SELECT").pressed();
boolean start = stick.getButton("START").pressed();
boolean a = stick.getButton("A").pressed();
boolean b = stick.getButton("B").pressed();
println(px, py, select, start, a, b); // these all work as intended
// Test the semaphore
if (buttonAreleased) randomCircle();
}
void randomCircle() {
background(random(255), random(255), random(255));
circle(random(width), random(height), 200);
buttonAreleased = false; // clear the semaphore
}
void chngBgCol() {
println("Button A released");
buttonAreleased = true; // set the semaphore
}
I am not promising that this will work but I think it will.
Thanks for responding so quickly @quark. I had a hunch it might involve different threads, and your research confirms this. I’ll go with your suggestion for a workaround using a boolean flag.