Need help w/ keyboard that take multiple inputs at once

I’m trying to make a program that can take for example, “LG” (pressed at the same time) as an input and output a unique letter. So far I’ve done the usual

if (key == 108) {
   lDown = true;
}
if (key == 103) {
   gDown = true;
}
if (lDown == true && gDown == true) {
   System.out.println("ʊər");
}

Right, the usual stuff. But the problem I’m running into is that the output isn’t ʊər it’s “l \n ʊər” I’ve tried making a while(breakloop == true) loop and saying breakloop = false; after every part. I’m not sure what to do. When I did this with triple letters it would end up printing “l” over and over again, so I’m not sure if I messed up the syntax of the while loop or not (been trying to figure out this for a long time and there are a lot of lines) I’ve copy pasted the code that repeats letters over and over. Also, I’m not too well-versed in how this forum works so please, if I’ve messed anything up or you need more information let me know.

for some reason I can’t attach my code because it says that “new users can only link 2 sites” or something but if it’s necessary to see the code lmk. It’s really messy and I brute forced a lot of solutions that never worked and didn’t clean it up so it’s kind of an eyesore.

Hi

Welcome to our community

Basically keyboard :keyboard::keyboard::keyboard: won’t type two keys at once
One of the two keys response fast than other depends on which hit first you are going to get LGGG etc or GLLL etc

Hello @Mook,

There are plenty of solutions for multiple keys in this forum that a search will reveal.

One simple example for just a and b keys:

boolean a, b;
int count = 0;

void setup()
  {
  size(200, 200);
  }

void draw()
  {
  background(255);

  if (a == true && b == true) 
    {
    //System.out.println("ʊərπ");
    println("ab");
    
println(count++);
    // Comment these two for non repeating !
    //a = false; 
    //b = false;
    }
  }

void keyPressed()
  {
  if (key == 'a') 
    a = true;
    
  if (key == 'b') 
    b = true;
  }
  
void keyReleased()
  {
  if (key == 'a')
    a = false;
  
  if (key == 'b')
    b = false;
  }

I had similar issues with some fonts to the sketch canvas and console and submitted this at the time:
Characters (such as "τ" or "π") not displaying correctly in current source · Issue #5413 · processing/processing · GitHub

With Processing 4.0b8 and the Consolas font selected in Preferences I get this:

References:

:)

Heres a good solution i use al the time, allows for any number of keys to be detected at once

ArrayList<Integer> keys = new ArrayList<Integer>();

PVector pos;
int radius = 15;

void setup() {
  size(600, 600);
  pos = new PVector(width/2, height/2);
}

void draw() {
  background(0);

  controls();

  noStroke();
  circle(pos.x, pos.y, radius*2);
}

void controls() {
  int speed = 5;
  if (keys.contains(UP)) pos.add(new PVector(0, -speed));
  if (keys.contains(DOWN)) pos.add(new PVector(0, speed));
  if (keys.contains(LEFT)) pos.add(new PVector(-speed, 0));
  if (keys.contains(RIGHT)) pos.add(new PVector(speed, 0));

  //if space pressed
  if (keys.contains(32)) { // keycode for space
    fill(255, 0, 0);
  } else fill(255);

  pos.x = constrain(pos.x, radius, width-radius);
  pos.y = constrain(pos.y, radius, height-radius);
}

void keyPressed() {
  //println(keyCode); use this to find the specific key code you want
  if (!keys.contains(keyCode)) keys.add(keyCode);
}

void keyReleased() {
  keys.remove(keys.indexOf((keyCode)));
}
2 Likes

Hello @Mook,

You are using:
System.out.println(“ʊər”);

Which OS are you using and version of Processing?
Which font have you selected in Preferences?

I tried all the different fonts in Preferences and can’t get this printed (there are ? for some characters) to the console area:

System.out.println("ʊərπ");
size(200, 200);
fill(0);
textSize(48);
text("ʊərπ", 20, 50);

I am using W10 Pro, Processing 4.0b7 and the Consolas font.

:)

Hi, I tried adding the a = false; b = false; when I print ab


but the output is still:

a
ab

I’m on windows 10, processing 3 and the default font (I didn’t change anything after downloading processing) but the letters themselves aren’t the problem, I also got “??”. I also tried

void keyPressed() {
boolean isDouble = true;
  if (key == 97) {
    aDown = true;
  }
  if (key == 101) {
    eDown = true;
  }
if (eDown == true && aDown == true) {
  System.out.println("ae");
  isDouble = false;
}
while (isDouble == false) {
  if (aDown == true && eDown == false) {
    System.out.println("a");
  }
  if (eDown == true && aDown == false) {
    System.out.println("e");
  }
 }
}
void keyReleased() {
  if (key == 97) {
    aDown = false;
  }
  if (key == 101) {
    aDown = false;
  }
}
boolean aDown, eDown;

but this only output “ae” once and doesn’t output anything else afterwards. My original post was badly worded, the letters it outputs don’t matter, it’s just a place holder to get things working first. Basically I’m trying to make a keyboard that makes different sounds when you press different keys. And since there are more sounds than keys I wanted two or three keys being pressed at once to make their own unique sound. Instead of uploading all the sounds, I just used System.out.println() to represent them for the time being. The problem I ran into was that pressing two keys at once would make two outputs, not one unique output. Thank you so much for taking the time to read this!

that’s what I was thinking but isn’t there a way to make the program wait for a split second to check if two keys are being pressed before sending the single key output. Also my keyboard can type glglglglgl it just takes good timing.

Hi in this link you can read multiple keys at same time with fast hit

the thing is, I have all of that in my code. for a program that only needs to move a character, a tiny forward movement before diagonal movement is fine. But for mine, pressing two keys at once will give two outputs. I want one output

Hi
Combined if in one command rather two see what happens

if (aDown == true && eDown == false) {
System.out.println(“a”);
}
if (eDown == true && aDown == false) {
System.out.println(“e”);

tried that, it gives the same output, here’s what i’ve tried

void keyPressed() {
boolean isDouble = true;
  if (key == 97) {
    aDown = true;
  }
  if (key == 101) {
    eDown = true;
  }
if (eDown == true && aDown == true) {
  System.out.println("ae");
  isDouble = false;
}
while (isDouble == false) {
  if (aDown == true && eDown == false) {
    System.out.println("a");
  }
  if (eDown == true && aDown == false) {
    System.out.println("e");
  }
 }
}
void keyReleased() {
  if (key == 97) {
    aDown = false;
  }
  if (key == 101) {
    aDown = false;
  }
}
boolean aDown, eDown;

this outputs once and then never again

void keyPressed() {
boolean isDouble = true;
  if (key == 97) {
    aDown = true;
  }
  if (key == 101) {
    eDown = true;
  }
if (eDown == true && aDown == true) {
  System.out.println("ae");
  isDouble = false;
}
  if (aDown == true && eDown == false) {
    System.out.println("a");
  }
  if (eDown == true && aDown == false) {
    System.out.println("e");
  }
 }
void keyReleased() {
  if (key == 97) {
    aDown = false;
  }
  if (key == 101) {
    aDown = false;
  }
}
boolean aDown, eDown;

this goes back to the original problem

@Mook is this more what you were looking for? i made it so holding both and only both a and e together change the background to red, can use that setup for anything though including playing a unique sound file
Edit: if you want a and e to do their own thing, simply add another if statement in draw asking if that list contains just their keyCode values

ArrayList<Integer> keys = new ArrayList<Integer>();

void setup() {
  size(1000, 1000);
}

void draw() {
  background(0);
  
  if (keys.contains(65) && keys.contains(69)){
    background(255,0,0);
  }
}

void keyPressed() {
  if (!keys.contains(keyCode)) {
    keys.add(keyCode);
  }
}

void keyReleased(){
  keys.remove(keys.indexOf(keyCode));
}

I tried it with the print statement instead and it wasnt the solution that you’re looking for but replace the if statement in draw with and it does what you want, if both keys aren’t pressed at exactly the same time and lifted at the same time you’ll still get either the a or e on their own, ill keep trying other solutions

if (keys.size() > 1) {
    if (keys.contains(65) && keys.contains(69)) {
      background(0, 0, 255);
      println("ab");
    }
  } else if (keys.size() == 1) {
    if (keys.contains(65)) {
      background(255, 0, 0);
      println("a");
    } 
    if (keys.contains(69)) {
      background(0, 255, 0);
      println("b");
    }
  }

Hello @Mook,

I have a working solution for my projects:

  • an ArrayList (keysize) was used to track track keys pressed\released
  • keyPressed() and keyReleased() were used
  • check for size of keysize == 2
  • combine the two key characters into a single String variable; this will represent your unique key ab, ba… yz, zy but not aa, bb, c
  • a boolean variable along with keyReleased() was set to true and\or false to control when I checked for a new pair and when I was done

This will give you 26*26 - 26 combinations; ab, ba… yz, zy but not aa, bb, cc

I plotted these when a key pair was pressed:

You may be able to adapt this to suit you.

Give it a try!

:)

Please format your code as per instructions here:
https://discourse.processing.org/faq#format-your-code
You can go back and edit it.

Hi, I was able to ask someone in person and they came up with a solution. The code is kind of complex but basically the keyboard starts out unarmed and once any key is pressed it becomes armed. Any other keys pressed within this period counts as a single press and the program prints out the ascii values.

class KeyManager {
  private final int HOTKEY_WAIT = 100; //(ms)
  
  private boolean[] keyPresses;
  
  HotKey result;
  private int first_press;
  private boolean armed;
  
  KeyManager() {
    keyPresses = new boolean[130];
    armed = true;
    result = new HotKey();
  }
  
  public void pressKey(char key) {
    int ascii = int(Character.toLowerCase(key));
    keyPresses[ascii] = true;
  }
  
  public void releaseKey(char key) {
    int ascii = int(Character.toLowerCase(key));
    keyPresses[ascii] = false;
  }
  
  //In draw loop
  public HotKey checkHotkeyPressed() {
    if (armed && allKeysUp()) { return new HotKey(); }
    
    if (armed && !allKeysUp()) {
      armed = false;
      first_press = millis();
    }
    
    //Key has been pressed
    if (millis()-first_press <= HOTKEY_WAIT) {
      
      if (result.full()) {
        return new HotKey();
      }
      
      for (int i = 0; i < keyPresses.length; i++) {
        if (result.full()) {
          break;
        }
        if (keyPresses[i] && !result.hasAscii(i)) {
          result.addKey(i);
        }
      }
      
    } else {
      if (allKeysUp()) { armed = true; }
      HotKey temp = result;
      result = new HotKey();
      return temp;
    }
    
    
    //Past time and not armed
    return new HotKey();
    
    
  }
  
  private boolean allKeysUp() {
    for (int i = 0; i < keyPresses.length; i++) {
      if (keyPresses[i]) { return false; }
    }
    return true;
  }
  
  
}

class HotKey {
  public int ascii1;
  public int ascii2;
  public int ascii3;
  
  public int length;
  
  HotKey() { length = 0; }
  HotKey(char a1) {
    ascii1 = int(Character.toLowerCase(a1));
    length = 1;
  }
  HotKey(char a1, char a2) {
    ascii1 = int(Character.toLowerCase(a1));
    ascii2 = int(Character.toLowerCase(a2));
    length = 2;
  }
  HotKey(char a1, char a2, char a3) {
    ascii1 = int(Character.toLowerCase(a1));
    ascii2 = int(Character.toLowerCase(a2));
    ascii3 = int(Character.toLowerCase(a3));
    length = 3;
  }
  
  public void addKey(int a) {
    if (length == 0) {
      length = 1;
      ascii1 = a;
    } else if (length == 1) {
      length = 2;
      ascii2 = a;
    } else if (length == 2) {
      length = 3;
      ascii3 = a;
    }
  }
  
  public boolean full() {
    return length >= 3;
  }
  
  public boolean hasAscii(int a) {
    if (length == 0) { return false; }
    if (length == 1) { return ascii1 == a; }
    if (length == 2) { return ascii1 == a || ascii2 == a; }
    if (length == 3) { return ascii1 == a || ascii2 == a || ascii3 == a; }
    return false;
  }
  
  public boolean isEquivalent(HotKey h) {
    if (length != h.length) { return false; }
    
    if (length == 1) { return ascii1 == h.ascii1; }
    if (length == 2) {
      if (ascii1 == h.ascii1 && ascii2 == h.ascii2) { return true; }
      if (ascii1 == h.ascii2 && ascii2 == h.ascii1) { return true; }
      return false;
    }
    if (length == 3) {
      if (ascii1 == h.ascii1 && ascii2 == h.ascii2 && ascii3 == h.ascii3) { return true; }
      if (ascii1 == h.ascii1 && ascii2 == h.ascii3 && ascii3 == h.ascii2) { return true; }
      if (ascii1 == h.ascii2 && ascii2 == h.ascii1 && ascii3 == h.ascii3) { return true; }
      if (ascii1 == h.ascii2 && ascii2 == h.ascii3 && ascii3 == h.ascii1) { return true; }
      if (ascii1 == h.ascii3 && ascii2 == h.ascii2 && ascii3 == h.ascii1) { return true; }
      if (ascii1 == h.ascii3 && ascii2 == h.ascii1 && ascii3 == h.ascii2) { return true; }
      return false;
    }
    return false;
  }
  
  @Override
  public String toString() {
    if (length == 0) { return "{}"; }
    if (length == 1) { return "{" + ascii1 + "}"; }
    if (length == 2) { return "{" + ascii1 + ", " + ascii2 + "}"; }
    if (length == 3) { return "{" + ascii1 + ", " + ascii2 + ", " + ascii3 + "}"; }
    
    println("UNCAUGHT LENGTH ERROR!");
    return "";
  }
  
}
KeyManager keyManager = new KeyManager();

HotKey cool_one = new HotKey('a', 'b');
HotKey cool_two = new HotKey('b', 'f', 'g');

void setup() {
  size(400, 400);
}

void draw() {
  background(150);
  
  HotKey pressed = keyManager.checkHotkeyPressed();
  if (pressed.length > 0) {
    println(pressed);
  }
  
  if (pressed.isEquivalent(cool_one)) {
    println("GOT COOL_ONE");
  }
  if (pressed.isEquivalent(cool_two)) {
    println("GOT COOL_TWO");
  }
  
}

void keyPressed() {
  //Guaranteed Ascii
  if (int(key) < 200) {
    keyManager.pressKey(key);
  }
}

void keyReleased() {
  //Guaranteed Ascii
  if (int(key) < 200) {
    keyManager.releaseKey(key);
  }
}

That’s the code he came up with. I’ll be able to reformat it with more if loops to make key specific actions. Thank you all for the help I appreciate it a lot!

I swear I saw you posted your solution for less than 1 minute and then it vanished!

Anyways, I’m gonna leave my own approach for every1 to see:

  • The solution above can keep track up to 6 keys at once.
  • Up to 6 keyCode values are stored as a 5-bit value inside the single int variable heldKeys.
  • Each keyCode is mapped via function abc() to a range of 1 to 26, representing ‘A’ to ‘Z’.
  • Once all keys are released, the final result of heldKeys is used as a key index to access the HashMap phs in order to get() its corresponding associated String object.
  • Either that String or an ERROR message is displayed on the canvas.
  • More questions about my sketch just ask away.
2 Likes

I did! but then it got removed by the auto moderator for some reason! anyways thank you so much for the help I’m pretty sure that works too

1 Like