wayland: Fix high-resolution scroll wheel discrete step calculation
Some wheels might send fewer or more than 120 fractions per step. In order to always register a discrete step, we count these as a step already at half(120/2) of one mouse wheel step in stepping mode. The timer resets the initial value of the step because the mouse can switch between free spin and stepping mode. When transitioning from free spin to stepping mode, the mouse calibrates its wheel position to the starting point and generates some fractions. As a result, our starting position can appear far from the zero point, potentially causing us to count two(or zero) steps instead of one. Additionally, the compositor might start when the mouse is in free spin mode(or the mouse could be connected in free spin mode), leading to the same issue. https://gitlab.freedesktop.org/libinput/libinput/-/issues/814
This commit is contained in:
parent
792ff84419
commit
361e2c3eba
2 changed files with 18 additions and 5 deletions
|
@ -133,8 +133,12 @@ void PointerInterfacePrivate::sendFrame()
|
|||
}
|
||||
}
|
||||
|
||||
bool PointerInterfacePrivate::AxisAccumulator::Axis::shouldReset(int newDirection) const
|
||||
bool PointerInterfacePrivate::AxisAccumulator::Axis::shouldReset(int newDirection, std::chrono::milliseconds newTimestamp) const
|
||||
{
|
||||
if (newTimestamp.count() - timestamp.count() >= 1000) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset the accumulator if the delta has opposite sign.
|
||||
return direction && ((direction < 0) != (newDirection < 0));
|
||||
}
|
||||
|
@ -220,18 +224,26 @@ static void updateAccumulators(Qt::Orientation orientation, qreal delta, qint32
|
|||
const int newDirection = deltaV120 > 0 ? 1 : -1;
|
||||
auto &accum = d->axisAccumulator.axis(orientation);
|
||||
|
||||
if (accum.shouldReset(newDirection)) {
|
||||
if (accum.shouldReset(newDirection, d->seat->timestamp())) {
|
||||
accum.reset();
|
||||
}
|
||||
|
||||
accum.timestamp = d->seat->timestamp();
|
||||
accum.direction = newDirection;
|
||||
|
||||
accum.axis += delta;
|
||||
accum.axis120 += deltaV120;
|
||||
|
||||
// ±120 is a "wheel click"
|
||||
valueDiscrete = accum.axis120 / 120;
|
||||
accum.axis120 -= valueDiscrete * 120;
|
||||
if (std::abs(accum.axis120) >= 60) {
|
||||
const int steps = accum.axis120 / 120;
|
||||
valueDiscrete += steps;
|
||||
if (steps == 0) {
|
||||
valueDiscrete += accum.direction;
|
||||
}
|
||||
|
||||
accum.axis120 -= valueDiscrete * 120;
|
||||
}
|
||||
|
||||
if (valueDiscrete) {
|
||||
// Accumulate the axis values to send to low-res clients
|
||||
|
|
|
@ -29,7 +29,7 @@ class PointerInterfacePrivate : public QtWaylandServer::wl_pointer
|
|||
{
|
||||
struct Axis
|
||||
{
|
||||
bool shouldReset(int newDirection) const;
|
||||
bool shouldReset(int newDirection, std::chrono::milliseconds newTimestamp) const;
|
||||
|
||||
void reset()
|
||||
{
|
||||
|
@ -40,6 +40,7 @@ class PointerInterfacePrivate : public QtWaylandServer::wl_pointer
|
|||
qint32 axis120 = 0;
|
||||
qreal axis = 0;
|
||||
int direction = 0;
|
||||
std::chrono::milliseconds timestamp = std::chrono::milliseconds::zero();
|
||||
};
|
||||
|
||||
Axis &axis(Qt::Orientation orientation)
|
||||
|
|
Loading…
Reference in a new issue