How to handle user input

So i was wondering what the simplest way to handle 50 some commands would be.

Say a user enters a command in a textfield and the code needs to handle each command separately. Is there something shorter than a if/else or case/break?

Thanks.:smiling_face_with_sunglasses:

Ahhh a minimum information problem :grin:

To get a useful answer you might want to include more information such as

  • What Processing mode are you using e.g. Java, Python, p5js … ?
  • What sort of commands are to being handled e.g. OS system commands … ?
  • Some context to the application area.

Thanks for the reply.

Working on this terminal software(Java mode) and am adding commands for user customization .e.g. (Font type, Color scheme, Language). Mainly to keep UI from being cluttered. The commands would be pretty simple for instance.

if (input == "f-unifont") {
  systemFont = "unifont";
}


So an if statement might not be the worst.

I see now that switch statements won’t work with strings(input from software is string type) so that one is out.

The reference does not show String as an expression but it will work.

switch / Reference / Processing.org

Example with a String:

String s = "B1";

//s = "A0";

switch(s) {
  case "A0": 
    println("Alpha");  // Does not execute
    break;
  case "B1": 
    println("Bravo");  // Does not execute
    break;
  default:             // Default executes if the case names
    println("None");   // don't match the switch parameter
    break;
}

The correct way to compare Strings is discussed here:

:)

2 Likes

Thanks @glv.

It seems that a switch or if statement are the best options.

Thanks for the help.

1 Like

Yes, there is.

I’m not much of a Processing/java programmer, I hang around more in the C/C++ world where function pointers are common and very suitable for this task; unfortunately Processing/java does not directly have function pointers.

The idea is to have a lookup table that looks like

|cmd|function|

e.g.

|abc|function 1|
|xyz|function 2|

For this you can use a HashMap (HashMap / Reference / Processing.org).

First you need to create the java equivalent of a function pointer (see e.g. How to use Function Pointers in Java | Gregory Gaines). Note that this is outside my area of knowledge so don’t ask.

// Wrapping interface
private interface FunctionPointer
{
  // Method signatures of pointed method
  void execute();
}

Now you can create a HashMap; I called it lookupTable.

// this hashmap links a string to a function
HashMap<String, FunctionPointer> lookupTable = new HashMap<String, FunctionPointer>();

Before you can populate the lookup table you need to define your functions; below two simple functions

public void func1()
{
  println("Called func1");
}

public void func2()
{
  println("Called func2");
}

Now you can populate the lookup table

void setup()
{
  // link user input and functions
  lookupTable.put("abc", this::func1);
  lookupTable.put("xyz", this::func2);
}

When user input is received, you can compare it with the keys of the entries in the lookup table; if it matches you can execute the associated function.

Full demo code below

import java.util.Map;

String userInput = "";


/********************************************
 Function pointer related
 Source: https://www.gregorygaines.com/blog/how-to-use-function-pointers-in-java/
 ********************************************/
// Wrapping interface
private interface FunctionPointer
{
  // Method signatures of pointed method
  void execute();
}

/********************************************
 HashMap
 Source: https://processing.org/reference/HashMap.html
 ********************************************/
// this hashmap links a string to a function
HashMap<String, FunctionPointer> lookupTable = new HashMap<String, FunctionPointer>();

/********************************************
 Your functions
 ********************************************/
public void func1()
{
  println("Called func1");
}

public void func2()
{
  println("Called func2");
}


void setup()
{
  // link user input and functions
  lookupTable.put("abc", this::func1);
  lookupTable.put("xyz", this::func2);

  // basic demo
  //FunctionPointer pointer1 = this::func1;
  //FunctionPointer pointer2 = this::func2;
  //pointer1.execute();
  //pointer2.execute();
}

void draw()
{
}

void keyPressed()
{
  // collect user input; for demo only 'a'..'z'
  if (key >= 'a' && key <='z')
  {
    userInput += key;
  } else
  {
    // linefeed terminates user input
    if (key == '\n')
    {
      // show user input
      println("'" + userInput + "'");
      // loop through hashmap
      for (Map.Entry e : lookupTable.entrySet())
      {
        // if user input matches key
        if (userInput.equals(e.getKey()))
        {
          // get function pointer
          FunctionPointer fp = (FunctionPointer)e.getValue();
          // and execute
          fp.execute();
        }
      }

      // clear the user input
      userInput = "";
    }
  }
}

When you type abc and press <Enter> function func1 is executed.
When you type xyz and press <Enter> function func2 is executed.

You can write a function setUnifont

void setUnifont()
{
  systemFont = "unifont";
}

and you can add that entry in setup() using

lookupTable.put("f-unifont", this::setUnifont);
2 Likes

Here is an alternative approach for the keyPressed() function. There was a reason why I used a HashMap (and not an array) but next forgot; one can easily retrieve the value based on the key and one can easily check if the entered command exists.

void keyPressed()
{
  // collect user input; for demo only 'a'..'z'
  if (key >= 'a' && key <='z')
  {
    userInput += key;
  } else
  {
    // linefeed terminates user input
    if (key == '\n')
    {
      // show user input
      println("'" + userInput + "'");

      if(lookupTable.containsKey(userInput))
      {
        if(lookupTable.get(userInput) != null)
        {
          lookupTable.get(userInput).execute();
        }
        else
        {
          println("Function not specified for command '" + userInput + "'");
        }
      }
      else
      {
        println("unknown command '" + userInput + "'");
      }

      // clear the user input
      userInput = "";
    }
  }
}

It also contains hardening in case you have not implemented a function for a command yet but the entry in the lookup table was prepared.

  // link user input and functions
  lookupTable.put("abc", this::func1);
  lookupTable.put("xyz", this::func2);
  lookupTable.put("x", null);

Command ‘x’ was prepared but no function was assigned yet (hence null).

Thank you @sterretje i will look into it.

Interesting. In version 3 strings were not supported in switch. I have used a work-around, functions as a switch but also allows the use of variables in the case equivalent.

void setup(){
  String[] x= {"A","B","Z",str(TAB),"V"};
  String somethingVariable= "Q";
  
  for( String a:x){
  print(a+": ");  
  commandLoop:
    {
      if( a.equals("A") ){
        // handle command A
        println("command A");
        break commandLoop;
      }
      
      if( a.equals("B") ){
        // handle command B
        println("command B");
        break commandLoop;
      }
      
      if( a.equals("Z") ){
        // handle command Z
        println("command Z");
        break commandLoop;
      }

      if( a.equals(str(TAB)) ){
        // handle command TAB
        println("command TAB");
        break commandLoop;
      }
      
      if( a.equals(somethingVariable) ){
        // handle command somethingVariable
        println("command somethingVariable",somethingVariable);
        break commandLoop;
      }
      
      // default
      println("command",a,"unknown");
      
    } // end commandLoop

}

Java 7 and high support strings in switch statements.
I can verify that Processing 3.5.4 works with your example.

Open Gemini response:

A Brief History

  • Early Versions: Processing was started in 2001, so it initially used older versions of Java (like Java 1.3 or 1.4).
  • Processing 2.x: The major release of Processing 2 (released between 2012 and 2014) was built on top of Java 6, but it could also run on Java 7. The developers began to incorporate features from newer Java releases as they became stable.
  • Processing 3.x: Processing 3, released in 2015, made the transition to Java 8, which was a significant update with new language features like lambdas.
  • Current Versions: The latest versions of Processing are now built on Java 17.

:)

Even though it used Java 8, we couldn’t use lambda syntax at all!