help with creating custom keyboard shortcuts

I want to create a few keyboard shortcuts for a module where they will work when the module is in “focus” like when the mouse is hovering. I’m having trouble getting the event to respond though. Here’s my code so far. Nothing happens when the mouse is over the module and I press SHIFT:

     void onHoverKey(const event::HoverKey &e) override {
		if (e.action == GLFW_PRESS) {
			if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) {
				DEBUG("SHIFT!!");
			}
		}
     }

I don’t know if you can detect shift on its own, since it’s a modifier.

Also, in general, if you don’t handle a hover key you need to call the base class implementation, I think.

It should return true if shift is down, like in this doc: macros

What do you mean calling the base class? Would that be e.consume(this)?

oh, ok. My Seq++ processes hover keys. You might take a look there. Also, if you have a keyboard input you might want to make the keys re-mappable. Seq++ does that also via a JSON file. Here’s an example where I call “the base class”:

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);
    }
}

bool NoteDisplay::isKeyWeNeedToStealFromRack(int key) {
#ifdef _USERKB
    if (!kbdManager->shouldGrabKeys()) {
        return false;
    }
#endif
    bool isCursor = false;
    switch (key) {
        case GLFW_KEY_LEFT:
        case GLFW_KEY_RIGHT:
        case GLFW_KEY_UP:
        case GLFW_KEY_DOWN:
        case GLFW_KEY_BACKSPACE:
        case GLFW_KEY_KP_DECIMAL:
        case GLFW_KEY_DELETE:
            isCursor = true;
    }
    return isCursor;
}

In that (ancient) code clearly isCursor is not really an accurate name. Also _USERKB is always defined - it enables the user keyboard mapping, which was a feature added after the initial release.

1 Like

Ok checking out the code now. Thanks for your help

1 Like

Ok I’m having trouble getting this to even work.

void onHoverKey(const event::HoverKey &e) override {
     DEBUG("hovering");
}

I can get it to work accept that I have no idea what I’m doing when it triggers. I thought that by having the mouse location on top of the module, and pressing a keyboard button that it should fire. But it doesn’t. So I’m confused about how this method even works.

beats me. on what object are you overriding onHoverKey? when you say “I can get it to work”, what are you doing?

Ah, I had onHoverKey inside of my display so it only worked for that part of the module, not the whole thing. I feel stupid now. But the mystery is getting solved!

hey, we’ve all done much stupider things than that, right?

1 Like

Whew, ok that was the problem. The onHoverKey() method needs to be in the ModuleWidget struct for it to work on the entire module. So if anyone stumbles across this thread hopefully this will save you the hours I spent on it.

Ok, another issue I’m having is combining keystrokes. I’m trying to create a kb shortcut like control + tab to trigger an event. I’ve tried this but nothing happens.

	void onHoverKey(const event::HoverKey &e) override {
		if (e.action == GLFW_PRESS) {
			bool tab = e.key == GLFW_KEY_TAB;
			bool ctl = (e.mods & RACK_MOD_MASK) == GLFW_MOD_CONTROL;

			if (tab && ctl) {
				e.consume(this);
				DEBUG("tab + control!!");
			}
     }

this would be much easier if you would just build Seq++ and poke at it. This stuff has been working in there since VCV 0.6…

1 Like

Try using RACK_MOD_CTRL instead of GLFW_MOD_CONTROL.

From the SDK:

/** Remaps Ctrl to Cmd on Mac
Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place of Ctrl on Linux/Windows.
*/
#if defined ARCH_MAC
	#define RACK_MOD_CTRL GLFW_MOD_SUPER
	#define RACK_MOD_CTRL_NAME "Cmd"
#else
	#define RACK_MOD_CTRL GLFW_MOD_CONTROL
	#define RACK_MOD_CTRL_NAME "Ctrl"
#endif
#define RACK_MOD_SHIFT_NAME "Shift"
#define RACK_MOD_ALT_NAME "Alt"

Oh yes you can. Check out the “shift pedal” module, I use it all the time, very useful.

I don’t want to use command on Mac because command + tab is already an OS defined shortcut. I specifically wanted to use ctrl + tab. I think it may have to do with the order in which the buttons are pressed.

I am…trying to figure out how your JSON file is being read.

Feel free to ask any questions.

Ok I see the problem. I found this for how VCV is using keyboard shortcuts, and when I use other keystroke combinations (other than tab) it works. I guess there’s just some weird behavior when combining control + tab.

I wonder if it’s related to the code snippet I posted yesterday. I found I had to do special processing on all the hover keys that rack uses if I wanted to be able to steal any of them.

Well, the new problem is that somehow Rack won’t accept any keyboard commands on that particular module where I’ve implemented the kb shortcuts. The first part is never consumed (like if I try to delete the module or duplicate it). But my shortcut finally works, lol. So I got it working only to break regular functionality in Rack. This is my code and I looked at VCV code for it.

	void onHoverKey(const event::HoverKey &e) override {
		OpaqueWidget::onHoverKey(e);
		if (e.isConsumed())
			return;

		if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
			if (e.key == GLFW_KEY_LEFT_BRACKET && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
				shiftPatternLeft(); // <-this works
				e.consume(this);
			}
}