From cb01a156075dd998d06490fe8f8ee19482b4f952 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 18 Sep 2024 05:56:22 -0400 Subject: [PATCH] Add wiget::getKeyCommandName() and getKeyName(). Use it instead of hard-coding key command strings. --- include/widget/event.hpp | 8 ++++++ src/app/MenuBar.cpp | 24 +++++++++--------- src/app/ModuleWidget.cpp | 20 +++++++-------- src/app/RackWidget.cpp | 22 ++++++++-------- src/plugin/Model.cpp | 2 +- src/ui/TextField.cpp | 8 +++--- src/widget/event.cpp | 55 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 38 deletions(-) diff --git a/include/widget/event.hpp b/include/widget/event.hpp index 9e82cdd2..b2e747c1 100644 --- a/include/widget/event.hpp +++ b/include/widget/event.hpp @@ -17,7 +17,11 @@ Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place o #define RACK_MOD_CTRL GLFW_MOD_CONTROL #define RACK_MOD_CTRL_NAME "Ctrl" #endif + +#define RACK_MOD_SHIFT GLFW_MOD_SHIFT #define RACK_MOD_SHIFT_NAME "Shift" + +#define RACK_MOD_ALT GLFW_MOD_ALT #define RACK_MOD_ALT_NAME "Alt" /** Filters actual mod keys from the mod flags. @@ -36,6 +40,10 @@ namespace rack { namespace widget { +std::string getKeyName(int key); +std::string getKeyCommandName(int key, int mods); + + struct Widget; diff --git a/src/app/MenuBar.cpp b/src/app/MenuBar.cpp index de2d27ab..c2c077ba 100644 --- a/src/app/MenuBar.cpp +++ b/src/app/MenuBar.cpp @@ -73,11 +73,11 @@ struct FileButton : MenuButton { menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { + menu->addChild(createMenuItem("New", widget::getKeyCommandName(GLFW_KEY_N, RACK_MOD_CTRL), []() { APP->patch->loadTemplateDialog(); })); - menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { + menu->addChild(createMenuItem("Open", widget::getKeyCommandName(GLFW_KEY_O, RACK_MOD_CTRL), []() { APP->patch->loadDialog(); })); @@ -90,11 +90,11 @@ struct FileButton : MenuButton { } }, settings::recentPatchPaths.empty())); - menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { + menu->addChild(createMenuItem("Save", widget::getKeyCommandName(GLFW_KEY_S, RACK_MOD_CTRL), []() { APP->patch->saveDialog(); })); - menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { + menu->addChild(createMenuItem("Save as", widget::getKeyCommandName(GLFW_KEY_S, RACK_MOD_CTRL | GLFW_MOD_SHIFT), []() { APP->patch->saveAsDialog(); })); @@ -102,7 +102,7 @@ struct FileButton : MenuButton { APP->patch->saveAsDialog(false); })); - menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { + menu->addChild(createMenuItem("Revert", widget::getKeyCommandName(GLFW_KEY_O, RACK_MOD_CTRL | GLFW_MOD_SHIFT), []() { APP->patch->revertDialog(); }, APP->patch->path == "")); @@ -119,7 +119,7 @@ struct FileButton : MenuButton { menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { + menu->addChild(createMenuItem("Quit", widget::getKeyCommandName(GLFW_KEY_Q, RACK_MOD_CTRL), []() { APP->window->close(); })); } @@ -147,7 +147,7 @@ struct EditButton : MenuButton { APP->history->undo(); } }; - menu->addChild(createMenuItem("", RACK_MOD_CTRL_NAME "+Z")); + menu->addChild(createMenuItem("", widget::getKeyCommandName(GLFW_KEY_Z, RACK_MOD_CTRL))); struct RedoItem : ui::MenuItem { void step() override { @@ -159,7 +159,7 @@ struct EditButton : MenuButton { APP->history->redo(); } }; - menu->addChild(createMenuItem("", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+Z")); + menu->addChild(createMenuItem("", widget::getKeyCommandName(GLFW_KEY_Z, RACK_MOD_CTRL | GLFW_MOD_SHIFT))); menu->addChild(createMenuItem("Clear cables", "", [=]() { APP->patch->disconnectDialog(); @@ -403,7 +403,7 @@ struct ViewButton : MenuButton { menu->addChild(createMenuLabel("Window")); bool fullscreen = APP->window->isFullScreen(); - std::string fullscreenText = "F11"; + std::string fullscreenText = widget::getKeyCommandName(GLFW_KEY_F11, 0); if (fullscreen) fullscreenText += " " CHECKMARK_STRING; menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { @@ -424,7 +424,7 @@ struct ViewButton : MenuButton { zoomSlider->box.size.x = 250.0; menu->addChild(zoomSlider); - menu->addChild(createMenuItem("Zoom to fit modules", "F4", [=]() { + menu->addChild(createMenuItem("Zoom to fit modules", widget::getKeyCommandName(GLFW_KEY_F4, 0), [=]() { APP->scene->rackScroll->zoomToModules(); })); @@ -668,7 +668,7 @@ struct EngineButton : MenuButton { menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - std::string cpuMeterText = "F3"; + std::string cpuMeterText = widget::getKeyCommandName(GLFW_KEY_F3, 0); if (settings::cpuMeter) cpuMeterText += " " CHECKMARK_STRING; menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() { @@ -986,7 +986,7 @@ struct HelpButton : MenuButton { APP->scene->addChild(tipWindowCreate()); })); - menu->addChild(createMenuItem("User manual", "F1", [=]() { + menu->addChild(createMenuItem("User manual", widget::getKeyCommandName(GLFW_KEY_F1, 0), [=]() { system::openBrowser("https://vcvrack.com/manual"); })); diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 9baddd92..ccbcead1 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -1015,13 +1015,13 @@ void ModuleWidget::createContextMenu() { // Preset menu->addChild(createSubmenuItem("Preset", "", [=](ui::Menu* menu) { - menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() { + menu->addChild(createMenuItem("Copy", widget::getKeyCommandName(GLFW_KEY_C, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->copyClipboard(); })); - menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() { + menu->addChild(createMenuItem("Paste", widget::getKeyCommandName(GLFW_KEY_V, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->pasteClipboardAction(); @@ -1063,28 +1063,28 @@ void ModuleWidget::createContextMenu() { })); // Initialize - menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() { + menu->addChild(createMenuItem("Initialize", widget::getKeyCommandName(GLFW_KEY_I, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->resetAction(); })); // Randomize - menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() { + menu->addChild(createMenuItem("Randomize", widget::getKeyCommandName(GLFW_KEY_R, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->randomizeAction(); })); // Disconnect cables - menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() { + menu->addChild(createMenuItem("Disconnect cables", widget::getKeyCommandName(GLFW_KEY_U, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->disconnectAction(); })); // Bypass - std::string bypassText = RACK_MOD_CTRL_NAME "+E"; + std::string bypassText = widget::getKeyCommandName(GLFW_KEY_E, RACK_MOD_CTRL); bool bypassed = module && module->isBypassed(); if (bypassed) bypassText += " " CHECKMARK_STRING; @@ -1095,28 +1095,28 @@ void ModuleWidget::createContextMenu() { })); // Duplicate - menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() { + menu->addChild(createMenuItem("Duplicate", widget::getKeyCommandName(GLFW_KEY_D, RACK_MOD_CTRL), [=]() { if (!weakThis) return; weakThis->cloneAction(false); })); // Duplicate with cables - menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() { + menu->addChild(createMenuItem("└ with cables", widget::getKeyCommandName(GLFW_KEY_D, RACK_MOD_CTRL | GLFW_MOD_SHIFT), [=]() { if (!weakThis) return; weakThis->cloneAction(true); })); // Delete - menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() { + menu->addChild(createMenuItem("Delete", widget::getKeyCommandName(GLFW_KEY_BACKSPACE, 0) + "/" + widget::getKeyCommandName(GLFW_KEY_DELETE, 0), [=]() { if (!weakThis) return; weakThis->removeAction(); }, false, true)); // Zoom to fit - menu->addChild(createMenuItem("Zoom to fit", RACK_MOD_CTRL_NAME "+F4", [=]() { + menu->addChild(createMenuItem("Zoom to fit", widget::getKeyCommandName(GLFW_KEY_F4, RACK_MOD_CTRL), [=]() { if (!weakThis) return; APP->scene->rackScroll->zoomToBound(weakThis->getBox()); diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 7bea8023..712341b1 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -1306,22 +1306,22 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { // Enable alwaysConsume of menu items if the number of selected modules changes // Select all - menu->addChild(createMenuItem("Select all", RACK_MOD_CTRL_NAME "+A", [=]() { + menu->addChild(createMenuItem("Select all", widget::getKeyCommandName(GLFW_KEY_A, RACK_MOD_CTRL), [=]() { selectAll(); }, false, true)); // Deselect - menu->addChild(createMenuItem("Deselect", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+A", [=]() { + menu->addChild(createMenuItem("Deselect", widget::getKeyCommandName(GLFW_KEY_A, RACK_MOD_CTRL | GLFW_MOD_SHIFT), [=]() { deselectAll(); }, n == 0, true)); // Copy - menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() { + menu->addChild(createMenuItem("Copy", widget::getKeyCommandName(GLFW_KEY_C, RACK_MOD_CTRL), [=]() { copyClipboardSelection(); }, n == 0)); // Paste - menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() { + menu->addChild(createMenuItem("Paste", widget::getKeyCommandName(GLFW_KEY_V, RACK_MOD_CTRL), [=]() { pasteClipboardAction(); }, false, true)); @@ -1331,22 +1331,22 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { }, n == 0)); // Initialize - menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() { + menu->addChild(createMenuItem("Initialize", widget::getKeyCommandName(GLFW_KEY_I, RACK_MOD_CTRL), [=]() { resetSelectionAction(); }, n == 0)); // Randomize - menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() { + menu->addChild(createMenuItem("Randomize", widget::getKeyCommandName(GLFW_KEY_R, RACK_MOD_CTRL), [=]() { randomizeSelectionAction(); }, n == 0)); // Disconnect cables - menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() { + menu->addChild(createMenuItem("Disconnect cables", widget::getKeyCommandName(GLFW_KEY_U, RACK_MOD_CTRL), [=]() { disconnectSelectionAction(); }, n == 0)); // Bypass - std::string bypassText = RACK_MOD_CTRL_NAME "+E"; + std::string bypassText = widget::getKeyCommandName(GLFW_KEY_E, RACK_MOD_CTRL); bool bypassed = (n > 0) && isSelectionBypassed(); if (bypassed) bypassText += " " CHECKMARK_STRING; @@ -1355,17 +1355,17 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) { }, n == 0, true)); // Duplicate - menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() { + menu->addChild(createMenuItem("Duplicate", widget::getKeyCommandName(GLFW_KEY_D, RACK_MOD_CTRL), [=]() { cloneSelectionAction(false); }, n == 0)); // Duplicate with cables - menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() { + menu->addChild(createMenuItem("└ with cables", widget::getKeyCommandName(GLFW_KEY_D, RACK_MOD_CTRL | GLFW_MOD_SHIFT), [=]() { cloneSelectionAction(true); }, n == 0)); // Delete - menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() { + menu->addChild(createMenuItem("Delete", widget::getKeyCommandName(GLFW_KEY_BACKSPACE, 0) + "/" + widget::getKeyCommandName(GLFW_KEY_DELETE, 0), [=]() { deleteSelectionAction(); }, n == 0, true)); } diff --git a/src/plugin/Model.cpp b/src/plugin/Model.cpp index f197b45e..20d92be7 100644 --- a/src/plugin/Model.cpp +++ b/src/plugin/Model.cpp @@ -156,7 +156,7 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { // manual std::string manualUrl = getManualUrl(); if (manualUrl != "") { - menu->addChild(createMenuItem("User manual", RACK_MOD_CTRL_NAME "+F1", [=]() { + menu->addChild(createMenuItem("User manual", widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() { system::openBrowser(manualUrl); })); } diff --git a/src/ui/TextField.cpp b/src/ui/TextField.cpp index 6173adb8..fcd640ec 100644 --- a/src/ui/TextField.cpp +++ b/src/ui/TextField.cpp @@ -349,25 +349,25 @@ void TextField::createContextMenu() { TextFieldCutItem* cutItem = new TextFieldCutItem; cutItem->text = "Cut"; - cutItem->rightText = RACK_MOD_CTRL_NAME "+X"; + cutItem->rightText = widget::getKeyCommandName(GLFW_KEY_X, RACK_MOD_CTRL); cutItem->textField = this; menu->addChild(cutItem); TextFieldCopyItem* copyItem = new TextFieldCopyItem; copyItem->text = "Copy"; - copyItem->rightText = RACK_MOD_CTRL_NAME "+C"; + copyItem->rightText = widget::getKeyCommandName(GLFW_KEY_C, RACK_MOD_CTRL); copyItem->textField = this; menu->addChild(copyItem); TextFieldPasteItem* pasteItem = new TextFieldPasteItem; pasteItem->text = "Paste"; - pasteItem->rightText = RACK_MOD_CTRL_NAME "+V"; + pasteItem->rightText = widget::getKeyCommandName(GLFW_KEY_V, RACK_MOD_CTRL); pasteItem->textField = this; menu->addChild(pasteItem); TextFieldSelectAllItem* selectAllItem = new TextFieldSelectAllItem; selectAllItem->text = "Select all"; - selectAllItem->rightText = RACK_MOD_CTRL_NAME "+A"; + selectAllItem->rightText = widget::getKeyCommandName(GLFW_KEY_A, RACK_MOD_CTRL); selectAllItem->textField = this; menu->addChild(selectAllItem); } diff --git a/src/widget/event.cpp b/src/widget/event.cpp index 9592565d..9028b3ed 100644 --- a/src/widget/event.cpp +++ b/src/widget/event.cpp @@ -9,6 +9,61 @@ namespace rack { namespace widget { +std::string getKeyName(int key) { + // glfwGetKeyName overrides + switch (key) { + case GLFW_KEY_SPACE: return "Space"; + } + + const char* keyNameC = glfwGetKeyName(key, GLFW_KEY_UNKNOWN); + if (keyNameC) { + std::string keyName = keyNameC; + if (keyName.size() == 1) + keyName[0] = std::toupper((unsigned char) keyName[0]); + return keyName; + } + + // Unprintable keys with names + switch (key) { + case GLFW_KEY_ESCAPE: return "Escape"; + case GLFW_KEY_ENTER: return "Enter"; + case GLFW_KEY_TAB: return "Tab"; + case GLFW_KEY_BACKSPACE: return "Backspace"; + case GLFW_KEY_INSERT: return "Insert"; + case GLFW_KEY_DELETE: return "Delete"; + case GLFW_KEY_RIGHT: return "Right"; + case GLFW_KEY_LEFT: return "Left"; + case GLFW_KEY_DOWN: return "Down"; + case GLFW_KEY_UP: return "Up"; + case GLFW_KEY_PAGE_UP: return "Page Up"; + case GLFW_KEY_PAGE_DOWN: return "Page Down"; + case GLFW_KEY_HOME: return "Home"; + case GLFW_KEY_END: return "End"; + case GLFW_KEY_KP_ENTER: return "Enter"; + } + + if (GLFW_KEY_F1 <= key && key <= GLFW_KEY_F25) + return string::f("F%d", key - GLFW_KEY_F1 + 1); + + return ""; +} + + +std::string getKeyCommandName(int key, int mods) { + std::string modsName; + if (mods & RACK_MOD_CTRL) { + modsName += RACK_MOD_CTRL_NAME "+"; + } + if (mods & GLFW_MOD_SHIFT) { + modsName += RACK_MOD_SHIFT_NAME "+"; + } + if (mods & GLFW_MOD_ALT) { + modsName += RACK_MOD_ALT_NAME "+"; + } + return modsName + getKeyName(key); +} + + void EventState::setHoveredWidget(widget::Widget* w) { if (w == hoveredWidget) return;