Multi-Button KeyPress


#1

What is the JUCE way I should go about to trigger something in my application if two different keys are pressed at the same time?

For example, let’s say I map the ‘1’ key on my keyboard to do something in my application. I also map the ‘2’ key to do something else. But I also want to have another separate trigger if the keys ‘1’ & ‘2’ are held down simultaneously.

I’m basically trying to setup a kind of toggle chain of three buttons to activate a specific button for each of these three key combinations: ‘1’ pressed independently, ‘2’ pressed independently, and ‘1’ & ‘2’ pressed/held simultaneously.


#2

It’s actually a simple Logic problem, there’s no specific Juce way of doing it:

if(isPressed(KeyA) && !isPressed(KeyB)) { }
else if(!isPressed(KeyA) && isPressed(KeyB)) { }
else if(isPressed(KeyA) && isPressed(KeyB)) { }

Write an “isPressed(key)” function that returns true/false


#3

I’m still confused on how to actually implement this.

I’ve created two KeyPress objects in a component and mapped them to keys.
I’ve also made that component a KeyListener so that it can receive a callback when keys are pressed.
I have to implement this callback in my component via the pure virtual function: bool keyPressed (const KeyPress &key, Component *originatingComponent).

But now I’m confused because within this callback, I only have reference to the one KeyPress the function gives me called key. So within this callback I can’t actually check if multiple keys are pressed. I only have access to this one key that initiated the callback.


#4

you have two approaches:

1). build something that will store currently pressed keys. whenever you get a keyPressed() event happening, you can check your keysThatHaveBeenPressed[] for the key in question. Building it similar to how the MidiKeyboardState class handles storing NoteOn’s and NoteOff would work really well.

  1. use static bool KeyPress::isKeyCurrentlyDown() and check for the key that you are looking for:
if( key == aKey ) {
  if(KeyPress::isKeyCurrentlyDown(bKey) ) { aKey and bKey are pressed }
  else if( !KeyPress::isKeyCurrentlyDown(bKey) { only aKey is pressed }
} else if( key == bKey ) { 
  if( KeyPress::isKeyCurrentlyDown(aKey)) { bKey and aKey are pressed }
  else if( !KeyPress::isKeyCurrentlyDown(aKey) { only bKey is pressed }
} etc

#5

Oh okay, this makes sense! Thank you!
The only problem I seem to be having is that the KeyListener portion of my Component is not registering any KeyPresses. I’m running a test to try and output the keypress code to the console, but it will not output anything.

class MyComponent : public Component, private KeyListener
{
    public:
        MyComponent()
        : aKey('A'),
          bKey('B')
        {
        }

        // . . .

    private:
        KeyPress aKey, bKey;


        bool keyPressed (const KeyPress &key, Component *originatingComponent) override
        {
            // This is where I'm going to put my if statements to check for buttons down
            // . . .
            // But here is my console test to make sure this function gets called:
            std::cout << key.getKeyCode();
        }
}

Am I setting up my KeyListener incorrectly?


#6

you didn’t add your class as a listener in the constructor:

void Component::addKeyListener ( KeyListener * newListener )

you gotta addKeyListener(this); in your constructor and removeKeyListener(this); in your destructor.


#7

If it’s a component you do not need a key listener. Just override bool Component::keyPressed (const KeyPress &key). Be sure to indicate that you want keyboard focus with setWantsKeyboardFocus (true); and call grabKeyboardFocus sometime later. You may need to call grabKeyboardFocus outside of your constructor as the parent component may override this again.


#8

@fabian 's solution worked! Thanks!

If anyone else comes along this topic, my final working code was put together in this structure:

class MyComponent : public Component
{
    public:
        MyComponent()
        : aKey('A'),     // Assigns keyboard key 'A' to this KeyPress
          bKey('B')     // Assigns keyboard key 'B' to this KeyPress
          {
          }

        // . . .

          bool keyPressed (const KeyPress &key) override
          {
              if (key = aKey)
              {
                  if (!bKey.isCurrentlyDown())
                      // Stuff to do only when 'A' is pressed . . .
                  else
                     // Stuff to do when 'A' was pressed while 'B'
                     // was being held down . . .
              }
              else if (key == bKey)
              {
                  if (!aKey.isCurrentlyDown())
                      // Stuff to do only when 'B' is pressed . . .
                  else
                     // Stuff to do when 'B' was pressed while 'A'
                     // was being held down . . .
              }
              else { }
          }

    private:
        KeyPress aKey, bKey;
        // . . .