From a5737d93fb39d7d82adbd0d678d90b70f860d2e5 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sat, 20 May 2023 12:54:35 -0400 Subject: [PATCH 1/4] Create option for control objects to be issued repeatedly if a keyboard key is held. Fixes https://github.com/mixxxdj/mixxx/issues/11569 Applies to: * beats_adjust_faster, beats_adjust_slower * beats_translate_earlier, beats_translate_later * beatjump_size_halve, beatjump_size_double * beatjump_forward, beatjump_backward * loop_halve, loop_double * beatjump_X_foward, beatjump_X_backward * rate_perm_down, rate_perm_down_small, rate_perm_up, rate_perm_up_small --- src/control/control.cpp | 6 ++++-- src/control/control.h | 11 +++++++++++ src/control/controlobject.h | 10 ++++++++++ src/controllers/keyboard/keyboardeventfilter.cpp | 13 +++---------- src/controllers/keyboard/keyboardeventfilter.h | 15 ++++++++++++++- src/engine/controls/bpmcontrol.cpp | 4 ++++ src/engine/controls/loopingcontrol.cpp | 8 ++++++++ src/engine/controls/ratecontrol.cpp | 4 ++++ 8 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/control/control.cpp b/src/control/control.cpp index c45708f0bbd..a9e2bb57aca 100644 --- a/src/control/control.cpp +++ b/src/control/control.cpp @@ -37,7 +37,8 @@ ControlDoublePrivate::ControlDoublePrivate() m_trackFlags(Stat::COUNT | Stat::SUM | Stat::AVERAGE | Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX), // default CO is read only - m_confirmRequired(true) { + m_confirmRequired(true), + m_kbd_repeatable(false) { m_value.setValue(0.0); } @@ -56,7 +57,8 @@ ControlDoublePrivate::ControlDoublePrivate( m_trackType(Stat::UNSPECIFIED), m_trackFlags(Stat::COUNT | Stat::SUM | Stat::AVERAGE | Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX), - m_confirmRequired(false) { + m_confirmRequired(false), + m_kbd_repeatable(false) { initialize(defaultValue); } diff --git a/src/control/control.h b/src/control/control.h index 69c6b6e10de..9af659c282b 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -80,6 +80,14 @@ class ControlDoublePrivate : public QObject { m_description = description; } + void setKbdRepeatable(bool enable) { + m_kbd_repeatable = enable; + } + + bool getKbdRepeatable() const { + return m_kbd_repeatable; + } + // Sets the control value. void set(double value, QObject* pSender); // directly sets the control value. Must be used from and only from the @@ -198,6 +206,9 @@ class ControlDoublePrivate : public QObject { // User-visible, i18n description for what the control does. QString m_description; + // If true, this control will be issued repeatedly if the keyboard key is held. + bool m_kbd_repeatable; + // The control value. ControlValueAtomic m_value; // The default control value. diff --git a/src/control/controlobject.h b/src/control/controlobject.h index a543b5ca48e..49d927a8172 100644 --- a/src/control/controlobject.h +++ b/src/control/controlobject.h @@ -53,6 +53,16 @@ class ControlObject : public QObject { } } + void setKbdRepeatable(bool enable) { + if (m_pControl) { + m_pControl->setKbdRepeatable(enable); + } + } + + bool getKbdRepeatable() const { + return m_pControl ? m_pControl->getKbdRepeatable() : false; + } + void addAlias(const ConfigKey& aliasKey) const { ControlDoublePrivate::insertAlias(aliasKey, m_key); } diff --git a/src/controllers/keyboard/keyboardeventfilter.cpp b/src/controllers/keyboard/keyboardeventfilter.cpp index c69b872414e..3a33f76f609 100644 --- a/src/controllers/keyboard/keyboardeventfilter.cpp +++ b/src/controllers/keyboard/keyboardeventfilter.cpp @@ -4,7 +4,6 @@ #include #include -#include "control/controlobject.h" #include "moc_keyboardeventfilter.cpp" #include "util/cmdlineargs.h" @@ -36,15 +35,9 @@ bool KeyboardEventFilter::eventFilter(QObject*, QEvent* e) { #else int keyId = ke->nativeScanCode(); #endif - //qDebug() << "KeyPress event =" << ke->key() << "KeyId =" << keyId; - // Run through list of active keys to see if the pressed key is already active - // Just for returning true if we are consuming this key event - - foreach (const KeyDownInformation& keyDownInfo, m_qActiveKeyList) { - if (keyDownInfo.keyId == keyId) { - return true; - } + if (shouldSkipHeldKey(keyId)) { + return true; } QKeySequence ks = getKeySeq(ke); @@ -76,7 +69,7 @@ bool KeyboardEventFilter::eventFilter(QObject*, QEvent* e) { } return result; } - } else if (e->type()==QEvent::KeyRelease) { + } else if (e->type() == QEvent::KeyRelease) { QKeyEvent* ke = (QKeyEvent*)e; #ifdef __APPLE__ diff --git a/src/controllers/keyboard/keyboardeventfilter.h b/src/controllers/keyboard/keyboardeventfilter.h index 5f49fd34dcd..f5b0ea291c1 100644 --- a/src/controllers/keyboard/keyboardeventfilter.h +++ b/src/controllers/keyboard/keyboardeventfilter.h @@ -1,8 +1,9 @@ #pragma once -#include #include +#include +#include "control/controlobject.h" #include "preferences/configobject.h" class ControlObject; @@ -39,6 +40,18 @@ class KeyboardEventFilter : public QObject { // Returns a valid QString with modifier keys from a QKeyEvent QKeySequence getKeySeq(QKeyEvent *e); + + // Run through list of active keys to see if the pressed key is already active + // and is not a control that repeats when held. + bool shouldSkipHeldKey(int keyId) { + foreach (const KeyDownInformation& keyDownInfo, m_qActiveKeyList) { + if (keyDownInfo.keyId == keyId && !keyDownInfo.pControl->getKbdRepeatable()) { + return true; + } + } + return false; + } + // List containing keys which is currently pressed QList m_qActiveKeyList; // Pointer to keyboard config object diff --git a/src/engine/controls/bpmcontrol.cpp b/src/engine/controls/bpmcontrol.cpp index 9219af09304..6c9759a17e6 100644 --- a/src/engine/controls/bpmcontrol.cpp +++ b/src/engine/controls/bpmcontrol.cpp @@ -68,18 +68,22 @@ BpmControl::BpmControl(const QString& group, m_pLocalBpm = new ControlObject(ConfigKey(group, "local_bpm")); m_pAdjustBeatsFaster = new ControlPushButton(ConfigKey(group, "beats_adjust_faster"), false); + m_pAdjustBeatsFaster->setKbdRepeatable(true); connect(m_pAdjustBeatsFaster, &ControlObject::valueChanged, this, &BpmControl::slotAdjustBeatsFaster, Qt::DirectConnection); m_pAdjustBeatsSlower = new ControlPushButton(ConfigKey(group, "beats_adjust_slower"), false); + m_pAdjustBeatsSlower->setKbdRepeatable(true); connect(m_pAdjustBeatsSlower, &ControlObject::valueChanged, this, &BpmControl::slotAdjustBeatsSlower, Qt::DirectConnection); m_pTranslateBeatsEarlier = new ControlPushButton(ConfigKey(group, "beats_translate_earlier"), false); + m_pTranslateBeatsEarlier->setKbdRepeatable(true); connect(m_pTranslateBeatsEarlier, &ControlObject::valueChanged, this, &BpmControl::slotTranslateBeatsEarlier, Qt::DirectConnection); m_pTranslateBeatsLater = new ControlPushButton(ConfigKey(group, "beats_translate_later"), false); + m_pTranslateBeatsLater->setKbdRepeatable(true); connect(m_pTranslateBeatsLater, &ControlObject::valueChanged, this, &BpmControl::slotTranslateBeatsLater, Qt::DirectConnection); diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 0526d21e5b0..d136528ba64 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -176,20 +176,24 @@ LoopingControl::LoopingControl(const QString& group, Qt::DirectConnection); m_pCOBeatJumpSizeHalve = new ControlPushButton(ConfigKey(group, "beatjump_size_halve")); + m_pCOBeatJumpSizeHalve->setKbdRepeatable(true); connect(m_pCOBeatJumpSizeHalve, &ControlObject::valueChanged, this, &LoopingControl::slotBeatJumpSizeHalve); m_pCOBeatJumpSizeDouble = new ControlPushButton(ConfigKey(group, "beatjump_size_double")); + m_pCOBeatJumpSizeDouble->setKbdRepeatable(true); connect(m_pCOBeatJumpSizeDouble, &ControlObject::valueChanged, this, &LoopingControl::slotBeatJumpSizeDouble); m_pCOBeatJumpForward = new ControlPushButton(ConfigKey(group, "beatjump_forward")); + m_pCOBeatJumpForward->setKbdRepeatable(true); connect(m_pCOBeatJumpForward, &ControlObject::valueChanged, this, &LoopingControl::slotBeatJumpForward); m_pCOBeatJumpBackward = new ControlPushButton(ConfigKey(group, "beatjump_backward")); + m_pCOBeatJumpBackward->setKbdRepeatable(true); connect(m_pCOBeatJumpBackward, &ControlObject::valueChanged, this, &LoopingControl::slotBeatJumpBackward); @@ -221,9 +225,11 @@ LoopingControl::LoopingControl(const QString& group, connect(m_pCOLoopScale, &ControlObject::valueChanged, this, &LoopingControl::slotLoopScale); m_pLoopHalveButton = new ControlPushButton(ConfigKey(group, "loop_halve")); + m_pLoopHalveButton->setKbdRepeatable(true); connect(m_pLoopHalveButton, &ControlObject::valueChanged, this, &LoopingControl::slotLoopHalve); m_pLoopDoubleButton = new ControlPushButton(ConfigKey(group, "loop_double")); + m_pLoopDoubleButton->setKbdRepeatable(true); connect(m_pLoopDoubleButton, &ControlObject::valueChanged, this, &LoopingControl::slotLoopDouble); @@ -1775,11 +1781,13 @@ BeatJumpControl::BeatJumpControl(const QString& group, double size) : m_dBeatJumpSize(size) { m_pJumpForward = new ControlPushButton( keyForControl(group, "beatjump_%1_forward", size)); + m_pJumpForward->setKbdRepeatable(true); connect(m_pJumpForward, &ControlObject::valueChanged, this, &BeatJumpControl::slotJumpForward, Qt::DirectConnection); m_pJumpBackward = new ControlPushButton( keyForControl(group, "beatjump_%1_backward", size)); + m_pJumpBackward->setKbdRepeatable(true); connect(m_pJumpBackward, &ControlObject::valueChanged, this, &BeatJumpControl::slotJumpBackward, Qt::DirectConnection); diff --git a/src/engine/controls/ratecontrol.cpp b/src/engine/controls/ratecontrol.cpp index bf76da8841c..455e84d15a3 100644 --- a/src/engine/controls/ratecontrol.cpp +++ b/src/engine/controls/ratecontrol.cpp @@ -104,24 +104,28 @@ RateControl::RateControl(const QString& group, connect(m_pButtonRatePermDown, &ControlObject::valueChanged, this, &RateControl::slotControlRatePermDown, Qt::DirectConnection); + m_pButtonRatePermDown->setKbdRepeatable(true); m_pButtonRatePermDownSmall = new ControlPushButton(ConfigKey(group,"rate_perm_down_small")); connect(m_pButtonRatePermDownSmall, &ControlObject::valueChanged, this, &RateControl::slotControlRatePermDownSmall, Qt::DirectConnection); + m_pButtonRatePermDownSmall->setKbdRepeatable(true); m_pButtonRatePermUp = new ControlPushButton(ConfigKey(group,"rate_perm_up")); connect(m_pButtonRatePermUp, &ControlObject::valueChanged, this, &RateControl::slotControlRatePermUp, Qt::DirectConnection); + m_pButtonRatePermUp->setKbdRepeatable(true); m_pButtonRatePermUpSmall = new ControlPushButton(ConfigKey(group,"rate_perm_up_small")); connect(m_pButtonRatePermUpSmall, &ControlObject::valueChanged, this, &RateControl::slotControlRatePermUpSmall, Qt::DirectConnection); + m_pButtonRatePermUpSmall->setKbdRepeatable(true); // Temporary rate-change buttons m_pButtonRateTempDown = From 1cdeac2775ca6e6c0f356a25cfe272a18a5a2554 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sat, 20 May 2023 15:36:11 -0400 Subject: [PATCH 2/4] Update src/controllers/keyboard/keyboardeventfilter.h use std::any_of instead of old foreach Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- src/controllers/keyboard/keyboardeventfilter.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllers/keyboard/keyboardeventfilter.h b/src/controllers/keyboard/keyboardeventfilter.h index f5b0ea291c1..4e35cc75d3d 100644 --- a/src/controllers/keyboard/keyboardeventfilter.h +++ b/src/controllers/keyboard/keyboardeventfilter.h @@ -44,12 +44,12 @@ class KeyboardEventFilter : public QObject { // Run through list of active keys to see if the pressed key is already active // and is not a control that repeats when held. bool shouldSkipHeldKey(int keyId) { - foreach (const KeyDownInformation& keyDownInfo, m_qActiveKeyList) { - if (keyDownInfo.keyId == keyId && !keyDownInfo.pControl->getKbdRepeatable()) { - return true; - } - } - return false; + return std::any_of( + m_qActiveKeyList.cbegin(), + m_qActiveKeyList.cend(), + [&](const KeyDownInformation& keyDownInfo) { + return keyDownInfo.keyId == keyId && !keyDownInfo.pControl->getKbdRepeatable(); + }); } // List containing keys which is currently pressed From dd449e40735db0b04769b0514f18a0fb47c73d94 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sun, 21 May 2023 14:44:32 -0400 Subject: [PATCH 3/4] keyboard repeat: also apply to potmeter controls --- src/control/controlpotmeter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/control/controlpotmeter.cpp b/src/control/controlpotmeter.cpp index 145d17613b8..e0c5631a674 100644 --- a/src/control/controlpotmeter.cpp +++ b/src/control/controlpotmeter.cpp @@ -91,6 +91,11 @@ PotmeterControls::PotmeterControls(const ConfigKey& key) &ControlPushButton::valueChanged, this, &PotmeterControls::decSmallValue); + m_controlUp.setKbdRepeatable(true); + m_controlUpSmall.setKbdRepeatable(true); + m_controlDown.setKbdRepeatable(true); + m_controlDownSmall.setKbdRepeatable(true); + connect(&m_controlSetDefault, &ControlPushButton::valueChanged, this, From 49d68169edc38e6f95009202e85ae253d1fc4ea0 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Tue, 23 May 2023 12:33:26 -0400 Subject: [PATCH 4/4] Keyboard Repeat: use camelCase var --- src/control/control.cpp | 4 ++-- src/control/control.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/control/control.cpp b/src/control/control.cpp index a9e2bb57aca..b7a9ac1f0f0 100644 --- a/src/control/control.cpp +++ b/src/control/control.cpp @@ -38,7 +38,7 @@ ControlDoublePrivate::ControlDoublePrivate() Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX), // default CO is read only m_confirmRequired(true), - m_kbd_repeatable(false) { + m_kbdRepeatable(false) { m_value.setValue(0.0); } @@ -58,7 +58,7 @@ ControlDoublePrivate::ControlDoublePrivate( m_trackFlags(Stat::COUNT | Stat::SUM | Stat::AVERAGE | Stat::SAMPLE_VARIANCE | Stat::MIN | Stat::MAX), m_confirmRequired(false), - m_kbd_repeatable(false) { + m_kbdRepeatable(false) { initialize(defaultValue); } diff --git a/src/control/control.h b/src/control/control.h index 9af659c282b..a33c4648f1f 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -81,11 +81,11 @@ class ControlDoublePrivate : public QObject { } void setKbdRepeatable(bool enable) { - m_kbd_repeatable = enable; + m_kbdRepeatable = enable; } bool getKbdRepeatable() const { - return m_kbd_repeatable; + return m_kbdRepeatable; } // Sets the control value. @@ -207,7 +207,7 @@ class ControlDoublePrivate : public QObject { QString m_description; // If true, this control will be issued repeatedly if the keyboard key is held. - bool m_kbd_repeatable; + bool m_kbdRepeatable; // The control value. ControlValueAtomic m_value;