[vlc-commits] [Git][videolan/vlc][3.0.x] 5 commits: qt: make Qt Mouse/Input/KeyEvent to VLC converter functions const

Steve Lhomme (@robUx4) gitlab at videolan.org
Thu Nov 6 15:00:53 UTC 2025



Steve Lhomme pushed to branch 3.0.x at VideoLAN / VLC


Commits:
5d1b310c by Pierre Lamot at 2025-11-05T14:59:45+01:00
qt: make Qt Mouse/Input/KeyEvent to VLC converter functions const

- - - - -
49e97a2a by Pierre Lamot at 2025-11-05T15:43:10+01:00
qt: introduce WheelToVLCConverter to aggregate wheel events as VLC keys

this class aggregates wheel events until a full step (120 angle units) is
reached in a direction and emits a synthesized event usable by VLC hotkeys

(cherry picked from commit 7498ac55db73dec778d97de88a758707964ebdc7 without the
QML related methods)

- - - - -
b28eb7a5 by Pierre Lamot at 2025-11-05T15:43:10+01:00
qt: fix scrolling vertically on input slider always scrolls forward

When scrolling vertically, angleDelta.x() is 0, so the backward direction was
never accounted for.

We now use wheel converter as it provides better handling of touch pads

- - - - -
1d52533d by Pierre Lamot at 2025-11-05T15:43:10+01:00
qt: fix scrolling horizontally on the volumne slider has no effect

We now use wheel converter as it provides better handling of touch pads

- - - - -
8da71b5a by Pierre Lamot at 2025-11-05T15:43:10+01:00
qt: fix wheel event on volume slider being interpreted multiple times

If the event isn't accepted it is forwarded to the parent widget which also
handles the wheel event. As a result, the if the vout as vertical scrolling used
for seeking, and we scroll vertically on the sound slider, both events would
occur when scrolling on the widget.

- - - - -


4 changed files:

- modules/gui/qt/util/customwidgets.cpp
- modules/gui/qt/util/customwidgets.hpp
- modules/gui/qt/util/input_slider.cpp
- modules/gui/qt/util/input_slider.hpp


Changes:

=====================================
modules/gui/qt/util/customwidgets.cpp
=====================================
@@ -109,7 +109,7 @@ void VLCQDial::paintEvent( QPaintEvent *event )
 /***************************************************************************
  * Hotkeys converters
  ***************************************************************************/
-int qtKeyModifiersToVLC( QInputEvent* e )
+int qtKeyModifiersToVLC( const QInputEvent* e )
 {
     int i_keyModifiers = 0;
     if( e->modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
@@ -265,7 +265,7 @@ static int keycmp( const void *a, const void *b )
     return *q - m->qt;
 }
 
-int qtEventToVLCKey( QKeyEvent *e )
+int qtEventToVLCKey( const QKeyEvent *e )
 {
     int qtk = e->key();
     uint32_t i_vlck = 0;
@@ -294,7 +294,7 @@ int qtEventToVLCKey( QKeyEvent *e )
     return i_vlck;
 }
 
-int qtWheelEventToVLCKey( QWheelEvent *e )
+int qtWheelEventToVLCKey( const QWheelEvent *e )
 {
     const qreal v_cos_deadzone = 0.45; // ~63 degrees
     const qreal h_cos_deadzone = 0.95; // ~15 degrees
@@ -437,3 +437,96 @@ YesNoCheckBox::YesNoCheckBox( QWidget *parent ) : QCheckBox( parent )
     });
 #endif
 }
+
+Qt::Orientations WheelToVLCConverter::getWheelOrientation(int x, int y)
+{
+    const qreal v_cos_deadzone = 0.45; // ~63 degrees
+    const qreal h_cos_deadzone = 0.95; // ~15 degrees
+
+    if (x == 0 && y == 0)
+        return Qt::Orientations{};
+
+    qreal cos = qFabs(x)/qSqrt(x*x + y*y);
+    if (cos < v_cos_deadzone)
+        return Qt::Vertical;
+    else if (cos > h_cos_deadzone)
+        return Qt::Horizontal;
+    return Qt::Orientations{};
+}
+
+void WheelToVLCConverter::wheelEvent( const QWheelEvent* e )
+{
+    if (!e)
+        return;
+
+    const int deltaPerStep = QWheelEvent::DefaultDeltasPerStep;
+
+    if (e->modifiers() != m_modifiers)
+    {
+        m_scrollAmount = {};
+        m_modifiers = e->modifiers();
+    }
+    if (e->buttons() != m_buttons)
+    {
+        m_scrollAmount = {};
+        m_buttons = e->buttons();
+    }
+
+    QPoint p = e->angleDelta();
+#if HAS_QT57
+    if (e->inverted())
+    {
+        const Qt::Orientations preliminaryOrientation = getWheelOrientation(p.x(), p.y());
+        if (preliminaryOrientation == Qt::Vertical)
+            p.setY(-p.y());
+        else if (preliminaryOrientation == Qt::Horizontal)
+            p.setX(-p.x());
+    }
+#endif
+    p += m_scrollAmount;
+
+    if (p.isNull())
+        return;
+
+    int i_vlck = qtKeyModifiersToVLC(e);  // Handle modifiers
+    Qt::Orientations orientation = getWheelOrientation(p.x(), p.y());
+    if (orientation == Qt::Vertical && qAbs(p.y()) >= deltaPerStep)
+    {
+        if (p.y() > 0)
+            i_vlck |= KEY_MOUSEWHEELUP;
+        else
+            i_vlck |= KEY_MOUSEWHEELDOWN;
+
+        const int steps = p.y() / deltaPerStep;
+
+        emit wheelUpDown(steps, e->modifiers());
+        //in practice this will emit once
+        for (int i = 0; i < qAbs(steps); i++)
+            emit vlcWheelKey(i_vlck);
+
+        m_scrollAmount.setX(0);
+        m_scrollAmount.setY(p.y() % deltaPerStep);
+
+    }
+    else if (orientation == Qt::Horizontal && qAbs(p.x()) >= deltaPerStep)
+    {
+        if (p.x() > 0)
+            i_vlck |= KEY_MOUSEWHEELLEFT;
+        else
+            i_vlck |= KEY_MOUSEWHEELRIGHT;
+
+        const int steps = p.x() / deltaPerStep;
+
+        emit wheelLeftRight(steps, e->modifiers());
+        //in practice this will emit once
+        for (int i = 0; i < qAbs(steps); i++)
+            emit vlcWheelKey(i_vlck);
+
+        m_scrollAmount.setY(0);
+        m_scrollAmount.setX(p.x() % deltaPerStep);
+    }
+    else
+    {
+        m_scrollAmount = p;
+    }
+}


=====================================
modules/gui/qt/util/customwidgets.hpp
=====================================
@@ -144,9 +144,53 @@ class QKeyEvent;
 class QWheelEvent;
 class QInputEvent;
 
-int qtKeyModifiersToVLC( QInputEvent* e );
-int qtEventToVLCKey( QKeyEvent *e );
-int qtWheelEventToVLCKey( QWheelEvent *e );
+int qtKeyModifiersToVLC( const QInputEvent* e );
+int qtEventToVLCKey( const QKeyEvent *e );
+int qtWheelEventToVLCKey( const QWheelEvent *e );
 QString VLCKeyToString( unsigned val, bool );
 
+/**
+ * @brief The WheelToVLCConverter class aggregates wheel events and
+ * emit a signal once it gathers a full scroll step, as VLC doesn't handle
+ * fractionnal scroll events
+ */
+class WheelToVLCConverter : public QObject
+{
+    Q_OBJECT
+
+public:
+    using QObject::QObject;
+
+public:
+    Qt::Orientations getWheelOrientation(int x, int y);
+
+signals:
+    /**
+     * @param vlcKey the VLC hotkey representation
+     */
+    void vlcWheelKey(int vlcKey);
+    /**
+     * @param steps: positive value indicated UP wheel events, negative DOWN wheel event
+     * @param modifiers are keyboard pressed modifiers
+     */
+    void wheelUpDown(int steps, Qt::KeyboardModifiers modifiers);
+    /**
+     * @param steps: positive value indicated UP wheel events, negative DOWN wheel event
+     * @param modifiers are keyboard pressed modifiers
+     */
+    void wheelLeftRight(int steps, Qt::KeyboardModifiers modifiers);
+
+public slots:
+    /**
+     * @brief qmlWheelEvent handles wheel events as emitted by QWidget
+     * @param e the wheel event
+     */
+    void wheelEvent(const QWheelEvent* e);
+
+private:
+    QPoint m_scrollAmount = {};
+    Qt::KeyboardModifiers m_modifiers = {};
+    Qt::MouseButtons m_buttons = {};
+};
+
 #endif


=====================================
modules/gui/qt/util/input_slider.cpp
=====================================
@@ -34,6 +34,8 @@
 #include "adapters/seekpoints.hpp"
 #include "input_manager.hpp"
 #include "imagehelper.hpp"
+#include "customwidgets.hpp"
+#include <vlc_actions.h>
 
 #include <QPaintEvent>
 #include <QPainter>
@@ -169,6 +171,31 @@ SeekSlider::SeekSlider( intf_thread_t *p_intf, Qt::Orientation q, QWidget *_pare
     CONNECT( hideHandleTimer, timeout(), this, hideHandle() );
     CONNECT( startAnimLoadingTimer, timeout(), this, startAnimLoading() );
     mTimeTooltip->installEventFilter( this );
+
+    connect(&wheelEventConverter, &WheelToVLCConverter::vlcWheelKey, this, [this](int vlcButton){
+        vlc_tick_t i_size = var_InheritInteger( this->p_intf->obj.libvlc, "short-jump-size" );
+        int i_mode = var_InheritInteger( this->p_intf->obj.libvlc, "hotkeys-x-wheel-mode" );
+
+        //ignore modifiers
+        switch (vlcButton & 0x00FF0000) {
+        case KEY_MOUSEWHEELDOWN:
+        case KEY_MOUSEWHEELLEFT:
+            if (i_mode != 3)
+                i_size = - i_size;
+            break;
+        case KEY_MOUSEWHEELUP:
+        case KEY_MOUSEWHEELRIGHT:
+            if (i_mode == 3)
+                i_size = - i_size;
+            break;
+        default:
+            break;
+        }
+
+        float posOffset = static_cast<float>( i_size ) / static_cast<float>( inputLength );
+        setValue( value() + posOffset * maximum() );
+        emit sliderDragged( value() / static_cast<float>( maximum() ) );
+    });
 }
 
 SeekSlider::~SeekSlider()
@@ -405,15 +432,7 @@ void SeekSlider::wheelEvent( QWheelEvent *event )
 {
     /* Don't do anything if we are for somehow reason sliding */
     if( !isSliding && isEnabled() )
-    {
-        vlc_tick_t i_size = var_InheritInteger( p_intf->obj.libvlc, "short-jump-size" );
-        int i_mode = var_InheritInteger( p_intf->obj.libvlc, "hotkeys-x-wheel-mode" );
-        if ( ( event->angleDelta().x() < 0 && i_mode != 3 ) || ( event->angleDelta().x() > 0 && i_mode == 3 ) )
-            i_size = - i_size;
-        float posOffset = static_cast<float>( i_size ) / static_cast<float>( inputLength );
-        setValue( value() + posOffset * maximum() );
-        emit sliderDragged( value() / static_cast<float>( maximum() ) );
-    }
+        wheelEventConverter.wheelEvent(event);
     event->accept();
 }
 
@@ -679,15 +698,33 @@ SoundSlider::SoundSlider( QWidget *_parent, float _i_step,
 
     pixGradient.setMask( mask );
     pixGradient2.setMask( mask );
+
+    connect(&wheelEventConverter, &WheelToVLCConverter::vlcWheelKey, this, [this](int vlcButton){
+        int newvalue = 0;
+        //ignore modifiers
+        switch (vlcButton & 0x00FF0000) {
+        case KEY_MOUSEWHEELDOWN:
+        case KEY_MOUSEWHEELLEFT:
+            newvalue = value() - f_step;
+            break;
+        case KEY_MOUSEWHEELUP:
+        case KEY_MOUSEWHEELRIGHT:
+            newvalue = value() + f_step;
+            break;
+        default:
+            return;
+        }
+
+        setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );
+        emit sliderMoved( value() );
+    });
 }
 
 void SoundSlider::wheelEvent( QWheelEvent *event )
 {
-    int newvalue = value() + event->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep * f_step;
-    setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );
-
+    wheelEventConverter.wheelEvent(event);
+    event->accept();
     emit sliderReleased();
-    emit sliderMoved( value() );
 }
 
 void SoundSlider::mousePressEvent( QMouseEvent *event )


=====================================
modules/gui/qt/util/input_slider.hpp
=====================================
@@ -31,6 +31,7 @@
 #endif
 
 #include "styles/seekstyle.hpp"
+#include "customwidgets.hpp"
 
 #include <QSlider>
 #include <QPainter>
@@ -121,6 +122,8 @@ private:
     QTimer *hideHandleTimer;
     QTimer *startAnimLoadingTimer;
 
+    WheelToVLCConverter wheelEventConverter;
+
 public slots:
     void setPosition( float, int64_t, int );
     void setSeekable( bool b ) { b_seekable = b ; }
@@ -175,6 +178,8 @@ private:
     QFont textfont;
     QRect textrect;
 
+    WheelToVLCConverter wheelEventConverter;
+
     void changeValue( int x ); /* Function to modify the value from pixel x() */
 };
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fe60420c4060e22c1660668f124b14da875f36be...8da71b5a45b8064a96bb576be86f03b8e17753b0

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fe60420c4060e22c1660668f124b14da875f36be...8da71b5a45b8064a96bb576be86f03b8e17753b0
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list