diff --git a/include/KeyboardShortcuts.h b/include/KeyboardShortcuts.h new file mode 100644 index 00000000000..63f6be6bb75 --- /dev/null +++ b/include/KeyboardShortcuts.h @@ -0,0 +1,77 @@ +/* + * KeyboardShortcuts.h - Cross-platform handling of keyboard modifier keys + * + * Copyright (c) 2025 Michael Gregorius + * Copyright (c) 2025 Tres Finocchiaro + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef LMMS_KEYBOARDSHORTCUTS_H +#define LMMS_KEYBOARDSHORTCUTS_H + +#include "lmmsconfig.h" + +#include "qnamespace.h" + + +namespace lmms +{ + +// Qt on macOS maps: +// - ControlModifier --> Command keys +// - MetaModifier value --> Control keys +// - Qt::AltModifier --> Option keys +// +// Our UI hints need to be adjusted to accommodate for this +constexpr const char* UI_CTRL_KEY = +#ifdef LMMS_BUILD_APPLE +"⌘"; +#else +"Ctrl"; +#endif + +constexpr const char* UI_ALT_KEY = +#ifdef LMMS_BUILD_APPLE +"Option"; +#else +"Alt"; +#endif + +// UI hint for copying OR linking a UI component +// this MUST be consistent with KBD_COPY_MODIFIER +constexpr const char* UI_COPY_KEY = +#ifdef LMMS_BUILD_APPLE +UI_ALT_KEY; +#else +UI_CTRL_KEY; +#endif + +// Shortcut for copying OR linking a UI component +// this MUST be consistent with UI_COPY_KEY +constexpr Qt::KeyboardModifier KBD_COPY_MODIFIER = +#ifdef LMMS_BUILD_APPLE +Qt::AltModifier; +#else +Qt::ControlModifier; +#endif + +} // namespace lmms + +#endif // LMMS_KEYBOARDSHORTCUTS_H diff --git a/include/lmms_basics.h b/include/lmms_basics.h index 63a2bf3adc2..ea937160304 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -69,15 +69,6 @@ constexpr char LADSPA_PATH_SEPERATOR = #define LMMS_STRINGIFY(s) LMMS_STR(s) #define LMMS_STR(PN) #PN -// Abstract away GUI CTRL key (linux/windows) vs ⌘ (apple) -constexpr const char* UI_CTRL_KEY = -#ifdef LMMS_BUILD_APPLE -"⌘"; -#else -"Ctrl"; -#endif - - } // namespace lmms #endif // LMMS_TYPES_H diff --git a/src/core/AutomationClip.cpp b/src/core/AutomationClip.cpp index 6d99abcc183..ef57a60d50a 100644 --- a/src/core/AutomationClip.cpp +++ b/src/core/AutomationClip.cpp @@ -29,6 +29,7 @@ #include "AutomationNode.h" #include "AutomationClipView.h" #include "AutomationTrack.h" +#include "KeyboardShortcuts.h" #include "LocaleHelper.h" #include "Note.h" #include "PatternStore.h" @@ -952,7 +953,7 @@ QString AutomationClip::name() const { return m_objects.front()->fullDisplayName(); } - return tr( "Drag a control while pressing <%1>" ).arg(UI_CTRL_KEY); + return tr( "Drag a control while pressing <%1>" ).arg(UI_COPY_KEY); } diff --git a/src/gui/AutomatableModelView.cpp b/src/gui/AutomatableModelView.cpp index 0e364993f06..2faf74064a5 100644 --- a/src/gui/AutomatableModelView.cpp +++ b/src/gui/AutomatableModelView.cpp @@ -31,6 +31,7 @@ #include "ControllerConnection.h" #include "embed.h" #include "GuiApplication.h" +#include "KeyboardShortcuts.h" #include "MainWindow.h" #include "StringPairDrag.h" #include "Clipboard.h" @@ -171,7 +172,7 @@ void AutomatableModelView::unsetModel() void AutomatableModelView::mousePressEvent( QMouseEvent* event ) { - if( event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier ) + if (event->button() == Qt::LeftButton && event->modifiers() & KBD_COPY_MODIFIER) { new gui::StringPairDrag( "automatable_model", QString::number( modelUntyped()->id() ), QPixmap(), widget() ); event->accept(); diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index a9f18d6fdc5..8985a047588 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -52,6 +52,7 @@ #include "Instrument.h" #include "InstrumentTrack.h" #include "InstrumentTrackWindow.h" +#include "KeyboardShortcuts.h" #include "MainWindow.h" #include "PatternStore.h" #include "PluginFactory.h" diff --git a/src/gui/ProjectNotes.cpp b/src/gui/ProjectNotes.cpp index a71f146c66e..bf760ec2190 100644 --- a/src/gui/ProjectNotes.cpp +++ b/src/gui/ProjectNotes.cpp @@ -40,6 +40,7 @@ #include "embed.h" #include "Engine.h" #include "GuiApplication.h" +#include "KeyboardShortcuts.h" #include "MainWindow.h" #include "Song.h" diff --git a/src/gui/StringPairDrag.cpp b/src/gui/StringPairDrag.cpp index 54f52c78413..7dc123c36da 100644 --- a/src/gui/StringPairDrag.cpp +++ b/src/gui/StringPairDrag.cpp @@ -61,7 +61,7 @@ StringPairDrag::StringPairDrag( const QString & _key, const QString & _value, auto m = new QMimeData(); m->setData( mimeType( MimeType::StringPair ), txt.toUtf8() ); setMimeData( m ); - exec( Qt::LinkAction, Qt::LinkAction ); + exec( Qt::CopyAction, Qt::CopyAction ); } diff --git a/src/gui/clips/ClipView.cpp b/src/gui/clips/ClipView.cpp index 09dc7960725..1941328195b 100644 --- a/src/gui/clips/ClipView.cpp +++ b/src/gui/clips/ClipView.cpp @@ -41,6 +41,7 @@ #include "GuiApplication.h" #include "InstrumentTrack.h" #include "InstrumentTrackView.h" +#include "KeyboardShortcuts.h" #include "MidiClip.h" #include "MidiClipView.h" #include "Note.h" @@ -633,7 +634,7 @@ void ClipView::mousePressEvent( QMouseEvent * me ) auto pClip = dynamic_cast(m_clip); const bool knifeMode = m_trackView->trackContainerView()->knifeMode(); - if ( me->modifiers() & Qt::ControlModifier && !(sClip && knifeMode) ) + if (me->modifiers() & KBD_COPY_MODIFIER && !(sClip && knifeMode)) { if( isSelected() ) { @@ -726,7 +727,7 @@ void ClipView::mousePressEvent( QMouseEvent * me ) QString hint = m_action == Action::Move || m_action == Action::MoveSelection ? tr( "Press <%1> and drag to make a copy." ) : tr( "Press <%1> for free resizing." ); - m_hint = TextFloat::displayMessage( tr( "Hint" ), hint.arg(UI_CTRL_KEY), + m_hint = TextFloat::displayMessage( tr( "Hint" ), hint.arg(UI_COPY_KEY), embed::getIconPixmap( "hint" ), 0 ); } } @@ -824,7 +825,7 @@ void ClipView::mouseMoveEvent( QMouseEvent * me ) } } - if( me->modifiers() & Qt::ControlModifier ) + if (me->modifiers() & KBD_COPY_MODIFIER) { delete m_hint; m_hint = nullptr; diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 387a10ab45f..cbd68e7ff4f 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -57,6 +57,7 @@ #include "GuiApplication.h" #include "FontHelper.h" #include "InstrumentTrack.h" +#include "KeyboardShortcuts.h" #include "MainWindow.h" #include "MidiClip.h" #include "PatternStore.h" diff --git a/src/gui/editors/TimeLineWidget.cpp b/src/gui/editors/TimeLineWidget.cpp index f75b1cabfac..bea6d43c0ad 100644 --- a/src/gui/editors/TimeLineWidget.cpp +++ b/src/gui/editors/TimeLineWidget.cpp @@ -37,6 +37,7 @@ #include "ConfigManager.h" #include "embed.h" #include "GuiApplication.h" +#include "KeyboardShortcuts.h" #include "NStateButton.h" #include "TextFloat.h" diff --git a/src/gui/tracks/TrackOperationsWidget.cpp b/src/gui/tracks/TrackOperationsWidget.cpp index def0a82cc9c..06e4346743f 100644 --- a/src/gui/tracks/TrackOperationsWidget.cpp +++ b/src/gui/tracks/TrackOperationsWidget.cpp @@ -40,6 +40,7 @@ #include "embed.h" #include "Engine.h" #include "InstrumentTrackView.h" +#include "KeyboardShortcuts.h" #include "PixmapButton.h" #include "Song.h" #include "StringPairDrag.h" @@ -180,9 +181,8 @@ TrackOperationsWidget::TrackOperationsWidget( TrackView * parent ) : */ void TrackOperationsWidget::mousePressEvent( QMouseEvent * me ) { - if( me->button() == Qt::LeftButton && - me->modifiers() & Qt::ControlModifier && - m_trackView->getTrack()->type() != Track::Type::Pattern) + if (me->button() == Qt::LeftButton && me->modifiers() & KBD_COPY_MODIFIER && + m_trackView->getTrack()->type() != Track::Type::Pattern) { DataFile dataFile( DataFile::Type::DragNDropData ); m_trackView->getTrack()->saveState( dataFile, dataFile.content() ); diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index a647df416cf..9337f92581f 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -55,6 +55,7 @@ #include "embed.h" #include "CaptionMenu.h" #include "ConfigManager.h" +#include "KeyboardShortcuts.h" #include "SimpleTextFloat.h" namespace lmms::gui @@ -125,7 +126,7 @@ void Fader::mouseMoveEvent(QMouseEvent* mouseEvent) void Fader::mousePressEvent(QMouseEvent* mouseEvent) { if (mouseEvent->button() == Qt::LeftButton && - !(mouseEvent->modifiers() & Qt::ControlModifier)) + !(mouseEvent->modifiers() & KBD_COPY_MODIFIER)) { AutomatableModel* thisModel = model(); if (thisModel) diff --git a/src/gui/widgets/FloatModelEditorBase.cpp b/src/gui/widgets/FloatModelEditorBase.cpp index 32ce564b64e..540a586f553 100644 --- a/src/gui/widgets/FloatModelEditorBase.cpp +++ b/src/gui/widgets/FloatModelEditorBase.cpp @@ -33,6 +33,7 @@ #include "CaptionMenu.h" #include "ControllerConnection.h" #include "GuiApplication.h" +#include "KeyboardShortcuts.h" #include "LocaleHelper.h" #include "MainWindow.h" #include "ProjectJournal.h" @@ -155,7 +156,7 @@ void FloatModelEditorBase::dropEvent(QDropEvent * de) void FloatModelEditorBase::mousePressEvent(QMouseEvent * me) { if (me->button() == Qt::LeftButton && - ! (me->modifiers() & Qt::ControlModifier) && + ! (me->modifiers() & KBD_COPY_MODIFIER) && ! (me->modifiers() & Qt::ShiftModifier)) { AutomatableModel *thisModel = model(); diff --git a/src/gui/widgets/LcdFloatSpinBox.cpp b/src/gui/widgets/LcdFloatSpinBox.cpp index 4b476bc0cdc..75762b8a1b8 100644 --- a/src/gui/widgets/LcdFloatSpinBox.cpp +++ b/src/gui/widgets/LcdFloatSpinBox.cpp @@ -42,6 +42,7 @@ #include "embed.h" #include "GuiApplication.h" #include "FontHelper.h" +#include "KeyboardShortcuts.h" #include "MainWindow.h" #include "lmms_math.h" @@ -139,7 +140,7 @@ void LcdFloatSpinBox::mousePressEvent(QMouseEvent* event) m_intStep = event->x() < m_wholeDisplay.width(); if (event->button() == Qt::LeftButton && - !(event->modifiers() & Qt::ControlModifier) && + !(event->modifiers() & KBD_COPY_MODIFIER) && event->y() < m_wholeDisplay.cellHeight() + 2) { m_mouseMoving = true; diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 3f12360ccdc..9d04d5fdb7e 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -28,6 +28,7 @@ #include #include "LcdSpinBox.h" +#include "KeyboardShortcuts.h" #include "CaptionMenu.h" @@ -79,7 +80,7 @@ void LcdSpinBox::contextMenuEvent(QContextMenuEvent* event) void LcdSpinBox::mousePressEvent( QMouseEvent* event ) { if( event->button() == Qt::LeftButton && - ! ( event->modifiers() & Qt::ControlModifier ) && + ! (event->modifiers() & KBD_COPY_MODIFIER) && event->y() < cellHeight() + 2 ) { m_mouseMoving = true;