From 0549b42ec0ca98953e449571401e469964aa94a3 Mon Sep 17 00:00:00 2001 From: Nevicar <5368799+Nevicar@users.noreply.github.com> Date: Sat, 10 Jan 2026 07:37:13 -0700 Subject: [PATCH] Fixed Return and Enter being treated as different keys on Mac OS (#6729) Co-authored-by: Chad Gorman Reviewed-by: Mm2PL --- CHANGELOG.md | 1 + src/controllers/hotkeys/HotkeyController.cpp | 28 ++++++--- src/controllers/hotkeys/HotkeyHelpers.cpp | 59 +++++++++++++++++++ src/controllers/hotkeys/HotkeyHelpers.hpp | 4 ++ src/widgets/dialogs/EditHotkeyDialog.cpp | 14 +++++ .../settingspages/KeyboardSettingsPage.cpp | 14 ++++- 6 files changed, 111 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26693087..bdca4601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - Bugfix: Fixed CMD + DELETE behavior in the user notes editing dialog for macOS. (#6676) - Bugfix: Fixed a potential crash when closing Chatterino with a slow network connection. (#6645) - Bugfix: Disable "Sort Tabs Alphabetically" action when notebook layout is locked. (#6710) +- Bugfix: Fixed Return and Enter being treated as different keys on Mac OS. (#6726) - Dev: Update release documentation. (#6498) - Dev: Make code sanitizers opt in with the `CHATTERINO_SANITIZER_SUPPORT` CMake option. After that's enabled, use the `SANITIZE_*` flag to enable individual sanitizers. (#6493) - Dev: Remove unused QTextCodec includes. (#6487) diff --git a/src/controllers/hotkeys/HotkeyController.cpp b/src/controllers/hotkeys/HotkeyController.cpp index cbb9951e..902ae08b 100644 --- a/src/controllers/hotkeys/HotkeyController.cpp +++ b/src/controllers/hotkeys/HotkeyController.cpp @@ -11,6 +11,7 @@ #include "util/RapidJsonSerializeQString.hpp" // IWYU pragma: keep #include +#include #include #include #include @@ -138,14 +139,27 @@ std::vector HotkeyController::shortcutsForCategory( }; auto qs = QKeySequence(hotkey->keySequence()); - auto stringified = qs.toString(QKeySequence::NativeText); - if (stringified.contains("Return")) - { - stringified.replace("Return", "Enter"); - auto copy = QKeySequence(stringified, QKeySequence::NativeText); - createShortcutFromKeySeq(copy); - } + // Create shortcut for the original key sequence createShortcutFromKeySeq(qs); + + // Qt treats Key_Return (main keyboard) and Key_Enter (numpad) as different keys, but they are expect to behave identically. + // Create a duplicate shortcut with the alternate key. + for (int i = 0; i < qs.count(); i++) + { + auto combo = qs[i]; + if (combo.key() == Qt::Key_Return) + { + QKeyCombination enterCombo(combo.keyboardModifiers(), + Qt::Key_Enter); + createShortcutFromKeySeq(QKeySequence(enterCombo)); + } + else if (combo.key() == Qt::Key_Enter) + { + QKeyCombination returnCombo(combo.keyboardModifiers(), + Qt::Key_Return); + createShortcutFromKeySeq(QKeySequence(returnCombo)); + } + } } return output; } diff --git a/src/controllers/hotkeys/HotkeyHelpers.cpp b/src/controllers/hotkeys/HotkeyHelpers.cpp index 0bd67d74..9337f0b4 100644 --- a/src/controllers/hotkeys/HotkeyHelpers.cpp +++ b/src/controllers/hotkeys/HotkeyHelpers.cpp @@ -7,8 +7,10 @@ #include "controllers/hotkeys/ActionNames.hpp" #include "controllers/hotkeys/HotkeyCategory.hpp" +#include #include +#include #include namespace chatterino { @@ -52,4 +54,61 @@ std::optional findHotkeyActionDefinition( return {}; } +QKeySequence normalizeKeySequence(const QKeySequence &seq) +{ + if (seq.isEmpty()) + { + return seq; + } + + // First, check if any normalization is needed + bool needsNormalization = false; + for (int i = 0; i < seq.count(); i++) + { + if (seq[i].key() == Qt::Key_Enter) + { + needsNormalization = true; + break; + } + } + + if (!needsNormalization) + { + return seq; + } + + // Build normalized key combinations, preserving all keys in the sequence + // QKeySequence supports up to 4 key combinations + std::array combos{}; + int count = seq.count(); + + for (int i = 0; i < count; i++) + { + auto combo = seq[i]; + if (combo.key() == Qt::Key_Enter) + { + combos.at(i) = + QKeyCombination(combo.keyboardModifiers(), Qt::Key_Return); + } + else + { + combos.at(i) = combo; + } + } + + // Construct QKeySequence with the appropriate number of keys + switch (count) + { + case 1: + return {combos.at(0)}; + case 2: + return {combos.at(0), combos.at(1)}; + case 3: + return {combos.at(0), combos.at(1), combos.at(2)}; + case 4: + default: + return {combos.at(0), combos.at(1), combos.at(2), combos.at(3)}; + } +} + } // namespace chatterino diff --git a/src/controllers/hotkeys/HotkeyHelpers.hpp b/src/controllers/hotkeys/HotkeyHelpers.hpp index 53a19df9..fe0ed6fa 100644 --- a/src/controllers/hotkeys/HotkeyHelpers.hpp +++ b/src/controllers/hotkeys/HotkeyHelpers.hpp @@ -6,6 +6,7 @@ #include "controllers/hotkeys/ActionNames.hpp" +#include #include #include @@ -17,4 +18,7 @@ std::vector parseHotkeyArguments(QString argumentString); std::optional findHotkeyActionDefinition( HotkeyCategory category, const QString &action); +// convert key_enter to key_return so that both keys function the same. preserves multi-key sequences and combinations. +QKeySequence normalizeKeySequence(const QKeySequence &seq); + } // namespace chatterino diff --git a/src/widgets/dialogs/EditHotkeyDialog.cpp b/src/widgets/dialogs/EditHotkeyDialog.cpp index b8e8f106..40600b0d 100644 --- a/src/widgets/dialogs/EditHotkeyDialog.cpp +++ b/src/widgets/dialogs/EditHotkeyDialog.cpp @@ -12,6 +12,8 @@ #include "controllers/hotkeys/HotkeyHelpers.hpp" #include "ui_EditHotkeyDialog.h" +#include + namespace chatterino { EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr hotkey, @@ -21,6 +23,18 @@ EditHotkeyDialog::EditHotkeyDialog(const std::shared_ptr hotkey, , data_(hotkey) { this->ui_->setupUi(this); + // normalize Key_Enter (numpad) to Key_Return so both Enter keys display and behave identically + QObject::connect( + this->ui_->keyComboEdit, &QKeySequenceEdit::keySequenceChanged, this, + [this](const QKeySequence &keySequence) { + auto normalized = normalizeKeySequence(keySequence); + if (normalized != keySequence) + { + // Block signals to prevent infinite loop + QSignalBlocker blocker(this->ui_->keyComboEdit); + this->ui_->keyComboEdit->setKeySequence(normalized); + } + }); this->setStyleSheet(R"(QToolTip { padding: 2px; background-color: #333333; diff --git a/src/widgets/settingspages/KeyboardSettingsPage.cpp b/src/widgets/settingspages/KeyboardSettingsPage.cpp index bfef14ac..0124795a 100644 --- a/src/widgets/settingspages/KeyboardSettingsPage.cpp +++ b/src/widgets/settingspages/KeyboardSettingsPage.cpp @@ -8,6 +8,7 @@ #include "common/QLogging.hpp" #include "controllers/hotkeys/Hotkey.hpp" #include "controllers/hotkeys/HotkeyController.hpp" +#include "controllers/hotkeys/HotkeyHelpers.hpp" #include "controllers/hotkeys/HotkeyModel.hpp" #include "util/LayoutCreator.hpp" #include "widgets/dialogs/EditHotkeyDialog.hpp" @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -94,8 +96,16 @@ KeyboardSettingsPage::KeyboardSettingsPage() auto *searchText = new QLabel("Search keybind:", this); QObject::connect(keySequenceInput, &QKeySequenceEdit::keySequenceChanged, - [view](const QKeySequence &keySequence) { - view->filterSearchResultsHotkey(keySequence); + this, + [view, keySequenceInput](const QKeySequence &keySequence) { + // Normalize Key_Enter (numpad) to Key_Return for consistent search + auto normalized = normalizeKeySequence(keySequence); + if (normalized != keySequence) + { + QSignalBlocker blocker(keySequenceInput); + keySequenceInput->setKeySequence(normalized); + } + view->filterSearchResultsHotkey(normalized); }); view->addCustomButton(searchText); view->addCustomButton(keySequenceInput);