Search code examples
javawhile-loopkeyboardprocessing

Processing: Java, KeyPressed() Not Detecting Whilst Running Function?


Looking for some help/guidance on how to solve this issue within my application. After reading several forum posts across various websites I think I have an idea about why this isn't working however am unsure why this happens in my application and how to implement a solution.

Looking for the application to wait until a response has been received from the user via the keyboard via the keyPressed() function. I've separated the application out into several functions (some not shown here) and am waiting for the response in a while loop in runTrialEvent(). However, The response is never picked up once I run the runTrialEvent() function. I know this is where the issue lies but don't fully understand why.

I have the following code in a function called runTrialEvent() which is run by pressing 't' on the keyboard.

runTrialEvent()

 void runTrialEvent(Serial myPort) 
 {
  
      //////////////////////////////////////////////
      //This While Loop is where the issues arise

      while (trialTimer.isFinished() == false && userResponded == false )
      {
        println("Awaiting User Response");
        
        delay (300);
      }

      //////////////////////////////////////////////////     
 
      if (userResponded == true)
      {
        //Debug Info
        println("User responded in time ");   
      }
      
      else if (trialTimer.isFinished() == true)
      {
         println("User failed to respond in time ");
      }
}

I have the input from user using keyPressed() which works before the loop fine. This code is:

keyPressed()

 void keyPressed() 
 {
 if (key == 'f' || key == 'F' )
 {
   println("User Answered First");
   //allTrials[i].setUserAnswer("F");
   userResponded = true;
   println("User Response Recorded ");
   
 }
 
 else if (key == 's' || key == 'S')
 {
   println("User Answered Second");
   //allTrials[i].setUserAnswer("S");
   userResponded = true;
   println("User Response Recorded ");
   
 }
 }

My draw() simply writes text on a window, so nothing is running there. If anyone has any solutions would be great. Any explanations as to why this happens would be greatly appreciated.

Thanks!


Solution

  • Processing uses a single thread to run all of its functions. That means if you make one function run forever, the other functions will never get a chance to fire.

    Please try to post a MCVE that shows your problem in as few lines as possible, while being complete enough for us to copy and paste to run ourselves. Here's an example program that shows your problem:

    String text = "";
    
    void draw(){
      background(64);
      textAlign(CENTER, CENTER);
      text(text, width/2, height/2);
    }
    
    void keyPressed(){
      text += key;
    }
    
    void mousePressed(){
    
      while(!text.equals("hello")){
        println("Waiting for text to equal hello.");
        delay(1000);
      }
    
    }
    

    This program is doing something very similar to what you're trying to do. It uses the keyPressed() function to handle input, and then the mousePressed() function checks and busy-waits for the text to equal a certain String. You might expect this to busy-wait until the user types hello.

    If you run this function, you'll notice that the keyPressed() function works fine, until you click the mouse. At that point it's stuck waiting for the text to equal hello, but that never happens because now the keyPressed() function never fires.

    (Notice how this program shows your problem without any extra code and without requiring an Arduino or any libraries. Please try to post code like this from now on.)

    Anyway, how do we fix this problem? You could create a second thread that handles your processing, but that's probably overkill for your purposes.

    Instead, you need to refactor your code to eliminate the busy-waiting altogether. One approach is using a boolean variable that keeps track of whether you've received data. Use that to check whether you need to do something, and then set it when you receive the data.

    Here is that approach in our small example program:

    String text = "";
    boolean helloReceived = false;
    
    void draw(){
      background(64);
      textAlign(CENTER, CENTER);
      text(text, width/2, height/2);
    }
    
    void keyPressed(){
      text += key;
    
      if(text.equals("hello")){
         helloReceived = true; 
      }
    }
    
    void mousePressed(){
    
      if(helloReceived){
        println("Text now equals hello!");
      }
    }
    

    Now the code uses a helloReceived variable to track whether the condition has been met. This is a little bit contrived, but I'm trying to create an example that's similar to what you're trying to do.

    This code is just an example, and your real code might need to be a little more complicated than a single boolean value. But the general answer is the same: you shouldn't busy-wait or use the delay() function, because it prevents other functions from being fired. Instead, refactor your code to eliminate the waiting altogether.