Skip to content

Commit e12f0c7

Browse files
Merge pull request #1798 from contour-terminal/fix/mouse-scroll
Fix mouse scrolling being too slow
2 parents 5edceba + f134866 commit e12f0c7

File tree

7 files changed

+147
-65
lines changed

7 files changed

+147
-65
lines changed

.github/workflows/build.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -777,11 +777,11 @@ jobs:
777777
with:
778778
name: contour-ubuntu2404-tests
779779
path: |
780-
build/linux-debug/src/crispy/crispy_test
781-
build/linux-debug/src/vtparser/vtparser_test
782-
build/linux-debug/src/vtbackend/vtbackend_test
783-
build/linux-debug/src/vtbackend/bench-headless
784-
build/linux-debug/src/vtrasterizer/vtrasterizer_test
780+
out/linux-debug/src/crispy/crispy_test
781+
out/linux-debug/src/vtparser/vtparser_test
782+
out/linux-debug/src/vtbackend/vtbackend_test
783+
out/linux-debug/src/vtbackend/bench-headless
784+
out/linux-debug/src/vtrasterizer/vtrasterizer_test
785785
test/images
786786
retention-days: 1
787787
# }}}
@@ -892,9 +892,9 @@ jobs:
892892
cpack --preset linux-release
893893
OS_VERSION=${{ matrix.os_version }}
894894
OS_VERSION=${OS_OVERRIDE/./_}
895-
mv -v "./build/linux-release/Contour-${{ steps.set_vars.outputs.VERSION_STRING }}-Linux-contour.deb" \
895+
mv -v "./out/linux-release/Contour-${{ steps.set_vars.outputs.VERSION_STRING }}-Linux-contour.deb" \
896896
"contour-${{ steps.set_vars.outputs.VERSION_STRING }}-ubuntu${{ matrix.os_version }}-amd64.deb"
897-
mv -v "./build/linux-release/Contour-${{ steps.set_vars.outputs.VERSION_STRING }}-Linux-contour-dbgsym.ddeb" \
897+
mv -v "./out/linux-release/Contour-${{ steps.set_vars.outputs.VERSION_STRING }}-Linux-contour-dbgsym.ddeb" \
898898
"contour-dbgsym-${{ steps.set_vars.outputs.VERSION_STRING }}-ubuntu${{ matrix.os_version }}-amd64.ddeb"
899899
- name: "Uploading artifact .deb package"
900900
uses: actions/upload-artifact@v4
@@ -933,13 +933,13 @@ jobs:
933933
- name: "install dependencies"
934934
run: ./scripts/ci-install-run-deps.sh valgrind
935935
- name: "test: crispy (via valgrind)"
936-
run: valgrind --error-exitcode=64 ./build/linux-debug/src/crispy/crispy_test
936+
run: valgrind --error-exitcode=64 ./out/linux-debug/src/crispy/crispy_test
937937
- name: "test: vtparser (via valgrind)"
938-
run: valgrind --error-exitcode=64 ./build/linux-debug/src/vtparser/vtparser_test
938+
run: valgrind --error-exitcode=64 ./out/linux-debug/src/vtparser/vtparser_test
939939
- name: "test: vtbackend (via valgrind)"
940-
run: valgrind --error-exitcode=64 ./build/linux-debug/src/vtbackend/vtbackend_test
940+
run: valgrind --error-exitcode=64 ./out/linux-debug/src/vtbackend/vtbackend_test
941941
- name: "test: vtrasterizer (via valgrind)"
942-
run: valgrind --error-exitcode=64 ./build/linux-debug/src/vtrasterizer/vtrasterizer_test
942+
run: valgrind --error-exitcode=64 ./out/linux-debug/src/vtrasterizer/vtrasterizer_test
943943
# }}}
944944
# {{{ Ubuntu 24.04: Test bench-headless
945945
test_ubuntu2404_bench_headless:
@@ -971,7 +971,7 @@ jobs:
971971
- name: "install dependencies"
972972
run: ./scripts/ci-install-run-deps.sh valgrind
973973
- name: "bench-headless: ${{ matrix.test_case }}"
974-
run: valgrind --error-exitcode=64 ./build/linux-debug/src/vtbackend/bench-headless ${{ matrix.test_case }} size 1
974+
run: valgrind --error-exitcode=64 ./out/linux-debug/src/vtbackend/bench-headless ${{ matrix.test_case }} size 1
975975
# }}}
976976
# {{{ Ubuntu check matrix
977977
check_ubuntu2404_matrix_test_matrix:

cmake/presets/common.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"name": "contour-common",
66
"hidden": true,
77
"description": "Common settings for all configurations",
8-
"binaryDir": "${sourceDir}/build/${presetName}",
8+
"binaryDir": "${sourceDir}/out/${presetName}",
99
"cacheVariables": {
1010
"CONTOUR_INSTALL_TOOLS": "ON",
1111
"CONTOUR_TESTING": "ON",

metainfo.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
<li>Fixes NumLock key handling (#1713)</li>
116116
<li>Fixes handling of multiple windows and tabs (#1725)</li>
117117
<li>Fixes crash on scaling down some symbols during font size change</li>
118+
<li>Fixes mouse scrolling speed being too slow</li>
118119
<li>Enables customizing predefined color palette (#1763)</li>
119120
<li>Ensure inserting new tabs happens right next to the currently active tab (#1695)</li>
120121
<li>Allow glyphs to underflow if they are not bigger than the cell size (#1603)</li>

src/contour/TerminalSession.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ TerminalSession::TerminalSession(TerminalSessionManager* manager,
234234
_profile { *_config.profile(_profileName) },
235235
_app { app },
236236
_currentColorPreference { app.colorPreference() },
237-
_accumulatedScrollX { 0 },
238-
_accumulatedScrollY { 0 },
237+
_accumulatedPixelScroll {},
238+
_accumulatedAngleScroll {},
239239
_terminal { *this,
240240
std::move(pty),
241241
createSettingsFromConfig(_config, _profile, _currentColorPreference),
@@ -804,6 +804,50 @@ void TerminalSession::requestWindowResize(Width width, Height height)
804804
_display->post([this, width, height]() { _display->resizeWindow(width, height); });
805805
}
806806

807+
void TerminalSession::addToAccumulatedScroll(crispy::point pixelDelta, crispy::point angleDelta) noexcept
808+
{
809+
if (angleDelta && !pixelDelta)
810+
_accumulatedPixelScroll = {};
811+
else
812+
_accumulatedPixelScroll += pixelDelta;
813+
814+
_accumulatedAngleScroll += angleDelta;
815+
}
816+
817+
std::tuple<LineOffset, ColumnOffset> TerminalSession::consumeScroll() noexcept
818+
{
819+
if (_accumulatedPixelScroll)
820+
{
821+
auto const pixelStepSize = crispy::point {
822+
.x = _display->cellSize().width.as<int>(),
823+
.y = _display->cellSize().height.as<int>(),
824+
};
825+
auto const pixelSteps = _accumulatedPixelScroll / pixelStepSize;
826+
827+
if (pixelSteps)
828+
{
829+
_accumulatedPixelScroll -= pixelSteps * pixelStepSize;
830+
_accumulatedAngleScroll = {};
831+
832+
return {
833+
LineOffset::cast_from(pixelSteps.y),
834+
ColumnOffset::cast_from(pixelSteps.x),
835+
};
836+
}
837+
}
838+
839+
auto const angleStepSize = double { 8 * 5 };
840+
auto const angleSteps = _accumulatedAngleScroll / angleStepSize;
841+
842+
_accumulatedAngleScroll -= angleSteps * angleStepSize;
843+
_accumulatedPixelScroll = {};
844+
845+
return {
846+
LineOffset::cast_from(angleSteps.y),
847+
ColumnOffset::cast_from(angleSteps.x),
848+
};
849+
}
850+
807851
QString TerminalSession::title() const
808852
{
809853
#if !defined(NDEBUG)

src/contour/TerminalSession.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,8 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
173173
return true;
174174
}
175175

176-
int getScrollX() const noexcept { return _accumulatedScrollX; }
177-
void addScrollX(int v) noexcept { _accumulatedScrollX += v; }
178-
void resetScrollX(int value) noexcept { _accumulatedScrollX = value; }
179-
180-
int getScrollY() const noexcept { return _accumulatedScrollY; }
181-
void addScrollY(int v) noexcept { _accumulatedScrollY += v; }
182-
void resetScrollY(int value) noexcept { _accumulatedScrollY = value; }
176+
void addToAccumulatedScroll(crispy::point pixelDelta, crispy::point angleDelta) noexcept;
177+
std::tuple<vtbackend::LineOffset, vtbackend::ColumnOffset> consumeScroll() noexcept;
183178

184179
QString title() const;
185180
void setTitle(QString const& value) { terminal().setWindowTitle(value.toStdString()); }
@@ -461,8 +456,8 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
461456
ContourGuiApp& _app;
462457
vtbackend::ColorPreference _currentColorPreference;
463458

464-
int _accumulatedScrollX;
465-
int _accumulatedScrollY;
459+
crispy::point _accumulatedPixelScroll;
460+
crispy::point _accumulatedAngleScroll;
466461

467462
vtbackend::Terminal _terminal;
468463
bool _terminatedAndWaitingForKeyPress = false;

src/contour/helper.cpp

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -113,37 +113,40 @@ namespace
113113
return QPoint { p.y(), p.x() };
114114
}
115115

116-
void sendWheelEventForDelta(QPoint const& delta,
117-
PixelCoordinate const& position,
118-
vtbackend::Modifiers modifiers,
119-
TerminalSession& session)
116+
void sendWheelEvent(crispy::point const& pixelDelta,
117+
crispy::point const& angleDelta,
118+
PixelCoordinate const& currentMousePixelPosition,
119+
vtbackend::Modifiers modifiers,
120+
TerminalSession& session)
120121
{
121122
using VTMouseButton = vtbackend::MouseButton;
122123

123-
session.addScrollX(delta.x());
124-
session.addScrollY(delta.y());
124+
session.addToAccumulatedScroll(pixelDelta, angleDelta);
125+
auto const [linesScroll, columnsScroll] = session.consumeScroll();
125126

126-
inputLog()("[{}] Accumulate scroll with current value {}",
127+
inputLog()("[{}] Accumulate scroll with by value {} pixelDelta / {} angleDelta, {} lines, {} columns "
128+
"(against {})",
127129
modifiers,
128-
crispy::point { .x = session.getScrollX(), .y = session.getScrollY() });
130+
pixelDelta,
131+
angleDelta,
132+
linesScroll,
133+
columnsScroll,
134+
session.terminal().cellPixelSize());
129135

130-
if (std::abs(session.getScrollX()) > unbox<int>(session.terminal().cellPixelSize().width))
136+
auto const horizontalScrollEvent =
137+
columnsScroll.as<int>() > 0 ? VTMouseButton::WheelRight : VTMouseButton::WheelLeft;
138+
139+
for (int i = 0; i < std::abs(columnsScroll.as<int>()); ++i)
131140
{
132-
session.sendMousePressEvent(modifiers,
133-
session.getScrollX() > 0 ? VTMouseButton::WheelRight
134-
: VTMouseButton::WheelLeft,
135-
position);
136-
session.resetScrollX(session.getScrollX() % unbox<int>(session.terminal().cellPixelSize().width));
141+
session.sendMousePressEvent(modifiers, horizontalScrollEvent, currentMousePixelPosition);
137142
}
138143

139-
if (std::abs(session.getScrollY()) > unbox<int>(session.terminal().cellPixelSize().height))
144+
auto const verticalScrollEvent =
145+
linesScroll.as<int>() > 0 ? VTMouseButton::WheelUp : VTMouseButton::WheelDown;
146+
147+
for (int i = 0; i < std::abs(linesScroll.as<int>()); ++i)
140148
{
141-
session.sendMousePressEvent(modifiers,
142-
session.getScrollY() > 0 ? VTMouseButton::WheelUp
143-
: VTMouseButton::WheelDown,
144-
position);
145-
session.resetScrollY(session.getScrollY()
146-
% unbox<int>(session.terminal().cellPixelSize().height));
149+
session.sendMousePressEvent(modifiers, verticalScrollEvent, currentMousePixelPosition);
147150
}
148151
}
149152

@@ -416,6 +419,9 @@ bool sendKeyEvent(QKeyEvent* event, vtbackend::KeyboardEventType eventType, Term
416419

417420
void sendWheelEvent(QWheelEvent* event, TerminalSession& session)
418421
{
422+
if (event->pixelDelta().isNull() && event->angleDelta().isNull())
423+
return;
424+
419425
using vtbackend::Modifier;
420426

421427
auto const modifiers = makeModifiers(event->modifiers());
@@ -427,28 +433,31 @@ void sendWheelEvent(QWheelEvent* event, TerminalSession& session)
427433
// it will send horizontal wheel events instead of vertical ones. We need to compensate
428434
// for that here.
429435

430-
if (!event->pixelDelta().isNull())
431-
{
436+
auto const pixelDelta = [&]() -> crispy::point {
437+
if (event->pixelDelta().isNull())
438+
return { .x = 0, .y = 0 };
439+
432440
auto const scaledPixelDelta = session.display()->contentScale() * event->pixelDelta();
433-
auto const pixelDelta = (modifiers & Modifier::Alt) ? transposed(scaledPixelDelta) : scaledPixelDelta;
441+
auto const x = scaledPixelDelta.x();
442+
auto const y = scaledPixelDelta.y();
443+
if (modifiers & Modifier::Alt)
444+
return { .x = y, .y = x };
445+
else
446+
return { .x = x, .y = y };
447+
}();
448+
449+
auto const angleDelta = [&]() -> crispy::point {
450+
if (event->angleDelta().isNull())
451+
return { .x = 0, .y = 0 };
434452

435-
sendWheelEventForDelta(pixelDelta, pixelPosition, modifiers, session);
436-
event->accept();
437-
}
438-
else if (!event->angleDelta().isNull())
439-
{
440453
auto const numDegrees =
441-
((modifiers & Modifier::Alt) ? transposed(event->angleDelta()) : event->angleDelta()) / 8;
442-
443-
auto const numSteps = numDegrees / 15;
444-
auto const cellSize = session.terminal().cellPixelSize();
445-
auto const scaledDelta = QPoint {
446-
numSteps.x() * unbox<int>(cellSize.width),
447-
numSteps.y() * unbox<int>(cellSize.height),
448-
};
449-
sendWheelEventForDelta(scaledDelta, pixelPosition, modifiers, session);
450-
event->accept();
451-
}
454+
((modifiers & Modifier::Alt) ? transposed(event->angleDelta()) : event->angleDelta());
455+
456+
return { .x = numDegrees.x(), .y = numDegrees.y() };
457+
}();
458+
459+
sendWheelEvent(pixelDelta, angleDelta, pixelPosition, modifiers, session);
460+
event->accept();
452461
}
453462

454463
void sendMousePressEvent(QMouseEvent* event, TerminalSession& session)

src/crispy/point.h

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#pragma once
33

44
#include <format>
5-
#include <ostream>
65

76
namespace crispy
87
{
@@ -11,6 +10,9 @@ struct [[nodiscard]] point
1110
{
1211
int x {};
1312
int y {};
13+
14+
constexpr bool operator!() const noexcept { return x == 0 && y == 0; }
15+
constexpr operator bool() const noexcept { return x != 0 || y != 0; }
1416
};
1517

1618
template <typename T>
@@ -26,6 +28,30 @@ constexpr point operator*(point p, double s) noexcept
2628
};
2729
}
2830

31+
constexpr point operator/(point p, double s) noexcept
32+
{
33+
return point {
34+
.x = static_cast<int>(static_cast<double>(p.x) / s),
35+
.y = static_cast<int>(static_cast<double>(p.y) / s),
36+
};
37+
}
38+
39+
constexpr point operator*(point a, point b) noexcept
40+
{
41+
return point {
42+
.x = a.x * b.x,
43+
.y = a.y * b.y,
44+
};
45+
}
46+
47+
constexpr point operator/(point a, point b) noexcept
48+
{
49+
return point {
50+
.x = a.x / b.x,
51+
.y = a.y / b.y,
52+
};
53+
}
54+
2955
constexpr point operator+(point a, point b) noexcept
3056
{
3157
return point { .x = a.x + b.x, .y = a.y + b.y };
@@ -38,6 +64,13 @@ constexpr point& operator+=(point& a, point b) noexcept
3864
return a;
3965
}
4066

67+
constexpr point& operator-=(point& a, point b) noexcept
68+
{
69+
a.x -= b.x;
70+
a.y -= b.y;
71+
return a;
72+
}
73+
4174
constexpr void swap(point& a, point& b) noexcept
4275
{
4376
point const c = a;

0 commit comments

Comments
 (0)