Capture keypress events on TransparentWidget?

Hello!

I’d like to do something when a user clicks on an arrow key while mousing over a transparent widget. I was already shown how to handle the mouse-over code here.

My next step: I’d like to take some action when the user clicks either the left or right arrow keys.

I found onHoverText in the API reference here, but I don’t know what it is or how to use it. This might be a completely separate question, but do these API members contain documentation in plain English that describe their function and include sample code?

Any direction would be appreciated.

Thanks! Bret

haha, nope. If you look at the source to our sequencer you can see these in use. Here’s part of it: https://github.com/squinkylabs/SquinkyVCV/blob/6cd92018eca23e92f8268916c103627f229af2cc/src/seq/NoteDisplay.h

1 Like

Awesome, thanks!

Here’s exactly what I needed: https://github.com/squinkylabs/SquinkyVCV/blob/6cd92018eca23e92f8268916c103627f229af2cc/src/seq/NoteDisplay.cpp#L383

Great, glad it helped. btw, @Vortico was extremely helpful when I was working though this, so if you have any more questions, you will get good answers.

Why are you using TransparentWidget? It is “a Widget that does not respond to events and does not pass events to children”. You should use OpaqueWidget if you want the user to interact with it.

Event classes are documented in event.hpp.

Thanks @Vortico,

I really didn’t know the difference from OpaqueWidget and TransparentWidget until just now. The reason I used OpaqueWidget was just out of ignorance. I was using code that I had copy/pasted and modified. Thanks for the information.

Thanks!

I’m almost there, but I ran into one little snag. My key event doesn’t seem to be getting consumed by VCV Rack. When I click on the left arrow key, I do get a debug message of KEY_LEFT pressed, but the rack interface also scrolls to the left.

Here’s my code:

void onHoverKey(const event::HoverKey &e) override
{
  DEBUG("Key: %d.  Action: %d", e.key, e.action);

  if (e.action == GLFW_PRESS)
  {
    switch (e.key) 
    {
      case GLFW_KEY_LEFT:
	 e.consume(this);
	 DEBUG("KEY_LEFT pressed");
	 break;
      case GLFW_KEY_RIGHT:
         break;
      default:
         OpaqueWidget::onHoverKey(e);
    }
  }
  else
  {
    OpaqueWidget::onHoverKey(e);
  }
}

Any suggestions?

did you copy the part of my code where I consume the event so that rack doesn’t get it?

void NoteDisplay::onHoverKey(const event::HoverKey &e)
{
    bool handled = handleKey(e.key, e.mods, e.action);
    if (handled) {
        e.consume(this);
    } else if (isKeyWeNeedToStealFromRack(e.key)) {
        // Swallow all hover events around cursor keys.
        // This keeps Rack from stealing them.
        e.consume(this);
    } else {
        OpaqueWidget::onHoverKey(e);
    }
}

Oh, I see that you did. Difference between transparent and opaque widgets?

That doesn’t seem to be the case. I had it as a transparent Wizard at first until Andrew corrected me.

I don’t know about Rack v1, but in Rack v2, the RackScrollWidget that holds the rack has been rewritten to handle arrow keys only if the HoverKey is not consumed by children.

I’ve simplified the problem and I’m still mystified. This code will not consume the press event for the left and right arrows, even if “got here” was reached.

void onHoverKey(const event::HoverKey & e) override {

  // e.consume(this);

  if (e.action == GLFW_PRESS && e.key == GLFW_KEY_LEFT) {
    DEBUG("got here");
    e.consume(this);
  } 
  else {
    OpaqueWidget::onHoverKey(e);
  }
}

But of course, this code consumes everything:

void onHoverKey(const event::HoverKey & e) override {
  e.consume(this); 
}

How strange is that?!

I notice you are looking at e.action. Does event::HoverKey have an e.action? My code doesn’t look at that.

I think so? I grabbed it from your code here:

(see your posted code above in this thread)

What I think may be happening is that another action, like key repeat, is tripping me up. This works fine without the action. I’ll probably roll with that for now and keep it simple. :slight_smile:

void onHoverKey(const event::HoverKey &e) override
{
	if (e.key == GLFW_KEY_LEFT)
	{
		e.consume(this);
		DEBUG("yes");
	}
}

Just for historical sake, here’s the code that is working well for my needs:

if (e.key == GLFW_KEY_RIGHT)
{
	e.consume(this);

	if(e.action == GLFW_PRESS)
	{
		// do stuff
	}
}

Okay, looks like Rack v1 behaves the same as the Rack v2 branch I’m working on. If you don’t consume the HoverKey when action == RACK_HELD, it’ll be consumed be its ancestor, RackScrollWidget by scrolling the rack.

1 Like