diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index ff942fc2..a60dcb02 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -37,7 +37,6 @@ struct ModuleWidget : widget::OpaqueWidget { void draw(const DrawArgs &args) override; void drawShadow(const DrawArgs &args); - void onHover(const event::Hover &e) override; void onButton(const event::Button &e) override; void onHoverKey(const event::HoverKey &e) override; void onDragStart(const event::DragStart &e) override; diff --git a/include/app/RackScrollWidget.hpp b/include/app/RackScrollWidget.hpp index 2696a52e..594c4d82 100644 --- a/include/app/RackScrollWidget.hpp +++ b/include/app/RackScrollWidget.hpp @@ -18,7 +18,7 @@ struct RackScrollWidget : ui::ScrollWidget { RackScrollWidget(); void step() override; void draw(const DrawArgs &args) override; - void onHover(const event::Hover &e) override; + void onHoverKey(const event::HoverKey &e) override; void onHoverScroll(const event::HoverScroll &e) override; void reset(); }; diff --git a/include/event.hpp b/include/event.hpp index 857c0217..6ce81894 100644 --- a/include/event.hpp +++ b/include/event.hpp @@ -2,6 +2,7 @@ #include "common.hpp" #include "math.hpp" #include +#include namespace rack { @@ -76,13 +77,16 @@ struct PositionBase { }; +#define RACK_HELD 3 + + /** An event prototype with a GLFW key. */ struct KeyBase { /** GLFW_KEY_* */ int key; /** GLFW_KEY_*. You should usually use `key` instead. */ int scancode; - /** GLFW_RELEASE, GLFW_PRESS, or GLFW_REPEAT */ + /** GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT, or RACK_HELD */ int action; /** GLFW_MOD_* */ int mods; @@ -338,6 +342,7 @@ struct State { /** For double-clicking */ double lastClickTime = -INFINITY; widget::Widget *lastClickedWidget = NULL; + std::set heldKeys; void setHovered(widget::Widget *w); void setDragged(widget::Widget *w, int button); diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index b3e20045..f149d3f2 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -304,19 +304,6 @@ void ModuleWidget::drawShadow(const DrawArgs &args) { nvgFill(args.vg); } -void ModuleWidget::onHover(const event::Hover &e) { - // Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. - if ((glfwGetKey(APP->window->win, GLFW_KEY_DELETE) == GLFW_PRESS - || glfwGetKey(APP->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) - && (APP->window->getMods() & RACK_MOD_MASK) == 0) { - removeAction(); - e.consume(NULL); - return; - } - - OpaqueWidget::onHover(e); -} - void ModuleWidget::onButton(const event::Button &e) { OpaqueWidget::onButton(e); if (e.isConsumed()) @@ -379,6 +366,18 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { } break; } } + + if (e.action == RACK_HELD) { + switch (e.key) { + case GLFW_KEY_DELETE: + case GLFW_KEY_BACKSPACE: { + if ((e.mods & RACK_MOD_MASK) == 0) { + removeAction(); + e.consume(NULL); + } + } break; + } + } } void ModuleWidget::onDragStart(const event::DragStart &e) { diff --git a/src/app/ParamWidget.cpp b/src/app/ParamWidget.cpp index 820e2e1c..04b79a13 100644 --- a/src/app/ParamWidget.cpp +++ b/src/app/ParamWidget.cpp @@ -47,7 +47,7 @@ struct ParamField : ui::TextField { } ui::MenuOverlay *overlay = getAncestorOfType(); - overlay->requestedDelete = true; + overlay->requestDelete(); e.consume(this); } diff --git a/src/app/RackScrollWidget.cpp b/src/app/RackScrollWidget.cpp index 3aa9c8fc..f27a7799 100644 --- a/src/app/RackScrollWidget.cpp +++ b/src/app/RackScrollWidget.cpp @@ -74,26 +74,40 @@ void RackScrollWidget::draw(const DrawArgs &args) { ScrollWidget::draw(args); } -void RackScrollWidget::onHover(const event::Hover &e) { +void RackScrollWidget::onHoverKey(const event::HoverKey &e) { + ScrollWidget::onHoverKey(e); + if (e.isConsumed()) + return; + // Scroll with arrow keys float arrowSpeed = 30.0; - if ((APP->window->getMods() & RACK_MOD_MASK) == (RACK_MOD_CTRL |GLFW_MOD_SHIFT)) + if ((e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL |GLFW_MOD_SHIFT)) arrowSpeed /= 16.0; - else if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) + else if ((e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) arrowSpeed *= 4.0; - else if ((APP->window->getMods() & RACK_MOD_MASK) == GLFW_MOD_SHIFT) + else if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) arrowSpeed /= 4.0; - if (glfwGetKey(APP->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) - offset.x -= arrowSpeed; - if (glfwGetKey(APP->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) - offset.x += arrowSpeed; - if (glfwGetKey(APP->window->win, GLFW_KEY_UP) == GLFW_PRESS) - offset.y -= arrowSpeed; - if (glfwGetKey(APP->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) - offset.y += arrowSpeed; - - ScrollWidget::onHover(e); + if (e.action == RACK_HELD) { + switch (e.key) { + case GLFW_KEY_LEFT: { + offset.x -= arrowSpeed; + e.consume(this); + } break; + case GLFW_KEY_RIGHT: { + offset.x += arrowSpeed; + e.consume(this); + } break; + case GLFW_KEY_UP: { + offset.y -= arrowSpeed; + e.consume(this); + } break; + case GLFW_KEY_DOWN: { + offset.y += arrowSpeed; + e.consume(this); + } break; + } + } } void RackScrollWidget::onHoverScroll(const event::HoverScroll &e) { diff --git a/src/event.cpp b/src/event.cpp index 0937ceb5..9c40a749 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -169,6 +169,13 @@ bool State::handleButton(math::Vec pos, int button, int action, int mods) { } bool State::handleHover(math::Vec pos, math::Vec mouseDelta) { + // Fake a key RACK_HELD event for each held key + int mods = 0; //APP->window->getMods(); + for (int key : heldKeys) { + int scancode = glfwGetKeyScancode(key); + handleKey(pos, key, scancode, RACK_HELD, mods); + } + if (draggedWidget) { // DragMove DragMove eDragMove; @@ -204,6 +211,7 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) { } bool State::handleLeave() { + heldKeys.clear(); setDragHovered(NULL); setHovered(NULL); return true; @@ -256,6 +264,16 @@ bool State::handleText(math::Vec pos, int codepoint) { } bool State::handleKey(math::Vec pos, int key, int scancode, int action, int mods) { + // Update heldKey state + if (action == GLFW_PRESS) { + heldKeys.insert(key); + } + else if (action == GLFW_RELEASE) { + auto it = heldKeys.find(key); + if (it != heldKeys.end()) + heldKeys.erase(it); + } + if (selectedWidget) { // SelectKey Context cSelectKey; diff --git a/src/ui/MenuItem.cpp b/src/ui/MenuItem.cpp index ff38a154..a4049829 100644 --- a/src/ui/MenuItem.cpp +++ b/src/ui/MenuItem.cpp @@ -81,7 +81,7 @@ void MenuItem::doAction() { MenuOverlay *overlay = getAncestorOfType(); if (overlay) { - overlay->requestedDelete = true; + overlay->requestDelete(); } } diff --git a/src/ui/MenuOverlay.cpp b/src/ui/MenuOverlay.cpp index fb5b9575..19074d81 100644 --- a/src/ui/MenuOverlay.cpp +++ b/src/ui/MenuOverlay.cpp @@ -23,7 +23,8 @@ void MenuOverlay::onButton(const event::Button &e) { return; if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { - requestedDelete = true; + requestDelete(); + e.consume(this); } } @@ -33,7 +34,8 @@ void MenuOverlay::onHoverKey(const event::HoverKey &e) { return; if (e.action == GLFW_PRESS && e.key == GLFW_KEY_ESCAPE) { - requestedDelete = true; + requestDelete(); + e.consume(this); } }