Skip to content

Commit 8007c4e

Browse files
committed
! Fix scroll to seek/change volume/playback rate changing too fast with touchpad
1 parent 765452d commit 8007c4e

File tree

2 files changed

+74
-25
lines changed

2 files changed

+74
-25
lines changed

src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
import {
2323
addKeyboardShortcutToActionTitle,
2424
showToast,
25-
writeFileWithPicker
25+
writeFileWithPicker,
26+
throttle,
2627
} from '../../helpers/utils'
2728

2829
/** @typedef {import('../../helpers/sponsorblock').SponsorBlockCategory} SponsorBlockCategory */
@@ -944,13 +945,13 @@ export default defineComponent({
944945

945946
if (event.ctrlKey || event.metaKey) {
946947
if (videoPlaybackRateMouseScroll.value) {
947-
mouseScrollPlaybackRate(event)
948+
mouseScrollPlaybackRateHandler(event)
948949
}
949950
} else {
950951
if (videoVolumeMouseScroll.value) {
951-
mouseScrollVolume(event)
952+
mouseScrollVolumeHandler(event)
952953
} else if (videoSkipMouseScroll.value) {
953-
mouseScrollSkip(event)
954+
mouseScrollSkipHandler(event)
954955
}
955956
}
956957
}
@@ -988,7 +989,7 @@ export default defineComponent({
988989
}
989990

990991
// make scrolling over volume slider change the volume
991-
container.value.querySelector('.shaka-volume-bar').addEventListener('wheel', mouseScrollVolume)
992+
container.value.querySelector('.shaka-volume-bar').addEventListener('wheel', mouseScrollVolumeHandler)
992993

993994
// title overlay when the video is fullscreened
994995
// placing this inside the controls container so that we can fade it in and out at the same time as the controls
@@ -1968,56 +1969,79 @@ export default defineComponent({
19681969

19691970
// #region mouse scroll handlers
19701971

1972+
const mouseScrollThrottleWaitMs = 100
1973+
19711974
/**
19721975
* @param {WheelEvent} event
19731976
*/
19741977
function mouseScrollPlaybackRate(event) {
1975-
event.preventDefault()
1976-
19771978
if ((event.deltaY < 0 || event.deltaX > 0)) {
19781979
changePlayBackRate(0.05)
19791980
} else if ((event.deltaY > 0 || event.deltaX < 0)) {
19801981
changePlayBackRate(-0.05)
19811982
}
19821983
}
1984+
const mouseScrollPlaybackRateThrottle = throttle(mouseScrollPlaybackRate, mouseScrollThrottleWaitMs)
1985+
/**
1986+
* @param {WheelEvent} event
1987+
*/
1988+
function mouseScrollPlaybackRateHandler(event) {
1989+
event.preventDefault()
1990+
1991+
mouseScrollPlaybackRateThrottle(event)
1992+
}
19831993

19841994
/**
19851995
* @param {WheelEvent} event
19861996
*/
19871997
function mouseScrollSkip(event) {
1998+
if ((event.deltaY < 0 || event.deltaX > 0)) {
1999+
seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), true)
2000+
} else if ((event.deltaY > 0 || event.deltaX < 0)) {
2001+
seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), true)
2002+
}
2003+
}
2004+
const mouseScrollSkipThrottle = throttle(mouseScrollSkip, mouseScrollThrottleWaitMs)
2005+
/**
2006+
* @param {WheelEvent} event
2007+
*/
2008+
function mouseScrollSkipHandler(event) {
19882009
if (canSeek()) {
19892010
event.preventDefault()
19902011

2012+
mouseScrollSkipThrottle(event)
2013+
}
2014+
}
2015+
2016+
/**
2017+
* @param {WheelEvent} event
2018+
*/
2019+
function mouseScrollVolume(event) {
2020+
const video_ = video.value
2021+
2022+
if (video_.muted && (event.deltaY < 0 || event.deltaX > 0)) {
2023+
video_.muted = false
2024+
video_.volume = 0
2025+
}
2026+
2027+
if (!video_.muted) {
19912028
if ((event.deltaY < 0 || event.deltaX > 0)) {
1992-
seekBySeconds(defaultSkipInterval.value * player.getPlaybackRate(), true)
2029+
changeVolume(0.05)
19932030
} else if ((event.deltaY > 0 || event.deltaX < 0)) {
1994-
seekBySeconds(-defaultSkipInterval.value * player.getPlaybackRate(), true)
2031+
changeVolume(-0.05)
19952032
}
19962033
}
19972034
}
1998-
2035+
const mouseScrollVolumeThrottle = throttle(mouseScrollVolume, mouseScrollThrottleWaitMs)
19992036
/**
20002037
* @param {WheelEvent} event
20012038
*/
2002-
function mouseScrollVolume(event) {
2039+
function mouseScrollVolumeHandler(event) {
20032040
if (!event.ctrlKey && !event.metaKey) {
20042041
event.preventDefault()
20052042
event.stopPropagation()
20062043

2007-
const video_ = video.value
2008-
2009-
if (video_.muted && (event.deltaY < 0 || event.deltaX > 0)) {
2010-
video_.muted = false
2011-
video_.volume = 0
2012-
}
2013-
2014-
if (!video_.muted) {
2015-
if ((event.deltaY < 0 || event.deltaX > 0)) {
2016-
changeVolume(0.05)
2017-
} else if ((event.deltaY > 0 || event.deltaX < 0)) {
2018-
changeVolume(-0.05)
2019-
}
2020-
}
2044+
mouseScrollVolumeThrottle(event)
20212045
}
20222046
}
20232047

src/renderer/helpers/utils.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,3 +1043,28 @@ export function debounce(func, wait) {
10431043
}, wait)
10441044
}
10451045
}
1046+
1047+
/**
1048+
* @template {Function} T
1049+
* @param {T} func
1050+
* @param {number} wait
1051+
* @returns {T}
1052+
*/
1053+
export function throttle(func, wait) {
1054+
let isWaiting
1055+
1056+
// Using a fully fledged function here instead of an arrow function
1057+
// so that we can get `this` and pass it onto the original function.
1058+
// Vue components using the options API use `this` alot.
1059+
return function (...args) {
1060+
const context = this
1061+
if (!isWaiting) {
1062+
func.apply(context, args)
1063+
1064+
isWaiting = true
1065+
setTimeout(() => {
1066+
isWaiting = false
1067+
}, wait)
1068+
}
1069+
}
1070+
}

0 commit comments

Comments
 (0)