From 590cf78b026f0de369c19f81c9a25b19770d1440 Mon Sep 17 00:00:00 2001 From: Kiichi Ito Date: Sun, 21 Jun 2026 21:15:17 +0900 Subject: [PATCH] Enter lyric melisma with the underscore key on non-US keyboards A lyric melisma is entered with the underscore character. Its default shortcut is Shift+-, which only yields '_' on US-ANSI keyboards. On layouts where '_' is a dedicated key (e.g. Japanese JIS on macOS) or is produced by a different combination (AZERTY, QWERTZ, ...), the shortcut layer never routes the underscore key to the add-melisma action, so a melisma cannot be entered at all. Handle the underscore key directly in the notation view while editing lyrics: Key_Underscore with no modifiers is claimed in shortcutOverrideEvent() and dispatched to add-melisma in keyPressEvent(), bypassing the keyboard-layout-dependent shortcut path. The dispatch is deferred to the next event-loop turn so add-melisma's edit teardown does not run while the key event is still being delivered. Shift+- keeps working on US layouts, and non-lyrics text editing is unaffected. Refs #14914 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../notationviewinputcontroller.cpp | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/notationscene/qml/MuseScore/NotationScene/notationviewinputcontroller.cpp b/src/notationscene/qml/MuseScore/NotationScene/notationviewinputcontroller.cpp index a9b14d8a210d5..0a80b17dcf13d 100644 --- a/src/notationscene/qml/MuseScore/NotationScene/notationviewinputcontroller.cpp +++ b/src/notationscene/qml/MuseScore/NotationScene/notationviewinputcontroller.cpp @@ -63,6 +63,12 @@ static bool seekAllowed(const mu::engraving::EngravingItem* element) return muse::contains(ALLOWED_TYPES, element->type()); } +static bool isEditingLyrics(const INotationInteractionPtr& interaction) +{ + const EngravingItem* element = interaction->selection()->element(); + return interaction->isTextEditingStarted() && element && element->isLyrics(); +} + NotationViewInputController::NotationViewInputController(IControlledView* view, const muse::modularity::ContextPtr& iocCtx) : muse::Contextable(iocCtx), m_view(view) { @@ -1451,6 +1457,13 @@ bool NotationViewInputController::shortcutOverrideEvent(QKeyEvent* event) } if (viewInteraction()->isEditingElement()) { + // The shortcut layer cannot route the underscore key to the add-melisma + // action on non-US keyboard layouts (e.g. JIS, where '_' is its own + // dedicated key rather than Shift+'-'). Claim it here so it is delivered + // as a key press and handled directly in keyPressEvent(). + if (key == Qt::Key_Underscore && event->modifiers() == Qt::NoModifier && isEditingLyrics(viewInteraction())) { + return true; + } return viewInteraction()->isEditAllowed(event); } @@ -1475,9 +1488,18 @@ void NotationViewInputController::keyPressEvent(QKeyEvent* event) m_view->asItem()->setCursor({}); event->accept(); } else if (viewInteraction()->isEditingElement()) { - viewInteraction()->editElement(event); - if (key == Qt::Key_Shift) { - viewInteraction()->updateTimeTickAnchors(event); + if (key == Qt::Key_Underscore && event->modifiers() == Qt::NoModifier && isEditingLyrics(viewInteraction())) { + // Underscore -> melisma in lyrics (the shortcut layer can't map '_' + // to add-melisma on non-US keyboard layouts; see shortcutOverrideEvent()). + // Dispatch on the next event-loop turn so add-melisma's text-edit + // teardown does not run while this key event is still being delivered. + QTimer::singleShot(0, m_view->asItem(), [this]() { dispatcher()->dispatch("add-melisma"); }); + event->accept(); + } else { + viewInteraction()->editElement(event); + if (key == Qt::Key_Shift) { + viewInteraction()->updateTimeTickAnchors(event); + } } } else if (key == Qt::Key_Shift) { viewInteraction()->updateTimeTickAnchors(event);