-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
plugin-volume: add support for hires wheel #1856
base: master
Are you sure you want to change the base?
Conversation
Not reproducible.
You'd have problem with that mouse everywhere; it should be broken. |
Why ? if the total (sum of the movement) is equal I should not have any problem. Anyway, which is the value returned by What is reporting
I can ask which kind of mouse do you have ? I have a "Logitech MX 2 Anywhere", and this show this behavior. Here http://who-t.blogspot.com/2021/08/libinput-and-high-resolution-wheel.html there are some explaination. |
OK, you meant that your mouse has a high resolution (rotates by less than 15° each time == its angle delta is less than 120). The sentences "The user can't control…" and "Some mouses send a lot of events…" made me think it was broken. Yes, the code fails to cover this case. IMO, a clean solution requires adding the steps cumulatively, until they reach (or pass) 15°.
More than 6 mice with 3 computers/laptops, whose steps were all 15°, but that's beside the point. |
I tried also this path; but this would require to add a further variable. I found faster to increase the "range" of the slider by a factor of 1000, and computing the volume as "slider->value() / 1000" You can see this other option here |
I haven't looked into it yet, but I think the cumulative method might be cleaner. I vaguely remember that it was used in |
It works, but it requires to turn the wheel by 3 "step" (or detent); is it the expected behavior ? |
This was my first thought; but then I realized that I would have to synchronize three things:
Anyway I will give another chance to having a counter in a separate variables |
It has a configurable "Wheel Delta Threshold". Anyway, I was thinking about a static local variable, like the one used in |
Before I go to sleep — I mean something like this: void VolumePopup::handleWheelEvent(QWheelEvent *event)
{
static int _delta = 0;
_delta += event->angleDelta().y();
if (qAbs(_delta) >= QWheelEvent::DefaultDeltasPerStep) {
m_volumeSlider->setSliderPosition(m_volumeSlider->sliderPosition()
+ (_delta / QWheelEvent::DefaultDeltasPerStep * m_volumeSlider->singleStep()));
_delta = 0;
}
} Does it feel natural with your mouse? |
I'm afraid, this |
You're right; I missed that last night. It should be replaced by a member variable. But what was important to me was UX with a hi-res mouse (which I don't have). In theory, it seems OK: the volume will change if the user turns the wheel by ~15° — one step for most mice, more for hi-res mice. Still waiting for @kreijack's reply.... |
@palinek |
Yes, but you can be taking "leftover" from one widget when processing the event on other widget. The same comes into play even with one widget -> scroll below threshold, leave widget, scroll on the widget again. I know all these are rather academical scenarios with close to no impact on UX, but pointing it out just for the sake of correctness. |
The user can be sure that the volume changes only once when he turns the wheel by 15°; practically, it makes no difference at which smaller degree it changes. The main point of a cumulative approach is that, without it, a high sensitivity could be annoying with a hi-res mouse. |
What about declaring _delta as "member variable" ? Moreover the "_delta" variable handling has to consider that:
I reworked a bit the @tsujan suggestion // file volumepopup.h
class VolumePopup {
[...]
int fractionWheelValue = 0;
}
// file volumepopup.cpp
void VolumePopup::handleWheelEvent(QWheelEvent *event)
{
fractionWheelValue += event->angleDelta().y();
// check if fractionWheelValue is enough to change the volume
// pay attention that fractionWheelValue may be > 0 or < 0
if (fractionWheelValue / QWheelEvent::DefaultDeltasPerStep != 0) {
m_volumeSlider->setSliderPosition(m_volumeSlider->sliderPosition()
+ (fractionWheelValue / QWheelEvent::DefaultDeltasPerStep * m_volumeSlider->singleStep()));
// we need to preserve the fraction part of the wheel movement
fractionWheelValue = fractionWheelValue % QWheelEvent::DefaultDeltasPerStep ;
}
}
[...]
void VolumePopup::handleDeviceVolumeChanged(int volume)
{
// we are updating the slider, reset the fractional part of the wheel movement
fractionWheelValue = 0;
[...]
void VolumePopup::handleSliderValueChanged(int value)
{
// we are updating the slider, reset the fractional part of the wheel movement
fractionWheelValue = 0;
[...]
//
|
Makes no difference. This way was more compact; hence suggesting it.
My mistake. Use You didn't answer my question: After using |
Ah sorry, I forgot to test it. Anyway I don't see any reasons why it should not work. I don't like the idea of having However we need
|
That wasn't an answer to the question I asked ;) I wouldn't ask if I had a hi-res mouse.
I don't want to start an aesthetic discussion. A simple code that works is preferable — the simpler, the better. And |
(it was "trapped" in the quotation, but in the last part of my last messages there was a [...] I will try a test :-) ) Anyway the test was successful. It works. The only think is that the tooltip which show the percent of volume flickers when the wheel mouse rotates. Do you have the same problem ?
I agree with you that making |
The Volume control plugin allows to change the volume using the mouse wheel. However for hires wheel this doesn't work. The volume change is controlled by the following formula: m_volumeSlider->setSliderPosition(m_volumeSlider->sliderPosition() + (event->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep * m_volumeSlider->singleStep())); For some kind of mouse where the wheel event is compose by a lot of small 'delta'; the ratio event->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep is less than 1; and because this ratio is between two integers it is rounded to 0. So store the fraction part of the wheel stroke in a static variable.
To show the new value, the instant tooltip is shown again. I don't see it as a problem. |
9f46b9c
to
195978b
Compare
Apparently, we don't: tooltip.mp4
I don't think so but can't tell for sure. The window manager and compositor have greater roles. I use KWin. If it still happens after changing your WM, you could open a report. Anyway, thanks for the PR! I'll review it tomorrow. |
Yes there is something different. However I am out of topic. This will be another issue. |
I'm afraid there are 4 problems:
The following PR doesn't have the above problems and guarantees that a tooltip is shown in the end: #1857 |
I, for one, completely agree here. The reasons are not aesthetic, but I already described the scenarios and you correctly addressed those. |
What was called "leftover" exists with a single instance too. When it can be ignored with a single instance, it can also be ignored with more — no practical impact (→ #1856 (comment) → first paragraph). |
That code is basically incorrect (→ #1856 (comment)). You can't get rid of the leftover in that way. You can only reset it with a timer (like the one in #1857), by assuming an end to a series of wheel rotations. But even that isn't worth cluttering the code. |
You assumption is that the "unit step" is a "non divisor" (i.e. x % y = 0) of the step (now 15°). The reality is that the hires step is a divisor of the step. This is true for my mice, and this should be true for all the hires wheel, and this to avoid you concern.
Could you elaborate this sentence ? The speed is the same: the steps are smaller but more frequent.
I am not saying that this is not true, but really it is not clear to me what is the irregularity
May be I am missing something obvious, but please could you elaborate a bit ?
I tested your code, and the tooltip problem is still here. |
I assumed that the above explanations were clear enough. I'm very sorry that I don't have time for more (hence, my short replies and my avoidance of repeating myself). As for testing with a hi-res mouse, there was a simple way of simulating any kind of it in the code. Everything is fully tested, not just theorized. Moreover, touchpad serves as a super hi-res tool when it comes to scrolling. |
Problem
The user can't control with the mouse wheel the volume level in the Volume Control plugin.
Analysis
Some mouses send a lot of events with "small" movement of the wheel. This invalidate some evaluation of the total stroke of the wheel.
In the Volume Control plugin, the volume was computed on the basis of the following formula:
However if
event->angleDelta().y()
is smaller thanQWheelEvent::DefaultDeltasPerStep
, their ratio is a value less than 1, which is zero when the math is integer based.If the math was floating point based, the problem would not happened.
Solution
To avoid this issue the
volumeSlider->singleStep()
is increased by a factor of 1000 and the multiplication is performed before the division.Of course all others computation will be scaled according:
volume = volumeSlider->value() / 1000
volumeSlider->singleStep
will be increased by a factor of 1000